summaryrefslogtreecommitdiff
path: root/src/jit
diff options
context:
space:
mode:
authorMikhail Skvortcov <m.skvortcov@partner.samsung.com>2017-05-15 13:23:12 +0300
committerMikhail Skvortcov <m.skvortcov@partner.samsung.com>2017-05-15 13:34:02 +0300
commit247f215eb97f0a28fadb1859fbc99404e996c4e5 (patch)
treecf372e6a0ae3b2f0280658a9d9affda8d55865f4 /src/jit
parent76cbc581382ebbcf745dd2b79ac02c419970808c (diff)
downloadcoreclr-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.cpp25
-rw-r--r--src/jit/codegenarmarch.cpp6
-rw-r--r--src/jit/codegenlinear.h4
-rw-r--r--src/jit/compiler.cpp2
-rw-r--r--src/jit/decomposelongs.cpp5
-rw-r--r--src/jit/gentree.cpp4
-rw-r--r--src/jit/gentree.h45
-rw-r--r--src/jit/gtlist.h19
-rw-r--r--src/jit/gtstructs.h3
-rw-r--r--src/jit/lsra.cpp8
-rw-r--r--src/jit/lsraarm.cpp9
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_