[RyuJIT/armarch] Put arguments with GT_BITCAST
authorHanjoung Lee <hanjoung.lee@samsung.com>
Mon, 25 Sep 2017 11:50:27 +0000 (20:50 +0900)
committerHanjoung Lee <hanjoung.lee@samsung.com>
Tue, 26 Sep 2017 02:16:08 +0000 (11:16 +0900)
Put arguments with GT_BITCAST instead of GT_COPY for arm32/arm64

Fix #14008

src/jit/codegenarmarch.cpp
src/jit/compiler.h
src/jit/gentree.cpp
src/jit/gentree.h
src/jit/gtlist.h
src/jit/gtstructs.h
src/jit/instr.cpp
src/jit/lower.cpp
src/jit/lsra.cpp
src/jit/lsraarm.cpp

index e9a12af..8c79919 100644 (file)
@@ -154,6 +154,42 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
             genCodeForCast(treeNode->AsOp());
             break;
 
+        case GT_BITCAST:
+        {
+            GenTree* op1 = treeNode->gtOp.gtOp1;
+            if (varTypeIsFloating(treeNode) != varTypeIsFloating(op1))
+            {
+#ifdef _TARGET_ARM64_
+                inst_RV_RV(INS_fmov, targetReg, genConsumeReg(op1), targetType);
+#else  // !_TARGET_ARM64_
+                if (varTypeIsFloating(treeNode))
+                {
+                    NYI_ARM("genRegCopy from 'int' to 'float'");
+                }
+                else
+                {
+                    assert(varTypeIsFloating(op1));
+
+                    if (op1->TypeGet() == TYP_FLOAT)
+                    {
+                        inst_RV_RV(INS_vmov_f2i, targetReg, genConsumeReg(op1), targetType);
+                    }
+                    else
+                    {
+                        regNumber otherReg = (regNumber)treeNode->AsMultiRegOp()->gtOtherReg;
+                        assert(otherReg != REG_NA);
+                        inst_RV_RV_RV(INS_vmov_d2i, targetReg, otherReg, genConsumeReg(op1), EA_8BYTE);
+                    }
+                }
+#endif // !_TARGET_ARM64_
+            }
+            else
+            {
+                inst_RV_RV(ins_Copy(targetType), targetReg, genConsumeReg(op1), targetType);
+            }
+        }
+        break;
+
         case GT_LCL_FLD_ADDR:
         case GT_LCL_VAR_ADDR:
             genCodeForLclAddr(treeNode);
index 0997154..b4203d6 100644 (file)
@@ -2033,6 +2033,8 @@ public:
 
     GenTree* gtNewPutArgReg(var_types type, GenTreePtr arg, regNumber argReg);
 
+    GenTree* gtNewBitCastNode(var_types type, GenTreePtr arg);
+
 protected:
     void gtBlockOpInit(GenTreePtr result, GenTreePtr dst, GenTreePtr srcOrFillVal, bool isVolatile);
 
