summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jit/codegenarm.cpp75
-rw-r--r--src/jit/codegenlinear.h2
-rw-r--r--src/jit/lsraarm.cpp66
3 files changed, 128 insertions, 15 deletions
diff --git a/src/jit/codegenarm.cpp b/src/jit/codegenarm.cpp
index 871caa57d2..e276b711c5 100644
--- a/src/jit/codegenarm.cpp
+++ b/src/jit/codegenarm.cpp
@@ -599,7 +599,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:
@@ -1654,6 +1658,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;
@@ -1802,6 +1812,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)
diff --git a/src/jit/codegenlinear.h b/src/jit/codegenlinear.h
index a53663503b..154d4845a0 100644
--- a/src/jit/codegenlinear.h
+++ b/src/jit/codegenlinear.h
@@ -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
diff --git a/src/jit/lsraarm.cpp b/src/jit/lsraarm.cpp
index e1f2d6d732..3a2206bf8d 100644
--- a/src/jit/lsraarm.cpp
+++ b/src/jit/lsraarm.cpp
@@ -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: