diff options
-rw-r--r-- | src/jit/codegenarm.cpp | 75 | ||||
-rw-r--r-- | src/jit/codegenlinear.h | 2 | ||||
-rw-r--r-- | src/jit/lsraarm.cpp | 66 |
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: |