From: Sergey Andreenko Date: Wed, 1 Nov 2017 19:06:26 +0000 (-0700) Subject: [RyuJit/ARMARCH] lower arg with list of float fields. (#14753) X-Git-Tag: accepted/tizen/base/20180629.140029~725 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=da2f7dfcf94ccf697550170ea437e5b6445ddb2d;p=platform%2Fupstream%2Fcoreclr.git [RyuJit/ARMARCH] lower arg with list of float fields. (#14753) apply bitcast on reg fields rename ReplaceArgWithPutArgOrBitcast --- diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp index ba3e37c..f62efd1 100644 --- a/src/jit/lower.cpp +++ b/src/jit/lower.cpp @@ -768,20 +768,20 @@ GenTree* Lowering::LowerSwitch(GenTree* node) // NOTE: this method deliberately does not update the call arg table. It must only // be used by NewPutArg and LowerArg; these functions are responsible for updating // the call arg table as necessary. -void Lowering::ReplaceArgWithPutArgOrCopy(GenTree** argSlot, GenTree* putArgOrCopy) +void Lowering::ReplaceArgWithPutArgOrBitcast(GenTree** argSlot, GenTree* putArgOrBitcast) { assert(argSlot != nullptr); assert(*argSlot != nullptr); - assert(putArgOrCopy->OperIsPutArg() || putArgOrCopy->OperIs(GT_BITCAST)); + assert(putArgOrBitcast->OperIsPutArg() || putArgOrBitcast->OperIs(GT_BITCAST)); GenTree* arg = *argSlot; // Replace the argument with the putarg/copy - *argSlot = putArgOrCopy; - putArgOrCopy->gtOp.gtOp1 = arg; + *argSlot = putArgOrBitcast; + putArgOrBitcast->gtOp.gtOp1 = arg; // Insert the putarg/copy into the block - BlockRange().InsertAfter(arg, putArgOrCopy); + BlockRange().InsertAfter(arg, putArgOrBitcast); } //------------------------------------------------------------------------ @@ -1009,7 +1009,7 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP fieldListPtr->gtOp.gtOp1, (ctr == 0) ? info->regNum : info->otherRegNum); // Splice in the new GT_PUTARG_REG node in the GT_FIELD_LIST - ReplaceArgWithPutArgOrCopy(&fieldListPtr->gtOp.gtOp1, newOper); + ReplaceArgWithPutArgOrBitcast(&fieldListPtr->gtOp.gtOp1, newOper); // Initialize all the gtRegNum's since the list won't be traversed in an LIR traversal. fieldListPtr->gtRegNum = REG_NA; @@ -1046,7 +1046,7 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP GenTreePtr newOper = comp->gtNewPutArgReg(curTyp, curOp, argReg); // Splice in the new GT_PUTARG_REG node in the GT_FIELD_LIST - ReplaceArgWithPutArgOrCopy(&fieldListPtr->gtOp.gtOp1, newOper); + ReplaceArgWithPutArgOrBitcast(&fieldListPtr->gtOp.gtOp1, newOper); // Update argReg for the next putarg_reg (if any) argReg = genRegArgNext(argReg); @@ -1219,8 +1219,7 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg) fgArgTabEntryPtr info = comp->gtArgEntryByNode(call, arg); assert(info->node == arg); - bool isReg = (info->regNum != REG_STK); - var_types type = arg->TypeGet(); + var_types type = arg->TypeGet(); if (varTypeIsSmall(type)) { @@ -1271,6 +1270,7 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg) #if !defined(_TARGET_64BIT_) if (varTypeIsLong(type)) { + bool isReg = (info->regNum != REG_STK); if (isReg) { noway_assert(arg->OperGet() == GT_LONG); @@ -1304,7 +1304,8 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg) GenTreePtr putArg = NewPutArg(call, fieldList, info, type); putArg->gtRegNum = info->regNum; - // We can't call ReplaceArgWithPutArgOrCopy here because it presumes that we are keeping the original arg. + // We can't call ReplaceArgWithPutArgOrBitcast here because it presumes that we are keeping the original + // arg. BlockRange().InsertBefore(arg, fieldList, putArg); BlockRange().Remove(arg); *ppArg = putArg; @@ -1315,37 +1316,46 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg) { #ifdef _TARGET_ARMARCH_ - if (isReg) + if (call->IsVarargs() || comp->opts.compUseSoftFP) { + // For vararg call or on armel, reg args should be all integer. // Insert a copy to move float value to integer register. - if ((call->IsVarargs() || comp->opts.compUseSoftFP) && varTypeIsFloating(type)) + if (varTypeIsFloating(type)) { - var_types intType = (type == TYP_DOUBLE) ? TYP_LONG : TYP_INT; - - GenTreePtr intArg; - - intArg = comp->gtNewBitCastNode(intType, arg); - intArg->gtRegNum = info->regNum; - #ifdef _TARGET_ARM_ - if (intType == TYP_LONG) +#ifdef DEBUG + if (type == TYP_DOUBLE) { - assert(info->numRegs == 2); - regNumber regNext = REG_NEXT(info->regNum); - // double type arg regs can only be either r0:r1 or r2:r3. - assert((info->regNum == REG_R0 && regNext == REG_R1) || - (info->regNum == REG_R2 && regNext == REG_R3)); - intArg->AsMultiRegOp()->gtOtherReg = regNext; + unsigned numRegs = info->numRegs; + regNumber regCurr = info->regNum; + assert(numRegs % 2 == 0); + for (unsigned i = 0; i < numRegs;) + { + regNumber regNext = REG_NEXT(regCurr); + // double type arg regs can only be either r0:r1 or r2:r3. + assert((regCurr == REG_R0 && regNext == REG_R1) || (regCurr == REG_R2 && regNext == REG_R3)); + + i += 2; + regCurr = REG_NEXT(regNext); + } } +#endif // DEBUG #endif // _TARGET_ARM_ - info->node = intArg; - ReplaceArgWithPutArgOrCopy(ppArg, intArg); + GenTreePtr intArg = LowerFloatArg(arg, info); + if (intArg != nullptr) + { + if (intArg != arg) + { + ReplaceArgWithPutArgOrBitcast(ppArg, intArg); + arg = intArg; + info->node = intArg; + } - // Update arg/type with new ones. - arg = intArg; - type = intType; + // update local variables. + type = arg->TypeGet(); + } } } #endif // _TARGET_ARMARCH_ @@ -1357,11 +1367,90 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg) // If an extra node is returned, splice it in the right place in the tree. if (arg != putArg) { - ReplaceArgWithPutArgOrCopy(ppArg, putArg); + ReplaceArgWithPutArgOrBitcast(ppArg, putArg); } } } +#ifdef _TARGET_ARMARCH_ +//------------------------------------------------------------------------ +// LowerFloatArg: Lower the float call argument on the arm platform. +// +// Arguments: +// arg - The arg node +// info - call argument info +// +// Return Value: +// Return nullptr, if no transformation was done; +// return arg if there was in place transformation; +// return a new tree if the root was changed. +// +GenTree* Lowering::LowerFloatArg(GenTree* arg, fgArgTabEntry* info) +{ + if (info->regNum != REG_STK) + { + if (arg->OperIsFieldList()) + { + GenTreeFieldList* currListNode = arg->AsFieldList(); + regNumber currRegNumber = info->regNum; + + // Transform fields that are passed as registers in place. + for (unsigned i = 0; i < info->numRegs; ++i) + { + assert(currListNode != nullptr); + GenTree* node = currListNode->Current(); + GenTree* intNode = LowerFloatArgReg(node, currRegNumber); + assert(intNode != nullptr); + + ReplaceArgWithPutArgOrBitcast(currListNode->pCurrent(), intNode); + currListNode->ChangeType(intNode->TypeGet()); + + currListNode = currListNode->Rest(); + currRegNumber = REG_NEXT(currRegNumber); + } + // List fields were replaced in place. + return arg; + } + else + { + return LowerFloatArgReg(arg, info->regNum); + } + } + else + { + // Do not change stack nodes. + return nullptr; + } +} + +//------------------------------------------------------------------------ +// LowerFloatArgReg: Lower the float call argument node that is passed via register. +// +// Arguments: +// arg - The arg node +// regNum - register number +// +// Return Value: +// Return new bitcast node, that moves float to int register. +// +GenTree* Lowering::LowerFloatArgReg(GenTree* arg, regNumber regNum) +{ + var_types floatType = arg->TypeGet(); + assert(varTypeIsFloating(floatType)); + var_types intType = (floatType == TYP_DOUBLE) ? TYP_LONG : TYP_INT; + GenTree* intArg = comp->gtNewBitCastNode(intType, arg); + intArg->gtRegNum = regNum; +#ifdef _TARGET_ARM_ + if (floatType == TYP_DOUBLE) + { + regNumber nextReg = REG_NEXT(regNum); + intArg->AsMultiRegOp()->gtOtherReg = nextReg; + } +#endif + return intArg; +} +#endif + // do lowering steps for each arg of a call void Lowering::LowerArgsForCall(GenTreeCall* call) { diff --git a/src/jit/lower.h b/src/jit/lower.h index 81683b9..2be5765 100644 --- a/src/jit/lower.h +++ b/src/jit/lower.h @@ -151,9 +151,14 @@ private: GenTree* LowerVirtualVtableCall(GenTreeCall* call); GenTree* LowerVirtualStubCall(GenTreeCall* call); void LowerArgsForCall(GenTreeCall* call); - void ReplaceArgWithPutArgOrCopy(GenTreePtr* ppChild, GenTreePtr newNode); + void ReplaceArgWithPutArgOrBitcast(GenTreePtr* ppChild, GenTreePtr newNode); GenTree* NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryPtr info, var_types type); void LowerArg(GenTreeCall* call, GenTreePtr* ppTree); +#ifdef _TARGET_ARMARCH_ + GenTree* LowerFloatArg(GenTree* arg, fgArgTabEntry* info); + GenTree* LowerFloatArgReg(GenTree* arg, regNumber regNum); +#endif + void InsertPInvokeCallProlog(GenTreeCall* call); void InsertPInvokeCallEpilog(GenTreeCall* call); void InsertPInvokeMethodProlog();