summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jit/codegenarmarch.cpp36
-rw-r--r--src/jit/compiler.h2
-rw-r--r--src/jit/gentree.cpp31
-rw-r--r--src/jit/gentree.h2
-rw-r--r--src/jit/gtlist.h4
-rw-r--r--src/jit/gtstructs.h2
-rw-r--r--src/jit/instr.cpp26
-rw-r--r--src/jit/lower.cpp13
-rw-r--r--src/jit/lsra.cpp20
-rw-r--r--src/jit/lsraarm.cpp35
10 files changed, 133 insertions, 38 deletions
diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp
index c8848d1c49..b3f191764b 100644
--- a/src/jit/codegenarmarch.cpp
+++ b/src/jit/codegenarmarch.cpp
@@ -154,6 +154,42 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
genCodeForCast(treeNode->AsOp());
break;
+ case GT_BITCAST:
+ {
+ GenTree* op1 = treeNode->gtOp.gtOp1;
+ if (varTypeIsFloating(treeNode) != varTypeIsFloating(op1))
+ {
+#ifdef _TARGET_ARM64_
+ inst_RV_RV(INS_fmov, targetReg, genConsumeReg(op1), targetType);
+#else // !_TARGET_ARM64_
+ if (varTypeIsFloating(treeNode))
+ {
+ NYI_ARM("genRegCopy from 'int' to 'float'");
+ }
+ else
+ {
+ assert(varTypeIsFloating(op1));
+
+ if (op1->TypeGet() == TYP_FLOAT)
+ {
+ inst_RV_RV(INS_vmov_f2i, targetReg, genConsumeReg(op1), targetType);
+ }
+ else
+ {
+ regNumber otherReg = (regNumber)treeNode->AsMultiRegOp()->gtOtherReg;
+ assert(otherReg != REG_NA);
+ inst_RV_RV_RV(INS_vmov_d2i, targetReg, otherReg, genConsumeReg(op1), EA_8BYTE);
+ }
+ }
+#endif // !_TARGET_ARM64_
+ }
+ else
+ {
+ inst_RV_RV(ins_Copy(targetType), targetReg, genConsumeReg(op1), targetType);
+ }
+ }
+ break;
+
case GT_LCL_FLD_ADDR:
case GT_LCL_VAR_ADDR:
genCodeForLclAddr(treeNode);
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index cce1f718fd..1dcc76338c 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -2033,6 +2033,8 @@ public:
GenTree* gtNewPutArgReg(var_types type, GenTreePtr arg, regNumber argReg);
+ GenTree* gtNewBitCastNode(var_types type, GenTreePtr arg);
+
protected:
void gtBlockOpInit(GenTreePtr result, GenTreePtr dst, GenTreePtr srcOrFillVal, bool isVolatile);
diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp
index 9962be0fde..965b5243ee 100644
--- a/src/jit/gentree.cpp
+++ b/src/jit/gentree.cpp
@@ -7058,7 +7058,7 @@ GenTree* Compiler::gtNewBlkOpNode(
// Returns the newly created PutArgReg node.
//
// Notes:
-// The node is generated as GenTreeMultiRegOp on armel, as GenTreeOp on all the other archs
+// The node is generated as GenTreeMultiRegOp on RyuJIT/armel, GenTreeOp on all the other archs.
//
GenTreePtr Compiler::gtNewPutArgReg(var_types type, GenTreePtr arg, regNumber argReg)
{
@@ -7076,6 +7076,35 @@ GenTreePtr Compiler::gtNewPutArgReg(var_types type, GenTreePtr arg, regNumber ar
return node;
}
+//------------------------------------------------------------------------
+// gtNewBitCastNode: Creates a new BitCast node.
+//
+// Arguments:
+// type - The actual type of the argument
+// arg - The argument node
+// argReg - The register that the argument will be passed in
+//
+// Return Value:
+// Returns the newly created BitCast node.
+//
+// Notes:
+// The node is generated as GenTreeMultiRegOp on RyuJIT/armel, as GenTreeOp on all the other archs.
+//
+GenTreePtr Compiler::gtNewBitCastNode(var_types type, GenTreePtr arg)
+{
+ assert(arg != nullptr);
+
+ GenTreePtr node = nullptr;
+#if !defined(LEGACY_BACKEND) && defined(ARM_SOFTFP)
+ // A BITCAST could be a MultiRegOp on armel since we could move a double register to two int registers.
+ node = new (this, GT_PUTARG_REG) GenTreeMultiRegOp(GT_BITCAST, type, arg, nullptr);
+#else
+ node = gtNewOperNode(GT_BITCAST, type, arg);
+#endif
+
+ return node;
+}
+
/*****************************************************************************
*
* Clones the given tree value and returns a copy of the given tree.
diff --git a/src/jit/gentree.h b/src/jit/gentree.h
index d15f007b32..62bd8cbb08 100644
--- a/src/jit/gentree.h
+++ b/src/jit/gentree.h
@@ -6053,7 +6053,7 @@ inline bool GenTree::IsMultiRegNode() const
}
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
- if (gtOper == GT_MUL_LONG || gtOper == GT_PUTARG_REG || gtOper == GT_COPY || OperIsPutArgSplit())
+ if (gtOper == GT_MUL_LONG || gtOper == GT_PUTARG_REG || gtOper == GT_BITCAST || OperIsPutArgSplit())
{
return true;
}
diff --git a/src/jit/gtlist.h b/src/jit/gtlist.h
index 47b3e52217..2c21fe1380 100644
--- a/src/jit/gtlist.h
+++ b/src/jit/gtlist.h
@@ -64,7 +64,11 @@ GTNODE(CMPXCHG , GenTreeCmpXchg ,0,GTK_SPECIAL)
GTNODE(MEMORYBARRIER , GenTree ,0,GTK_LEAF|GTK_NOVALUE)
GTNODE(CAST , GenTreeCast ,0,GTK_UNOP|GTK_EXOP) // conversion to another type
+#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
+GTNODE(BITCAST , GenTreeMultiRegOp ,0,GTK_UNOP) // reinterpretation of bits as another type
+#else
GTNODE(BITCAST , GenTreeUnOp ,0,GTK_UNOP) // reinterpretation of bits as another type
+#endif
GTNODE(CKFINITE , GenTreeOp ,0,GTK_UNOP|GTK_NOCONTAIN) // Check for NaN
GTNODE(LCLHEAP , GenTreeOp ,0,GTK_UNOP|GTK_NOCONTAIN) // alloca()
GTNODE(JMP , GenTreeVal ,0,GTK_LEAF|GTK_NOVALUE) // Jump to another function
diff --git a/src/jit/gtstructs.h b/src/jit/gtstructs.h
index 1661809f6c..853ccebe9f 100644
--- a/src/jit/gtstructs.h
+++ b/src/jit/gtstructs.h
@@ -108,7 +108,7 @@ GTSTRUCT_1(AllocObj , GT_ALLOCOBJ)
GTSTRUCT_2(CC , GT_JCC, GT_SETCC)
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
#ifdef ARM_SOFTFP
-GTSTRUCT_2(MultiRegOp , GT_MUL_LONG, GT_PUTARG_REG)
+GTSTRUCT_3(MultiRegOp , GT_MUL_LONG, GT_PUTARG_REG, GT_BITCAST)
#else
GTSTRUCT_1(MultiRegOp , GT_MUL_LONG)
#endif
diff --git a/src/jit/instr.cpp b/src/jit/instr.cpp
index e250902472..e9b001cc4a 100644
--- a/src/jit/instr.cpp
+++ b/src/jit/instr.cpp
@@ -3714,14 +3714,32 @@ instruction CodeGen::ins_FloatCopy(var_types type)
instruction CodeGen::ins_CopyIntToFloat(var_types srcType, var_types dstType)
{
- // Not used and not implemented
- unreached();
+ assert((dstType == TYP_FLOAT) || (dstType == TYP_DOUBLE));
+ assert((srcType == TYP_INT) || (srcType == TYP_UINT) || (srcType == TYP_LONG) || (srcType == TYP_ULONG));
+
+ if ((srcType == TYP_LONG) || (srcType == TYP_ULONG))
+ {
+ return INS_vmov_i2d;
+ }
+ else
+ {
+ return INS_vmov_i2f;
+ }
}
instruction CodeGen::ins_CopyFloatToInt(var_types srcType, var_types dstType)
{
- // Not used and not implemented
- unreached();
+ assert((srcType == TYP_FLOAT) || (srcType == TYP_DOUBLE));
+ assert((dstType == TYP_INT) || (dstType == TYP_UINT) || (dstType == TYP_LONG) || (dstType == TYP_ULONG));
+
+ if ((dstType == TYP_LONG) || (dstType == TYP_ULONG))
+ {
+ return INS_vmov_d2i;
+ }
+ else
+ {
+ return INS_vmov_f2i;
+ }
}
instruction CodeGen::ins_FloatCompare(var_types type)
diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp
index 9c35a23b9c..27559c8394 100644
--- a/src/jit/lower.cpp
+++ b/src/jit/lower.cpp
@@ -777,7 +777,7 @@ void Lowering::ReplaceArgWithPutArgOrCopy(GenTree** argSlot, GenTree* putArgOrCo
{
assert(argSlot != nullptr);
assert(*argSlot != nullptr);
- assert(putArgOrCopy->OperIsPutArg() || putArgOrCopy->OperIs(GT_COPY));
+ assert(putArgOrCopy->OperIsPutArg() || putArgOrCopy->OperIs(GT_BITCAST));
GenTree* arg = *argSlot;
@@ -1310,12 +1310,15 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
{
var_types intType = (type == TYP_DOUBLE) ? TYP_LONG : TYP_INT;
- GenTreePtr intArg = new (comp, GT_COPY) GenTreeCopyOrReload(GT_COPY, intType, arg);
-
- if (comp->opts.compUseSoftFP)
+ GenTreePtr intArg = comp->gtNewBitCastNode(intType, arg);
+ intArg->gtRegNum = info->regNum;
+#ifdef ARM_SOFTFP
+ if (intType == TYP_LONG)
{
- intArg->gtFlags |= GTF_VAR_DEATH;
+ assert(info->numRegs == 2);
+ intArg->AsMultiRegOp()->gtOtherReg = REG_NEXT(info->regNum);
}
+#endif // ARM_SOFTFP
info->node = intArg;
ReplaceArgWithPutArgOrCopy(ppArg, intArg);
diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp
index e6a1b16926..6d6567d810 100644
--- a/src/jit/lsra.cpp
+++ b/src/jit/lsra.cpp
@@ -134,18 +134,12 @@ void lsraAssignRegToTree(GenTreePtr tree, regNumber reg, unsigned regIdx)
tree->gtRegNum = reg;
}
#if defined(_TARGET_ARM_)
- else if (tree->OperGet() == GT_MUL_LONG || tree->OperGet() == GT_PUTARG_REG)
+ else if (tree->OperGet() == GT_MUL_LONG || tree->OperGet() == GT_PUTARG_REG || tree->OperGet() == GT_BITCAST)
{
assert(regIdx == 1);
GenTreeMultiRegOp* mul = tree->AsMultiRegOp();
mul->gtOtherReg = reg;
}
- else if (tree->OperGet() == GT_COPY)
- {
- assert(regIdx == 1);
- GenTreeCopyOrReload* copy = tree->AsCopyOrReload();
- copy->gtOtherRegs[0] = (regNumberSmall)reg;
- }
else if (tree->OperGet() == GT_PUTARG_SPLIT)
{
GenTreePutArgSplit* putArg = tree->AsPutArgSplit();
@@ -4051,7 +4045,8 @@ void LinearScan::buildRefPositionsForNode(GenTree* tree,
regMaskTP candidates = getUseCandidates(useNode);
#ifdef _TARGET_ARM_
- if (useNode->OperIsPutArgSplit() || (compiler->opts.compUseSoftFP && useNode->OperIsPutArgReg()))
+ if (useNode->OperIsPutArgSplit() ||
+ (compiler->opts.compUseSoftFP && (useNode->OperIsPutArgReg() || useNode->OperGet() == GT_BITCAST)))
{
// get i-th candidate, set bits in useCandidates must be in sequential order.
candidates = genFindLowestReg(candidates & ~currCandidates);
@@ -4129,9 +4124,6 @@ void LinearScan::buildRefPositionsForNode(GenTree* tree,
// push defs
LocationInfoList locationInfoList;
LsraLocation defLocation = currentLoc + 1;
-#ifdef ARM_SOFTFP
- regMaskTP remainingUseCandidates = useCandidates;
-#endif
for (int i = 0; i < produce; i++)
{
regMaskTP currCandidates = candidates;
@@ -4155,10 +4147,10 @@ void LinearScan::buildRefPositionsForNode(GenTree* tree,
}
#ifdef ARM_SOFTFP
// If oper is GT_PUTARG_REG, set bits in useCandidates must be in sequential order.
- else if (tree->OperIsMultiRegOp() || tree->OperGet() == GT_COPY)
+ else if (tree->OperIsMultiRegOp() || tree->OperGet() == GT_BITCAST)
{
- useCandidates = genFindLowestReg(remainingUseCandidates);
- remainingUseCandidates &= ~useCandidates;
+ currCandidates = genFindLowestReg(candidates);
+ candidates &= ~currCandidates;
}
#endif // ARM_SOFTFP
#endif // _TARGET_ARM_
diff --git a/src/jit/lsraarm.cpp b/src/jit/lsraarm.cpp
index a0ec93a524..f35a23a72b 100644
--- a/src/jit/lsraarm.cpp
+++ b/src/jit/lsraarm.cpp
@@ -690,18 +690,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_COPY:
info->srcCount = 1;
-#ifdef ARM_SOFTFP
- // This case currently only occurs for double types that are passed as TYP_LONG;
- // actual long types would have been decomposed by now.
- if (tree->TypeGet() == TYP_LONG)
- {
- info->dstCount = 2;
- }
- else
-#endif
- {
- assert(info->dstCount == 1);
- }
+ assert(info->dstCount == 1);
break;
case GT_PUTARG_SPLIT:
@@ -716,6 +705,28 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
TreeNodeInfoInitPutArgReg(tree->AsUnOp());
break;
+ case GT_BITCAST:
+ {
+ info->srcCount = 1;
+ assert(info->dstCount == 1);
+ regNumber argReg = tree->gtRegNum;
+ regMaskTP argMask = genRegMask(argReg);
+#ifdef ARM_SOFTFP
+ // If type of node is `long` then it is actually `double`.
+ // The actual `long` types must have been transformed as a field list with two fields.
+ if (tree->TypeGet() == TYP_LONG)
+ {
+ info->dstCount++;
+ assert(genRegArgNext(argReg) == REG_NEXT(argReg));
+ argMask |= genRegMask(REG_NEXT(argReg));
+ }
+#endif // ARM_SOFTFP
+ info->setDstCandidates(this, argMask);
+ info->setSrcCandidates(this, argMask);
+ tree->AsUnOp()->gtOp1->gtLsraInfo.isTgtPref = true;
+ }
+ break;
+
default:
#ifdef DEBUG
char message[256];