From 2fc8a975c441f33a16c99fdf4960dcdff125addc Mon Sep 17 00:00:00 2001 From: Hyung-Kyu Choi Date: Mon, 13 Mar 2017 22:24:00 +0900 Subject: [PATCH] [Ryujit/ARM32] Support shift and rotate for decomposed long Signed-off-by: Hyung-Kyu Choi Commit migrated from https://github.com/dotnet/coreclr/commit/ea3b0538ae876d19f1aa9c6d2fb1357870800909 --- src/coreclr/src/jit/codegenarm.cpp | 75 ++++++++++++++++++++++++++++++++++++- src/coreclr/src/jit/codegenlinear.h | 2 +- src/coreclr/src/jit/lsraarm.cpp | 66 +++++++++++++++++++++++++------- 3 files changed, 128 insertions(+), 15 deletions(-) diff --git a/src/coreclr/src/jit/codegenarm.cpp b/src/coreclr/src/jit/codegenarm.cpp index e9f8ff2..5c5ca79 100644 --- a/src/coreclr/src/jit/codegenarm.cpp +++ b/src/coreclr/src/jit/codegenarm.cpp @@ -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 (<>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/coreclr/src/jit/codegenlinear.h b/src/coreclr/src/jit/codegenlinear.h index af545fe..6ee7713 100644 --- a/src/coreclr/src/jit/codegenlinear.h +++ b/src/coreclr/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/coreclr/src/jit/lsraarm.cpp b/src/coreclr/src/jit/lsraarm.cpp index e1f2d6d..3a2206b 100644 --- a/src/coreclr/src/jit/lsraarm.cpp +++ b/src/coreclr/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: -- 2.7.4