-
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
Conversation
Tagging subscribers to this area: @JulieLeeMSFT Issue DetailsI added the optimization and marked the PR as a draft until it is checked by reviewers.
|
src/coreclr/jit/morph.cpp
Outdated
// Fold (~x + 1) to -x. | ||
if (op1->OperIs(GT_NOT) && op2->IsIntegralConst(1)) | ||
{ | ||
op1->SetOper(GT_NEG); |
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.
It's good practice here to call op1->SetVNsFromNode(add)
after this to inherit the VN from the add
. Also, I suggest we move this under OptimizationEnabled()
below.
does it guard against code
expected
actual
|
We generally try to canonicalize constants to the right and restate subtractions with constants in terms of additions with constants. It seems reasonable to me to handle more constants than |
@SkiFoD Sure, @kasperk81 thank you for your notice. |
src/coreclr/jit/morph.cpp
Outdated
// 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; | ||
} |
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/TqTfq3dEq
I 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
// Do not do this if "op2" is constant for canonicalization purposes. | |
if (op1->OperIs(GT_NEG) && !op2->OperIs(GT_NEG) && !op2->IsIntegralConst() && gtCanSwapOrder(op1, op2)) | |
{ | |
add->SetOper(GT_SUB); | |
add->gtOp1 = op2; | |
add->gtOp2 = op1->AsOp()->gtGetOp1(); | |
DEBUG_DESTROY_NODE(op1); | |
return add; | |
} |
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).
src/coreclr/jit/morph.cpp
Outdated
// 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 comment
The 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 -(~x) => x + 1
and ~(-x) => x - 1
. However, I think you should check if there are occurrences in SPMI to see if we should bother with it.
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 had played with it and tried different variations, but there were not any occurrences in SPMI, so I reverted the changes.
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.
LGTM. Thanks for trying some of the additional variations, even if it didn't turn out to be profitable. I'll launch some additional testing.
/azp run Fuzzlyn |
Azure Pipelines successfully started running 1 pipeline(s). |
Sorry, missed that you had marked this as ready. Thanks! |
I added the optimization and marked the PR as a draft until it is checked by reviewers.