Skip to content

[NFC] Move larger bits.h functions into bits.cpp - #9362

Open
tlively wants to merge 3 commits into
mainfrom
bits-cpp
Open

tlively wants to merge 3 commits into
mainfrom
bits-cpp

Conversation

@tlively

@tlively tlively commented Nov 7, 2026

Copy link
Copy Markdown
Member

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.

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.
@tlively
tlively requested a review from a team as a code owner November 7, 2026 01:48
@tlively
tlively requested review from stevenfontanella and removed request for a team November 7, 2026 01:49

@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 introduces a new src/ir/bits.cpp file to centralize bit manipulation utilities and updates various headers and build configurations to support this module. The review highlighted a missing direct include for ir/properties.h and identified precision loss issues in the bit-tracking logic for RemSInt32 and RemSInt64 when dealing with negative divisors, providing actionable code suggestions to resolve these bugs.

Comment thread src/ir/bits.cpp
*/

#include "ir/bits.h"
#include "ir/boolean.h"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The header ir/boolean.h is included but not directly used in this file. Instead, Properties::emitsBoolean is used, which is defined in ir/properties.h. To adhere to the principle of direct includes and avoid relying on transitive includes, ir/properties.h should be included directly.

Suggested change
#include "ir/boolean.h"
#include "ir/properties.h"

Comment thread src/ir/bits.cpp
Comment on lines +201 to +210
case RemSInt32: {
if (auto* c = binary->right->dynCast<Const>()) {
auto maxBitsLeft = getMaxBits(binary->left);
// if left may be negative, the result may be negative
if (maxBitsLeft == 32) {
return 32;
}
auto bitsRight = Index(ceilLog2(c->value.geti32()));
return std::min(maxBitsLeft, bitsRight);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

When the divisor c is negative, c->value.geti32() returns a negative value. Passing a negative value to ceilLog2 (which expects an unsigned value) causes it to be cast to a very large unsigned integer, resulting in ceilLog2 returning 32 and losing precision in the bit-tracking analysis. Using the absolute value of the divisor avoids this precision loss.

      case RemSInt32: {
        if (auto* c = binary->right->dynCast<Const>()) {
          auto maxBitsLeft = getMaxBits(binary->left);
          // if left may be negative, the result may be negative
          if (maxBitsLeft == 32) {
            return 32;
          }
          auto val = c->value.geti32();
          auto absVal = val < 0 ? -uint32_t(val) : uint32_t(val);
          auto bitsRight = Index(ceilLog2(absVal));
          return std::min(maxBitsLeft, bitsRight);
        }

Comment thread src/ir/bits.cpp
Comment on lines +297 to +306
case RemSInt64: {
if (auto* c = binary->right->dynCast<Const>()) {
auto maxBitsLeft = getMaxBits(binary->left);
// if left may be negative, the result may be negative
if (maxBitsLeft == 64) {
return 64;
}
auto bitsRight = Index(ceilLog2(c->value.geti64()));
return std::min(maxBitsLeft, bitsRight);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Similar to RemSInt32, when the divisor c is negative, c->value.geti64() returns a negative value. Passing this to ceilLog2 causes a cast to a very large unsigned integer, resulting in ceilLog2 returning 64 and losing precision. Using the absolute value of the divisor avoids this precision loss.

      case RemSInt64: {
        if (auto* c = binary->right->dynCast<Const>()) {
          auto maxBitsLeft = getMaxBits(binary->left);
          // if left may be negative, the result may be negative
          if (maxBitsLeft == 64) {
            return 64;
          }
          auto val = c->value.geti64();
          auto absVal = val < 0 ? -uint64_t(val) : uint64_t(val);
          auto bitsRight = Index(ceilLog2(absVal));
          return std::min(maxBitsLeft, bitsRight);
        }

This branch has not been deployed

No deployments
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.

1 participant