Skip to content

JIT: Fix GenTree::IsPow2 functions#127615

Open
BoyBaykiller wants to merge 5 commits intodotnet:mainfrom
BoyBaykiller:fix-isPow2
Open

JIT: Fix GenTree::IsPow2 functions#127615
BoyBaykiller wants to merge 5 commits intodotnet:mainfrom
BoyBaykiller:fix-isPow2

Conversation

@BoyBaykiller
Copy link
Copy Markdown
Contributor

@BoyBaykiller BoyBaykiller commented Apr 30, 2026

IsIntegralConstUnsignedPow2 was passing in sign extended value to isPow2. So it wasn't actually unsigned. For example: 1 << 31 would not be recognized as pow2.

Add a UnsignedIntegralValue that gives the zero-extended literal. Use it in IsIntegralConstUnsignedPow2 to fix it's impl.
Also use it in fgMorphUModToAndSub and a place in lower.

@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Apr 30, 2026
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Apr 30, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

@BoyBaykiller
Copy link
Copy Markdown
Contributor Author

@tannergooding

Comment thread src/coreclr/jit/utils.h Outdated
@BoyBaykiller
Copy link
Copy Markdown
Contributor Author

BoyBaykiller commented May 1, 2026

There was an assert failure in arm emitter helper func which I still had to address

@tannergooding
Copy link
Copy Markdown
Member

CC. @dotnet/jit-contrib, @EgorBo, @kg for secondary review

Comment thread src/coreclr/jit/utils.h Outdated
UINT64 lowBitsMask = maxVal - 1;
UINT64 signBitsMask = ~lowBitsMask | (1ULL << (width - 1)); // The high bits must be set, and the top bit
// (sign bit) must be set.
assert((value < maxVal) || ((value & signBitsMask) == signBitsMask));
Copy link
Copy Markdown
Member

@EgorBo EgorBo May 2, 2026

Choose a reason for hiding this comment

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

why do we remove this assert?

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.

my understanding it checks that we properly truncated/sign-extended input

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

After fixing fgMorphUModToAndSub this assert no longer fires. However I am still not sure why it was done in the first place here. Let me know if I should revert this change. @EgorBo

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Like it asserts the bits in value above 'width' are 0. But why? It seems like a unnecessary limitation. My new impl is still fulfilling the contract of the function.

Comment thread src/coreclr/jit/gentree.h Outdated
Copy link
Copy Markdown
Member

@EgorBo EgorBo left a comment

Choose a reason for hiding this comment

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

if (bitOp->IsIntegralConstUnsignedPow2())
{
INT64 bit = bitOp->AsIntConCommon()->IntegralValue();

While you change the behavior of this functions to ignore upper bits, it seems like we have uses where that is not expected, we need to inspect them all and fix, otherwise you're introducing a correctness issue

@EgorBo
Copy link
Copy Markdown
Member

EgorBo commented May 2, 2026

if (bitOp->IsIntegralConstUnsignedPow2())
{
INT64 bit = bitOp->AsIntConCommon()->IntegralValue();

While you change the behavior of this functions to ignore upper bits, it seems like we have uses where that is not expected, we need to inspect them all and fix, otherwise you're introducing a correctness issue

from a quick look, another instance of that in fgMorphUModToAndSub

@BoyBaykiller
Copy link
Copy Markdown
Contributor Author

BoyBaykiller commented May 2, 2026

The problem is I am not even sure what IsIntegralConstUnsignedPow2() was meant to do in the first place which is why I originally just called popcnt(x) == 1 in my other PR and added a GenTree::UnsignedIntegralValue() thing that gives the zero-extended value.

It seems like existing callers of this function want to know if there is only a single bit set. For example the fgMorphUModToAndSub opt can only be performed in that case - so that's fine and I don't see any issue here. The diffs show that it enables the previously missed 1<<31 case.

Regarding the RISCV code in lower. I am not sure it is doing what the author intended.
We have:

// If 'test' is a single bit test...
//
if (bitOp->IsIntegralConstUnsignedPow2())
{
    INT64 bit  = bitOp->AsIntConCommon()->IntegralValue();
    int   log2 = BitOperations::Log2((UINT64)bit);
    bitOp->AsIntConCommon()->SetIntegralValue(log2);
    return true;
}

The Log2 here must be here to find the bit position. But the code is using bitOp->AsIntConCommon()->IntegralValue() which as we know sign extends values. So this code now gets entered for 1<<31 but then fails with it's assumptions at log2 because bitOp->AsIntConCommon()->IntegralValue() gives us a value with the upper 32 bits set.

I think we should add back my GenTree::UnsignedIntegralValue() and use that here (as well as in IsIntegralConstUnsignedPow2)

@EgorBo
Copy link
Copy Markdown
Member

EgorBo commented May 2, 2026

I think we should add back my GenTree::UnsignedIntegralValue() and use that here (as well as in IsIntegralConstUnsignedPow2)

I think we should just use truncated value in that RISC-V path

@BoyBaykiller
Copy link
Copy Markdown
Contributor Author

I think we should just use truncated value in that RISC-V path

What's the corresponding API for getting such "truncated value"?

* add UnsignedIntegralValue
* use it from IsIntegralConstUnsignedPow2 and riscv bit-opt in lower
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants