[RyuJIT/ARM32] Internal register candadate for split struct argument
authorHyeongseok Oh <hseok82.oh@samsung.com>
Tue, 11 Jul 2017 01:49:55 +0000 (10:49 +0900)
committerHyeongseok Oh <hseok82.oh@samsung.com>
Tue, 11 Jul 2017 01:49:55 +0000 (10:49 +0900)
Change candidate mask for internal register candidate to not include target registers.
On codegen phase, if addrReg is allocated to be destroyed by targetReg,
we use internal register as addrReg.

src/jit/codegenarmarch.cpp
src/jit/lsraarmarch.cpp

index e514644..3339e56 100644 (file)
@@ -1019,6 +1019,11 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode)
             // Generate code to load the address that we need into a register
             genConsumeAddress(addrNode);
             addrReg = addrNode->gtRegNum;
+
+            // If addrReg equal to baseReg, we use the last target register as alternative baseReg.
+            // Because the candidate mask for the internal baseReg does not include any of the target register,
+            // we can ensure that baseReg, addrReg, and the last target register are not all same.
+            assert(baseReg != addrReg);
         }
 
         // If we have an HFA we can't have any GC pointers,
@@ -1062,7 +1067,8 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode)
             nextIndex += 1;
         }
 
-        // Set registers
+        // We set up the registers in order, so that we assign the last target register `baseReg` is no longer in use,
+        // in case we had to reuse the last target register for it.
         structOffset = 0;
         for (unsigned idx = 0; idx < treeNode->gtNumRegs; idx++)
         {
@@ -1077,7 +1083,12 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode)
             else
             {
                 // check for case of destroying the addrRegister while we still need it
-                assert(targetReg != addrReg);
+                if (targetReg == addrReg && idx != treeNode->gtNumRegs - 1)
+                {
+                    assert(targetReg != baseReg);
+                    emit->emitIns_R_R(INS_mov, emitTypeSize(type), baseReg, addrReg);
+                    addrReg = baseReg;
+                }
 
                 // Load from our address expression source
                 emit->emitIns_R_R_I(INS_ldr, emitTypeSize(type), targetReg, addrReg, structOffset);
index a42ef4b..c4f124f 100644 (file)
@@ -843,9 +843,11 @@ void Lowering::TreeNodeInfoInitPutArgSplit(GenTreePutArgSplit* argNode, TreeNode
         assert(putArgChild->TypeGet() == TYP_STRUCT);
         assert(putArgChild->OperGet() == GT_OBJ);
 
-        argNode->gtLsraInfo.srcCount = 1;
         // We could use a ldr/str sequence so we need a internal register
+        argNode->gtLsraInfo.srcCount         = 1;
         argNode->gtLsraInfo.internalIntCount = 1;
+        regMaskTP internalMask               = RBM_ALLINT & ~argMask;
+        argNode->gtLsraInfo.setInternalCandidates(m_lsra, internalMask);
 
         GenTreePtr objChild = putArgChild->gtOp.gtOp1;
         if (objChild->OperGet() == GT_LCL_VAR_ADDR)