index bcf8d36..367813b 100644 (file)
@@ -7058,7 +7058,7 @@ GenTree* Compiler::gtNewBlkOpNode(
 //    Returns the newly created PutArgReg node.
 //
 // Notes:
-//    The node is generated as GenTreeMultiRegOp on armel, as GenTreeOp on all the other archs
+//    The node is generated as GenTreeMultiRegOp on RyuJIT/armel, GenTreeOp on all the other archs.
 //
 GenTreePtr Compiler::gtNewPutArgReg(var_types type, GenTreePtr arg, regNumber argReg)
 {
@@ -7076,6 +7076,35 @@ GenTreePtr Compiler::gtNewPutArgReg(var_types type, GenTreePtr arg, regNumber ar
     return node;
 }
 
+//------------------------------------------------------------------------
+// gtNewBitCastNode: Creates a new BitCast node.
+//
+// Arguments:
+//    type   - The actual type of the argument
+//    arg    - The argument node
+//    argReg - The register that the argument will be passed in
+//
+// Return Value:
+//    Returns the newly created BitCast node.
+//
+// Notes:
+//    The node is generated as GenTreeMultiRegOp on RyuJIT/armel, as GenTreeOp on all the other archs.
+//
+GenTreePtr Compiler::gtNewBitCastNode(var_types type, GenTreePtr arg)
+{
+    assert(arg != nullptr);
+
+    GenTreePtr node = nullptr;
+#if !defined(LEGACY_BACKEND) && defined(ARM_SOFTFP)
+    // A BITCAST could be a MultiRegOp on armel since we could move a double register to two int registers.
+    node = new (this, GT_PUTARG_REG) GenTreeMultiRegOp(GT_BITCAST, type, arg, nullptr);
+#else
+    node            = gtNewOperNode(GT_BITCAST, type, arg);
+#endif
+
+    return node;
+}
+
 /*****************************************************************************
  *
  *  Clones the given tree value and returns a copy of the given tree.
index a8911d0..6609571 100644 (file)
@@ -6044,7 +6044,7 @@ inline bool GenTree::IsMultiRegNode() const
     }
 
 #if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
-    if (gtOper == GT_MUL_LONG || gtOper == GT_PUTARG_REG || gtOper == GT_COPY || OperIsPutArgSplit())
+    if (gtOper == GT_MUL_LONG || gtOper == GT_PUTARG_REG || gtOper == GT_BITCAST || OperIsPutArgSplit())
     {
         return true;
     }
index b9098da..6646cc3 100644 (file)
@@ -64,7 +64,11 @@ GTNODE(CMPXCHG          , GenTreeCmpXchg     ,0,GTK_SPECIAL)
 GTNODE(MEMORYBARRIER    , GenTree            ,0,GTK_LEAF|GTK_NOVALUE)
 
 GTNODE(CAST             , GenTreeCast        ,0,GTK_UNOP|GTK_EXOP)      // conversion to another type
+#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
+GTNODE(BITCAST          , GenTreeMultiRegOp  ,0,GTK_UNOP)               // reinterpretation of bits as another type
+#else
 GTNODE(BITCAST          , GenTreeUnOp        ,0,GTK_UNOP)               // reinterpretation of bits as another type
+#endif
 GTNODE(CKFINITE         , GenTreeOp          ,0,GTK_UNOP|GTK_NOCONTAIN) // Check for NaN
 GTNODE(LCLHEAP          , GenTreeOp          ,0,GTK_UNOP|GTK_NOCONTAIN) // alloca()
 GTNODE(JMP              , GenTreeVal         ,0,GTK_LEAF|GTK_NOVALUE)   // Jump to another function
index 1661809..853cceb 100644 (file)
@@ -108,7 +108,7 @@ GTSTRUCT_1(AllocObj    , GT_ALLOCOBJ)
 GTSTRUCT_2(CC          , GT_JCC, GT_SETCC)
 #if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
 #ifdef ARM_SOFTFP
-GTSTRUCT_2(MultiRegOp  , GT_MUL_LONG, GT_PUTARG_REG)
+GTSTRUCT_3(MultiRegOp  , GT_MUL_LONG, GT_PUTARG_REG, GT_BITCAST)
 #else
 GTSTRUCT_1(MultiRegOp  , GT_MUL_LONG)
 #endif
index e250902..e9b001c 100644 (file)
@@ -3714,14 +3714,32 @@ instruction CodeGen::ins_FloatCopy(var_types type)
 
 instruction CodeGen::ins_CopyIntToFloat(var_types srcType, var_types dstType)
 {
-    // Not used and not implemented
-    unreached();
+    assert((dstType == TYP_FLOAT) || (dstType == TYP_DOUBLE));
+    assert((srcType == TYP_INT) || (srcType == TYP_UINT) || (srcType == TYP_LONG) || (srcType == TYP_ULONG));
+
+    if ((srcType == TYP_LONG) || (srcType == TYP_ULONG))
+    {
+        return INS_vmov_i2d;
+    }
+    else
+    {
+        return INS_vmov_i2f;
+    }
 }
 
 instruction CodeGen::ins_CopyFloatToInt(var_types srcType, var_types dstType)
 {
-    // Not used and not implemented
-    unreached();
+    assert((srcType == TYP_FLOAT) || (srcType == TYP_DOUBLE));
+    assert((dstType == TYP_INT) || (dstType == TYP_UINT) || (dstType == TYP_LONG) || (dstType == TYP_ULONG));
+
+    if ((dstType == TYP_LONG) || (dstType == TYP_ULONG))
+    {
+        return INS_vmov_d2i;
+    }
+    else
+    {
+        return INS_vmov_f2i;
+    }
 }
 
 instruction CodeGen::ins_FloatCompare(var_types type)
index 2a126d3..793422b 100644 (file)
@@ -762,7 +762,7 @@ void Lowering::ReplaceArgWithPutArgOrCopy(GenTree** argSlot, GenTree* putArgOrCo
 {
     assert(argSlot != nullptr);
     assert(*argSlot != nullptr);
-    assert(putArgOrCopy->OperIsPutArg() || putArgOrCopy->OperIs(GT_COPY));
+    assert(putArgOrCopy->OperIsPutArg() || putArgOrCopy->OperIs(GT_BITCAST));
 
     GenTree* arg = *argSlot;
 
@@ -1295,12 +1295,15 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
         {
             var_types intType = (type == TYP_DOUBLE) ? TYP_LONG : TYP_INT;
 
-            GenTreePtr intArg = new (comp, GT_COPY) GenTreeCopyOrReload(GT_COPY, intType, arg);
-
-            if (comp->opts.compUseSoftFP)
+            GenTreePtr intArg = comp->gtNewBitCastNode(intType, arg);
+            intArg->gtRegNum  = info->regNum;
+#ifdef ARM_SOFTFP
+            if (intType == TYP_LONG)
             {
-                intArg->gtFlags |= GTF_VAR_DEATH;
+                assert(info->numRegs == 2);
+                intArg->AsMultiRegOp()->gtOtherReg = REG_NEXT(info->regNum);
             }
+#endif // ARM_SOFTFP
 
             info->node = intArg;
             ReplaceArgWithPutArgOrCopy(ppArg, intArg);
index 47e6d32..54754f4 100644 (file)
@@ -134,18 +134,12 @@ void lsraAssignRegToTree(GenTreePtr tree, regNumber reg, unsigned regIdx)
         tree->gtRegNum = reg;
     }
 #if defined(_TARGET_ARM_)
-    else if (tree->OperGet() == GT_MUL_LONG || tree->OperGet() == GT_PUTARG_REG)
+    else if (tree->OperGet() == GT_MUL_LONG || tree->OperGet() == GT_PUTARG_REG || tree->OperGet() == GT_BITCAST)
     {
         assert(regIdx == 1);
         GenTreeMultiRegOp* mul = tree->AsMultiRegOp();
         mul->gtOtherReg        = reg;
     }
-    else if (tree->OperGet() == GT_COPY)
-    {
-        assert(regIdx == 1);
-        GenTreeCopyOrReload* copy = tree->AsCopyOrReload();
-        copy->gtOtherRegs[0]      = (regNumberSmall)reg;
-    }
     else if (tree->OperGet() == GT_PUTARG_SPLIT)
     {
         GenTreePutArgSplit* putArg = tree->AsPutArgSplit();
@@ -4038,7 +4032,8 @@ void LinearScan::buildRefPositionsForNode(GenTree*                  tree,
 
             regMaskTP candidates = getUseCandidates(useNode);
 #ifdef _TARGET_ARM_
-            if (useNode->OperIsPutArgSplit() || (compiler->opts.compUseSoftFP && useNode->OperIsPutArgReg()))
+            if (useNode->OperIsPutArgSplit() ||
+                (compiler->opts.compUseSoftFP && (useNode->OperIsPutArgReg() || useNode->OperGet() == GT_BITCAST)))
             {
                 // get i-th candidate, set bits in useCandidates must be in sequential order.
                 candidates = genFindLowestReg(candidates & ~currCandidates);
@@ -4116,9 +4111,6 @@ void LinearScan::buildRefPositionsForNode(GenTree*                  tree,
     // push defs
     LocationInfoList locationInfoList;
     LsraLocation     defLocation = currentLoc + 1;
-#ifdef ARM_SOFTFP
-    regMaskTP remainingUseCandidates = useCandidates;
-#endif
     for (int i = 0; i < produce; i++)
     {
         regMaskTP currCandidates = candidates;
@@ -4142,10 +4134,10 @@ void LinearScan::buildRefPositionsForNode(GenTree*                  tree,
         }
 #ifdef ARM_SOFTFP
         // If oper is GT_PUTARG_REG, set bits in useCandidates must be in sequential order.
-        else if (tree->OperIsMultiRegOp() || tree->OperGet() == GT_COPY)
+        else if (tree->OperIsMultiRegOp() || tree->OperGet() == GT_BITCAST)
         {
-            useCandidates = genFindLowestReg(remainingUseCandidates);
-            remainingUseCandidates &= ~useCandidates;
+            currCandidates = genFindLowestReg(candidates);
+            candidates &= ~currCandidates;
         }
 #endif // ARM_SOFTFP
 #endif // _TARGET_ARM_
index 09246b6..862fe37 100644 (file)
@@ -708,18 +708,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
 
         case GT_COPY:
             info->srcCount = 1;
-#ifdef ARM_SOFTFP
-            // This case currently only occurs for double types that are passed as TYP_LONG;
-            // actual long types would have been decomposed by now.
-            if (tree->TypeGet() == TYP_LONG)
-            {
-                info->dstCount = 2;
-            }
-            else
-#endif
-            {
-                assert(info->dstCount == 1);
-            }
+            assert(info->dstCount == 1);
             break;
 
         case GT_PUTARG_SPLIT:
@@ -734,6 +723,28 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
             TreeNodeInfoInitPutArgReg(tree->AsUnOp());
             break;
 
+        case GT_BITCAST:
+        {
+            info->srcCount = 1;
+            assert(info->dstCount == 1);
+            regNumber argReg  = tree->gtRegNum;
+            regMaskTP argMask = genRegMask(argReg);
+#ifdef ARM_SOFTFP
+            // If type of node is `long` then it is actually `double`.
+            // The actual `long` types must have been transformed as a field list with two fields.
+            if (tree->TypeGet() == TYP_LONG)
+            {
+                info->dstCount++;
+                assert(genRegArgNext(argReg) == REG_NEXT(argReg));
+                argMask |= genRegMask(REG_NEXT(argReg));
+            }
+#endif // ARM_SOFTFP
+            info->setDstCandidates(this, argMask);
+            info->setSrcCandidates(this, argMask);
+            tree->AsUnOp()->gtOp1->gtLsraInfo.isTgtPref = true;
+        }
+        break;
+
         default:
 #ifdef DEBUG
             char message[256];