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

Skip to content

JIT: Add morphing to LE_UN/GT_UN(expr, uint.MaxValue) (dotnet#76525) #113037

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

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

Conversation

shunkino
Copy link

@shunkino shunkino commented Mar 2, 2025

Add morphing for comparison between uint.MaxValue and a ulong value.

Contribute to: #76525

@Copilot Copilot AI review requested due to automatic review settings March 2, 2025 00:09
@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 Mar 2, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Mar 2, 2025
Copy link
Contributor

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

@shunkino
Copy link
Author

shunkino commented Mar 2, 2025

@dotnet-policy-service agree company="Microsoft"

@EgorBo
Copy link
Member

EgorBo commented Mar 2, 2025

Seems like CI failed with

 ISSUE: <ASSERT> #263216 D:\a\_work\1\s\src\coreclr\jit\codegenxarch.cpp (4912) - Assertion failed 'operandReg != REG_RCX' in 'bug.Program:TestEntryPoint():int' during 'Generate code' (IL size 42; hash 0x8feb9733; FullOpts)

GenTreeOp* shiftNode = gtNewOperNode(GT_RSZ, TYP_LONG, op1, icon32);
shiftNode->SetMorphed(this);

cmp->gtOp1 = shiftNode;
Copy link
Member

@EgorBo EgorBo Mar 2, 2025

Choose a reason for hiding this comment

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

EQ/NE(RSZ(expr, 32), 0).

I don't see where that 0 is set here, what is cmp->gtOp2 at this point?

Copy link
Author

Choose a reason for hiding this comment

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

I believe this line sets op2 to 0. All other morphing done in fgOptimizeRelationalComparisonWithConst also don't set 0 explicitly.

op2->SetIntegralValue(0);

@jakobbotsch
Copy link
Member

Seems like CI failed with

 ISSUE: <ASSERT> #263216 D:\a\_work\1\s\src\coreclr\jit\codegenxarch.cpp (4912) - Assertion failed 'operandReg != REG_RCX' in 'bug.Program:TestEntryPoint():int' during 'Generate code' (IL size 42; hash 0x8feb9733; FullOpts)

That's probably because this PR isn't handling the things pointed out here: #76525 (comment)

@shunkino
Copy link
Author

Seems like CI failed with

 ISSUE: <ASSERT> #263216 D:\a\_work\1\s\src\coreclr\jit\codegenxarch.cpp (4912) - Assertion failed 'operandReg != REG_RCX' in 'bug.Program:TestEntryPoint():int' during 'Generate code' (IL size 42; hash 0x8feb9733; FullOpts)

That's probably because this PR isn't handling the things pointed out here: #76525 (comment)

Thank you for pointing it out. Will check the issue comment and fix.

@shunkino shunkino force-pushed the jit-uint-maxvalue-compare-76525 branch 2 times, most recently from 4fe1edc to 907e97c Compare March 25, 2025 05:09
Comment on lines 4184 to 4190
#ifdef TARGET_XARCH
// Do not optimize, BMI2 shrx does not set zero flag
if (op1->OperIs(GT_RSZ) && !op1->AsOp()->gtGetOp2()->OperIsConst())
{
return cmp;
}
#endif // TARGET_XARCH
Copy link
Author

Choose a reason for hiding this comment

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

Seems like CI failed with

 ISSUE: <ASSERT> #263216 D:\a\_work\1\s\src\coreclr\jit\codegenxarch.cpp (4912) - Assertion failed 'operandReg != REG_RCX' in 'bug.Program:TestEntryPoint():int' during 'Generate code' (IL size 42; hash 0x8feb9733; FullOpts)

That's probably because this PR isn't handling the things pointed out here: #76525 (comment)

@jakobbotsch I've implemented the exclusion logic based on your comment. Can you check this? I've thought of checking op2 in LowerShift() and set the flag which tells OptimizeConstCompare() not to optimize, but I think that's redundant and went for directly checking op2 of GT_RSZ here.

@@ -4181,6 +4181,13 @@ GenTree* Lowering::OptimizeConstCompare(GenTree* cmp)
if (cmp->OperIs(GT_EQ, GT_NE) && op2->IsIntegralConst(0) && op1->SupportsSettingZeroFlag() &&
BlockRange().TryGetUse(cmp, &use))
{
#ifdef TARGET_XARCH
// Do not optimize, BMI2 shrx does not set zero flag
if (op1->OperIs(GT_RSZ) && !op1->AsOp()->gtGetOp2()->OperIsConst())
Copy link
Member

Choose a reason for hiding this comment

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

Can you introduce a function like IsProfitableToSetZeroFlag and put this in there, and check it from the if above? Mainly in case more optimizations get added in the future which we would not want to skip for RSZ.

Also, I think SupportsSettingZeroFlag can work for all shifts and rotations and this profitability check should also happen for those (at the minimum this should also check GT_RSH).

Copy link
Author

Choose a reason for hiding this comment

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

@jakobbotsch
Moved this logic to IsProfitableToSetZeroFlag function. Also, added several operations to SupportsSettingZeroFlag for future optimizations.

@jakobbotsch
Copy link
Member

There are some cases in the diffs where the optimization is not kicking in:
image

Can you check why?

@jakobbotsch
Copy link
Member

I just noticed that the above was a tier 0 method. It looks like fgOptimizeRelationalComparisonWithConst runs even in tier 0.
Can you add an OptimizationEnabled check to the case you are introducing in fgOptimizeRelationalComparisonWithConst since it relies on further optimizations in the backend to happen?

* Add morphing for comparison between uint.MaxValue and a ulong value.
* Remove assertions, which no longer is relevant.
* Add a check to lsra to only use BMI2 if zero flag will not be set.
* Add a profitability check to optimize EQ/NE(op, 0) only if op has constant operand.
@shunkino shunkino force-pushed the jit-uint-maxvalue-compare-76525 branch from 907e97c to 440adf9 Compare March 31, 2025 15:58
bool Lowering::IsProfitableToSetZeroFlag(GenTree* op) const
{
#ifdef TARGET_XARCH
if (op->OperIs(GT_LSH, GT_RSH, GT_RSZ, GT_ROR))
Copy link
Author

Choose a reason for hiding this comment

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

I've listed all ops that might set zero flag (GT_LSH, GT_RSH, GT_RSZ, GT_ROL, GT_ROR) in SupportsSettingZeroFlag, and filter it here to check if BMI2 version exists.

Copy link
Member

Choose a reason for hiding this comment

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

Is it missing GT_ROL?

Copy link
Author

@shunkino shunkino Apr 8, 2025

Choose a reason for hiding this comment

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

As far as I was able to search, there seems to be no operation for shift left on BMI2. So, I droped it from this if statement.
https://en.wikipedia.org/wiki/X86_instruction_listings

RORX reg,r/m,imm8 VEX.LZ.F2.0F3A F0 /r ib Rotate right by immediate without affecting flags.
SARX ra,r/m,rb VEX.LZ.F3.0F38 F7 /r Arithmetic shift right without updating flags.For SARX, SHRX and SHLX, the shift-amount specified in rb is masked to 5 bits for 32-bit operand size and 6 bits for 64-bit operand size.
SHRX ra,r/m,rb VEX.LZ.F2.0F38 F7 /r Logical shift right without updating flags.
SHLX ra,r/m,rb VEX.LZ.66.0F38 F7 /r Shift left without updating flags.

Copy link
Member

@saucecontrol saucecontrol Apr 22, 2025

Choose a reason for hiding this comment

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

We use rorx for GT_ROL under the same conditions we would use it for GT_ROR.

// There is no 'rolx', so for rol, we use rorx with the shift value adjusted.
if (tree->OperIs(GT_ROL))
{
shiftByValue &= (size * BITS_PER_BYTE - 1);
shiftByValue = (size * BITS_PER_BYTE - shiftByValue);
}
inst_RV_TT_IV(INS_rorx, size, tree->GetRegNum(), operand, shiftByValue, INS_OPTS_NONE);

Copy link
Author

Choose a reason for hiding this comment

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

Thank you for pointing this out. I'll put GT_ROL to the criteria.

@jakobbotsch
Copy link
Member

/azp run Fuzzlyn

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@shunkino
Copy link
Author

Hi @jakobbotsch, I tried to review the Fuzzlyn results, but there are many errors that I’m having trouble interpreting. Sorry to bother you, but could you help me understand what they mean or guide me on how to proceed? Thanks in advance!

@jakobbotsch
Copy link
Member

I think the Fuzzlyn found issues are unrelated to this PR. I need to take another look, but I don't think anything more is needed from your side.

@jakobbotsch jakobbotsch self-requested a review April 17, 2025 09:43
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.

4 participants