From b766ac8acced779442230a0662ab9ff56c609b74 Mon Sep 17 00:00:00 2001 From: Brian Sullivan Date: Tue, 28 Jun 2016 17:32:33 -0700 Subject: [PATCH] Split the lvIsMultiRegArgOrRet into two bits Currently for all targets that have MultiReg return LclVars we require that they not be struct promoted. But on ARM64 we do allow for MultiReg #argument LclVars to be struct promoted. Thus we have to disentagle this value into two distinct bool values to implement MultiReg returns for Arm64. Commit migrated from https://github.com/dotnet/coreclr/commit/1472efcd7d07a5238a8ed091a628df843d7ad437 --- src/coreclr/src/jit/codegenxarch.cpp | 10 +++++----- src/coreclr/src/jit/compiler.h | 12 +++++++++++- src/coreclr/src/jit/flowgraph.cpp | 6 +++--- src/coreclr/src/jit/gschecks.cpp | 3 ++- src/coreclr/src/jit/importer.cpp | 12 ++++++------ src/coreclr/src/jit/lclvars.cpp | 4 ++-- src/coreclr/src/jit/lower.cpp | 10 +++++----- src/coreclr/src/jit/lowerxarch.cpp | 2 +- src/coreclr/src/jit/morph.cpp | 10 +++++++--- 9 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index 6c356e6..38cbdd1 100755 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -1513,7 +1513,7 @@ CodeGen::genStructReturn(GenTreePtr treeNode) { GenTreeLclVarCommon* lclVar = op1->AsLclVarCommon(); LclVarDsc* varDsc = &(compiler->lvaTable[lclVar->gtLclNum]); - assert(varDsc->lvIsMultiRegArgOrRet); + assert(varDsc->lvIsMultiRegRet); ReturnTypeDesc retTypeDesc; retTypeDesc.InitializeReturnType(compiler, varDsc->lvVerTypeInfo.GetClassHandle()); @@ -2763,11 +2763,11 @@ CodeGen::genMultiRegCallStoreToLocal(GenTreePtr treeNode) assert(varTypeIsStruct(treeNode)); // Assumption: current x64 Unix implementation requires that a multi-reg struct - // var in 'var = call' is flagged as lvIsMultiRegArgOrRet to prevent it from + // var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from // being struct promoted. unsigned lclNum = treeNode->AsLclVarCommon()->gtLclNum; LclVarDsc* varDsc = &(compiler->lvaTable[lclNum]); - noway_assert(varDsc->lvIsMultiRegArgOrRet); + noway_assert(varDsc->lvIsMultiRegRet); GenTree* op1 = treeNode->gtGetOp1(); GenTree* actualOp1 = op1->gtSkipReloadOrCopy(); @@ -2876,11 +2876,11 @@ CodeGen::genMultiRegCallStoreToLocal(GenTreePtr treeNode) assert(varTypeIsLong(treeNode)); // Assumption: current x86 implementation requires that a multi-reg long - // var in 'var = call' is flagged as lvIsMultiRegArgOrRet to prevent it from + // var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from // being promoted. unsigned lclNum = treeNode->AsLclVarCommon()->gtLclNum; LclVarDsc* varDsc = &(compiler->lvaTable[lclNum]); - noway_assert(varDsc->lvIsMultiRegArgOrRet); + noway_assert(varDsc->lvIsMultiRegRet); GenTree* op1 = treeNode->gtGetOp1(); GenTree* actualOp1 = op1->gtSkipReloadOrCopy(); diff --git a/src/coreclr/src/jit/compiler.h b/src/coreclr/src/jit/compiler.h index 3c3f811..62a1831 100644 --- a/src/coreclr/src/jit/compiler.h +++ b/src/coreclr/src/jit/compiler.h @@ -280,7 +280,9 @@ public: unsigned char lvOverlappingFields :1; // True when we have a struct with possibly overlapping fields unsigned char lvContainsHoles :1; // True when we have a promoted struct that contains holes unsigned char lvCustomLayout :1; // True when this struct has "CustomLayout" - unsigned char lvIsMultiRegArgOrRet:1; // Is this a struct that would be passed or returned in multiple registers? + + unsigned char lvIsMultiRegArg :1; // true if this is a multireg LclVar struct used in an argument context + unsigned char lvIsMultiRegRet :1; // true if this is a multireg LclVar struct assigned from a multireg call #ifdef FEATURE_HFA unsigned char _lvIsHfa :1; // Is this a struct variable who's class handle is an HFA type @@ -410,6 +412,14 @@ public: #endif // _TARGET_ARM64_ } + // lvIsMultiRegArgOrRet() + // returns true if this is a multireg LclVar struct used in an argument context + // or if this is a multireg LclVar struct assigned from a multireg call + bool lvIsMultiRegArgOrRet() + { + return lvIsMultiRegArg || lvIsMultiRegRet; + } + private: regNumberSmall _lvRegNum; // Used to store the register this variable is in (or, the low register of a register pair). diff --git a/src/coreclr/src/jit/flowgraph.cpp b/src/coreclr/src/jit/flowgraph.cpp index 7b4b33b..826bcf4 100644 --- a/src/coreclr/src/jit/flowgraph.cpp +++ b/src/coreclr/src/jit/flowgraph.cpp @@ -8207,7 +8207,7 @@ void Compiler::fgAddInternal() { lvaTable[genReturnLocal].lvType = TYP_STRUCT; lvaSetStruct(genReturnLocal, info.compMethodInfo->args.retTypeClass, true); - lvaTable[genReturnLocal].lvIsMultiRegArgOrRet = true; + lvaTable[genReturnLocal].lvIsMultiRegRet = true; } else { @@ -21504,10 +21504,10 @@ GenTreePtr Compiler::fgAssignStructInlineeToVar(GenTreePtr child, CORINFO_CLASS_ newInlinee = gtNewAssignNode(dst, src); // When returning a multi-register value in a local var, make sure the variable is - // marked as lvIsMultiRegArgOrRet, so it does not get promoted. + // marked as lvIsMultiRegRet, so it does not get promoted. if (src->AsCall()->HasMultiRegRetVal()) { - lvaTable[tmpNum].lvIsMultiRegArgOrRet = true; + lvaTable[tmpNum].lvIsMultiRegRet = true; } // If inlinee was comma, but a deeper call, new inlinee is (, , , v05 = call()) diff --git a/src/coreclr/src/jit/gschecks.cpp b/src/coreclr/src/jit/gschecks.cpp index f118ced..d368b3b 100644 --- a/src/coreclr/src/jit/gschecks.cpp +++ b/src/coreclr/src/jit/gschecks.cpp @@ -484,7 +484,8 @@ void Compiler::gsParamsToShadows() dst = gtNewOperNode(GT_ADDR, TYP_BYREF, dst); opAssign = gtNewCpObjNode(dst, src, clsHnd, false); - lvaTable[shadowVar].lvIsMultiRegArgOrRet = lvaTable[lclNum].lvIsMultiRegArgOrRet; + lvaTable[shadowVar].lvIsMultiRegArg = lvaTable[lclNum].lvIsMultiRegArg; + lvaTable[shadowVar].lvIsMultiRegRet = lvaTable[lclNum].lvIsMultiRegRet; } else { diff --git a/src/coreclr/src/jit/importer.cpp b/src/coreclr/src/jit/importer.cpp index b786cab..76fc5a4 100644 --- a/src/coreclr/src/jit/importer.cpp +++ b/src/coreclr/src/jit/importer.cpp @@ -1148,7 +1148,7 @@ GenTreePtr Compiler::impAssignStructPtr(GenTreePtr dest, assert(!src->gtCall.IsVarargs() && "varargs not allowed for System V OSs."); // Make the struct non promotable. The eightbytes could contain multiple fields. - lvaTable[lcl->gtLclVarCommon.gtLclNum].lvIsMultiRegArgOrRet = true; + lvaTable[lcl->gtLclVarCommon.gtLclNum].lvIsMultiRegRet = true; #endif } else @@ -7541,7 +7541,7 @@ GenTreePtr Compiler::impFixupStructReturnType(GenTreePtr op, CORINFO_CL { // Make sure that this struct stays in memory and doesn't get promoted. unsigned lclNum = op->gtLclVarCommon.gtLclNum; - lvaTable[lclNum].lvIsMultiRegArgOrRet = true; + lvaTable[lclNum].lvIsMultiRegRet = true; return op; } @@ -7565,7 +7565,7 @@ GenTreePtr Compiler::impFixupStructReturnType(GenTreePtr op, CORINFO_CL // This LCL_VAR is an HFA return value, it stays as a TYP_STRUCT unsigned lclNum = op->gtLclVarCommon.gtLclNum; // Make sure this struct type stays as struct so that we can return it as an HFA - lvaTable[lclNum].lvIsMultiRegArgOrRet = true; + lvaTable[lclNum].lvIsMultiRegRet = true; return op; } @@ -13164,7 +13164,7 @@ FIELD_DONE: // rdi/rsi (depending whether there is a "this"). unsigned tmp = lvaGrabTemp(true DEBUGARG("UNBOXing a register returnable nullable")); - lvaTable[tmp].lvIsMultiRegArgOrRet = true; + lvaTable[tmp].lvIsMultiRegArg = true; lvaSetStruct(tmp, resolvedToken.hClass, true /* unsafe value cls check */); op2 = gtNewLclvNode(tmp, TYP_STRUCT); @@ -13973,7 +13973,7 @@ void Compiler::impMarkLclDstNotPromotable(unsigned tmpNum, GenTreePtr src, CORIN (hfaType == TYP_FLOAT && hfaSlots == sizeof(float) / REGSIZE_BYTES)) { // Make sure this struct type stays as struct so we can receive the call in a struct. - lvaTable[tmpNum].lvIsMultiRegArgOrRet = true; + lvaTable[tmpNum].lvIsMultiRegRet = true; } } } @@ -13992,7 +13992,7 @@ GenTreePtr Compiler::impAssignMultiRegTypeToVar(GenTreePtr op, CORINFO_CLASS_HAN assert(IsMultiRegReturnedType(hClass)); // Mark the var so that fields are not promoted and stay together. - lvaTable[tmpNum].lvIsMultiRegArgOrRet = true; + lvaTable[tmpNum].lvIsMultiRegRet = true; #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) return ret; diff --git a/src/coreclr/src/jit/lclvars.cpp b/src/coreclr/src/jit/lclvars.cpp index f129bff..cf6e2b0 100644 --- a/src/coreclr/src/jit/lclvars.cpp +++ b/src/coreclr/src/jit/lclvars.cpp @@ -765,7 +765,7 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo * varDscInfo) varDsc->lvSetIsHfa(); varDsc->lvSetIsHfaRegArg(); varDsc->SetHfaType(hfaType); - varDsc->lvIsMultiRegArgOrRet = (varDsc->lvHfaSlots() > 1); + varDsc->lvIsMultiRegArg = (varDsc->lvHfaSlots() > 1); } varDsc->lvIsRegArg = 1; @@ -1747,7 +1747,7 @@ void Compiler::lvaPromoteLongVars() lclNum++) { LclVarDsc * varDsc = &lvaTable[lclNum]; - if(!varTypeIsLong(varDsc) || varDsc->lvDoNotEnregister || varDsc->lvIsMultiRegArgOrRet || (varDsc->lvRefCnt == 0)) + if(!varTypeIsLong(varDsc) || varDsc->lvDoNotEnregister || varDsc->lvIsMultiRegArgOrRet() || (varDsc->lvRefCnt == 0)) { continue; } diff --git a/src/coreclr/src/jit/lower.cpp b/src/coreclr/src/jit/lower.cpp index 7a39bfa..26f3a53 100755 --- a/src/coreclr/src/jit/lower.cpp +++ b/src/coreclr/src/jit/lower.cpp @@ -411,16 +411,16 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data) if (parent->gtOper == GT_STORE_LCL_VAR) { // If parent is already a STORE_LCL_VAR, we can skip it if - // it is already marked as lvIsMultiRegArgOrRet + // it is already marked as lvIsMultiRegRet unsigned varNum = parent->AsLclVarCommon()->gtLclNum; - if (comp->lvaTable[varNum].lvIsMultiRegArgOrRet) + if (comp->lvaTable[varNum].lvIsMultiRegRet) { break; } else if (!comp->lvaTable[varNum].lvPromoted) { - // If var wasn't promoted, we can just set lvIsMultiRegArgOrRet - comp->lvaTable[varNum].lvIsMultiRegArgOrRet = true; + // If var wasn't promoted, we can just set lvIsMultiRegRet + comp->lvaTable[varNum].lvIsMultiRegRet = true; break; } } @@ -436,7 +436,7 @@ void Lowering::DecomposeNode(GenTreePtr* pTree, Compiler::fgWalkData* data) assert(stLclVar->OperIsLocalStore()); unsigned varNum = stLclVar->AsLclVarCommon()->gtLclNum; - comp->lvaTable[varNum].lvIsMultiRegArgOrRet = true; + comp->lvaTable[varNum].lvIsMultiRegRet = true; comp->fgFixupIfCallArg(data->parentStack, tree, *treePtr); // Decompose new node diff --git a/src/coreclr/src/jit/lowerxarch.cpp b/src/coreclr/src/jit/lowerxarch.cpp index d53f048..6fd09f8 100644 --- a/src/coreclr/src/jit/lowerxarch.cpp +++ b/src/coreclr/src/jit/lowerxarch.cpp @@ -904,7 +904,7 @@ Lowering::TreeNodeInfoInitReturn(GenTree* tree) { GenTreeLclVarCommon* lclVarCommon = op1->AsLclVarCommon(); LclVarDsc* varDsc = &(compiler->lvaTable[lclVarCommon->gtLclNum]); - assert(varDsc->lvIsMultiRegArgOrRet); + assert(varDsc->lvIsMultiRegRet); // Mark var as contained if not enregistrable. if (!varTypeIsEnregisterableStruct(op1)) diff --git a/src/coreclr/src/jit/morph.cpp b/src/coreclr/src/jit/morph.cpp index 034507e..e1e035a 100644 --- a/src/coreclr/src/jit/morph.cpp +++ b/src/coreclr/src/jit/morph.cpp @@ -4470,7 +4470,7 @@ GenTreePtr Compiler::fgMorphMultiregStructArg(GenTreePtr arg, fgArgTabEntryPt // assert((varDsc->lvSize() == 2*TARGET_POINTER_SIZE) || varDsc->lvIsHfa()); - varDsc->lvIsMultiRegArgOrRet = true; + varDsc->lvIsMultiRegArg = true; #ifdef DEBUG if (verbose) @@ -15705,11 +15705,15 @@ void Compiler::fgPromoteStructs() tooManyLocals = true; } #if !FEATURE_MULTIREG_STRUCT_PROMOTE - else if (varDsc->lvIsMultiRegArgOrRet) + else if (varDsc->lvIsMultiRegArg) { - JITDUMP("Skipping V%02u: marked lvIsMultiRegArgOrRet.\n", lclNum); + JITDUMP("Skipping V%02u: marked lvIsMultiRegArg.\n", lclNum); } #endif // !FEATURE_MULTIREG_STRUCT_PROMOTE + else if (varDsc->lvIsMultiRegRet) + { + JITDUMP("Skipping V%02u: marked lvIsMultiRegRet.\n", lclNum); + } else if (varTypeIsStruct(varDsc)) { lvaCanPromoteStructVar(lclNum, &structPromotionInfo); -- 2.7.4