Supported contained bitcast under STORE_LCL_VAR/FLD on arm32/64. (#56122)
authorSergey Andreenko <seandree@microsoft.com>
Fri, 23 Jul 2021 17:13:16 +0000 (10:13 -0700)
committerGitHub <noreply@github.com>
Fri, 23 Jul 2021 17:13:16 +0000 (10:13 -0700)
* Return contained bitcast to arm lowering.

* Supported contained bitcast for arm64.

* support contained bitcast arm32.

* Fix arm32.

* fix

* fix assert

* improve comments

src/coreclr/jit/codegenarm.cpp
src/coreclr/jit/codegenarm64.cpp
src/coreclr/jit/instr.cpp
src/coreclr/jit/lowerarmarch.cpp
src/coreclr/jit/lsrabuild.cpp

index 49fc8c9..4cd5f03 100644 (file)
@@ -998,11 +998,24 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
     // Ensure that lclVar nodes are typed correctly.
     assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet()));
 
-    GenTree* data = tree->gtOp1;
-
-    assert(!data->isContained());
+    GenTree*  data    = tree->gtOp1;
+    regNumber dataReg = REG_NA;
     genConsumeReg(data);
-    regNumber dataReg = data->GetRegNum();
+
+    if (data->isContained())
+    {
+        assert(data->OperIs(GT_BITCAST));
+        const GenTree* bitcastSrc = data->AsUnOp()->gtGetOp1();
+        assert(!bitcastSrc->isContained());
+        dataReg = bitcastSrc->GetRegNum();
+    }
+    else
+    {
+
+        dataReg = data->GetRegNum();
+    }
+    assert(dataReg != REG_NA);
+
     if (tree->IsOffsetMisaligned())
     {
         // Arm supports unaligned access only for integer types,
@@ -1027,7 +1040,7 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
     else
     {
         emitAttr    attr = emitTypeSize(targetType);
-        instruction ins  = ins_Store(targetType);
+        instruction ins  = ins_StoreFromSrc(dataReg, targetType);
         emit->emitIns_S_R(ins, attr, dataReg, varNum, offset);
     }
 
@@ -1073,8 +1086,19 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree)
         {
             genConsumeRegs(data);
 
-            assert(!data->isContained());
-            regNumber dataReg = data->GetRegNum();
+            regNumber dataReg = REG_NA;
+
+            if (data->isContained())
+            {
+                assert(data->OperIs(GT_BITCAST));
+                const GenTree* bitcastSrc = data->AsUnOp()->gtGetOp1();
+                assert(!bitcastSrc->isContained());
+                dataReg = bitcastSrc->GetRegNum();
+            }
+            else
+            {
+                dataReg = data->GetRegNum();
+            }
             assert(dataReg != REG_NA);
 
             regNumber targetReg = tree->GetRegNum();
@@ -1083,7 +1107,7 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree)
             {
                 inst_set_SV_var(tree);
 
-                instruction ins  = ins_Store(targetType);
+                instruction ins  = ins_StoreFromSrc(dataReg, targetType);
                 emitAttr    attr = emitTypeSize(targetType);
 
                 emitter* emit = GetEmitter();
index b0dd9ad..fa7e8fd 100644 (file)
@@ -1940,6 +1940,13 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
         assert(data->IsIntegralConst(0));
         dataReg = REG_ZR;
     }
+    else if (data->isContained())
+    {
+        assert(data->OperIs(GT_BITCAST));
+        const GenTree* bitcastSrc = data->AsUnOp()->gtGetOp1();
+        assert(!bitcastSrc->isContained());
+        dataReg = bitcastSrc->GetRegNum();
+    }
     else
     {
         assert(!data->isContained());
@@ -1947,7 +1954,7 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
     }
     assert(dataReg != REG_NA);
 
-    instruction ins = ins_Store(targetType);
+    instruction ins = ins_StoreFromSrc(dataReg, targetType);
 
     emitAttr attr = emitActualTypeSize(targetType);
 
@@ -2015,10 +2022,11 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* lclNode)
         regNumber dataReg = REG_NA;
         if (data->isContained())
         {
-            // This is only possible for a zero-init.
-            assert(data->IsIntegralConst(0) || data->IsSIMDZero());
+            // This is only possible for a zero-init or bitcast.
+            const bool zeroInit = (data->IsIntegralConst(0) || data->IsSIMDZero());
+            assert(zeroInit || data->OperIs(GT_BITCAST));
 
-            if (varTypeIsSIMD(targetType))
+            if (zeroInit && varTypeIsSIMD(targetType))
             {
                 if (targetReg != REG_NA)
                 {
@@ -2040,8 +2048,16 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* lclNode)
                 }
                 return;
             }
