-
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
[x64][SysV] Classify empty structs for passing like padding #103799
Changes from 2 commits
aba87b6
131a3c5
cb22839
db406a7
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 |
---|---|---|
|
@@ -2114,11 +2114,14 @@ bool MethodTable::ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassi | |
|
||
DWORD numIntroducedFields = GetNumIntroducedInstanceFields(); | ||
|
||
// It appears the VM gives a struct with no fields of size 1. | ||
// Don't pass in register such structure. | ||
if (numIntroducedFields == 0) | ||
{ | ||
return false; | ||
helperPtr->largestFieldOffset = startOffsetOfStruct; | ||
LOG((LF_JIT, LL_EVERYTHING, "%*s**** Classify empty struct %s (%p) like padding, startOffset %d, total struct size %d\n", | ||
nestingLevel * 5, "", this->GetDebugClassName(), this, startOffsetOfStruct, helperPtr->structSize)); | ||
|
||
AssignClassifiedEightByteTypes(helperPtr, nestingLevel); | ||
return true; | ||
} | ||
|
||
// The SIMD Intrinsic types are meant to be handled specially and should not be passed as struct registers | ||
|
@@ -2334,7 +2337,12 @@ bool MethodTable::ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassin | |
// No fields. | ||
if (numIntroducedFields == 0) | ||
{ | ||
return false; | ||
helperPtr->largestFieldOffset = startOffsetOfStruct; | ||
LOG((LF_JIT, LL_EVERYTHING, "%*s**** Classify empty struct %s (%p) like padding, startOffset %d, total struct size %d\n", | ||
nestingLevel * 5, "", this->GetDebugClassName(), this, startOffsetOfStruct, helperPtr->structSize)); | ||
|
||
AssignClassifiedEightByteTypes(helperPtr, nestingLevel); | ||
return true; | ||
} | ||
|
||
bool hasImpliedRepeatedFields = HasImpliedRepeatedFields(this); | ||
|
@@ -2586,8 +2594,12 @@ void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe | |
// Calculate the eightbytes and their types. | ||
|
||
int lastFieldOrdinal = sortedFieldOrder[largestFieldOffset]; | ||
unsigned int offsetAfterLastFieldByte = largestFieldOffset + helperPtr->fieldSizes[lastFieldOrdinal]; | ||
SystemVClassificationType lastFieldClassification = helperPtr->fieldClassifications[lastFieldOrdinal]; | ||
unsigned int lastFieldSize = (lastFieldOrdinal >= 0) ? helperPtr->fieldSizes[lastFieldOrdinal] : 0; | ||
unsigned int offsetAfterLastFieldByte = largestFieldOffset + lastFieldSize; | ||
_ASSERTE(offsetAfterLastFieldByte <= helperPtr->structSize); | ||
SystemVClassificationType lastFieldClassification = (lastFieldOrdinal >= 0) | ||
? helperPtr->fieldClassifications[lastFieldOrdinal] | ||
: SystemVClassificationTypeNoClass; | ||
|
||
unsigned int usedEightBytes = 0; | ||
unsigned int accumulatedSizeForEightBytes = 0; | ||
|
@@ -2614,6 +2626,8 @@ void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe | |
// the SysV ABI spec. | ||
fieldSize = 1; | ||
fieldClassificationType = offset < offsetAfterLastFieldByte ? SystemVClassificationTypeNoClass : lastFieldClassification; | ||
if (offset % SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES == 0) // new eightbyte | ||
foundFieldInEightByte = false; | ||
} | ||
else | ||
{ | ||
|
@@ -2666,13 +2680,16 @@ void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe | |
} | ||
} | ||
|
||
if ((offset + 1) % SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES == 0) // If we just finished checking the last byte of an eightbyte | ||
// If we just finished checking the last byte of an eightbyte or the entire struct | ||
if ((offset + 1) % SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES == 0 || (offset + 1) == helperPtr->structSize) | ||
{ | ||
if (!foundFieldInEightByte) | ||
{ | ||
// If we didn't find a field in an eight-byte (i.e. there are no explicit offsets that start a field in this eightbyte) | ||
// If we didn't find a field in an eightbyte (i.e. there are no explicit offsets that start a field in this eightbyte) | ||
// then the classification of this eightbyte might be NoClass. We can't hand a classification of NoClass to the JIT | ||
// so set the class to Integer (as though the struct has a char[8] padding) if the class is NoClass. | ||
// | ||
// TODO: Fix JIT, NoClass eightbytes are valid and passing them is broken because of this. | ||
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. Do you plan to fix this TODO in this PR? 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. No. It would require going through the JIT like I did in #101796 for RISC-V and fix in many places. Right now my priority is on RISC-V but when I'm done with #101796 I can revisit it. By then @jakobbotsch's ongoing effort to centralize ABI passing infos will probably be more advanced, which will also facilitate fixing x64. |
||
if (helperPtr->eightByteClassifications[offset / SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES] == SystemVClassificationTypeNoClass) | ||
{ | ||
helperPtr->eightByteClassifications[offset / SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES] = SystemVClassificationTypeInteger; | ||
|
@@ -2705,9 +2722,9 @@ void MethodTable::AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHe | |
LOG((LF_JIT, LL_EVERYTHING, " **** Number EightBytes: %d\n", helperPtr->eightByteCount)); | ||
for (unsigned i = 0; i < helperPtr->eightByteCount; i++) | ||
{ | ||
_ASSERTE(helperPtr->eightByteClassifications[i] != SystemVClassificationTypeNoClass); | ||
LOG((LF_JIT, LL_EVERYTHING, " **** eightByte %d -- classType: %s, eightByteOffset: %d, eightByteSize: %d\n", | ||
i, GetSystemVClassificationTypeName(helperPtr->eightByteClassifications[i]), helperPtr->eightByteOffsets[i], helperPtr->eightByteSizes[i])); | ||
_ASSERTE(helperPtr->eightByteClassifications[i] != SystemVClassificationTypeNoClass); | ||
} | ||
#endif // _DEBUG | ||
} | ||
|
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.
What does the difference between NoClass and something like
char[8]
end up being? For significant padding (structs with explicit layout) it seems like we have to consider them to be the same or things will end up odd/wrong.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.
char[8] is an INTEGER eightbyte which gets assigned an integer register for passing; a NO_CLASS eightbyte doesn't get any register. Passing on the stack is the same, though (NO_CLASS padding does take up space).
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.
Opened #104098 as I'll need an URL for ActiveIssue in tests in future PRs.
Meanwhile this smaller fix is ready for 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.
Does this fix handle the significant padding cases correctly (i.e. as before this change)?
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 should, the NO_CLASS -> INTEGER eightbyte reclassification is still there. And I didn't see any CLR tests (prio1) go off on Checked build, assuming there are tests for significant padding by now.