From 0603f5b9ab96b20f72d006ab78a9b0c608c034df Mon Sep 17 00:00:00 2001 From: Hanjoung Lee Date: Mon, 25 Sep 2017 20:50:27 +0900 Subject: [PATCH] [RyuJIT/armarch] Put arguments with GT_BITCAST Put arguments with GT_BITCAST instead of GT_COPY for arm32/arm64 Fix #14008 --- src/jit/codegenarmarch.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/jit/compiler.h | 2 ++ src/jit/gentree.cpp | 31 ++++++++++++++++++++++++++++++- src/jit/gentree.h | 2 +- src/jit/gtlist.h | 4 ++++ src/jit/gtstructs.h | 2 +- src/jit/instr.cpp | 26 ++++++++++++++++++++++---- src/jit/lower.cpp | 13 ++++++++----- src/jit/lsra.cpp | 20 ++++++-------------- src/jit/lsraarm.cpp | 35 +++++++++++++++++++++++------------ 10 files changed, 133 insertions(+), 38 deletions(-) diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp index e9a12af..8c79919 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 0997154..b4203d6 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 bcf8d36..367813b 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 a8911d0..6609571 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -6044,7 +6044,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 b9098da..6646cc3 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 1661809..853cceb 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 e250902..e9b001c 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 2a126d3..793422b 100644 --- a/src/jit/lower.cpp +++ b/src/jit/lower.cpp @@ -762,7 +762,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; @@ -1295,12 +1295,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 47e6d32..54754f4 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(); @@ -4038,7 +4032,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); @@ -4116,9 +4111,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; @@ -4142,10 +4134,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 09246b6..862fe37 100644 --- a/src/jit/lsraarm.cpp +++ b/src/jit/lsraarm.cpp @@ -708,18 +708,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: @@ -734,6 +723,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]; -- 2.7.4