diff options
author | Mikhail Skvortcov <m.skvortcov@partner.samsung.com> | 2017-05-15 13:23:12 +0300 |
---|---|---|
committer | Mikhail Skvortcov <m.skvortcov@partner.samsung.com> | 2017-05-15 13:34:02 +0300 |
commit | 247f215eb97f0a28fadb1859fbc99404e996c4e5 (patch) | |
tree | cf372e6a0ae3b2f0280658a9d9affda8d55865f4 /src/jit | |
parent | 76cbc581382ebbcf745dd2b79ac02c419970808c (diff) | |
download | coreclr-247f215eb97f0a28fadb1859fbc99404e996c4e5.tar.gz coreclr-247f215eb97f0a28fadb1859fbc99404e996c4e5.tar.bz2 coreclr-247f215eb97f0a28fadb1859fbc99404e996c4e5.zip |
RyuJIT/ARM32: Enable GT_MUL_LONG codegen.
Diffstat (limited to 'src/jit')
-rw-r--r-- | src/jit/codegenarm.cpp | 25 | ||||
-rw-r--r-- | src/jit/codegenarmarch.cpp | 6 | ||||
-rw-r--r-- | src/jit/codegenlinear.h | 4 | ||||
-rw-r--r-- | src/jit/compiler.cpp | 2 | ||||
-rw-r--r-- | src/jit/decomposelongs.cpp | 5 | ||||
-rw-r--r-- | src/jit/gentree.cpp | 4 | ||||
-rw-r--r-- | src/jit/gentree.h | 45 | ||||
-rw-r--r-- | src/jit/gtlist.h | 19 | ||||
-rw-r--r-- | src/jit/gtstructs.h | 3 | ||||
-rw-r--r-- | src/jit/lsra.cpp | 8 | ||||
-rw-r--r-- | src/jit/lsraarm.cpp | 9 |
11 files changed, 114 insertions, 16 deletions
diff --git a/src/jit/codegenarm.cpp b/src/jit/codegenarm.cpp index 40371e358c..ce559f1dd3 100644 --- a/src/jit/codegenarm.cpp +++ b/src/jit/codegenarm.cpp @@ -1977,13 +1977,34 @@ void CodeGen::genStoreLongLclVar(GenTree* treeNode) { assert((op1->gtFlags & GTF_MUL_64RSLT) != 0); + GenTreeMulLong* mul = op1->AsMulLong(); + // Stack store - getEmitter()->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), REG_LNGRET_LO, lclNum, 0); - getEmitter()->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), REG_LNGRET_HI, lclNum, + getEmitter()->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), mul->gtRegNum, lclNum, 0); + getEmitter()->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), mul->gtOtherReg, lclNum, genTypeSize(TYP_INT)); } } +//------------------------------------------------------------------------ +// genCodeForMulLong: Generates code for int*int->long multiplication +// +// Arguments: +// node - the GT_MUL_LONG node +// +// Return Value: +// None. +// +void CodeGen::genCodeForMulLong(GenTreeMulLong* node) +{ + genConsumeOperands(node); + GenTree* src1 = node->gtOp1; + GenTree* src2 = node->gtOp2; + instruction ins = node->IsUnsigned() ? INS_umull : INS_smull; + getEmitter()->emitIns_R_R_R_R(ins, EA_4BYTE, node->gtRegNum, node->gtOtherReg, src1->gtRegNum, src2->gtRegNum); + genProduceReg(node); +} + #endif // _TARGET_ARM_ #endif // !LEGACY_BACKEND diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp index 103ce47625..f03ffc2c18 100644 --- a/src/jit/codegenarmarch.cpp +++ b/src/jit/codegenarmarch.cpp @@ -189,6 +189,12 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode) genCodeForIndir(treeNode->AsIndir()); break; +#ifdef _TARGET_ARM_ + case GT_MUL_LONG: + genCodeForMulLong(treeNode->AsMulLong()); + break; +#endif // _TARGET_ARM_ + #ifdef _TARGET_ARM64_ case GT_MULHI: diff --git a/src/jit/codegenlinear.h b/src/jit/codegenlinear.h index 3bd0eacf0d..bfb7d9d49a 100644 --- a/src/jit/codegenlinear.h +++ b/src/jit/codegenlinear.h @@ -23,6 +23,10 @@ void genCodeForMulHi(GenTreeOp* treeNode); void genLeaInstruction(GenTreeAddrMode* lea); void genSetRegToCond(regNumber dstReg, GenTreePtr tree); +#if defined(_TARGET_ARM_) +void genCodeForMulLong(GenTreeMulLong* treeNode); +#endif // _TARGET_ARM_ + #if !defined(_TARGET_64BIT_) void genLongToIntCast(GenTreePtr treeNode); #endif diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp index 1c24b93abe..2dcdfdc03a 100644 --- a/src/jit/compiler.cpp +++ b/src/jit/compiler.cpp @@ -9321,7 +9321,7 @@ int cTreeFlagsIR(Compiler* comp, GenTree* tree) break; case GT_MUL: -#if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND) +#if !defined(_TARGET_64BIT_) && !defined(LEGACY_BACKEND) case GT_MUL_LONG: #endif diff --git a/src/jit/decomposelongs.cpp b/src/jit/decomposelongs.cpp index 4168e77c1c..cc6b4fc81e 100644 --- a/src/jit/decomposelongs.cpp +++ b/src/jit/decomposelongs.cpp @@ -1554,7 +1554,8 @@ GenTree* DecomposeLongs::DecomposeRotate(LIR::Use& use) // these nodes, we convert them into GT_MUL_LONGs, undo the cast from int to long by // stripping out the lo ops, and force them into the form var = mul, as we do for // GT_CALLs. In codegen, we then produce a mul instruction that produces the result -// in edx:eax, and store those registers on the stack in genStoreLongLclVar. +// in edx:eax on x86 or in any two chosen by RA registers on arm32, and store those +// registers on the stack in genStoreLongLclVar. // // All other GT_MULs have been converted to helper calls in morph.cpp // @@ -1587,7 +1588,7 @@ GenTree* DecomposeLongs::DecomposeMul(LIR::Use& use) tree->gtOp.gtOp1 = op1->gtGetOp1(); tree->gtOp.gtOp2 = op2->gtGetOp1(); - tree->SetOperRaw(GT_MUL_LONG); + tree->SetOper(GT_MUL_LONG); return StoreNodeToVar(use); } diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index 5063f6878c..bda07f16ce 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -10209,7 +10209,7 @@ void Compiler::gtDispNode(GenTreePtr tree, IndentStack* indentStack, __in __in_z goto DASH; case GT_MUL: -#if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND) +#if !defined(_TARGET_64BIT_) && !defined(LEGACY_BACKEND) case GT_MUL_LONG: #endif if (tree->gtFlags & GTF_MUL_64RSLT) @@ -17083,4 +17083,4 @@ regNumber GenTree::ExtractTempReg(regMaskTP mask /* = (regMaskTP)-1 */) return genRegNumFromMask(tempRegMask); } -#endif // !LEGACY_BACKEND
\ No newline at end of file +#endif // !LEGACY_BACKEND diff --git a/src/jit/gentree.h b/src/jit/gentree.h index 0d487be62e..bb1a15761b 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -1700,6 +1700,9 @@ public: // Returns true if it is a call node returning its value in more than one register inline bool IsMultiRegCall() const; + // Returns true if it is a node returning its value in more than one register + inline bool IsMultiRegNode() const; + // Returns true if it is a GT_COPY or GT_RELOAD node inline bool IsCopyOrReload() const; @@ -3720,6 +3723,23 @@ struct GenTreeCmpXchg : public GenTree #endif }; +#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_) +struct GenTreeMulLong : public GenTreeOp +{ + regNumber gtOtherReg; + + GenTreeMulLong(var_types type, GenTreePtr op1, GenTreePtr op2) : GenTreeOp(GT_MUL_LONG, type, op1, op2) + { + } + +#if DEBUGGABLE_GENTREE + GenTreeMulLong() : GenTreeOp() + { + } +#endif +}; +#endif + struct GenTreeFptrVal : public GenTree { CORINFO_METHOD_HANDLE gtFptrMethod; @@ -5352,6 +5372,31 @@ inline bool GenTree::IsMultiRegCall() const return false; } +//----------------------------------------------------------------------------------- +// IsMultiRegNode: whether a node returning its value in more than one register +// +// Arguments: +// None +// +// Return Value: +// Returns true if this GenTree is a multi-reg node. +inline bool GenTree::IsMultiRegNode() const +{ + if (IsMultiRegCall()) + { + return true; + } + +#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_) + if (gtOper == GT_MUL_LONG) + { + return true; + } +#endif + + return false; +} + //------------------------------------------------------------------------- // IsCopyOrReload: whether this is a GT_COPY or GT_RELOAD node. // diff --git a/src/jit/gtlist.h b/src/jit/gtlist.h index 826eaf1207..5af2f5bb78 100644 --- a/src/jit/gtlist.h +++ b/src/jit/gtlist.h @@ -175,7 +175,7 @@ GTNODE(LEA , "lea" ,GenTreeAddrMode ,0,GTK_BINOP|GTK_EX // nodes such as calls, returns and stores of long lclVars. GTNODE(LONG , "gt_long" ,GenTreeOp ,0,GTK_BINOP) -// The following are nodes representing x86 specific long operators, including +// The following are nodes representing x86/arm32 specific long operators, including // high operators of a 64-bit operations that requires a carry/borrow, which are // named GT_XXX_HI for consistency, low operators of 64-bit operations that need // to not be modified in phases post-decompose, and operators that return 64-bit @@ -186,12 +186,17 @@ GTNODE(SUB_LO , "-Lo" ,GenTreeOp ,0,GTK_BINOP) GTNODE(SUB_HI , "-Hi" ,GenTreeOp ,0,GTK_BINOP) GTNODE(DIV_HI , "/Hi" ,GenTreeOp ,0,GTK_BINOP) GTNODE(MOD_HI , "%Hi" ,GenTreeOp ,0,GTK_BINOP) -GTNODE(MUL_LONG , "*long" ,GenTreeOp ,1,GTK_BINOP) // A mul that returns the 2N bit result of an NxN multiply. This op - // is used for x86 multiplies that take two ints and return a long - // result. All other multiplies with long results are morphed into - // helper calls. It is similar to GT_MULHI, the difference being that - // GT_MULHI drops the lo part of the result, whereas GT_MUL_LONG keeps - // both parts of the result. + +// A mul that returns the 2N bit result of an NxN multiply. This op is used for +// multiplies that take two ints and return a long result. All other multiplies +// with long results are morphed into helper calls. It is similar to GT_MULHI, +// the difference being that GT_MULHI drops the lo part of the result, whereas +// GT_MUL_LONG keeps both parts of the result. +#if defined(_TARGET_X86_) +GTNODE(MUL_LONG , "*long" ,GenTreeOp ,1,GTK_BINOP) +#elif defined (_TARGET_ARM_) +GTNODE(MUL_LONG , "*long" ,GenTreeMulLong ,1,GTK_BINOP) +#endif // The following are nodes that specify shifts that take a GT_LONG op1. The GT_LONG // contains the hi and lo parts of three operand shift form where one op will be diff --git a/src/jit/gtstructs.h b/src/jit/gtstructs.h index ac912407be..c4a4f73e37 100644 --- a/src/jit/gtstructs.h +++ b/src/jit/gtstructs.h @@ -102,6 +102,9 @@ GTSTRUCT_1(SIMD , GT_SIMD) #endif // FEATURE_SIMD GTSTRUCT_1(AllocObj , GT_ALLOCOBJ) GTSTRUCT_1(JumpCC , GT_JCC) +#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_) +GTSTRUCT_1(MulLong , GT_MUL_LONG) +#endif /*****************************************************************************/ #undef GTSTRUCT_0 #undef GTSTRUCT_1 diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp index 647b0587f6..fae6a79532 100644 --- a/src/jit/lsra.cpp +++ b/src/jit/lsra.cpp @@ -133,6 +133,14 @@ void lsraAssignRegToTree(GenTreePtr tree, regNumber reg, unsigned regIdx) { tree->gtRegNum = reg; } +#if defined(_TARGET_ARM_) + else if (tree->OperGet() == GT_MUL_LONG) + { + assert(regIdx == 1); + GenTreeMulLong* mul = tree->AsMulLong(); + mul->gtOtherReg = reg; + } +#endif // _TARGET_ARM_ else { assert(tree->IsMultiRegCall()); diff --git a/src/jit/lsraarm.cpp b/src/jit/lsraarm.cpp index 0d1cfe6bfa..925c61d6ca 100644 --- a/src/jit/lsraarm.cpp +++ b/src/jit/lsraarm.cpp @@ -236,7 +236,7 @@ void Lowering::TreeNodeInfoInit(GenTree* tree) case GT_STORE_LCL_FLD: case GT_STORE_LCL_VAR: - if (tree->gtGetOp1()->OperGet() == GT_LONG) + if (varTypeIsLong(tree->gtGetOp1())) { info->srcCount = 2; } @@ -456,6 +456,11 @@ void Lowering::TreeNodeInfoInit(GenTree* tree) } break; + case GT_MUL_LONG: + info->srcCount = 2; + info->dstCount = 2; + break; + case GT_LIST: case GT_FIELD_LIST: case GT_ARGPLACE: @@ -739,7 +744,7 @@ void Lowering::TreeNodeInfoInit(GenTree* tree) } // end switch (tree->OperGet()) // We need to be sure that we've set info->srcCount and info->dstCount appropriately - assert((info->dstCount < 2) || tree->IsMultiRegCall()); + assert((info->dstCount < 2) || tree->IsMultiRegNode()); } #endif // _TARGET_ARM_ |