Check layout compatibility before morphing `OBJ(ADDR(LCL_VAR))` into a list of promot...
authorSingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
Wed, 29 Jun 2022 22:19:25 +0000 (01:19 +0300)
committerGitHub <noreply@github.com>
Wed, 29 Jun 2022 22:19:25 +0000 (00:19 +0200)
* Fix non-x86 targets

* Fix x86

* Add tests

src/coreclr/jit/morph.cpp
src/tests/JIT/Directed/StructABI/TypeMismatchedArgs.cs

index df1b2b4..dd4da1e 100644 (file)
@@ -3489,35 +3489,32 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
 #if defined(TARGET_X86)
         if (isStructArg)
         {
-            GenTree* lclNode = argx->OperIs(GT_LCL_VAR) ? argx : fgIsIndirOfAddrOfLocal(argx);
-            if ((lclNode != nullptr) &&
-                (lvaGetPromotionType(lclNode->AsLclVarCommon()->GetLclNum()) == Compiler::PROMOTION_TYPE_INDEPENDENT))
-            {
-                // Make a GT_FIELD_LIST of the field lclVars.
-                GenTreeLclVarCommon* lcl       = lclNode->AsLclVarCommon();
-                LclVarDsc*           varDsc    = lvaGetDesc(lcl);
-                GenTreeFieldList*    fieldList = new (this, GT_FIELD_LIST) GenTreeFieldList();
-                arg.SetEarlyNode(fieldList);
-
-                for (unsigned fieldLclNum = varDsc->lvFieldLclStart;
-                     fieldLclNum < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++fieldLclNum)
-                {
-                    LclVarDsc* fieldVarDsc = lvaGetDesc(fieldLclNum);
-                    GenTree*   fieldLcl;
+            GenTreeLclVar* lcl = nullptr;
 
-                    if (fieldLclNum == varDsc->lvFieldLclStart)
-                    {
-                        lcl->SetLclNum(fieldLclNum);
-                        lcl->SetOperResetFlags(GT_LCL_VAR);
-                        lcl->gtType = fieldVarDsc->TypeGet();
-                        fieldLcl    = lcl;
-                    }
-                    else
-                    {
-                        fieldLcl = gtNewLclvNode(fieldLclNum, fieldVarDsc->TypeGet());
-                    }
-
-                    fieldList->AddField(this, fieldLcl, fieldVarDsc->lvFldOffset, fieldVarDsc->TypeGet());
+            // TODO-ADDR: always perform "OBJ(ADDR(LCL)) => LCL" transformation in local morph and delete this code.
+            if (argx->OperGet() == GT_OBJ)
+            {
+                if (argx->gtGetOp1()->OperIs(GT_ADDR) && argx->gtGetOp1()->gtGetOp1()->OperIs(GT_LCL_VAR))
+                {
+                    lcl = argx->gtGetOp1()->gtGetOp1()->AsLclVar();
+                }
+            }
+            else if (argx->OperGet() == GT_LCL_VAR)
+            {
+                lcl = argx->AsLclVar();
+            }
+            if ((lcl != nullptr) && (lvaGetPromotionType(lcl->GetLclNum()) == PROMOTION_TYPE_INDEPENDENT))
+            {
+                if (argx->OperIs(GT_LCL_VAR) ||
+                    ClassLayout::AreCompatible(argx->AsObj()->GetLayout(), lvaGetDesc(lcl)->GetLayout()))
+                {
+                    argx = fgMorphLclArgToFieldlist(lcl);
+                    arg.SetEarlyNode(argx);
+                }
+                else
+                {
+                    // Set DNER to block independent promotion.
+                    lvaSetVarDoNotEnregister(lcl->GetLclNum() DEBUGARG(DoNotEnregisterReason::IsStructArg));
                 }
             }
         }
@@ -3699,25 +3696,35 @@ GenTree* Compiler::fgMorphMultiregStructArg(CallArg* arg)
     if (arg->AbiInfo.GetRegNum() == REG_STK)
 #endif
     {
-        GenTreeLclVarCommon* lcl       = nullptr;
-        GenTree*             actualArg = argNode->gtEffectiveVal();
+        GenTreeLclVar* lcl       = nullptr;
+        GenTree*       actualArg = argNode->gtEffectiveVal();
 
+        // TODO-ADDR: always perform "OBJ(ADDR(LCL)) => LCL" transformation in local morph and delete this code.
         if (actualArg->OperGet() == GT_OBJ)
         {
             if (actualArg->gtGetOp1()->OperIs(GT_ADDR) && actualArg->gtGetOp1()->gtGetOp1()->OperIs(GT_LCL_VAR))
             {
-                lcl = actualArg->gtGetOp1()->gtGetOp1()->AsLclVarCommon();
+                lcl = actualArg->gtGetOp1()->gtGetOp1()->AsLclVar();
             }
         }
         else if (actualArg->OperGet() == GT_LCL_VAR)
         {
-            lcl = actualArg->AsLclVarCommon();
+            lcl = actualArg->AsLclVar();
         }
         if (lcl != nullptr)
         {
             if (lvaGetPromotionType(lcl->GetLclNum()) == PROMOTION_TYPE_INDEPENDENT)
             {
-                argNode = fgMorphLclArgToFieldlist(lcl);
+                if (argNode->OperIs(GT_LCL_VAR) ||
+                    ClassLayout::AreCompatible(argNode->AsObj()->GetLayout(), lvaGetDesc(lcl)->GetLayout()))
+                {
+                    argNode = fgMorphLclArgToFieldlist(lcl);
+                }
+                else
+                {
+                    // Set DNER to block independent promotion.
+                    lvaSetVarDoNotEnregister(lcl->GetLclNum() DEBUGARG(DoNotEnregisterReason::IsStructArg));
+                }
             }
 #ifdef TARGET_LOONGARCH64
             else if (argNode->TypeGet() == TYP_STRUCT)
index 8850934..ceb0bdc 100644 (file)
@@ -46,6 +46,16 @@ public unsafe class TypeMismatchedArgs
             return 106;
         }
 
+        if (ProblemWithPromotedStruct_Unix_x64(new StructWithFourLongs { LongOne = 1, LongTwo = 2, LongThree = 3, LongFour = 4 }))
+        {
+            return 107;
+        }
+
+        if (ProblemWithPromotedStruct_x86(new DblLngStruct { FirstLngValue = 1, SecondLngValue = 2 }))
+        {
+            return 108;
+        }
+
         return 100;
     }
 
@@ -107,6 +117,22 @@ public unsafe class TypeMismatchedArgs
     }
 
     [MethodImpl(MethodImplOptions.NoInlining)]
+    private static bool ProblemWithPromotedStruct_Unix_x64(StructWithFourLongs b)
+    {
+        var c = b;
+
+        return CallForDblStructs(default, default, default, default, *(DblLngStruct*)&c) != c.LongTwo;
+    }
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    private static bool ProblemWithPromotedStruct_x86(DblLngStruct a)
+    {
+        var b = a;
+
+        return CallForStructWithIndex(*(StructWithIndex*)&b) != (int)(b.FirstLngValue >> 32);
+    }
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
     private static float CallForVector4(Vector4 value) => value.X;
 
     [MethodImpl(MethodImplOptions.NoInlining)]
@@ -123,6 +149,12 @@ public unsafe class TypeMismatchedArgs
 
     [MethodImpl(MethodImplOptions.NoInlining)]
     private static float CallForFltStruct(FltStruct value) => value.Flt;
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    private static long CallForDblStructs(DblLngStruct arg0, DblLngStruct arg1, DblLngStruct arg2, DblLngStruct arg3, DblLngStruct stkArg) => stkArg.SecondLngValue;
+
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    static int CallForStructWithIndex(StructWithIndex value) => value.Value;
 }
 
 [StructLayout(LayoutKind.Explicit)]
@@ -206,3 +238,9 @@ struct FltStruct
 {
     public float Flt;
 }
+
+struct StructWithIndex
+{
+    public int Index;
+    public int Value;
+}