Split the lvIsMultiRegArgOrRet into two bits
authorBrian Sullivan <briansul@microsoft.com>
Wed, 29 Jun 2016 00:32:33 +0000 (17:32 -0700)
committerBrian Sullivan <briansul@microsoft.com>
Wed, 29 Jun 2016 18:20:40 +0000 (11:20 -0700)
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
src/coreclr/src/jit/compiler.h
src/coreclr/src/jit/flowgraph.cpp
src/coreclr/src/jit/gschecks.cpp
src/coreclr/src/jit/importer.cpp
src/coreclr/src/jit/lclvars.cpp
src/coreclr/src/jit/lower.cpp
src/coreclr/src/jit/lowerxarch.cpp
src/coreclr/src/jit/morph.cpp

index 6c356e6..38cbdd1 100755 (executable)
@@ -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();
index 3c3f811..62a1831 100644 (file)
@@ -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).
index 7b4b33b..826bcf4 100644 (file)
@@ -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())
index f118ced..d368b3b 100644 (file)
@@ -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
         {
index b786cab..76fc5a4 100644 (file)
@@ -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;
index f129bff..cf6e2b0 100644 (file)
@@ -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;
         }
index 7a39bfa..26f3a53 100755 (executable)
@@ -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
index d53f048..6fd09f8 100644 (file)
@@ -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))
index 034507e..e1e035a 100644 (file)
@@ -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);