[Ryujit/ARM32] Support shift and rotate for decomposed long
authorHyung-Kyu Choi <hk0110.choi@samsung.com>
Mon, 13 Mar 2017 13:24:00 +0000 (22:24 +0900)
committerHyung-Kyu Choi <hk0110.choi@samsung.com>
Mon, 13 Mar 2017 15:03:03 +0000 (00:03 +0900)
Signed-off-by: Hyung-Kyu Choi <hk0110.choi@samsung.com>
Commit migrated from https://github.com/dotnet/coreclr/commit/ea3b0538ae876d19f1aa9c6d2fb1357870800909

src/coreclr/src/jit/codegenarm.cpp
src/coreclr/src/jit/codegenlinear.h
src/coreclr/src/jit/lsraarm.cpp

index e9f8ff2..5c5ca79 100644 (file)
@@ -597,7 +597,11 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
         case GT_RSZ:
         case GT_ROR:
             genCodeForShift(treeNode);
-            // genCodeForShift() calls genProduceReg()
+            break;
+
+        case GT_LSH_HI:
+        case GT_RSH_LO:
+            genCodeForShiftLong(treeNode);
             break;
 
         case GT_CAST:
@@ -1652,6 +1656,12 @@ instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
         case GT_SUB_HI:
             ins = INS_sbc;
             break;
+        case GT_LSH_HI:
+            ins = INS_SHIFT_LEFT_LOGICAL;
+            break;
+        case GT_RSH_LO:
+            ins = INS_SHIFT_RIGHT_LOGICAL;
+            break;
         default:
             unreached();
             break;
@@ -1800,6 +1810,69 @@ void CodeGen::genCodeForInitBlk(GenTreeBlk* initBlkNode)
 }
 
 //------------------------------------------------------------------------
+// genCodeForShiftLong: Generates the code sequence for a GenTree node that
+// represents a three operand bit shift or rotate operation (<<Hi, >>Lo).
+//
+// Arguments:
+//    tree - the bit shift node (that specifies the type of bit shift to perform).
+//
+// Assumptions:
+//    a) All GenTrees are register allocated.
+//    b) The shift-by-amount in tree->gtOp.gtOp2 is a contained constant
+//
+void CodeGen::genCodeForShiftLong(GenTreePtr tree)
+{
+    // Only the non-RMW case here.
+    genTreeOps oper = tree->OperGet();
+    assert(oper == GT_LSH_HI || oper == GT_RSH_LO);
+
+    GenTree* operand = tree->gtOp.gtOp1;
+    assert(operand->OperGet() == GT_LONG);
+    assert(operand->gtOp.gtOp1->isUsedFromReg());
+    assert(operand->gtOp.gtOp2->isUsedFromReg());
+
+    GenTree* operandLo = operand->gtGetOp1();
+    GenTree* operandHi = operand->gtGetOp2();
+
+    regNumber regLo = operandLo->gtRegNum;
+    regNumber regHi = operandHi->gtRegNum;
+
+    genConsumeOperands(tree->AsOp());
+
+    var_types   targetType = tree->TypeGet();
+    instruction ins        = genGetInsForOper(oper, targetType);
+
+    GenTreePtr shiftBy = tree->gtGetOp2();
+
+    assert(shiftBy->isContainedIntOrIImmed());
+
+    unsigned int count = shiftBy->AsIntConCommon()->IconValue();
+
+    regNumber regResult = (oper == GT_LSH_HI) ? regHi : regLo;
+
+    if (regResult != tree->gtRegNum)
+    {
+        inst_RV_RV(INS_mov, tree->gtRegNum, regResult, targetType);
+    }
+
+    if (oper == GT_LSH_HI)
+    {
+        inst_RV_SH(ins, EA_4BYTE, tree->gtRegNum, count);
+        getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, tree->gtRegNum, tree->gtRegNum, regLo, 32 - count,
+                                      INS_FLAGS_DONT_CARE, INS_OPTS_LSR);
+    }
+    else
+    {
+        assert(oper == GT_RSH_LO);
+        inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, EA_4BYTE, tree->gtRegNum, count);
+        getEmitter()->emitIns_R_R_R_I(INS_OR, EA_4BYTE, tree->gtRegNum, tree->gtRegNum, regHi, 32 - count,
+                                      INS_FLAGS_DONT_CARE, INS_OPTS_LSL);
+    }
+
+    genProduceReg(tree);
+}
+
+//------------------------------------------------------------------------
 // genRegCopy: Generate a register copy.
 //
 void CodeGen::genRegCopy(GenTree* treeNode)
