-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Next round of Struct Improvements #36146
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -3665,31 +3665,21 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call) | |
| #else // UNIX_AMD64_ABI | ||
| // On Unix, structs are always passed by value. | ||
| // We only need a copy if we have one of the following: | ||
| // - We have a lclVar that has been promoted and is passed in registers. | ||
| // - The sizes don't match for a non-lclVar argument. | ||
| // - We have a known struct type (e.g. SIMD) that requires multiple registers. | ||
| // TODO-Amd64-Unix-CQ: The first case could and should be handled without copies. | ||
| // TODO-Amd64-Unix-Throughput: We don't need to keep the structDesc in the argEntry if it's not | ||
| // actually passed in registers. | ||
| if (argEntry->isPassedInRegisters()) | ||
| { | ||
| assert(argEntry->structDesc.passedInRegisters); | ||
| if (lclVar != nullptr) | ||
| { | ||
| if (lvaGetPromotionType(lclVar->AsLclVarCommon()->GetLclNum()) == | ||
| PROMOTION_TYPE_INDEPENDENT) | ||
| { | ||
| copyBlkClass = objClass; | ||
| } | ||
| } | ||
| else if (argObj->OperIs(GT_OBJ)) | ||
| if (argObj->OperIs(GT_OBJ)) | ||
| { | ||
| if (passingSize != structSize) | ||
| { | ||
| copyBlkClass = objClass; | ||
| } | ||
| } | ||
| else | ||
| else if (lclVar == nullptr) | ||
| { | ||
| // This should only be the case of a value directly producing a known struct type. | ||
| assert(argObj->TypeGet() != TYP_STRUCT); | ||
|
|
@@ -9720,7 +9710,9 @@ GenTree* Compiler::fgMorphInitBlock(GenTree* tree) | |
| } | ||
| #endif // LOCAL_ASSERTION_PROP | ||
|
|
||
| if (destLclVar->lvPromoted) | ||
| // If we have already determined that a promoted TYP_STRUCT lclVar will not be enregistered, | ||
| // we are better off doing a block init. | ||
| if (destLclVar->lvPromoted && (!destLclVar->lvDoNotEnregister || !destLclNode->TypeIs(TYP_STRUCT))) | ||
| { | ||
| GenTree* newTree = fgMorphPromoteLocalInitBlock(destLclNode->AsLclVar(), initVal, blockSize); | ||
|
|
||
|
|
@@ -10604,15 +10596,30 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree) | |
| // Are both dest and src promoted structs? | ||
| if (destDoFldAsg && srcDoFldAsg) | ||
| { | ||
| // Both structs should be of the same type, or each have a single field of the same type. | ||
| // Both structs should be of the same type, or have the same number of fields of the same type. | ||
| // If not we will use a copy block. | ||
| if (lvaTable[destLclNum].lvVerTypeInfo.GetClassHandle() != | ||
| lvaTable[srcLclNum].lvVerTypeInfo.GetClassHandle()) | ||
| bool misMatchedTypes = false; | ||
| if (destLclVar->lvVerTypeInfo.GetClassHandle() != srcLclVar->lvVerTypeInfo.GetClassHandle()) | ||
| { | ||
| unsigned destFieldNum = lvaTable[destLclNum].lvFieldLclStart; | ||
| unsigned srcFieldNum = lvaTable[srcLclNum].lvFieldLclStart; | ||
| if ((lvaTable[destLclNum].lvFieldCnt != 1) || (lvaTable[srcLclNum].lvFieldCnt != 1) || | ||
| (lvaTable[destFieldNum].lvType != lvaTable[srcFieldNum].lvType)) | ||
| if (destLclVar->lvFieldCnt != srcLclVar->lvFieldCnt) | ||
| { | ||
| misMatchedTypes = true; | ||
| } | ||
| else | ||
| { | ||
| for (int i = 0; i < destLclVar->lvFieldCnt; i++) | ||
| { | ||
| LclVarDsc* destFieldVarDsc = lvaGetDesc(destLclVar->lvFieldLclStart + i); | ||
| LclVarDsc* srcFieldVarDsc = lvaGetDesc(srcLclVar->lvFieldLclStart + i); | ||
| if ((destFieldVarDsc->lvType != srcFieldVarDsc->lvType) || | ||
| (destFieldVarDsc->lvFldOffset != srcFieldVarDsc->lvFldOffset)) | ||
| { | ||
| misMatchedTypes = true; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| if (misMatchedTypes) | ||
| { | ||
| requiresCopyBlock = true; // Mismatched types, leave as a CopyBlock | ||
| JITDUMP(" with mismatched types"); | ||
|
Contributor
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. Can we leave one of them (dst or src) as an independently promoted struct? Set
Contributor
Author
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. That's an interesting question. I don't want to hold up this PR, but I'll file an issue for that. |
||
|
|
||
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.
Could you give me an example when do we generate
ASGbetween structs with different struct handles?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.
There are at least two ways this can happen:
System.Span<Canon>andSystem.Span<String>in an assignment due to an inline.There were about 1500 instances of this on linux/x64 I believe.
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.
Thank you for the explanation.