-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Do not promote struct locals with holes #62645
Conversation
Tagging subscribers to this area: @JulieLeeMSFT Issue DetailsIn #43870 , when we added more support for multireg args, we added a check for struct's field count. We didn't check if the total size of struct matched the combined size of both the fields. That led us to generate code that partially copy the struct fields on stack when passing as arguments. Add an explicit check to verify the combined size matches. Fixes: #62597
|
/azp list |
/azp run runtime-coreclr jitstress |
No pipelines are associated with this pull request. |
/azp run runtime-coreclr jitstress |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-coreclr jitstressregs |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run runtime-coreclr libraries-jitstress |
Azure Pipelines successfully started running 1 pipeline(s). |
/azp run Antigen |
/azp run Fuzzlyn |
Azure Pipelines successfully started running 1 pipeline(s). |
@dotnet/jit-contrib |
Azure Pipelines successfully started running 1 pipeline(s). |
src/coreclr/jit/lclvars.cpp
Outdated
if (structPromotionInfo.fieldCnt == 2) | ||
{ | ||
unsigned structSize = varDsc->GetLayout()->GetSize(); | ||
if (structPromotionInfo.fields[0].fldSize * 2 != structSize) |
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.
Wouldn't this be better and more general?
if (structPromotionInfo.fields[0].fldSize * 2 != structSize) | |
if (structPromotionInfo.containsHoles) |
(e.g., why *2
instead of fields[0].fldSize + fields[1].fldSize
?)
Seems like the next condition maybe should also check containsHoles
in case there's an explicit layout struct of a single SIMD field where the explicit layout is larger than the SIMD field
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, I actually had fields[0].fldSize + fields[1].fldSize
but somehow I didn't push that change. Let me do 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.
Looking at the code around, containsHoles
does exactly that, so I should just replace this check with containHoles
. Perhaps I should also add a check for customLayout
the way it is done here:
runtime/src/coreclr/jit/lclvars.cpp
Lines 2018 to 2021 in 7dcb289
else if (varDsc->lvIsMultiRegRet && structPromotionInfo.containsHoles && structPromotionInfo.customLayout) | |
{ | |
JITDUMP("Not promoting multi-reg returned struct local V%02u with holes.\n", lclNum); | |
shouldPromote = false; |
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.
Yes, probably should add && structPromotionInfo.customLayout
as well. I think the logic here is: a default/automatic struct layout might end up with holes due to alignment padding, but users can't depend on values in that padding. However, if the user explicitly set a custom/explicit layout, then we can't depend on the padding/holes being uninteresting.
Is there some easy way to repro this without generating IL at runtime? Dynamic methods bypass tiering (and thus OSR/PGO) and so we won't get as much coverage as we would from a source example. |
I will try to find out. |
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
Any asm diffs?
Presumably this is a back-port candidate
I will post the result once the asmdiff pipeline completes.
That's right. I will start the process once I see the asmdiffs. |
/azp run runtime-coreclr jitstress |
/azp run runtime-coreclr jitstressregs |
/azp run runtime-coreclr libraries-jitstress |
Azure Pipelines successfully started running 1 pipeline(s). |
2 similar comments
Azure Pipelines successfully started running 1 pipeline(s). |
Azure Pipelines successfully started running 1 pipeline(s). |
asmdiffs results: https://dev.azure.com/dnceng/public/_build/results?buildId=1507589&view=ms.vss-build-web.run-extensions-tab The worst difference are around 228 bytes in windows/linux arm64. I also inspected diffs from other platforms, and almost all of them are coming because we stop promoting the
|
I took a quick glance at the code to better understand what's going on, and I noticed something: a comment in |
Your observations are correct @ltrzesniewski. However, currently, the code that checks for "can" and "should" are intermixed and probably we need to separate out some day. I just wanted to have the fix close to the place where we do similar check for "returned struct": runtime/src/coreclr/jit/lclvars.cpp Lines 2018 to 2021 in f18f658
|
/backport to release/6.0 |
Started backporting to release/6.0: https://github.com/dotnet/runtime/actions/runs/1574362543 |
In #43870 , when we added more support for multireg args, we added a check for struct's field count. We didn't check if the total size of struct matched the combined size of both the fields. That led us to generate code that partially copy the struct fields on stack when passing as arguments. Add an explicit check to verify the combined size matches.
Fixes: #62597