-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Optimization for "~x + 1" to "-x" (#69003) #69600
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12913,6 +12913,39 @@ GenTree* Compiler::fgOptimizeAddition(GenTreeOp* add) | |
DEBUG_DESTROY_NODE(add); | ||
return op1; | ||
} | ||
|
||
// Fold (~x + GT_CNS_INT/GT_CNS_LNG) to ((GT_CNS_INT/GT_CNS_LNG - 1) - x). | ||
// Ex. (~x + 2) = (1 - x) | ||
if (op1->OperIs(GT_NOT) && op2->IsIntegralConst() && | ||
(op2->AsIntCon()->IconValue() > 1 || op2->AsIntCon()->IconValue() < 1)) | ||
{ | ||
|
||
add->SetOper(GT_SUB); | ||
|
||
add->gtOp1 = op2; | ||
GenTreeIntCon* constOp2 = op2->AsIntCon(); | ||
constOp2->SetValueTruncating(constOp2->IconValue() - 1); | ||
|
||
add->gtOp2 = op1->AsOp()->gtGetOp1(); | ||
DEBUG_DESTROY_NODE(op1); | ||
|
||
return add; | ||
} | ||
|
||
// Fold (-1 - (~x)) to x | ||
if ((op1->OperIs(GT_NEG) && op1->AsOp()->gtGetOp1()->OperIs(GT_NOT)) && | ||
op2->IsIntegralConst(-1)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be better to do this as two separate transforms There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had played with it and tried different variations, but there were not any occurrences in SPMI, so I reverted the changes. |
||
{ | ||
GenTree* res = op1->AsOp()->gtGetOp1()->AsOp()->gtGetOp1(); | ||
res->SetVNsFromNode(add); | ||
|
||
DEBUG_DESTROY_NODE(op1); | ||
DEBUG_DESTROY_NODE(op2); | ||
DEBUG_DESTROY_NODE(add); | ||
return res; | ||
} | ||
|
||
|
||
} | ||
|
||
return nullptr; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jakobbotsch I added this code to support compilation of
(~x + 2)
as shown here https://godbolt.org/z/TqTfq3dEqI don't like this part tho, because it generates worse diffs and I don't like that I have to to put Const Node to the left.
Diff with this code
Diff without this code
What do you think of this part of code? Have I missed anything which makes the diffs worse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see that other code in the JIT leaves
-a + C
alone:runtime/src/coreclr/jit/morph.cpp
Lines 12883 to 12893 in f832309
I would do the same here to avoid introducing this pattern with a constant on the left.
Besides, it is not clear that
C - x
is always preferred over~x + C
as it requires an extra register on x86/x64. The JIT does not have mechanism for picking between two forms like this depending on register pressure.So I think you should go back to just optimizing
~x + 1
. You can also experiment with~x + C => -x + (C - 1)
and see if that unlocks further optimizations (you can check occurrences in SPMI).