-
-            dataReg = REG_ZR;
+            if (zeroInit)
+            {
+                dataReg = REG_ZR;
+            }
+            else
+            {
+                const GenTree* bitcastSrc = data->AsUnOp()->gtGetOp1();
+                assert(!bitcastSrc->isContained());
+                dataReg = bitcastSrc->GetRegNum();
+            }
         }
         else
         {
@@ -2054,7 +2070,7 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* lclNode)
         {
             inst_set_SV_var(lclNode);
 
-            instruction ins  = ins_Store(targetType);
+            instruction ins  = ins_StoreFromSrc(dataReg, targetType);
             emitAttr    attr = emitActualTypeSize(targetType);
 
             emit->emitIns_S_R(ins, attr, dataReg, varNum, /* offset */ 0);
index ac37c4c..a1d62e6 100644 (file)
@@ -2024,31 +2024,38 @@ instruction CodeGenInterface::ins_Store(var_types dstType, bool aligned /*=false
 // Return Value:
 //   the instruction to use
 //
-// Notes:
-//   The function currently does not expect float srcReg with integral dstType and will assert on such cases.
-//
 instruction CodeGenInterface::ins_StoreFromSrc(regNumber srcReg, var_types dstType, bool aligned /*=false*/)
 {
+    assert(srcReg != REG_NA);
+
     bool dstIsFloatType = isFloatRegType(dstType);
     bool srcIsFloatReg  = genIsValidFloatReg(srcReg);
     if (srcIsFloatReg == dstIsFloatType)
     {
         return ins_Store(dstType, aligned);
     }
-
-    assert(!srcIsFloatReg && dstIsFloatType && "not expecting an integer type passed in a float reg");
-    assert(!varTypeIsSmall(dstType) && "not expecting small float types");
-
-    instruction ins = INS_invalid;
-#if defined(TARGET_XARCH)
-    ins = INS_mov;
-#elif defined(TARGET_ARMARCH)
-    ins     = INS_str;
-#else
-    NYI("ins_Store");
-#endif
-    assert(ins != INS_invalid);
-    return ins;
+    else
+    {
+        // We know that we are writing to memory, so make the destination type same
+        // as the source type.
+        var_types dstTypeForStore = TYP_UNDEF;
+        unsigned  dstSize         = genTypeSize(dstType);
+        switch (dstSize)
+        {
+            case 4:
+                dstTypeForStore = srcIsFloatReg ? TYP_FLOAT : TYP_INT;
+                break;
+#if defined(TARGET_64BIT)
+            case 8:
+                dstTypeForStore = srcIsFloatReg ? TYP_DOUBLE : TYP_LONG;
+                break;
+#endif // TARGET_64BIT
+            default:
+                assert(!"unexpected write to the stack.");
+                break;
+        }
+        return ins_Store(dstTypeForStore, aligned);
+    }
 }
 
 #if defined(TARGET_XARCH)
index 13af2ea..ce61061 100644 (file)
@@ -1555,9 +1555,6 @@ void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) const
     assert(storeLoc->OperIsLocalStore());
     GenTree* op1 = storeLoc->gtGetOp1();
 
-#if 0
-    // TODO-ARMARCH-CQ: support contained bitcast under STORE_LCL_VAR/FLD,
-    // currently codegen does not expect it.
     if (op1->OperIs(GT_BITCAST))
     {
         // If we know that the source of the bitcast will be in a register, then we can make
@@ -1570,7 +1567,6 @@ void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) const
             return;
         }
     }
-#endif
 
     const LclVarDsc* varDsc = comp->lvaGetDesc(storeLoc);
 
index 7eeddf4..b10bd7e 100644 (file)
@@ -3410,7 +3410,7 @@ int LinearScan::BuildStoreLoc(GenTreeLclVarCommon* storeLoc)
 
     // Second, use source registers.
 
-    if (op1->IsMultiRegNode())
+    if (op1->IsMultiRegNode() && (op1->GetMultiRegCount() > 1))
     {
         // This is the case where the source produces multiple registers.
         // This must be a store lclvar.