Changes to ReturnTypeDesc support more than two return registers
authorBrian Sullivan <briansul@microsoft.com>
Thu, 23 Jun 2016 02:37:59 +0000 (19:37 -0700)
committerBrian Sullivan <briansul@microsoft.com>
Fri, 24 Jun 2016 21:58:47 +0000 (14:58 -0700)
Changed m_regType into an array
Renamed the Initialize method to InitializeReturnType

src/jit/codegenxarch.cpp
src/jit/gentree.cpp
src/jit/gentree.h
src/jit/importer.cpp
src/jit/lclvars.cpp
src/jit/morph.cpp

index d45c181..e464bd0 100755 (executable)
@@ -186,7 +186,7 @@ void                CodeGen::genEmitGSCookieCheck(bool pushReg)
         if (compiler->compMethodReturnsMultiRegRetType())
         {
             ReturnTypeDesc retTypeDesc;
-            retTypeDesc.Initialize(compiler, compiler->info.compMethodInfo->args.retTypeClass);
+            retTypeDesc.InitializeReturnType(compiler, compiler->info.compMethodInfo->args.retTypeClass);
             unsigned regCount = retTypeDesc.GetReturnRegCount();
 
             // Only x86 and x64 Unix ABI allows multi-reg return and
@@ -1516,7 +1516,7 @@ CodeGen::genStructReturn(GenTreePtr treeNode)
         assert(varDsc->lvIsMultiRegArgOrRet);
 
         ReturnTypeDesc retTypeDesc;
-        retTypeDesc.Initialize(compiler, varDsc->lvVerTypeInfo.GetClassHandle());
+        retTypeDesc.InitializeReturnType(compiler, varDsc->lvVerTypeInfo.GetClassHandle());
         unsigned regCount = retTypeDesc.GetReturnRegCount();
         assert(regCount == MAX_RET_REG_COUNT);
 
index ba4dabd..3e77e17 100644 (file)
@@ -14082,9 +14082,7 @@ bool GenTree::isCommutativeSIMDIntrinsic()
 // Return Value
 //    None
 //
-// Note:
-//    Right now it is implemented only for x64 unix.
-void ReturnTypeDesc::Initialize(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd)
+void ReturnTypeDesc::InitializeReturnType(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd)
 {
     assert(!m_inited);
 
@@ -14096,23 +14094,19 @@ void ReturnTypeDesc::Initialize(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd)
 
     if (structDesc.passedInRegisters)
     {
-        if (structDesc.eightByteCount == 1)
-        {
-            m_regType0 = comp->GetEightByteType(structDesc, 0);
-        }
-        else
+        for (int i=0; i<structDesc.eightByteCount; i++)
         {
-            assert(structDesc.eightByteCount == 2);
-            m_regType0 = comp->GetEightByteType(structDesc, 0);
-            m_regType1 = comp->GetEightByteType(structDesc, 1);
+            assert(i < MAX_RET_REG_COUNT);
+            m_regType[i] = comp->GetEightByteType(structDesc, i);
         }
     }
 
 #elif defined(_TARGET_X86_)
-    // TODO-X86: Assumes we are only using ReturnTypeDesc for longs on x86. Will
-    // need to be updated in the future to handle other return types
-    m_regType0 = TYP_INT;
-    m_regType1 = TYP_INT;
+    // TODO-X86: Assumes we are only using ReturnTypeDesc for longs on x86.
+    // Will need to be updated in the future to handle other return types
+    assert(MAX_RET_REG_COUNT == 2);
+    m_regType[0] = TYP_INT;
+    m_regType[1] = TYP_INT;
 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
 
 #ifdef DEBUG
index ed3ef94..3e7c988 100644 (file)
@@ -2395,8 +2395,7 @@ enum class InlineObservation;
 struct ReturnTypeDesc
 {
 private:
-    var_types m_regType0;
-    var_types m_regType1;
+    var_types m_regType[MAX_RET_REG_COUNT];
 
 #ifdef DEBUG
     bool m_inited;
@@ -2408,15 +2407,16 @@ public:
         Reset();
     }
 
-    // Initialize type descriptor given its type handle
-    void Initialize(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd);
+    // Initialize the return type descriptor given its type handle
+    void InitializeReturnType(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd);
 
     // Reset type descriptor to defaults
     void Reset()
     {
-        m_regType0 = TYP_UNKNOWN;
-        m_regType1 = TYP_UNKNOWN;
-
+        for (unsigned i = 0; i < MAX_RET_REG_COUNT; ++i)
+        {
+            m_regType[i] = TYP_UNKNOWN;
+        }
 #ifdef DEBUG
         m_inited = false;
 #endif
@@ -2436,20 +2436,24 @@ public:
         assert(m_inited);
 
         int regCount = 0;
-        if (m_regType0 != TYP_UNKNOWN)
+        for (unsigned i = 0; i < MAX_RET_REG_COUNT; ++i)
         {
-            ++regCount;
-
-            if (m_regType1 != TYP_UNKNOWN)
+            if (m_regType[i] == TYP_UNKNOWN)
             {
-                ++regCount;
+                break;
             }
+            // otherwise
+            regCount++;
         }
-        else
+
+#ifdef DEBUG
+        // Any remaining elements in m_regTypes[] should also be TYP_UNKNOWN
+        for (unsigned i = regCount+1; i < MAX_RET_REG_COUNT; ++i)
         {
-            // If regType0 is TYP_UNKNOWN then regType1 must also be TYP_UNKNOWN.
-            assert(m_regType1 == TYP_UNKNOWN);
+            assert(m_regType[i] == TYP_UNKNOWN);
         }
+#endif        
+
         return regCount;
     }
 
@@ -2463,9 +2467,19 @@ public:
     // Return Value:
     //    Returns true if the type is returned in multiple return registers.
     //    False otherwise.
+    // Note that we only have to examine the first two values to determine this
+    //
     bool IsMultiRegRetType() const
     {
-        return GetReturnRegCount() > 1;
+        if (MAX_RET_REG_COUNT < 2)
+        {
+            return false;
+        }
+        else
+        {
+            return ((m_regType[0] != TYP_UNKNOWN) &&
+                    (m_regType[1] != TYP_UNKNOWN));
+        }
     }
 
     //--------------------------------------------------------------------------
@@ -2477,21 +2491,14 @@ public:
     //
     // Return Value:
     //    var_type of the return register specified by its index.
-    //    Return TYP_UNKNOWN if index > number of return registers.
+    //    asserts if the index does not have a valid register return type.
+    
     var_types GetReturnRegType(unsigned index)
     {
-        assert(index < GetReturnRegCount());
-
-        if (index == 0)
-        {
-            return m_regType0;
-        }
-        else if (index == 1)
-        {
-            return m_regType1;
-        }
+        var_types result = m_regType[index];
+        assert(result != TYP_UNKNOWN);
 
-        return TYP_UNKNOWN;
+        return result;
     }
 
     // Get ith ABI return register 
@@ -4051,8 +4058,6 @@ struct GenTreeCopyOrReload : public GenTreeUnOp
     // Return Value:
     //    None.
     //
-    // TODO-ARM: Implement this routine for Arm64 and Arm32
-    // TODO-X86: Implement this routine for x86
     void SetRegNumByIdx(regNumber reg, unsigned idx)
     {
         assert(idx < MAX_RET_REG_COUNT);
@@ -4061,7 +4066,7 @@ struct GenTreeCopyOrReload : public GenTreeUnOp
         {
             gtRegNum = reg;
         }
-#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+#if FEATURE_MULTIREG_RET
         else
         {
             gtOtherRegs[idx - 1] = reg;
index 7410147..b786cab 100644 (file)
@@ -7376,6 +7376,14 @@ GenTreePtr                Compiler::impFixupCallStructReturn(GenTreePtr     call
 
     call->gtCall.gtRetClsHnd = retClsHnd;
 
+    GenTreeCall* callNode = call->AsCall();
+
+#if FEATURE_MULTIREG_RET
+    // Initialize Return type descriptor of call node    
+    ReturnTypeDesc* retTypeDesc = callNode->GetReturnTypeDesc();
+    retTypeDesc->InitializeReturnType(this, retClsHnd);
+#endif // FEATURE_MULTIREG_RET
+
 #if FEATURE_MULTIREG_RET && defined(FEATURE_HFA)
     // There is no fixup necessary if the return type is a HFA struct.
     // HFA structs are returned in registers for ARM32 and ARM64
@@ -7407,8 +7415,6 @@ GenTreePtr                Compiler::impFixupCallStructReturn(GenTreePtr     call
     }
 #elif defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
 
-    GenTreeCall* callNode = call->AsCall();
-
     // Not allowed for FEATURE_CORCLR which is the only SKU available for System V OSs.
     assert(!callNode->IsVarargs() && "varargs not allowed for System V OSs.");
 
@@ -7416,10 +7422,6 @@ GenTreePtr                Compiler::impFixupCallStructReturn(GenTreePtr     call
     // single eightbyte return type below.
     callNode->gtReturnType = call->gtType;
 
-    // Initialize Return type descriptor of call node    
-    ReturnTypeDesc* retTypeDesc = callNode->GetReturnTypeDesc();
-    retTypeDesc->Initialize(this, retClsHnd);
-
     unsigned retRegCount = retTypeDesc->GetReturnRegCount();
     if (retRegCount != 0)
     {
@@ -7501,7 +7503,7 @@ GenTreePtr                Compiler::impInitCallReturnTypeDesc(GenTreePtr     cal
 
     // Initialize Return type descriptor of call node
     ReturnTypeDesc* retTypeDesc = callNode->GetReturnTypeDesc();
-    retTypeDesc->Initialize(this, retClsHnd);
+    retTypeDesc->InitializeReturnType(this, retClsHnd);
 
     unsigned retRegCount = retTypeDesc->GetReturnRegCount();
     // must be a long returned in two registers
@@ -14236,7 +14238,7 @@ bool Compiler::impReturnInstruction(BasicBlock *block, int prefixFlags, OPCODE &
                     // Same as !IsHfa but just don't bother with impAssignStructPtr.
 #else // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
                 ReturnTypeDesc retTypeDesc;
-                retTypeDesc.Initialize(this, retClsHnd);
+                retTypeDesc.InitializeReturnType(this, retClsHnd);
                 unsigned retRegCount = retTypeDesc.GetReturnRegCount();
 
                 if (retRegCount != 0)
index 2d21856..f129bff 100644 (file)
@@ -144,7 +144,7 @@ void                Compiler::lvaInitTypeRef()
         {
 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING            
             ReturnTypeDesc retTypeDesc;
-            retTypeDesc.Initialize(this, info.compMethodInfo->args.retTypeClass);
+            retTypeDesc.InitializeReturnType(this, info.compMethodInfo->args.retTypeClass);
 
             if (retTypeDesc.GetReturnRegCount() > 1)
             {
index c4336de..510d1e1 100644 (file)
@@ -89,7 +89,7 @@ GenTreePtr          Compiler::fgMorphIntoHelperCall(GenTreePtr      tree,
         GenTreeCall* callNode = tree->AsCall();
         ReturnTypeDesc* retTypeDesc = callNode->GetReturnTypeDesc();
         retTypeDesc->Reset();
-        retTypeDesc->Initialize(this, callNode->gtRetClsHnd);
+        retTypeDesc->InitializeReturnType(this, callNode->gtRetClsHnd);
         callNode->ClearOtherRegs();
         
         NYI("Helper with TYP_LONG return type");