Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fold "X < NN && X >= 0" to "X u>= NN" #115240

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Conversation

EgorBo
Copy link
Member

@EgorBo EgorBo commented May 2, 2025

void Test(int x, int[] arr)
{
    if (x < arr.Length && x >= 0)
        Console.WriteLine();
}

codegen diff: https://www.diffchecker.com/x8sugXxP/

Also, I used the logic from #93531 but guarded it under "global prop" only to avoid regressions.

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label May 2, 2025
Copy link
Contributor

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

@@ -5551,6 +5551,17 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree,
case GT_NULLCHECK:
return optAssertionProp_Ind(assertions, tree, stmt);

case GT_ARR_LENGTH:
Copy link
Member

Choose a reason for hiding this comment

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

Does this handling mean Span won't quite light up?

Copy link
Member Author

Choose a reason for hiding this comment

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

In this specific case we have ARR_LENGTH(obj) and we try to remove GTF_EXCEPT from ARR_LENGTH node if obj is known to be non-null (e.g. via assertions). It's not needed for span because: 1) in 99% of cases Span is promoted to locals (so the length is a local) 2) null check is not needed for Span anyway

@rhuijben
Copy link

rhuijben commented May 4, 2025

Do you really want to apply this on such a scale?

How about Test(~4, new int[10}); where the behavior changes?

There must be some code relying on these simple checks to just work as expected.

This is a nice optimization under controlled circumstances like Span, but can break spectacular.

@tannergooding
Copy link
Member

How about Test(~4, new int[10}); where the behavior changes?

What change?

~4 becomes -5. X < NN is therefore -5 < 10 which is true so it evaluates the second half where -5 >= 0 which would be false

It transforms that to (unsigned)x < NN. So we get 4294967291 < 10 which is false.

— In general x < NN && x >= 0 to X u< NN and x >= NN || x < 0 to X u>= NN are safe transforms provided the NN condition is met (which more specifically means the most significant bit isn’t set, including for unsigned), which is what the transform is limited against.

Speaking of, however, are we handling both forms of the comparison @EgorBo? That is both the && and the || variants to ensure either branching pattern works?

@rhuijben
Copy link

rhuijben commented May 4, 2025

Test(int.MinValye+4) was the case I tried to write. Sorry for the confusion.
This optimization is simply assuming not the whole integer range is used.

You might get away with this if you are at the same time using a bigger types, which may just work on 64 bit depending on processor type. But we can't just break normal integer ranges.

@tannergooding
Copy link
Member

That wouldn’t fail either, it is -2147483644 as signed and 2147483652 as unsigned which is less than 0 and greater than 10, respectively

This transform is safe for any two’s complement integer where NN is known to not have the most significant bit set (and therefore would be never negative if interpreted as a signed value).

@rhuijben
Copy link

rhuijben commented May 4, 2025

Yes, under that assumption the >= 0 check is always true. But with the short sample code it is impossible to prove that it is net set. And using the array length is just any other positive integer as bound as it is not used to access the array. That doesn't say anything about the index integer.

But it looks like the changed code already does 'a fe'w more checks than this simple example code.

@tannergooding
Copy link
Member

The length of an array is statically known to be “never negative” when interpreted as signed, it is an invariant of the runtime and is what makes this safe.

This PR is taking advantage of that invariant

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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants