From 2ec2564d65063b3f80b349ea22e72ce293f4cffe Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 21 May 2024 16:35:01 -0700 Subject: [PATCH] LSRA: Refactor some of the methods around creating kill set (#102469) * refactor code around buildkill * fix build errors * some more errors * jit format * fix riscv64 * make retTypeDesc as noway_assert * fix riscv64 errors * jit format --- src/coreclr/jit/lsra.h | 32 +++-- src/coreclr/jit/lsraarm.cpp | 6 +- src/coreclr/jit/lsraarm64.cpp | 14 +-- src/coreclr/jit/lsraarmarch.cpp | 58 +++++---- src/coreclr/jit/lsrabuild.cpp | 190 +++++++++++++++++++++++------- src/coreclr/jit/lsrariscv64.cpp | 64 ++++++---- src/coreclr/jit/lsraxarch.cpp | 83 +++++++------ src/coreclr/jit/targetriscv64.cpp | 8 +- 8 files changed, 307 insertions(+), 148 deletions(-) diff --git a/src/coreclr/jit/lsra.h b/src/coreclr/jit/lsra.h index 7d1624a578045f..082cfe6d10d0e0 100644 --- a/src/coreclr/jit/lsra.h +++ b/src/coreclr/jit/lsra.h @@ -1051,7 +1051,7 @@ class LinearScan : public LinearScanInterface void buildRefPositionsForNode(GenTree* tree, LsraLocation loc); #if FEATURE_PARTIAL_SIMD_CALLEE_SAVE - void buildUpperVectorSaveRefPositions(GenTree* tree, LsraLocation currentLoc, regMaskTP fpCalleeKillSet); + void buildUpperVectorSaveRefPositions(GenTree* tree, LsraLocation currentLoc DEBUG_ARG(regMaskTP fpCalleeKillSet)); void buildUpperVectorRestoreRefPosition( Interval* lclVarInterval, LsraLocation currentLoc, GenTree* node, bool isUse, unsigned multiRegIdx); #endif // FEATURE_PARTIAL_SIMD_CALLEE_SAVE @@ -1999,19 +1999,27 @@ class LinearScan : public LinearScanInterface void getTgtPrefOperands(GenTree* tree, GenTree* op1, GenTree* op2, bool* prefOp1, bool* prefOp2); bool supportsSpecialPutArg(); - int BuildSimple(GenTree* tree); - int BuildOperandUses(GenTree* node, regMaskTP candidates = RBM_NONE); - void AddDelayFreeUses(RefPosition* refPosition, GenTree* rmwNode); - int BuildDelayFreeUses(GenTree* node, - GenTree* rmwNode = nullptr, - regMaskTP candidates = RBM_NONE, - RefPosition** useRefPosition = nullptr); - int BuildIndirUses(GenTreeIndir* indirTree, regMaskTP candidates = RBM_NONE); - int BuildAddrUses(GenTree* addr, regMaskTP candidates = RBM_NONE); - void HandleFloatVarArgs(GenTreeCall* call, GenTree* argNode, bool* callHasFloatRegArgs); + int BuildSimple(GenTree* tree); + int BuildOperandUses(GenTree* node, regMaskTP candidates = RBM_NONE); + void AddDelayFreeUses(RefPosition* refPosition, GenTree* rmwNode); + int BuildDelayFreeUses(GenTree* node, + GenTree* rmwNode = nullptr, + regMaskTP candidates = RBM_NONE, + RefPosition** useRefPosition = nullptr); + int BuildIndirUses(GenTreeIndir* indirTree, regMaskTP candidates = RBM_NONE); + int BuildAddrUses(GenTree* addr, regMaskTP candidates = RBM_NONE); + void HandleFloatVarArgs(GenTreeCall* call, GenTree* argNode, bool* callHasFloatRegArgs); + RefPosition* BuildDef(GenTree* tree, regMaskTP dstCandidates = RBM_NONE, int multiRegIdx = 0); void BuildDefs(GenTree* tree, int dstCount, regMaskTP dstCandidates = RBM_NONE); - void BuildDefsWithKills(GenTree* tree, int dstCount, regMaskTP dstCandidates, regMaskTP killMask); + void BuildCallDefs(GenTree* tree, int dstCount, regMaskTP dstCandidates); + void BuildKills(GenTree* tree, regMaskTP killMask); +#if defined(TARGET_ARMARCH) || defined(TARGET_RISCV64) + void BuildDefWithKills(GenTree* tree, regMaskTP dstCandidates, regMaskTP killMask); +#else + void BuildDefWithKills(GenTree* tree, int dstCount, regMaskTP dstCandidates, regMaskTP killMask); +#endif // TARGET_ARMARCH || TARGET_RISCV64 + void BuildCallDefsWithKills(GenTree* tree, int dstCount, regMaskTP dstCandidates, regMaskTP killMask); int BuildReturn(GenTree* tree); #ifdef TARGET_XARCH diff --git a/src/coreclr/jit/lsraarm.cpp b/src/coreclr/jit/lsraarm.cpp index 2192265984d68e..e653514d3c14c0 100644 --- a/src/coreclr/jit/lsraarm.cpp +++ b/src/coreclr/jit/lsraarm.cpp @@ -373,7 +373,7 @@ int LinearScan::BuildNode(GenTree* tree) assert(dstCount == 0); BuildUse(tree->gtGetOp1()); killMask = compiler->compHelperCallKillSet(CORINFO_HELP_STOP_FOR_GC); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; case GT_MUL: @@ -422,7 +422,7 @@ int LinearScan::BuildNode(GenTree* tree) // This kills GC refs in callee save regs srcCount = 0; assert(dstCount == 0); - BuildDefsWithKills(tree, 0, RBM_NONE, RBM_NONE); + BuildKills(tree, RBM_NONE); break; case GT_LONG: @@ -469,7 +469,7 @@ int LinearScan::BuildNode(GenTree* tree) case GT_RETURN: srcCount = BuildReturn(tree); killMask = getKillSetForReturn(); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; case GT_RETFILT: diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index c133a4a6917762..31f4d114d544a6 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -666,14 +666,14 @@ int LinearScan::BuildNode(GenTree* tree) srcCount = 0; assert(dstCount == 0); killMask = getKillSetForProfilerHook(); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; case GT_START_PREEMPTGC: // This kills GC refs in callee save regs srcCount = 0; assert(dstCount == 0); - BuildDefsWithKills(tree, 0, RBM_NONE, RBM_NONE); + BuildKills(tree, RBM_NONE); break; case GT_CNS_DBL: @@ -738,7 +738,7 @@ int LinearScan::BuildNode(GenTree* tree) case GT_RETURN: srcCount = BuildReturn(tree); killMask = getKillSetForReturn(); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; #ifdef SWIFT_SUPPORT @@ -747,7 +747,7 @@ int LinearScan::BuildNode(GenTree* tree) // Plus one for error register srcCount = BuildReturn(tree) + 1; killMask = getKillSetForReturn(); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; #endif // SWIFT_SUPPORT @@ -839,7 +839,7 @@ int LinearScan::BuildNode(GenTree* tree) srcCount = 1; assert(dstCount == 0); killMask = compiler->compHelperCallKillSet(CORINFO_HELP_STOP_FOR_GC); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; case GT_MOD: @@ -1927,11 +1927,11 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou if ((dstCount == 1) || (dstCount == 2)) { - BuildDef(intrinsicTree, dstCandidates); + BuildDef(intrinsicTree); if (dstCount == 2) { - BuildDef(intrinsicTree, dstCandidates, 1); + BuildDef(intrinsicTree, RBM_NONE, 1); } } else diff --git a/src/coreclr/jit/lsraarmarch.cpp b/src/coreclr/jit/lsraarmarch.cpp index d40e91cdb8c545..e70de49a8e793c 100644 --- a/src/coreclr/jit/lsraarmarch.cpp +++ b/src/coreclr/jit/lsraarmarch.cpp @@ -127,9 +127,9 @@ int LinearScan::BuildIndir(GenTreeIndir* indirTree) // int LinearScan::BuildCall(GenTreeCall* call) { - bool hasMultiRegRetVal = false; - const ReturnTypeDesc* retTypeDesc = nullptr; - regMaskTP dstCandidates = RBM_NONE; + bool hasMultiRegRetVal = false; + const ReturnTypeDesc* retTypeDesc = nullptr; + regMaskTP singleDstCandidates = RBM_NONE; int srcCount = 0; int dstCount = 0; @@ -227,26 +227,24 @@ int LinearScan::BuildCall(GenTreeCall* call) { // The ARM CORINFO_HELP_INIT_PINVOKE_FRAME helper uses a custom calling convention that returns with // TCB in REG_PINVOKE_TCB. fgMorphCall() sets the correct argument registers. - dstCandidates = RBM_PINVOKE_TCB; + singleDstCandidates = RBM_PINVOKE_TCB; } else #endif // TARGET_ARM - if (hasMultiRegRetVal) - { - assert(retTypeDesc != nullptr); - dstCandidates = retTypeDesc->GetABIReturnRegs(call->GetUnmanagedCallConv()); - } - else if (varTypeUsesFloatArgReg(registerType)) - { - dstCandidates = RBM_FLOATRET; - } - else if (registerType == TYP_LONG) - { - dstCandidates = RBM_LNGRET; - } - else + if (!hasMultiRegRetVal) { - dstCandidates = RBM_INTRET; + if (varTypeUsesFloatArgReg(registerType)) + { + singleDstCandidates = RBM_FLOATRET; + } + else if (registerType == TYP_LONG) + { + singleDstCandidates = RBM_LNGRET; + } + else + { + singleDstCandidates = RBM_INTRET; + } } // First, count reg args @@ -399,7 +397,25 @@ int LinearScan::BuildCall(GenTreeCall* call) // Now generate defs and kills. regMaskTP killMask = getKillSetForCall(call); - BuildDefsWithKills(call, dstCount, dstCandidates, killMask); + if (dstCount > 0) + { + if (hasMultiRegRetVal) + { + assert(retTypeDesc != nullptr); + regMaskTP multiDstCandidates = retTypeDesc->GetABIReturnRegs(call->GetUnmanagedCallConv()); + assert(genCountBits(multiDstCandidates) > 0); + BuildCallDefsWithKills(call, dstCount, multiDstCandidates, killMask); + } + else + { + assert(dstCount == 1); + BuildDefWithKills(call, singleDstCandidates, killMask); + } + } + else + { + BuildKills(call, killMask); + } #ifdef SWIFT_SUPPORT if (call->HasSwiftErrorHandling()) @@ -836,7 +852,7 @@ int LinearScan::BuildBlockStore(GenTreeBlk* blkNode) buildInternalRegisterUses(); regMaskTP killMask = getKillSetForBlockStore(blkNode); - BuildDefsWithKills(blkNode, 0, RBM_NONE, killMask); + BuildKills(blkNode, killMask); return useCount; } diff --git a/src/coreclr/jit/lsrabuild.cpp b/src/coreclr/jit/lsrabuild.cpp index 43c75a118b218d..1ddcd4d56411b5 100644 --- a/src/coreclr/jit/lsrabuild.cpp +++ b/src/coreclr/jit/lsrabuild.cpp @@ -1459,7 +1459,8 @@ Interval* LinearScan::getUpperVectorInterval(unsigned varIndex) // But we will use as a proxy any node that kills floating point registers. // (Note that some calls are masquerading as other nodes at this point so we can't just check for calls.) // -void LinearScan::buildUpperVectorSaveRefPositions(GenTree* tree, LsraLocation currentLoc, regMaskTP fpCalleeKillSet) +void LinearScan::buildUpperVectorSaveRefPositions(GenTree* tree, + LsraLocation currentLoc DEBUG_ARG(regMaskTP fpCalleeKillSet)) { if ((tree != nullptr) && tree->IsCall()) { @@ -3037,7 +3038,7 @@ void setTgtPref(Interval* interval, RefPosition* tgtPrefUse) #endif // !TARGET_ARM //------------------------------------------------------------------------ -// BuildDef: Build a RefTypeDef RefPosition for the given node +// BuildDef: Build one RefTypeDef RefPosition for the given node at given index // // Arguments: // tree - The node that defines a register @@ -3130,7 +3131,7 @@ RefPosition* LinearScan::BuildDef(GenTree* tree, regMaskTP dstCandidates, int mu } //------------------------------------------------------------------------ -// BuildDef: Build one or more RefTypeDef RefPositions for the given node +// BuildDef: Build one or more RefTypeDef RefPositions for the given call node // // Arguments: // tree - The node that defines a register @@ -3140,61 +3141,76 @@ RefPosition* LinearScan::BuildDef(GenTree* tree, regMaskTP dstCandidates, int mu // Notes: // Adds the RefInfo for the definitions to the defList. // -void LinearScan::BuildDefs(GenTree* tree, int dstCount, regMaskTP dstCandidates) +void LinearScan::BuildCallDefs(GenTree* tree, int dstCount, regMaskTP dstCandidates) { - bool fixedReg = false; - if ((dstCount > 1) && (dstCandidates != RBM_NONE) && ((int)genCountBits(dstCandidates) == dstCount)) - { - fixedReg = true; - } - const ReturnTypeDesc* retTypeDesc = nullptr; - if (tree->IsMultiRegCall()) + assert(dstCount > 0); + assert((int)genCountBits(dstCandidates) == dstCount); + assert(tree->IsMultiRegCall()); + + const ReturnTypeDesc* retTypeDesc = tree->AsCall()->GetReturnTypeDesc(); + assert(retTypeDesc != nullptr); + if (retTypeDesc == nullptr) { - retTypeDesc = tree->AsCall()->GetReturnTypeDesc(); + return; } + for (int i = 0; i < dstCount; i++) { - regMaskTP thisDstCandidates; - if (fixedReg) - { - // In case of multi-reg call node, we have to query the i'th position return register. - // For all other cases of multi-reg definitions, the registers must be in sequential order. - if (retTypeDesc != nullptr) - { - thisDstCandidates = genRegMask( - tree->AsCall()->GetReturnTypeDesc()->GetABIReturnReg(i, tree->AsCall()->GetUnmanagedCallConv())); - assert((dstCandidates & thisDstCandidates) != RBM_NONE); - } - else - { - thisDstCandidates = genFindLowestBit(dstCandidates); - } - dstCandidates &= ~thisDstCandidates; - } - else - { - thisDstCandidates = dstCandidates; - } + // In case of multi-reg call node, we have to query the i'th position return register. + // For all other cases of multi-reg definitions, the registers must be in sequential order. + regMaskTP thisDstCandidates = + genRegMask(retTypeDesc->GetABIReturnReg(i, tree->AsCall()->GetUnmanagedCallConv())); + + assert((dstCandidates & thisDstCandidates) != RBM_NONE); + dstCandidates &= ~thisDstCandidates; + BuildDef(tree, thisDstCandidates, i); } } //------------------------------------------------------------------------ -// BuildDef: Build one or more RefTypeDef RefPositions for the given node, -// as well as kills as specified by the given mask. +// BuildDef: Build one or more RefTypeDef RefPositions for the given node // // Arguments: // tree - The node that defines a register // dstCount - The number of registers defined by the node -// dstCandidates - The candidate registers for the definition -// killMask - The mask of registers killed by this node +// dstCandidates - the candidate registers for the definition // // Notes: // Adds the RefInfo for the definitions to the defList. -// The def and kill functionality is folded into a single method so that the -// save and restores of upper vector registers can be bracketed around the def. +// Also, the `dstCandidates` is assumed to be of "onlyOne" type. If there are +// both gpr and float registers, use `BuildDefs` that takes `AllRegsMask` // -void LinearScan::BuildDefsWithKills(GenTree* tree, int dstCount, regMaskTP dstCandidates, regMaskTP killMask) +void LinearScan::BuildDefs(GenTree* tree, int dstCount, regMaskTP dstCandidates) +{ + assert(dstCount > 0); + + if ((dstCandidates == RBM_NONE) || ((int)genCountBits(dstCandidates) != dstCount)) + { + // This is not fixedReg case, so just create definitions based on dstCandidates + for (int i = 0; i < dstCount; i++) + { + BuildDef(tree, dstCandidates, i); + } + return; + } + + for (int i = 0; i < dstCount; i++) + { + regMaskTP thisDstCandidates = genFindLowestBit(dstCandidates); + BuildDef(tree, thisDstCandidates, i); + dstCandidates &= ~thisDstCandidates; + } +} + +//------------------------------------------------------------------------ +// BuildDef: Build Kills RefPositions as specified by the given mask. +// +// Arguments: +// tree - The node that defines a register +// killMask - The mask of registers killed by this node +// +void LinearScan::BuildKills(GenTree* tree, regMaskTP killMask) { assert(killMask == getKillSetForNode(tree)); @@ -3217,13 +3233,101 @@ void LinearScan::BuildDefsWithKills(GenTree* tree, int dstCount, regMaskTP dstCa // if ((killMask & RBM_FLT_CALLEE_TRASH) != RBM_NONE) { - buildUpperVectorSaveRefPositions(tree, currentLoc + 1, killMask); + buildUpperVectorSaveRefPositions(tree, currentLoc + 1 DEBUG_ARG(killMask & RBM_FLT_CALLEE_TRASH)); } #endif // FEATURE_PARTIAL_SIMD_CALLEE_SAVE } +} + +#if defined(TARGET_ARMARCH) || defined(TARGET_RISCV64) + +//------------------------------------------------------------------------ +// BuildDefWithKills: Build one RefTypeDef RefPositions for the given node, +// as well as kills as specified by the given mask. +// +// Arguments: +// tree - The call node that defines a register +// dstCandidates - The candidate registers for the definition +// killMask - The mask of registers killed by this node +// +// Notes: +// Adds the RefInfo for the definitions to the defList. +// The def and kill functionality is folded into a single method so that the +// save and restores of upper vector registers can be bracketed around the def. +// +void LinearScan::BuildDefWithKills(GenTree* tree, regMaskTP dstCandidates, regMaskTP killMask) +{ + assert(!tree->AsCall()->HasMultiRegRetVal()); + assert((int)genCountBits(dstCandidates) == 1); + + // Build the kill RefPositions + BuildKills(tree, killMask); + BuildDef(tree, dstCandidates); +} + +#else +//------------------------------------------------------------------------ +// BuildDefWithKills: Build one or two (for 32-bit) RefTypeDef RefPositions for the given node, +// as well as kills as specified by the given mask. +// +// Arguments: +// tree - The call node that defines a register +// dstCandidates - The candidate registers for the definition +// killMask - The mask of registers killed by this node +// +// Notes: +// Adds the RefInfo for the definitions to the defList. +// The def and kill functionality is folded into a single method so that the +// save and restores of upper vector registers can be bracketed around the def. +// +void LinearScan::BuildDefWithKills(GenTree* tree, int dstCount, regMaskTP dstCandidates, regMaskTP killMask) +{ + // Build the kill RefPositions + BuildKills(tree, killMask); + +#ifdef TARGET_64BIT + // For 64 bits, + assert(dstCount == 1); + BuildDef(tree, dstCandidates); +#else + if (dstCount == 1) + { + BuildDef(tree, dstCandidates); + } + else + { + assert(dstCount == 2); + BuildDefs(tree, 2, dstCandidates); + } +#endif // TARGET_64BIT +} +#endif + +//------------------------------------------------------------------------ +// BuildCallDefsWithKills: Build one or more RefTypeDef RefPositions for the given node, +// as well as kills as specified by the given mask. +// +// Arguments: +// tree - The node that defines a register +// dstCount - The number of registers defined by the node +// dstCandidates - The candidate registers for the definition +// killMask - The mask of registers killed by this node +// +// Notes: +// Adds the RefInfo for the definitions to the defList. +// The def and kill functionality is folded into a single method so that the +// save and restores of upper vector registers can be bracketed around the def. +// +void LinearScan::BuildCallDefsWithKills(GenTree* tree, int dstCount, regMaskTP dstCandidates, regMaskTP killMask) +{ + assert(dstCount > 0); + assert(dstCandidates != RBM_NONE); + + // Build the kill RefPositions + BuildKills(tree, killMask); - // Now, create the Def(s) - BuildDefs(tree, dstCount, dstCandidates); + // And then the Def(s) + BuildCallDefs(tree, dstCount, dstCandidates); } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/lsrariscv64.cpp b/src/coreclr/jit/lsrariscv64.cpp index 6af21c06ab208d..d495246f9d1ea4 100644 --- a/src/coreclr/jit/lsrariscv64.cpp +++ b/src/coreclr/jit/lsrariscv64.cpp @@ -131,14 +131,14 @@ int LinearScan::BuildNode(GenTree* tree) srcCount = 0; assert(dstCount == 0); killMask = getKillSetForProfilerHook(); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; case GT_START_PREEMPTGC: // This kills GC refs in callee save regs srcCount = 0; assert(dstCount == 0); - BuildDefsWithKills(tree, 0, RBM_NONE, RBM_NONE); + BuildKills(tree, RBM_NONE); break; case GT_CNS_DBL: @@ -171,7 +171,7 @@ int LinearScan::BuildNode(GenTree* tree) case GT_RETURN: srcCount = BuildReturn(tree); killMask = getKillSetForReturn(); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; case GT_RETFILT: @@ -273,7 +273,7 @@ int LinearScan::BuildNode(GenTree* tree) srcCount = 1; assert(dstCount == 0); killMask = compiler->compHelperCallKillSet(CORINFO_HELP_STOP_FOR_GC); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; case GT_MUL: @@ -838,9 +838,9 @@ int LinearScan::BuildIndir(GenTreeIndir* indirTree) // int LinearScan::BuildCall(GenTreeCall* call) { - bool hasMultiRegRetVal = false; - const ReturnTypeDesc* retTypeDesc = nullptr; - regMaskTP dstCandidates = RBM_NONE; + bool hasMultiRegRetVal = false; + const ReturnTypeDesc* retTypeDesc = nullptr; + regMaskTP singleDstCandidates = RBM_NONE; int srcCount = 0; int dstCount = 0; @@ -908,22 +908,20 @@ int LinearScan::BuildCall(GenTreeCall* call) // Set destination candidates for return value of the call. - if (hasMultiRegRetVal) + if (!hasMultiRegRetVal) { - assert(retTypeDesc != nullptr); - dstCandidates = retTypeDesc->GetABIReturnRegs(call->GetUnmanagedCallConv()); - } - else if (varTypeUsesFloatArgReg(registerType)) - { - dstCandidates = RBM_FLOATRET; - } - else if (registerType == TYP_LONG) - { - dstCandidates = RBM_LNGRET; - } - else - { - dstCandidates = RBM_INTRET; + if (varTypeUsesFloatArgReg(registerType)) + { + singleDstCandidates = RBM_FLOATRET; + } + else if (registerType == TYP_LONG) + { + singleDstCandidates = RBM_LNGRET; + } + else + { + singleDstCandidates = RBM_INTRET; + } } // First, count reg args @@ -1035,7 +1033,25 @@ int LinearScan::BuildCall(GenTreeCall* call) // Now generate defs and kills. regMaskTP killMask = getKillSetForCall(call); - BuildDefsWithKills(call, dstCount, dstCandidates, killMask); + if (dstCount > 0) + { + if (hasMultiRegRetVal) + { + assert(retTypeDesc != nullptr); + regMaskTP multiDstCandidates = retTypeDesc->GetABIReturnRegs(call->GetUnmanagedCallConv()); + assert(genCountBits(multiDstCandidates) > 0); + BuildCallDefsWithKills(call, dstCount, multiDstCandidates, killMask); + } + else + { + assert(dstCount == 1); + BuildDefWithKills(call, singleDstCandidates, killMask); + } + } + else + { + BuildKills(call, killMask); + } // No args are placed in registers anymore. placedArgRegs = RBM_NONE; @@ -1345,7 +1361,7 @@ int LinearScan::BuildBlockStore(GenTreeBlk* blkNode) buildInternalRegisterUses(); regMaskTP killMask = getKillSetForBlockStore(blkNode); - BuildDefsWithKills(blkNode, 0, RBM_NONE, killMask); + BuildKills(blkNode, killMask); return useCount; } diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index 3f2865aa50f326..c636fa34759026 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -138,14 +138,14 @@ int LinearScan::BuildNode(GenTree* tree) // This kills GC refs in callee save regs srcCount = 0; assert(dstCount == 0); - BuildDefsWithKills(tree, 0, RBM_NONE, RBM_NONE); + BuildKills(tree, RBM_NONE); break; case GT_PROF_HOOK: srcCount = 0; assert(dstCount == 0); killMask = getKillSetForProfilerHook(); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; case GT_CNS_INT: @@ -190,7 +190,7 @@ int LinearScan::BuildNode(GenTree* tree) case GT_RETURN: srcCount = BuildReturn(tree); killMask = getKillSetForReturn(); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; #ifdef SWIFT_SUPPORT @@ -199,7 +199,7 @@ int LinearScan::BuildNode(GenTree* tree) // Plus one for error register srcCount = BuildReturn(tree) + 1; killMask = getKillSetForReturn(); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); break; #endif // SWIFT_SUPPORT @@ -306,7 +306,7 @@ int LinearScan::BuildNode(GenTree* tree) srcCount = BuildOperandUses(tree->gtGetOp1()); buildInternalRegisterUses(); killMask = compiler->compHelperCallKillSet(CORINFO_HELP_STOP_FOR_GC); - BuildDefsWithKills(tree, 0, RBM_NONE, killMask); + BuildKills(tree, killMask); } break; @@ -1147,11 +1147,11 @@ int LinearScan::BuildShiftRotate(GenTree* tree) // int LinearScan::BuildCall(GenTreeCall* call) { - bool hasMultiRegRetVal = false; - const ReturnTypeDesc* retTypeDesc = nullptr; - int srcCount = 0; - int dstCount = 0; - regMaskTP dstCandidates = RBM_NONE; + bool hasMultiRegRetVal = false; + const ReturnTypeDesc* retTypeDesc = nullptr; + int srcCount = 0; + int dstCount = 0; + regMaskTP singleDstCandidates = RBM_NONE; assert(!call->isContained()); if (call->TypeGet() != TYP_VOID) @@ -1185,36 +1185,33 @@ int LinearScan::BuildCall(GenTreeCall* call) // The x86 CORINFO_HELP_INIT_PINVOKE_FRAME helper uses a custom calling convention that returns with // TCB in REG_PINVOKE_TCB. AMD64/ARM64 use the standard calling convention. fgMorphCall() sets the // correct argument registers. - dstCandidates = RBM_PINVOKE_TCB; + singleDstCandidates = RBM_PINVOKE_TCB; } else #endif // TARGET_X86 - if (hasMultiRegRetVal) - { - assert(retTypeDesc != nullptr); - dstCandidates = retTypeDesc->GetABIReturnRegs(call->GetUnmanagedCallConv()); - assert((int)genCountBits(dstCandidates) == dstCount); - } - else if (varTypeUsesFloatReg(registerType)) + if (!hasMultiRegRetVal) { + if (varTypeUsesFloatReg(registerType)) + { #ifdef TARGET_X86 - // The return value will be on the X87 stack, and we will need to move it. - dstCandidates = allRegs(registerType); + // The return value will be on the X87 stack, and we will need to move it. + singleDstCandidates = allRegs(registerType); #else // !TARGET_X86 - dstCandidates = RBM_FLOATRET; + singleDstCandidates = RBM_FLOATRET; #endif // !TARGET_X86 - } - else - { - assert(varTypeUsesIntReg(registerType)); - - if (registerType == TYP_LONG) - { - dstCandidates = RBM_LNGRET; } else { - dstCandidates = RBM_INTRET; + assert(varTypeUsesIntReg(registerType)); + + if (registerType == TYP_LONG) + { + singleDstCandidates = RBM_LNGRET; + } + else + { + singleDstCandidates = RBM_INTRET; + } } } @@ -1375,7 +1372,25 @@ int LinearScan::BuildCall(GenTreeCall* call) // Now generate defs and kills. regMaskTP killMask = getKillSetForCall(call); - BuildDefsWithKills(call, dstCount, dstCandidates, killMask); + if (dstCount > 0) + { + if (hasMultiRegRetVal) + { + assert(retTypeDesc != nullptr); + regMaskTP multiDstCandidates = retTypeDesc->GetABIReturnRegs(call->GetUnmanagedCallConv()); + assert((int)genCountBits(multiDstCandidates) == dstCount); + BuildCallDefsWithKills(call, dstCount, multiDstCandidates, killMask); + } + else + { + assert(dstCount == 1); + BuildDefWithKills(call, dstCount, singleDstCandidates, killMask); + } + } + else + { + BuildKills(call, killMask); + } #ifdef SWIFT_SUPPORT if (call->HasSwiftErrorHandling()) @@ -1667,7 +1682,7 @@ int LinearScan::BuildBlockStore(GenTreeBlk* blkNode) buildInternalRegisterUses(); regMaskTP killMask = getKillSetForBlockStore(blkNode); - BuildDefsWithKills(blkNode, 0, RBM_NONE, killMask); + BuildKills(blkNode, killMask); return useCount; } @@ -1959,7 +1974,7 @@ int LinearScan::BuildModDiv(GenTree* tree) buildInternalRegisterUses(); regMaskTP killMask = getKillSetForModDiv(tree->AsOp()); - BuildDefsWithKills(tree, 1, dstCandidates, killMask); + BuildDefWithKills(tree, 1, dstCandidates, killMask); return srcCount; } @@ -3086,7 +3101,7 @@ int LinearScan::BuildMul(GenTree* tree) containedMemOp = op2; } regMaskTP killMask = getKillSetForMul(tree->AsOp()); - BuildDefsWithKills(tree, dstCount, dstCandidates, killMask); + BuildDefWithKills(tree, dstCount, dstCandidates, killMask); return srcCount; } diff --git a/src/coreclr/jit/targetriscv64.cpp b/src/coreclr/jit/targetriscv64.cpp index 581087b5cc63f8..ea4c99872b7949 100644 --- a/src/coreclr/jit/targetriscv64.cpp +++ b/src/coreclr/jit/targetriscv64.cpp @@ -131,8 +131,8 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, regNumber secondReg = (isSecondFloat ? m_floatRegs : m_intRegs).Dequeue(); return {2, new (comp, CMK_ABI) - ABIPassingSegment[]{ABIPassingSegment::InRegister(firstReg, 0, firstSize), - ABIPassingSegment::InRegister(secondReg, offset, secondSize)}}; + ABIPassingSegment[2]{ABIPassingSegment::InRegister(firstReg, 0, firstSize), + ABIPassingSegment::InRegister(secondReg, offset, secondSize)}}; } } else @@ -162,8 +162,8 @@ ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, { assert(varTypeIsStruct(type)); return {2, new (comp, CMK_ABI) - ABIPassingSegment[]{passSlot(0, TARGET_POINTER_SIZE), - passSlot(TARGET_POINTER_SIZE, passedSize - TARGET_POINTER_SIZE)}}; + ABIPassingSegment[2]{passSlot(0, TARGET_POINTER_SIZE), + passSlot(TARGET_POINTER_SIZE, passedSize - TARGET_POINTER_SIZE)}}; } } }