Skip to content
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 for x ^ 0 opt (#65071) #65072

Merged
merged 5 commits into from
Mar 28, 2022
Merged

Draft for x ^ 0 opt (#65071) #65072

merged 5 commits into from
Mar 28, 2022

Conversation

SkiFoD
Copy link
Contributor

@SkiFoD SkiFoD commented Feb 9, 2022

@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 Feb 9, 2022
@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Feb 9, 2022
@ghost
Copy link

ghost commented Feb 9, 2022

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

Issue Details

#65071

Author: SkiFoD
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -


return op1;
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Consider moving to morph, e.g. x*0 -> 0:

runtime/src/coreclr/jit/morph.cpp

Lines 13723 to 13733 in fe24ab3

if (mult == 0)
{
// We may be able to throw away op1 (unless it has side-effects)
if ((op1->gtFlags & GTF_SIDE_EFFECT) == 0)
{
DEBUG_DESTROY_NODE(op1);
DEBUG_DESTROY_NODE(mul);
return op2; // Just return the "0" node
}

Copy link
Member

Choose a reason for hiding this comment

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

in theory you can also improve this x * 0 by not giving up on side effects and making a COMMA but it's up to you.
Just make sure you don't drop CSE candidates

Copy link
Contributor Author

Choose a reason for hiding this comment

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

in theory you can also improve this x * 0 by not giving up on side effects and making a COMMA but it's up to you. Just make sure you don't drop CSE candidates

Could you give me more details about this? I'm a very newbie in the project and a lot of obvious things are not that obvious for me yet😊

Copy link
Contributor

Choose a reason for hiding this comment

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

Don't worry, none of those things were obvious, :)

@EgorBo
Copy link
Member

EgorBo commented Feb 9, 2022

Btw, we already have X ^ 0 -> X in morph, but for Vectors 😄

src/coreclr/jit/morph.cpp Outdated Show resolved Hide resolved
@SingleAccretion
Copy link
Contributor

I took a look at the regressions. They are caused by missing CSEs of the following form:

-CSE candidate #01, key=$40 in BB01, [cost= 3, size= 3]:
-N003 (  3,  3) CSE #01 (use)[000087] ------------              *  XOR       int    <l:$40, c:$483>
-N001 (  1,  1)              [000085] ------------              +--*  LCL_VAR   int    V07 tmp3         u:2 (last use) <l:$40, c:$483>
-N002 (  1,  1)              [000761] ------------              \--*  CNS_INT   int    0 $40

Apparently those help the RA allocate more optimally (even as otherwise they are clearly not useful - the XOR is a NOP).

(Notably, not always - we have some improvements in these tests as well)

Seeing as the diffs are in basically one test that has been duplicated via code generation, I personally think it would be ok to accept the regressions while leaving the optimization in morph. It should help CSE (and the rest of the frontend) make better decisions in other situations.

src/coreclr/jit/morph.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/morph.cpp Outdated Show resolved Hide resolved
// The optimized tree, currently always a local variable, in case any transformations
// were performed. Otherwise, "nullptr", guaranteeing no state change.
//
GenTree* Compiler::fgOptimizeBitwiseXor(GenTreeOp* xorOp)
Copy link
Contributor

Choose a reason for hiding this comment

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

You could leave a TODO-Cleanup: move the optimizations from "fgMorphSmpOpOptional" to this method..

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I moved the xor related code into this method and noticed that the condition of this branch looks odd to me.

runtime/src/coreclr/jit/morph.cpp

Lines 13901 to 13909 in 3449312

else if (op2->IsIntegralConst(1) && op1->OperIsCompare())
{
/* "binaryVal ^ 1" is "!binaryVal" */
gtReverseCond(op1);
DEBUG_DESTROY_NODE(op2);
DEBUG_DESTROY_NODE(xorOp);
return op1;
}

Is it actually possible for a child node of XOR node to be a compare node? If I'm not wrong then it is a good candidate to be removed and extend the previous condition with || op2->IsIntegralConst(1) since "x ^ -1 " = "~x" and "x ^ 1" = "~x". Correct me if I'm wrong :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Is it actually possible for a child node of XOR node to be a compare node?

Why not?

ldarg 0
ldarg 1
ceq
ldc.i4 1
xor

Would produce a tree that this is looking for. Not sure how often this is hit in practice (you can remove it and see what SPMI tells, I would guess we'll see lots of such patterns in auto-generated IL in tests).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, you are right. Removing the conditions emits 2 small regressions. What do you think of "x ^ 1" = "~x"? A little investigation gives me this diff
diff_summary.17.md
Doesn't look good, does it?

Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think of "x ^ 1" = "~x"?

Are you suggesting to apply it for any x, not just compares? But that would not be correct, it only affects the lowest bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All right. Thank you.

@SkiFoD SkiFoD marked this pull request as ready for review February 10, 2022 11:45
@SingleAccretion
Copy link
Contributor

The code changes LGTM. However, it seems there are real regressions on 32 bit platforms, I took a look - they're all CSE-induced as well. It seems we're better of with CSEing a TYP_LONG LCL_VAR-equivalents with decomposition in the picture (not totally sure why - didn't have time to dig deep).

@dotnet/jit-contrib for opinions.

@JulieLeeMSFT JulieLeeMSFT added this to the 7.0.0 milestone Feb 16, 2022
@EgorBo
Copy link
Member

EgorBo commented Feb 21, 2022

@SkiFoD sorry for the delay, could you please rebase your PR against latest Main? so we can kick spmi once again

@EgorBo
Copy link
Member

EgorBo commented Mar 14, 2022

@SkiFoD I'm really sorry, was distracted a bit - could you please resolve the conflict and tag me back so we can merge it?

@SkiFoD
Copy link
Contributor Author

SkiFoD commented Mar 15, 2022

@EgorBo I updated the branch and run SPMI once again. I got confussed by the results so I'd like to know your opinion on them.

src/coreclr/jit/morph.cpp Outdated Show resolved Hide resolved
else if (op2->IsIntegralConst(1) && op1->OperIsCompare())
{
/* "binaryVal ^ 1" is "!binaryVal" */
gtReverseCond(op1);
Copy link
Member

Choose a reason for hiding this comment

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

I realize that it's not your code but it looks weird that it doesn't use return value

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I see it modifies the node if it's OperIsCompare

@EgorBo
Copy link
Member

EgorBo commented Mar 15, 2022

Looks good to me, thanks! let's wait for the last job to finish

@EgorBo EgorBo merged commit 071e772 into dotnet:main Mar 28, 2022
@EgorBo
Copy link
Member

EgorBo commented Mar 28, 2022

@SkiFoD thank you for the contribution!

@SkiFoD
Copy link
Contributor Author

SkiFoD commented Mar 28, 2022

@SingleAccretion @EgorBo Thank you both for guiding me through. Learnt a lot, Pleasure to work with you.

@ghost ghost locked as resolved and limited conversation to collaborators Apr 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
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.

5 participants