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);
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);
// 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)
{
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.
}
#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;
}
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
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
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)
{
assert(argSlot != nullptr);
assert(*argSlot != nullptr);
- assert(putArgOrCopy->OperIsPutArg() || putArgOrCopy->OperIs(GT_COPY));
+ assert(putArgOrCopy->OperIsPutArg() || putArgOrCopy->OperIs(GT_BITCAST));
GenTree* arg = *argSlot;
{
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);
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();
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);
// 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;
}
#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_
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:
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];