index af545fe..6ee7713 100644 (file)
@@ -158,7 +158,7 @@ void genSetRegToIcon(regNumber reg, ssize_t val, var_types type = TYP_INT, insFl
 
 void genCodeForShift(GenTreePtr tree);
 
-#if defined(_TARGET_X86_)
+#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
 void genCodeForShiftLong(GenTreePtr tree);
 #endif
 
index e1f2d6d..3a2206b 100644 (file)
@@ -382,6 +382,55 @@ void Lowering::TreeNodeInfoInitReturn(GenTree* tree)
 }
 
 //------------------------------------------------------------------------
+// TreeNodeInfoInitShiftRotate: Set the NodeInfo for a shift or rotate.
+//
+// Arguments:
+//    tree      - The node of interest
+//
+// Return Value:
+//    None.
+//
+void Lowering::TreeNodeInfoInitShiftRotate(GenTree* tree)
+{
+    TreeNodeInfo* info = &(tree->gtLsraInfo);
+    LinearScan*   l    = m_lsra;
+
+    info->srcCount = 2;
+    info->dstCount = 1;
+
+    GenTreePtr shiftBy = tree->gtOp.gtOp2;
+    GenTreePtr source  = tree->gtOp.gtOp1;
+    if (shiftBy->IsCnsIntOrI())
+    {
+        l->clearDstCount(shiftBy);
+        info->srcCount--;
+    }
+
+    // The first operand of a GT_LSH_HI and GT_RSH_LO oper is a GT_LONG so that
+    // we can have a three operand form. Increment the srcCount.
+    if (tree->OperGet() == GT_LSH_HI || tree->OperGet() == GT_RSH_LO)
+    {
+        assert(source->OperGet() == GT_LONG);
+
+        info->srcCount++;
+
+        if (tree->OperGet() == GT_LSH_HI)
+        {
+            GenTreePtr sourceLo              = source->gtOp.gtOp1;
+            sourceLo->gtLsraInfo.isDelayFree = true;
+        }
+        else
+        {
+            GenTreePtr sourceHi              = source->gtOp.gtOp2;
+            sourceHi->gtLsraInfo.isDelayFree = true;
+        }
+
+        source->gtLsraInfo.hasDelayFreeSrc = true;
+        info->hasDelayFreeSrc              = true;
+    }
+}
+
+//------------------------------------------------------------------------
 // TreeNodeInfoInitPutArgReg: Set the NodeInfo for a PUTARG_REG.
 //
 // Arguments:
@@ -1205,19 +1254,10 @@ void Lowering::TreeNodeInfoInit(GenTree* tree)
         case GT_RSH:
         case GT_RSZ:
         case GT_ROR:
-        {
-            info->srcCount = 2;
-            info->dstCount = 1;
-
-            GenTreePtr shiftBy = tree->gtOp.gtOp2;
-            GenTreePtr source  = tree->gtOp.gtOp1;
-            if (shiftBy->IsCnsIntOrI())
-            {
-                l->clearDstCount(shiftBy);
-                info->srcCount--;
-            }
-        }
-        break;
+        case GT_LSH_HI:
+        case GT_RSH_LO:
+            TreeNodeInfoInitShiftRotate(tree);
+            break;
 
         case GT_EQ:
         case GT_NE: