Skip to content

[Bits] Use abs(rhs) in getMaxBits for rem_s - #9364

Merged
tlively merged 6 commits into
mainfrom
max-bits-rem-s
Nov 10, 2026
Merged

tlively merged 6 commits into
mainfrom
max-bits-rem-s

Conversation

@tlively

@tlively tlively commented Nov 7, 2026

Copy link
Copy Markdown
Member

Previously, Provider::getMaxBits passed the signed constant divisor directly to ceilLog2 for RemSInt32 and RemSInt64. For negative divisors (other than INT_MIN), converting to unsigned produced a value with the high bit set, causing ceilLog2 to return 32 or 64 and losing precision even when the dividend was known to be non-negative. Take the unsigned absolute value of the divisor before calling ceilLog2 so negative divisors get the same magnitude bit bound as positive ones.

Move makeSignExt, makePackedFieldGet, getSignExtValue, getAlmostSignExt, getZeroExtValue, Provider::getMaxBits, and Provider::getSignExtKeptBits out of src/ir/bits.h into src/ir/bits.cpp, and add missing direct #includes to files that previously relied on transitive includes from bits.h.
Previously, Provider::getMaxBits passed the signed constant divisor directly to ceilLog2 for RemSInt32 and RemSInt64. For negative divisors (other than INT_MIN), converting to unsigned produced a value with the high bit set, causing ceilLog2 to return 32 or 64 and losing precision even when the dividend was known to be non-negative. Take the unsigned absolute value of the divisor before calling ceilLog2 so negative divisors get the same magnitude bit bound as positive ones.
@tlively
tlively requested a review from a team as a code owner November 7, 2026 03:14
@tlively
tlively requested review from stevenfontanella and removed request for a team November 7, 2026 03:15

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request updates Provider::getMaxBits in src/ir/bits.cpp to handle negative divisors by calculating their absolute value as unsigned integers before computing ceilLog2. This enables optimizations like folding redundant masks for negative constant divisors, which is verified by the newly added unit and integration tests. The review feedback points out that applying the unary minus operator to unsigned types (e.g., -uint32_t(rhs)) can trigger MSVC warning C4146, potentially breaking builds that treat warnings as errors. It is recommended to use the suggested 0 - uint32_t(rhs) and 0 - uint64_t(rhs) alternatives to avoid this warning.

Comment thread src/ir/bits.cpp Resolved
Comment thread src/ir/bits.cpp Resolved
Base automatically changed from bits-cpp to main November 9, 2026 18:38
Comment thread src/cfg/cfg-traversal.h

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 did all this change?

Comment thread src/ir/bits.h

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.

Looks like this moves a large amount of code out from a header into source files - can we do that as an NFC PR first? Otherwise, the actual rem_s change is hard to pinpoint.

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.

Yes, this actually includes an NFC PR that already landed. Merged main to clean up the diff now.

Comment thread test/example/cpp-unit.cpp
assert_equal(getMaxBits(&b), 3);
c0.value = Literal(int32_t(-1));
c1.value = Literal(int32_t(-4));
assert_equal(getMaxBits(&b), 32);

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.

The rhs is -4, which in absolute value is 4, which is 2 bits. Shouldn't the result be 2 and not 32?

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.

+1 same question. LGTM otherwise

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.

That comes from here: https://github.com/WebAssembly/binaryen/pull/9364/changes#diff-6ff45ddead31428b20efeba2b73d4e2c4764eb01d31eec2ab168a656e9de78e0R213-R216. It reasons that if the left hand side can be negative, so can the result.

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.

Hmm, can we remove that pre-existing bit, then? Can leave it to later, maybe with a TODO in the tests that give odd results atm.

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.

No, that is important for correctness in general. For example, in this test: https://github.com/WebAssembly/binaryen/pull/9364/changes#diff-a94a68e8de6450424e23594987df4a57904920644e71a2f3fb5c481a41ebe1d2R9666-R9676

The only reason that you, the reader, know there is a more precise answer here is because you're looking at a concrete value on the LHS, and not just a judgment of its maximum bits. We could get the more precise result by specifically handling the case where the LHS and RHS are both constants, but that's better left to Precompute.

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.

Actually, IIUC, -1 %s -4 == -1, so this is already a fully precise result.

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.

Right, a signed value being divided... I forgot that.

@tlively
tlively merged commit 39db7d2 into main Nov 10, 2026
18 checks passed
@tlively
tlively deleted the max-bits-rem-s branch November 10, 2026 23:31
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.

3 participants