Skip to content

ConstraintAnalysis: Parse AND operations - #9075

Merged
kripken merged 59 commits into
WebAssembly:mainfrom
kripken:c.AND
Sep 9, 2026
Merged

ConstraintAnalysis: Parse AND operations#9075
kripken merged 59 commits into
WebAssembly:mainfrom
kripken:c.AND

Conversation

@kripken

@kripken kripken commented Sep 4, 2026

Copy link
Copy Markdown
Member

Handles this common code pattern:

(if
  (i32.and (A) (B))
  (then ..

We can apply both A and B in the first arm, and !(A && B) in the second.

Also pattern-match eqz(eqz(..)) as that is the only way to represent != 0
in a nested position (otherwise, just if (local.get) works, which we already
matched).

@kripken
kripken requested a review from tlively September 4, 2026 15:47
@kripken
kripken requested a review from a team as a code owner September 4, 2026 15:47
Comment thread src/ir/constraint.cpp Outdated
Comment on lines +751 to +752
if (auto* nested = unary->value->dynCast<Unary>()) {
if (Abstract::getUnary(nested->value->type, Abstract::EqZ) ==

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a good place for matches.

Comment thread src/ir/constraint.h
Comment on lines +287 to +289
// Negate the entire list of constraints. If we fail to generate something
// that can be represented as a list of ANDed constraints, the list will be
// empty (i.e., we can prove nothing).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me what the second sentence has to do with negation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It just explains what happens when we fail. Negating A && B does not always lead to something that can be represented as C && D - in general it is C || D.

Comment thread src/ir/constraint.cpp Outdated
Comment on lines +841 to +844
if (auto* binary = curr->dynCast<Binary>()) {
// An AND can be recursively processed: both sides must be true.
if (Abstract::getBinary(binary->left->type, Abstract::And) ==
binary->op) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also be nice to use matches here.

// branch, and use them.
if (auto branch = getBranchConstraints(block, out);
branch && checkRelevancy(*branch)) {
filterRelevant(branch), !branch.empty()) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of the comma operator!

ConstIterator(const Iterator& other)
: wasm::ParentIndexIterator<const inplace_vector<T, N>*, ConstIterator>{
other.parent, other.index} {}
ConstIterator(const ConstIterator& other) = default;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why these changes?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't honestly explain, this is C++ magic beyond my ken...

I was completely stuck on getting this to build, and AI suggested this fix, which works.

Comment thread test/gtest/constraint.cpp

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see new tests for negate. Should there be some?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The else arms in the lit tests check this. I didn't add unit tests on top of that (seemed excessive?)

@kripken

kripken commented Sep 9, 2026

Copy link
Copy Markdown
Member Author

Match usage added.

Comment thread src/ir/constraint.cpp Outdated
Comment on lines +752 to +753
if (Match::matches(unary->value,
Match::unary(Abstract::EqZ, Match::local(&get)))) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best to use using namespace Match; to reduce verbosity here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, though it is annoying as it shadows other locals here, and doesn't work that cleanly. Still shorter I guess.

Comment thread src/ir/constraint.cpp
LocalGet* get;
if (Match::matches(unary->value,
Match::unary(Abstract::EqZ, Match::local(&get)))) {
if (matches(u->value, unary(Abstract::EqZ, Match::local(&get)))) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it doesn't compile without Match:: in front of local, I couldn't figure out... must be overlapping with some other global namespace name

@kripken
kripken merged commit d57c2a8 into WebAssembly:main Sep 9, 2026
16 checks passed
@kripken
kripken deleted the c.AND branch September 9, 2026 23:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants