-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Slightly improve MinOpts JIT TP #105250
Slightly improve MinOpts JIT TP #105250
Conversation
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch |
assert(compMinOptsIsSet); | ||
return canUseAllOpts; | ||
} | ||
bool Tier0OptimizationEnabled() const |
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.
A minor nit is that OptimizationEnabled
and Tier0OptimizationEnabled
both existing may be a bit confusing. Is there any idea what we would call the levels if this were some kind of OptimizationLevel
enum, just for ideas on what we could call it as an alternative?
I think this is fine for now, because getting better names is a more involved change; just wanted to check if there were any other ideas/suggestions for the interim
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.
Yep, I agree that it doesn't look pretty, but a proper refactoring will be quite big and hard to review
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.
any idea what we would call the levels if this were some kind of OptimizationLevel enum, just for ideas on what we could call it as an alternative?
Not yet. Andy suggested to use OptLevel: NoOpts, Size, Speed where Size implies "light-weight". The problem that we already have optLevel in jit, but we never use it (it's always Blended) so it all needs some re-thinking
} | ||
|
||
unsigned level = 1; | ||
if (tree->OperIsSimple()) |
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.
nit: Might be worth a small comment saying that we are intentionally not handling hwintrinsics (they otherwise normally support GTF_REVERSE_OPS and other considerations).
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'll add a comment, but we skip a lot of trees here, it was driven by asmdiff + tpdiff results
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.
but we skip a lot of trees here
👍, had mostly thought it might be worth a callout because it normally mirrors a lot of the SimpleOp
handling (unlike any other node), so figured it might be worth a special note/callout
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.
This LGTM and is a very nice improvement overall.
Couple questions and one missed place where the new logic could also be used.
@jakobbotsch @tannergooding cc @dotnet/jit-contrib Could you please take another look as I've pushed more changes since your last approve. TL;DR: I've introduced a stripped version of As we discussed in Discord, it might makes sense to introduce a single IR walk e.g. before Rationalization to do the swap where profitable, but I am leaving this for a future PR. Diffs with noticeable improvements for MinOpts as expected. |
// We don't re-order operands in LIR anyway. | ||
return 0; |
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.
Does it ever get called?
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.
Does it ever get called?
Not sure, but the original function gtSetEvalOrder
contained this check
// Check for a nilary operator | ||
if (op1 == nullptr) | ||
{ | ||
assert(op2 == 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.
In what cases do we get here?
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 also copied from the original function. Looks like GT_RETURN
for void is so (and RETFILT
)
unsigned levelOp2 = gtSetEvalOrderMinOpts(op2); | ||
|
||
bool allowSwap = true; | ||
// TODO: Introduce a function to check whether we can swap the order of its operands or not. |
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.
Should this TODO be removed? Not sure I understand what it refers to. If it refers to extract the below logic into a function, why not just do that in this PR?
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'd better remove the comment then for now, I don't mind. The idea is to share quirks with the Tier1 version (esp for STOREIND/STORE_BLK)
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.
Might be useful enough to leave a comment that it should be kept in sync with the quirks in the tier 1 version (and likewise in the tier 1 version)
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.
Moved both to a single helper, to keep the quirks in one place
src/coreclr/jit/gentree.cpp
Outdated
} | ||
|
||
// In case op2 assigns to a local var that is used in op1, we have to evaluate op1 first. | ||
if (gtMayHaveStoreInterference(op2, op1)) |
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.
You probably don't need this expensive version in MinOpts. It can be the conservative (op2->gtFlags & GTF_ASG) != 0
that existed before #97409.
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.
You probably don't need this expensive version in MinOpts. It can be the conservative
(op2->gtFlags & GTF_ASG) != 0
that existed before #97409.
just tried - it adds +28k bytes size regression for benchmarks.run_pgo
collection
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.
Ah ok, fine to leave it then. (Actually looks like I called out explicitly doing it in MinOpts in that PR as well)
A few tricks to mitigate regressions which raised concerns in #105190
PS: I still want to rewrite all OptimizationEnabled/Disabled into an OptLevel like Andy once suggested, but didn't want to do it here.