diff --git a/src/coreclr/jit/abi.cpp b/src/coreclr/jit/abi.cpp index e20f82b50c6158..5762c274a24cf5 100644 --- a/src/coreclr/jit/abi.cpp +++ b/src/coreclr/jit/abi.cpp @@ -460,6 +460,28 @@ unsigned ABIPassingInformation::CountRegsAndStackSlots() const return numSlots; } +//----------------------------------------------------------------------------- +// StackBytesConsumes: +// Count the amount of stack bytes consumed by this argument. +// +// Return Value: +// Bytes. +// +unsigned ABIPassingInformation::StackBytesConsumed() const +{ + unsigned numBytes = 0; + + for (const ABIPassingSegment& seg : Segments()) + { + if (seg.IsPassedOnStack()) + { + numBytes += seg.GetStackSize(); + } + } + + return numBytes; +} + //----------------------------------------------------------------------------- // FromSegment: // Create ABIPassingInformation from a single segment. diff --git a/src/coreclr/jit/abi.h b/src/coreclr/jit/abi.h index 4133dbf61d93fc..dcb7b73aacff57 100644 --- a/src/coreclr/jit/abi.h +++ b/src/coreclr/jit/abi.h @@ -130,6 +130,7 @@ struct ABIPassingInformation bool HasExactlyOneStackSegment() const; bool IsSplitAcrossRegistersAndStack() const; unsigned CountRegsAndStackSlots() const; + unsigned StackBytesConsumed() const; static ABIPassingInformation FromSegment(Compiler* comp, bool passedByRef, const ABIPassingSegment& segment); static ABIPassingInformation FromSegmentByValue(Compiler* comp, const ABIPassingSegment& segment); diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index 21fb0691bc2451..8184b20068387e 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -3526,7 +3526,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call) for (CallArg& arg : call->gtArgs.Args()) { - for (const ABIPassingSegment& seg : arg.NewAbiInfo.Segments()) + for (const ABIPassingSegment& seg : arg.AbiInfo.Segments()) { if (seg.IsPassedInRegister() && ((trashedByEpilog & seg.GetRegisterMask()) != 0)) { diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 205e46ec0969ee..dbdd45d0eedc56 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -6046,7 +6046,9 @@ regNumber CodeGen::getCallIndirectionCellReg(GenTreeCall* call) if (call->GetIndirectionCellArgKind() != WellKnownArg::None) { CallArg* indirCellArg = call->gtArgs.FindWellKnownArg(call->GetIndirectionCellArgKind()); - assert((indirCellArg != nullptr) && (indirCellArg->AbiInfo.GetRegNum() == result)); + assert(indirCellArg != nullptr); + assert(indirCellArg->AbiInfo.HasExactlyOneRegisterSegment()); + assert(indirCellArg->AbiInfo.Segment(0).GetRegister() == result); } #endif @@ -7502,7 +7504,7 @@ void CodeGen::genCallPlaceRegArgs(GenTreeCall* call) // Consume all the arg regs for (CallArg& arg : call->gtArgs.LateArgs()) { - ABIPassingInformation& abiInfo = arg.NewAbiInfo; + ABIPassingInformation& abiInfo = arg.AbiInfo; GenTree* argNode = arg.GetLateNode(); #if FEATURE_MULTIREG_ARGS @@ -7594,7 +7596,7 @@ void CodeGen::genCallPlaceRegArgs(GenTreeCall* call) { for (CallArg& arg : call->gtArgs.Args()) { - for (const ABIPassingSegment& seg : arg.NewAbiInfo.Segments()) + for (const ABIPassingSegment& seg : arg.AbiInfo.Segments()) { if (seg.IsPassedInRegister() && genIsValidFloatReg(seg.GetRegister())) { diff --git a/src/coreclr/jit/codegenloongarch64.cpp b/src/coreclr/jit/codegenloongarch64.cpp index ec8ad25bc232d5..ceb64e2fc355cb 100644 --- a/src/coreclr/jit/codegenloongarch64.cpp +++ b/src/coreclr/jit/codegenloongarch64.cpp @@ -6043,9 +6043,9 @@ void CodeGen::genCallInstruction(GenTreeCall* call) for (CallArg& arg : call->gtArgs.Args()) { - for (unsigned i = 0; i < arg.NewAbiInfo.NumSegments; i++) + for (unsigned i = 0; i < arg.AbiInfo.NumSegments; i++) { - const ABIPassingSegment& seg = arg.NewAbiInfo.Segment(i); + const ABIPassingSegment& seg = arg.AbiInfo.Segment(i); if (seg.IsPassedInRegister() && ((trashedByEpilog & seg.GetRegisterMask()) != 0)) { JITDUMP("Tail call node:\n"); diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index 54cd716b1ccebd..9a4736eef737ed 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -6098,9 +6098,9 @@ void CodeGen::genCallInstruction(GenTreeCall* call) for (CallArg& arg : call->gtArgs.Args()) { - for (unsigned i = 0; i < arg.NewAbiInfo.NumSegments; i++) + for (unsigned i = 0; i < arg.AbiInfo.NumSegments; i++) { - const ABIPassingSegment& seg = arg.NewAbiInfo.Segment(i); + const ABIPassingSegment& seg = arg.AbiInfo.Segment(i); if (seg.IsPassedInRegister() && ((trashedByEpilog & seg.GetRegisterMask()) != 0)) { JITDUMP("Tail call node:\n"); diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index ecdf3cc876ac9c..1e43cc1e84952e 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -5976,7 +5976,7 @@ void CodeGen::genCall(GenTreeCall* call) genCallPlaceRegArgs(call); -#if defined(TARGET_X86) || defined(UNIX_AMD64_ABI) +#if defined(TARGET_X86) // The call will pop its arguments. // for each putarg_stk: target_ssize_t stackArgBytes = 0; @@ -5990,7 +5990,7 @@ void CodeGen::genCall(GenTreeCall* call) stackArgBytes += argSize; #ifdef DEBUG - assert(argSize == arg.AbiInfo.ByteSize); + assert(argSize == arg.AbiInfo.StackBytesConsumed()); if (source->TypeIs(TYP_STRUCT) && !source->OperIs(GT_FIELD_LIST)) { unsigned loadSize = source->GetLayout(compiler)->GetSize(); @@ -8393,7 +8393,8 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* putArgStk) #ifdef DEBUG CallArg* callArg = putArgStk->gtCall->gtArgs.FindByNode(putArgStk); assert(callArg != nullptr); - assert(argOffset == callArg->AbiInfo.ByteOffset); + assert(callArg->AbiInfo.HasExactlyOneStackSegment()); + assert(argOffset == callArg->AbiInfo.Segment(0).GetStackOffset()); #endif if (data->isContainedIntOrIImmed()) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index b5282654e23836..fab2870ae9de81 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3933,6 +3933,7 @@ class Compiler const char* gtGetWellKnownArgNameForArgMsg(WellKnownArg arg); void gtGetArgMsg(GenTreeCall* call, CallArg* arg, char* bufp, unsigned bufLength); void gtGetLateArgMsg(GenTreeCall* call, CallArg* arg, char* bufp, unsigned bufLength); + void gtPrintABILocation(const ABIPassingInformation& abiInfo, char** bufp, unsigned* bufLength); void gtDispArgList(GenTreeCall* call, GenTree* lastCallOperand, IndentStack* indentStack); void gtDispFieldSeq(FieldSeq* fieldSeq, ssize_t offset); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 0caa873b8b46aa..95087e29be2304 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -1162,134 +1162,6 @@ GenTree* GenTreeFieldList::SoleFieldOrThis() return this; } -//--------------------------------------------------------------- -// IsHfaArg: Is this arg considered a homogeneous floating-point aggregate? -// -bool CallArgABIInformation::IsHfaArg() const -{ - if (GlobalJitOptions::compFeatureHfa) - { - return IsHfa(GetHfaElemKind()); - } - else - { - return false; - } -} - -//--------------------------------------------------------------- -// IsHfaRegArg: Is this an HFA argument passed in registers? -// -bool CallArgABIInformation::IsHfaRegArg() const -{ - if (GlobalJitOptions::compFeatureHfa) - { - return IsHfa(GetHfaElemKind()) && IsPassedInRegisters(); - } - else - { - return false; - } -} - -//--------------------------------------------------------------- -// GetHfaType: Get the type of each element of the HFA arg. -// -var_types CallArgABIInformation::GetHfaType() const -{ - if (GlobalJitOptions::compFeatureHfa) - { - return HfaTypeFromElemKind(GetHfaElemKind()); - } - else - { - return TYP_UNDEF; - } -} - -//--------------------------------------------------------------- -// SetHfaType: Set the type of each element of the HFA arg. -// -// Arguments: -// type - The new type for each element -// hfaSlots - How many registers are used by the HFA. -// -// Remarks: -// This can only be called after the passing mode of the argument (registers -// or stack) has been determined. When passing HFAs of doubles on ARM it is -// expected that `hfaSlots` refers to the number of float registers used, -// i.e. twice the number of doubles being passed. This function will convert -// that into double registers and set `NumRegs` appropriately. -// -void CallArgABIInformation::SetHfaType(var_types type, unsigned hfaSlots) -{ - if (GlobalJitOptions::compFeatureHfa) - { - if (type != TYP_UNDEF) - { - // We must already have set the passing mode. - assert(NumRegs != 0 || GetStackByteSize() != 0); - // We originally set numRegs according to the size of the struct, but if the size of the - // hfaType is not the same as the pointer size, we need to correct it. - // Note that hfaSlots is the number of registers we will use. For ARM, that is twice - // the number of "double registers". - unsigned numHfaRegs = hfaSlots; -#ifdef TARGET_ARM - if (type == TYP_DOUBLE) - { - // Must be an even number of registers. - assert((NumRegs & 1) == 0); - numHfaRegs = hfaSlots / 2; - } -#endif // TARGET_ARM - - if (!IsHfaArg()) - { - // We haven't previously set this; do so now. - CorInfoHFAElemType elemKind = HfaElemKindFromType(type); - SetHfaElemKind(elemKind); - // Ensure we've allocated enough bits. - assert(GetHfaElemKind() == elemKind); - if (IsPassedInRegisters()) - { - NumRegs = numHfaRegs; - } - } - else - { - // We've already set this; ensure that it's consistent. - if (IsPassedInRegisters()) - { - assert(NumRegs == numHfaRegs); - } - assert(type == HfaTypeFromElemKind(GetHfaElemKind())); - } - } - } -} - -//--------------------------------------------------------------- -// GetStackByteSize: Get the number of stack bytes used to pass this argument. -// -// Returns: -// For pure register arguments, this returns 0. -// For pure stack arguments, this returns ByteSize. -// For split arguments the return value is between 0 and ByteSize. -// -unsigned CallArgABIInformation::GetStackByteSize() const -{ - if (!IsSplit() && NumRegs > 0) - { - return 0; - } - - assert(!IsHfaArg() || !IsSplit()); - - assert(ByteSize > TARGET_POINTER_SIZE * NumRegs); - const unsigned stackByteSize = ByteSize - TARGET_POINTER_SIZE * NumRegs; - return stackByteSize; -} - #ifdef DEBUG void NewCallArg::ValidateTypes() { @@ -1371,7 +1243,7 @@ CallArgs::CallArgs() , m_hasRetBuffer(false) , m_isVarArgs(false) , m_abiInformationDetermined(false) - , m_newAbiInformationDetermined(false) + , m_hasAddedFinalArgs(false) , m_hasRegArgs(false) , m_hasStackArgs(false) , m_argsComplete(false) @@ -1980,7 +1852,7 @@ void CallArgs::PushLateBack(CallArg* arg) // void CallArgs::Remove(CallArg* arg) { - assert(!m_abiInformationDetermined && !m_argsComplete); + assert(!m_hasAddedFinalArgs && !m_argsComplete); CallArg** slot = &m_head; while (*slot != nullptr) @@ -2601,9 +2473,7 @@ bool GenTreeCall::Equals(GenTreeCall* c1, GenTreeCall* c2) // void CallArgs::ResetFinalArgsAndABIInfo() { - m_newAbiInformationDetermined = false; - - if (!IsAbiInformationDetermined()) + if (!m_hasAddedFinalArgs) { return; } @@ -2633,6 +2503,7 @@ void CallArgs::ResetFinalArgsAndABIInfo() } } + m_hasAddedFinalArgs = false; m_abiInformationDetermined = false; } @@ -9907,6 +9778,7 @@ void CallArgs::InternalCopyFrom(Compiler* comp, CallArgs* other, CopyNodeFunc co m_hasRetBuffer = other->m_hasRetBuffer; m_isVarArgs = other->m_isVarArgs; m_abiInformationDetermined = other->m_abiInformationDetermined; + m_hasAddedFinalArgs = other->m_hasAddedFinalArgs; m_hasRegArgs = other->m_hasRegArgs; m_hasStackArgs = other->m_hasStackArgs; m_argsComplete = other->m_argsComplete; @@ -9928,7 +9800,6 @@ void CallArgs::InternalCopyFrom(Compiler* comp, CallArgs* other, CopyNodeFunc co carg->m_needPlace = arg.m_needPlace; carg->m_processed = arg.m_processed; carg->AbiInfo = arg.AbiInfo; - carg->NewAbiInfo = arg.NewAbiInfo; *tail = carg; tail = &carg->m_next; } @@ -13274,41 +13145,7 @@ void Compiler::gtGetArgMsg(GenTreeCall* call, CallArg* arg, char* bufp, unsigned } else if (call->gtArgs.IsAbiInformationDetermined()) { -#ifdef TARGET_ARM - if (arg->AbiInfo.IsSplit()) - { - regNumber firstReg = arg->AbiInfo.GetRegNum(); - if (arg->AbiInfo.NumRegs == 1) - { - sprintf_s(bufp, bufLength, " %s out+%02x", compRegVarName(firstReg), arg->AbiInfo.ByteOffset); - } - else - { - regNumber lastReg = REG_STK; - char separator = (arg->AbiInfo.NumRegs == 2) ? ',' : '-'; - if (arg->AbiInfo.IsHfaRegArg()) - { - unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + arg->AbiInfo.NumRegs - 1; - lastReg = genMapFloatRegArgNumToRegNum(lastRegNum); - } - else - { - unsigned lastRegNum = - genMapIntRegNumToRegArgNum(firstReg, call->GetUnmanagedCallConv()) + arg->AbiInfo.NumRegs - 1; - lastReg = genMapIntRegArgNumToRegNum(lastRegNum, call->GetUnmanagedCallConv()); - } - sprintf_s(bufp, bufLength, " %s%c%s out+%02x", compRegVarName(firstReg), separator, - compRegVarName(lastReg), arg->AbiInfo.ByteOffset); - } - - return; - } -#endif // TARGET_ARM -#if FEATURE_FIXED_OUT_ARGS - sprintf_s(bufp, bufLength, " out+%02x", arg->AbiInfo.ByteOffset); -#else - sprintf_s(bufp, bufLength, " on STK"); -#endif + gtPrintABILocation(arg->AbiInfo, &bufp, &bufLength); } } @@ -13323,65 +13160,112 @@ void Compiler::gtGetArgMsg(GenTreeCall* call, CallArg* arg, char* bufp, unsigned // // Return Value: // No return value, but bufp is written. - +// void Compiler::gtGetLateArgMsg(GenTreeCall* call, CallArg* arg, char* bufp, unsigned bufLength) { assert(arg->GetLateNode() != nullptr); - regNumber argReg = arg->AbiInfo.GetRegNum(); gtPrintArgPrefix(call, arg, &bufp, &bufLength); + gtPrintABILocation(arg->AbiInfo, &bufp, &bufLength); +} -#if FEATURE_FIXED_OUT_ARGS - if (argReg == REG_STK) - { - sprintf_s(bufp, bufLength, " in out+%02x", arg->AbiInfo.ByteOffset); - } - else +//------------------------------------------------------------------------ +// gtPrintABILocation: Print location that an argument is being passed in. +// +// Arguments: +// abiInfo - Passing information +// bufp - Pointer to buffer +// bufLength - Remaining length of buffer +// +void Compiler::gtPrintABILocation(const ABIPassingInformation& abiInfo, char** bufp, unsigned* bufLength) +{ + regNumber firstReg = REG_NA; + regNumber lastReg = REG_NA; + + int numPrinted; +#define PRINTF_BUF(...) \ + numPrinted = sprintf_s(*bufp, *bufLength, __VA_ARGS__); \ + assert((numPrinted > 0) && ((unsigned)numPrinted < *bufLength)); \ + *bufp += numPrinted; \ + *bufLength -= (unsigned)numPrinted; + + auto printRegs = [&]() { + if (firstReg == REG_NA) + { + return; + } + + bool printSeparately = firstReg == lastReg; + +#ifdef TARGET_XARCH + // No numeric arg regs, always print separately + printSeparately = true; #endif - { -#ifdef TARGET_ARM - if (arg->AbiInfo.IsSplit()) + + if (printSeparately) { - regNumber firstReg = arg->AbiInfo.GetRegNum(); - if (arg->AbiInfo.NumRegs == 1) + regNumber reg = firstReg; + while (true) { - sprintf_s(bufp, bufLength, " %s out+%02x", compRegVarName(firstReg), arg->AbiInfo.ByteOffset); + PRINTF_BUF(" %s", getRegName(reg)); + if (reg == lastReg) + { + break; + } + reg = REG_NEXT(reg); } - else + } + else + { + // Numeric arg regs, print as a range + PRINTF_BUF(" %s%c%s", getRegName(firstReg), REG_NEXT(firstReg) == lastReg ? ' ' : '-', getRegName(lastReg)); + } + + firstReg = REG_NA; + lastReg = REG_NA; + }; + + for (const ABIPassingSegment& segment : abiInfo.Segments()) + { + if (segment.IsPassedInRegister()) + { + regMaskTP regs = segment.GetRegisterMask(); + while (regs != RBM_NONE) { - regNumber lastReg = REG_STK; - char separator = (arg->AbiInfo.NumRegs == 2) ? ',' : '-'; - if (arg->AbiInfo.IsHfaRegArg()) + regNumber reg = genFirstRegNumFromMaskAndToggle(regs); + if (firstReg == REG_NA) { - unsigned lastRegNum = genMapFloatRegNumToRegArgNum(firstReg) + arg->AbiInfo.NumRegs - 1; - lastReg = genMapFloatRegArgNumToRegNum(lastRegNum); + firstReg = reg; + lastReg = reg; + } + else if (REG_NEXT(lastReg) == reg) + { + lastReg = reg; } else { - unsigned lastRegNum = - genMapIntRegNumToRegArgNum(firstReg, call->GetUnmanagedCallConv()) + arg->AbiInfo.NumRegs - 1; - lastReg = genMapIntRegArgNumToRegNum(lastRegNum, call->GetUnmanagedCallConv()); + printRegs(); + firstReg = reg; + lastReg = reg; } - sprintf_s(bufp, bufLength, " %s%c%s out+%02x", compRegVarName(firstReg), separator, - compRegVarName(lastReg), arg->AbiInfo.ByteOffset); } - - return; - } -#endif // TARGET_ARM -#if FEATURE_MULTIREG_ARGS - if (arg->AbiInfo.NumRegs >= 2) - { - char separator = (arg->AbiInfo.NumRegs == 2) ? ',' : '-'; - sprintf_s(bufp, bufLength, " %s%c%s", compRegVarName(argReg), separator, - compRegVarName(arg->AbiInfo.GetRegNum(arg->AbiInfo.NumRegs - 1))); } else -#endif { - sprintf_s(bufp, bufLength, " in %s", compRegVarName(argReg)); + printRegs(); + +#if FEATURE_FIXED_OUT_ARGS + int numPrinted = sprintf_s(*bufp, *bufLength, " out+%02x", segment.GetStackOffset()); +#else + int numPrinted = sprintf_s(*bufp, *bufLength, " STK"); +#endif + assert((numPrinted > 0) && ((unsigned)numPrinted < *bufLength)); + *bufp += numPrinted; + *bufLength -= (unsigned)numPrinted; } } + + printRegs(); } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index a7b2bdfade7e26..e01d9705eb0d4a 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -4570,151 +4570,6 @@ enum class WellKnownArg : unsigned const char* getWellKnownArgName(WellKnownArg arg); #endif -struct CallArgABIInformation -{ - CallArgABIInformation() - : NumRegs(0) - , ByteOffset(0) - , ByteSize(0) - , ArgType(TYP_UNDEF) -#if FEATURE_ARG_SPLIT - , m_isSplit(false) -#endif -#ifdef FEATURE_HFA_FIELDS_PRESENT - , m_hfaElemKind(CORINFO_HFA_ELEM_NONE) -#endif - { - for (size_t i = 0; i < MAX_ARG_REG_COUNT; i++) - { - RegNums[i] = REG_NA; - } - } - -private: - // The registers to use when passing this argument, set to REG_STK for - // arguments passed on the stack - regNumberSmall RegNums[MAX_ARG_REG_COUNT]; - -public: - // Count of number of registers that this argument uses. Note that on ARM, - // if we have a double hfa, this reflects the number of DOUBLE registers. - unsigned NumRegs; - unsigned ByteOffset; - unsigned ByteSize; - // The type used to pass this argument. This is generally the original - // argument type, but when a struct is passed as a scalar type, this is - // that type. Note that if a struct is passed by reference, this will still - // be the struct type. - var_types ArgType : 5; - -private: -#if FEATURE_ARG_SPLIT - // True when this argument is split between the registers and OutArg area - bool m_isSplit : 1; -#endif - -#ifdef FEATURE_HFA_FIELDS_PRESENT - // What kind of an HFA this is (CORINFO_HFA_ELEM_NONE if it is not an HFA). - CorInfoHFAElemType m_hfaElemKind : 3; -#endif - -public: - CorInfoHFAElemType GetHfaElemKind() const - { -#ifdef FEATURE_HFA_FIELDS_PRESENT - return m_hfaElemKind; -#else - NOWAY_MSG("GetHfaElemKind"); - return CORINFO_HFA_ELEM_NONE; -#endif - } - - void SetHfaElemKind(CorInfoHFAElemType elemKind) - { -#ifdef FEATURE_HFA_FIELDS_PRESENT - m_hfaElemKind = elemKind; -#else - NOWAY_MSG("SetHfaElemKind"); -#endif - } - - bool IsHfaArg() const; - bool IsHfaRegArg() const; - var_types GetHfaType() const; - void SetHfaType(var_types type, unsigned hfaSlots); - - regNumber GetRegNum() const - { - return (regNumber)RegNums[0]; - } - - regNumber GetOtherRegNum() const - { - return (regNumber)RegNums[1]; - } - regNumber GetRegNum(unsigned int i) - { - assert(i < MAX_ARG_REG_COUNT); - return (regNumber)RegNums[i]; - } - void SetRegNum(unsigned int i, regNumber regNum) - { - assert(i < MAX_ARG_REG_COUNT); - RegNums[i] = (regNumberSmall)regNum; - } - - bool IsSplit() const - { -#if FEATURE_ARG_SPLIT - return compFeatureArgSplit() && m_isSplit; -#else // FEATURE_ARG_SPLIT - return false; -#endif - } - void SetSplit(bool value) - { -#if FEATURE_ARG_SPLIT - m_isSplit = value; -#endif - } - - bool IsPassedInRegisters() const - { - return !IsSplit() && (NumRegs != 0); - } - - bool IsPassedInFloatRegisters() const - { -#ifdef TARGET_X86 - return false; -#else - return isValidFloatArgReg(GetRegNum()); -#endif - } - - bool IsMismatchedArgType() const - { -#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - return genIsValidIntReg(GetRegNum()) && varTypeUsesFloatReg(ArgType); -#else - return false; -#endif // TARGET_LOONGARCH64 || TARGET_RISCV64 - } - - // Get the number of bytes that this argument is occupying on the stack, - // including padding up to the target pointer size for platforms - // where a stack argument can't take less. - unsigned GetStackByteSize() const; - - // Return number of stack slots that this argument is taking. - // This value is not meaningful on Apple arm64 where multiple arguments can - // be passed in the same stack slot. - unsigned GetStackSlotsNumber() const - { - return roundUp(GetStackByteSize(), TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE; - } -}; - struct NewCallArg { // The node being passed. @@ -4801,8 +4656,7 @@ class CallArg } public: - CallArgABIInformation AbiInfo; - ABIPassingInformation NewAbiInfo; + ABIPassingInformation AbiInfo; CallArg(const NewCallArg& arg) : CallArg() @@ -4871,11 +4725,11 @@ class CallArgs // made for this call. unsigned m_padStkAlign; #endif - bool m_hasThisPointer : 1; - bool m_hasRetBuffer : 1; - bool m_isVarArgs : 1; - bool m_abiInformationDetermined : 1; - bool m_newAbiInformationDetermined : 1; + bool m_hasThisPointer : 1; + bool m_hasRetBuffer : 1; + bool m_isVarArgs : 1; + bool m_abiInformationDetermined : 1; + bool m_hasAddedFinalArgs : 1; // True if we have one or more register arguments. bool m_hasRegArgs : 1; // True if we have one or more stack arguments. @@ -4937,7 +4791,7 @@ class CallArgs void AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call); void ResetFinalArgsAndABIInfo(); - void DetermineNewABIInfo(Compiler* comp, GenTreeCall* call); + void DetermineABIInfo(Compiler* comp, GenTreeCall* call); void ArgsComplete(Compiler* comp, GenTreeCall* call); void EvalArgsToTemps(Compiler* comp, GenTreeCall* call); @@ -4951,7 +4805,6 @@ class CallArgs void SetIsVarArgs() { m_isVarArgs = true; } void ClearIsVarArgs() { m_isVarArgs = false; } bool IsAbiInformationDetermined() const { return m_abiInformationDetermined; } - bool IsNewAbiInformationDetermined() const { return m_newAbiInformationDetermined; } // TODO-Remove: Workaround for bad codegen in MSVC versions < 19.41, see // https://github.com/dotnet/runtime/pull/104370#issuecomment-2222910359 diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index c6910a3a037f10..56882a27d32b30 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1562,7 +1562,7 @@ void Lowering::LowerArg(GenTreeCall* call, CallArg* callArg) // If we hit this we are probably double-lowering. assert(!arg->OperIsPutArg()); - const ABIPassingInformation& abiInfo = callArg->NewAbiInfo; + const ABIPassingInformation& abiInfo = callArg->AbiInfo; JITDUMP("Passed in "); DBEXEC(comp->verbose, abiInfo.Dump()); @@ -1589,7 +1589,7 @@ void Lowering::LowerArg(GenTreeCall* call, CallArg* callArg) if (varTypeIsLong(arg)) { - assert(callArg->NewAbiInfo.CountRegsAndStackSlots() == 2); + assert(callArg->AbiInfo.CountRegsAndStackSlots() == 2); noway_assert(arg->OperIs(GT_LONG)); GenTreeFieldList* fieldList = new (comp, GT_FIELD_LIST) GenTreeFieldList(); @@ -3531,14 +3531,10 @@ void Lowering::LowerCFGCall(GenTreeCall* call) call->gtArgs.PushLateBack(targetArg); // Set up ABI information for this arg. - targetArg->NewAbiInfo = + targetArg->AbiInfo = ABIPassingInformation::FromSegmentByValue(comp, ABIPassingSegment::InRegister(REG_DISPATCH_INDIRECT_CALL_ADDR, 0, TARGET_POINTER_SIZE)); - targetArg->AbiInfo.ArgType = callTarget->TypeGet(); - targetArg->AbiInfo.SetRegNum(0, REG_DISPATCH_INDIRECT_CALL_ADDR); - targetArg->AbiInfo.NumRegs = 1; - targetArg->AbiInfo.ByteSize = TARGET_POINTER_SIZE; // Lower the newly added args now that call is updated LowerArg(call, targetArg); diff --git a/src/coreclr/jit/lsrabuild.cpp b/src/coreclr/jit/lsrabuild.cpp index 37344c6d754ff9..5d4a166dd61fbb 100644 --- a/src/coreclr/jit/lsrabuild.cpp +++ b/src/coreclr/jit/lsrabuild.cpp @@ -3126,7 +3126,7 @@ int LinearScan::BuildCallArgUses(GenTreeCall* call) continue; } - assert(!arg.NewAbiInfo.HasAnyRegisterSegment()); + assert(!arg.AbiInfo.HasAnyRegisterSegment()); assert(argNode->OperIs(GT_PUTARG_STK)); } diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index 0cd162a6c5a25c..12c5617da229b5 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -1283,7 +1283,7 @@ int LinearScan::BuildCall(GenTreeCall* call) { for (CallArg& arg : call->gtArgs.LateArgs()) { - for (const ABIPassingSegment& seg : arg.NewAbiInfo.Segments()) + for (const ABIPassingSegment& seg : arg.AbiInfo.Segments()) { if (seg.IsPassedInRegister() && genIsValidFloatReg(seg.GetRegister())) { diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 28fafb47d0af96..9544bac68f3109 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -751,26 +751,13 @@ void CallArg::Dump(Compiler* comp) { printf("CallArg[[%06u].%s", comp->dspTreeID(GetNode()), GenTree::OpName(GetNode()->OperGet())); printf(" %s", varTypeName(m_signatureType)); - printf(" (%s)", NewAbiInfo.IsPassedByReference() ? "By ref" : "By value"); - if (AbiInfo.GetRegNum() != REG_STK) + printf(" (%s)", AbiInfo.IsPassedByReference() ? "By ref" : "By value"); + printf(", %u segments:", AbiInfo.NumSegments); + for (const ABIPassingSegment& segment : AbiInfo.Segments()) { - printf(", %u reg%s:", AbiInfo.NumRegs, AbiInfo.NumRegs == 1 ? "" : "s"); - for (unsigned i = 0; i < AbiInfo.NumRegs; i++) - { - printf(" %s", getRegName(AbiInfo.GetRegNum(i))); - } - } - if (AbiInfo.GetStackByteSize() > 0) - { - printf(", byteSize=%u, byteOffset=%u", AbiInfo.ByteSize, AbiInfo.ByteOffset); - } - if (GetLateNode() != nullptr) - { - printf(", isLate"); - } - if (AbiInfo.IsSplit()) - { - printf(", isSplit"); + printf(" <"); + segment.Dump(); + printf(">"); } if (m_needPlace) { @@ -780,10 +767,6 @@ void CallArg::Dump(Compiler* comp) { printf(", processed"); } - if (AbiInfo.IsHfaRegArg()) - { - printf(", isHfa(%s)", varTypeName(AbiInfo.GetHfaType())); - } if (m_wellKnownArg != WellKnownArg::None) { printf(", wellKnown[%s]", getWellKnownArgName(m_wellKnownArg)); @@ -811,21 +794,14 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) assert(argx != nullptr); bool canEvalToTemp = true; - if (arg.AbiInfo.GetRegNum() == REG_STK) - { - assert(m_hasStackArgs); #if !FEATURE_FIXED_OUT_ARGS + if (!arg.AbiInfo.HasAnyRegisterSegment()) + { // Non-register arguments are evaluated and pushed in order; they // should never go in the late arg list. canEvalToTemp = false; -#endif } -#if FEATURE_ARG_SPLIT - else if (arg.AbiInfo.IsSplit()) - { - assert(m_hasStackArgs); - } -#endif // FEATURE_ARG_SPLIT +#endif // If the argument tree contains a store (GTF_ASG) then the argument and // and every earlier argument (except constants) must be evaluated into temps @@ -859,7 +835,7 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) } #if !FEATURE_FIXED_OUT_ARGS - if (prevArg.AbiInfo.GetRegNum() == REG_STK) + if (!prevArg.AbiInfo.HasAnyRegisterSegment()) { // All stack args are already evaluated and placed in order // in this case. @@ -904,7 +880,7 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) continue; } - if (otherArg.AbiInfo.GetRegNum() == REG_STK) + if (!otherArg.AbiInfo.HasAnyRegisterSegment()) { treatLikeCall = true; break; @@ -945,7 +921,7 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) } #if !FEATURE_FIXED_OUT_ARGS - if (prevArg.AbiInfo.GetRegNum() == REG_STK) + if (!prevArg.AbiInfo.HasAnyRegisterSegment()) { // All stack args are already evaluated and placed in order // in this case. @@ -962,12 +938,12 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) #if FEATURE_FIXED_OUT_ARGS // Or, if they are stored into the FIXED_OUT_ARG area // we require that they be moved to the late list - else if (prevArg.AbiInfo.GetRegNum() == REG_STK) + else if (!prevArg.AbiInfo.HasAnyRegisterSegment()) { prevArg.m_needPlace = true; } #if FEATURE_ARG_SPLIT - else if (prevArg.AbiInfo.IsSplit()) + else if (prevArg.AbiInfo.IsSplitAcrossRegistersAndStack()) { prevArg.m_needPlace = true; } @@ -1008,7 +984,7 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) } #if !FEATURE_FIXED_OUT_ARGS - if (prevArg.AbiInfo.GetRegNum() == REG_STK) + if (!prevArg.AbiInfo.HasAnyRegisterSegment()) { // All stack args are already evaluated and placed in order // in this case. @@ -1065,7 +1041,7 @@ void CallArgs::ArgsComplete(Compiler* comp, GenTreeCall* call) // Examine the register args that are currently not marked needTmp // - if (!arg.m_needTmp && (arg.AbiInfo.GetRegNum() != REG_STK)) + if (!arg.m_needTmp && arg.AbiInfo.HasAnyRegisterSegment()) { if (hasStackArgsWeCareAbout) { @@ -1181,7 +1157,7 @@ void CallArgs::SortArgs(Compiler* comp, GenTreeCall* call, CallArg** sortedArgs) CallArg* arg = sortedArgs[curInx]; - if (arg->AbiInfo.GetRegNum() != REG_STK) + if (arg->AbiInfo.HasAnyRegisterSegment()) { regCount++; } @@ -1484,7 +1460,7 @@ void CallArgs::EvalArgsToTemps(Compiler* comp, GenTreeCall* call) // Only the register arguments need to be replaced with placeholder nodes. // Stacked arguments are evaluated and pushed (or stored into the stack) in order. // - if (arg.AbiInfo.GetRegNum() == REG_STK) + if (!arg.AbiInfo.HasAnyRegisterSegment()) continue; #endif @@ -1550,33 +1526,14 @@ void CallArgs::EvalArgsToTemps(Compiler* comp, GenTreeCall* call) LclVarDsc* varDsc = comp->lvaGetDesc(tmpVarNum); var_types lclVarType = genActualType(argx->gtType); - var_types scalarType = TYP_UNKNOWN; if (setupArg->OperIsCopyBlkOp()) { setupArg = comp->fgMorphCopyBlock(setupArg); -#if defined(TARGET_ARMARCH) || defined(UNIX_AMD64_ABI) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - if ((lclVarType == TYP_STRUCT) && (arg.AbiInfo.ArgType != TYP_STRUCT)) - { - scalarType = arg.AbiInfo.ArgType; - } -#endif // TARGET_ARMARCH || defined (UNIX_AMD64_ABI) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) } - // scalarType can be set to a wider type for ARM or unix amd64 architectures: (3 => 4) or (5,6,7 => - // 8) - if ((scalarType != TYP_UNKNOWN) && (scalarType != lclVarType)) - { - // Create a GT_LCL_FLD using the wider type to go to the late argument list - defArg = comp->gtNewLclFldNode(tmpVarNum, scalarType, 0); - - comp->lvaSetVarDoNotEnregister(tmpVarNum DEBUGARG(DoNotEnregisterReason::LocalField)); - } - else - { - // Create a copy of the temp to go to the late argument list - defArg = comp->gtNewLclvNode(tmpVarNum, lclVarType); - } + // Create a copy of the temp to go to the late argument list + defArg = comp->gtNewLclvNode(tmpVarNum, lclVarType); defArg->SetMorphed(comp); } @@ -1600,7 +1557,7 @@ void CallArgs::EvalArgsToTemps(Compiler* comp, GenTreeCall* call) // this argument so we have to replace it in the gtCallArgs list // (the initial argument evaluation list) with a placeholder. // - if ((arg.AbiInfo.GetRegNum() == REG_STK) && !arg.m_needPlace) + if (!arg.AbiInfo.HasAnyRegisterSegment() && !arg.m_needPlace) { continue; } @@ -1612,13 +1569,13 @@ void CallArgs::EvalArgsToTemps(Compiler* comp, GenTreeCall* call) #ifdef DEBUG if (comp->verbose) { - if (arg.AbiInfo.GetRegNum() == REG_STK) + if (arg.AbiInfo.HasAnyRegisterSegment()) { - printf("Deferred stack argument :\n"); + printf("Deferred argument:\n"); } else { - printf("Deferred argument ('%s'):\n", getRegName(arg.AbiInfo.GetRegNum())); + printf("Deferred stack argument:\n"); } comp->gtDispTree(argx); @@ -1649,12 +1606,15 @@ void CallArgs::EvalArgsToTemps(Compiler* comp, GenTreeCall* call) #ifdef DEBUG if (comp->verbose) { - printf("\nRegister placement order: "); + printf("\nRegister placement order:"); for (CallArg& arg : LateArgs()) { - if (arg.AbiInfo.GetRegNum() != REG_STK) + for (const ABIPassingSegment& segment : arg.AbiInfo.Segments()) { - printf("%s ", getRegName(arg.AbiInfo.GetRegNum())); + if (segment.IsPassedInRegister()) + { + printf(" %s", getRegName(segment.GetRegister())); + } } } printf("\n"); @@ -1766,12 +1726,11 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call { assert(&call->gtArgs == this); - if (IsAbiInformationDetermined()) + if (m_hasAddedFinalArgs) { - // We've already determined ABI information. return; } - JITDUMP("Initializing arg info for %d.%s:\n", call->gtTreeID, GenTree::OpName(call->gtOper)); + JITDUMP("Adding final args and determining ABI info for [%06u]:\n", Compiler::dspTreeID(call)); m_hasRegArgs = false; m_hasStackArgs = false; @@ -1965,170 +1924,21 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call JITDUMP("Argument %u ABI info: ", GetIndex(&arg)); DBEXEC(VERBOSE, abiInfo.Dump()); - arg.NewAbiInfo = abiInfo; - arg.AbiInfo = CallArgABIInformation(); - - if (varTypeIsStruct(argSigType)) - { - assert(argx == arg.GetEarlyNode()); - - Compiler::structPassingKind howToPassStruct; - var_types structBaseType = - comp->getArgTypeForStruct(argSigClass, &howToPassStruct, IsVarArgs(), argLayout->GetSize()); -#if defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) - if (arg.NewAbiInfo.HasAnyFloatingRegisterSegment()) - { - // Struct passed according to hardware floating-point calling convention - assert(!arg.NewAbiInfo.HasAnyStackSegment()); - assert(howToPassStruct == Compiler::SPK_ByValue || howToPassStruct == Compiler::SPK_PrimitiveType); - if (arg.NewAbiInfo.NumSegments == 2) - { - // On LoongArch64, "getPrimitiveTypeForStruct" will incorrectly return "TYP_LONG" - // for "struct { float, float }", and retyping to a primitive here will cause the - // multi-reg morphing to not kick in (the struct in question needs to be passed in - // two FP registers). Here is just keep "structBaseType" as "TYP_STRUCT". - // TODO-LoongArch64: fix "getPrimitiveTypeForStruct". - structBaseType = TYP_STRUCT; - } - else - { - assert(arg.NewAbiInfo.NumSegments == 1); - structBaseType = arg.NewAbiInfo.Segment(0).GetRegisterType(); - } - } -#endif // defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) - arg.AbiInfo.ArgType = structBaseType == TYP_UNKNOWN ? argx->TypeGet() : structBaseType; - } - else - { - arg.AbiInfo.ArgType = argx->TypeGet(); - } - - if (abiInfo.IsSplitAcrossRegistersAndStack()) - { - m_hasStackArgs = true; - m_hasRegArgs = true; - - arg.AbiInfo.SetSplit(true); - arg.AbiInfo.ByteOffset = 0; - unsigned regNumIndex = 0; - for (const ABIPassingSegment& segment : abiInfo.Segments()) - { - if (segment.IsPassedInRegister()) - { - if (regNumIndex < MAX_ARG_REG_COUNT) - { - arg.AbiInfo.SetRegNum(regNumIndex, segment.GetRegister()); - regNumIndex++; - } - - arg.AbiInfo.NumRegs++; - } - else - { - assert(segment.GetStackOffset() == 0); - } - } - } - else if (abiInfo.HasAnyRegisterSegment()) - { - // This is a register argument - m_hasRegArgs = true; - - unsigned regNumIndex = 0; - for (const ABIPassingSegment& segment : abiInfo.Segments()) - { - if (regNumIndex < MAX_ARG_REG_COUNT) - { - arg.AbiInfo.SetRegNum(regNumIndex, segment.GetRegister()); - regNumIndex++; - } - - arg.AbiInfo.NumRegs++; + arg.AbiInfo = abiInfo; -#ifdef TARGET_ARM - // Old style ABI info expects two registers counted for these segments. - if (segment.GetRegisterType() == TYP_DOUBLE) - { - arg.AbiInfo.NumRegs++; - - if (argSigType == TYP_DOUBLE) - { - arg.AbiInfo.SetRegNum(regNumIndex, REG_NEXT(segment.GetRegister())); - regNumIndex++; - } - } -#endif - } - } - else + for (const ABIPassingSegment& segment : abiInfo.Segments()) { - assert(abiInfo.HasAnyStackSegment()); - // We only expect to see one stack segment in these cases. - assert(abiInfo.NumSegments == 1); - // This is a stack argument - m_hasStackArgs = true; - const ABIPassingSegment& segment = abiInfo.Segment(0); - arg.AbiInfo.SetRegNum(0, REG_STK); - arg.AbiInfo.ByteOffset = segment.GetStackOffset(); - } - - // TODO-Cleanup: remove HFA information from VarDsc. - var_types hfaType = TYP_UNDEF; - bool isHfaArg = false; - unsigned hfaSlots = 0; - - if (GlobalJitOptions::compFeatureHfa) - { - hfaType = comp->GetHfaType(argSigClass); - isHfaArg = varTypeIsValidHfaType(hfaType); - - if (TargetOS::IsWindows && TargetArchitecture::IsArm64 && IsVarArgs()) + if (segment.IsPassedOnStack()) { - // Make sure for vararg methods isHfaArg is not true. - isHfaArg = false; - } - - if (isHfaArg) - { - hfaSlots = comp->GetHfaCount(argSigClass); - - // If we have a HFA struct it's possible we transition from a method that originally - // only had integer types to now start having FP types. We have to communicate this - // through this flag since LSRA later on will use this flag to determine whether - // or not to track the FP register set. - // - comp->compFloatingPointUsed = true; - } - } - - if (arg.NewAbiInfo.IsPassedByReference()) - { - arg.AbiInfo.ByteSize = TARGET_POINTER_SIZE; - } - else - { - unsigned size = argLayout != nullptr ? argLayout->GetSize() : genTypeSize(argSigType); - - // Apple arm64 reuses the same stack slot for multiple args in some - // cases; old ABI info reflects that in the size. - // Primitives and float HFAs do not necessarily take up full stack - // slots. - if (compAppleArm64Abi() && (!varTypeIsStruct(argSigType) || (isHfaArg && (hfaType == TYP_FLOAT)))) - { - arg.AbiInfo.ByteSize = size; + m_hasStackArgs = true; } else { - arg.AbiInfo.ByteSize = roundUp(size, TARGET_POINTER_SIZE); + m_hasRegArgs = true; + comp->compFloatingPointUsed |= genIsValidFloatReg(segment.GetRegister()); } } - - if (isHfaArg) - { - arg.AbiInfo.SetHfaType(hfaType, hfaSlots); - } - } // end foreach argument loop + } m_argsStackSize = classifier.StackSize(); @@ -2145,8 +1955,8 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call } #endif - m_abiInformationDetermined = true; - m_newAbiInformationDetermined = true; + m_abiInformationDetermined = true; + m_hasAddedFinalArgs = true; } //------------------------------------------------------------------------ @@ -2158,7 +1968,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call // comp - The compiler object. // call - The call to which the CallArgs belongs. // -void CallArgs::DetermineNewABIInfo(Compiler* comp, GenTreeCall* call) +void CallArgs::DetermineABIInfo(Compiler* comp, GenTreeCall* call) { ClassifierInfo info; info.CallConv = call->GetUnmanagedCallConv(); @@ -2182,17 +1992,17 @@ void CallArgs::DetermineNewABIInfo(Compiler* comp, GenTreeCall* call) if (nonStdRegNum == REG_NA) { - arg.NewAbiInfo = classifier.Classify(comp, argSigType, argLayout, arg.GetWellKnownArg()); + arg.AbiInfo = classifier.Classify(comp, argSigType, argLayout, arg.GetWellKnownArg()); } else { ABIPassingSegment segment = ABIPassingSegment::InRegister(nonStdRegNum, 0, TARGET_POINTER_SIZE); - arg.NewAbiInfo = ABIPassingInformation::FromSegmentByValue(comp, segment); + arg.AbiInfo = ABIPassingInformation::FromSegmentByValue(comp, segment); } } - m_argsStackSize = classifier.StackSize(); - m_newAbiInformationDetermined = true; + m_argsStackSize = classifier.StackSize(); + m_abiInformationDetermined = true; } //------------------------------------------------------------------------ @@ -2336,14 +2146,6 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call) } } - // TODO-ARGS: Review this, is it really necessary to treat them specially here? - if (call->gtArgs.IsNonStandard(this, call, &arg) && arg.AbiInfo.IsPassedInRegisters()) - { - flagsSummary |= argx->gtFlags; - continue; - } - assert(arg.AbiInfo.ByteSize > 0); - // For pointers to locals we can skip reporting GC info and also skip zero initialization. // NOTE: We deferred this from the importer because of the inliner. if (argx->OperIs(GT_LCL_ADDR)) @@ -2354,7 +2156,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call) if (varTypeIsStruct(arg.GetSignatureType()) && !reMorphing) { bool makeOutArgCopy = false; - if (arg.NewAbiInfo.IsPassedByReference()) + if (arg.AbiInfo.IsPassedByReference()) { makeOutArgCopy = true; } @@ -2464,12 +2266,11 @@ bool Compiler::fgTryMorphStructArg(CallArg* arg) GenTree* argNode = *use; assert(varTypeIsStruct(argNode)); - bool isSplit = arg->NewAbiInfo.IsSplitAcrossRegistersAndStack(); + bool isSplit = arg->AbiInfo.IsSplitAcrossRegistersAndStack(); #ifdef TARGET_ARM - if ((isSplit && (arg->NewAbiInfo.CountRegsAndStackSlots() > 4)) || - (!isSplit && arg->NewAbiInfo.HasAnyStackSegment())) + if ((isSplit && (arg->AbiInfo.CountRegsAndStackSlots() > 4)) || (!isSplit && arg->AbiInfo.HasAnyStackSegment())) #else - if (!arg->NewAbiInfo.HasAnyRegisterSegment()) + if (!arg->AbiInfo.HasAnyRegisterSegment()) #endif { if (argNode->OperIs(GT_LCL_VAR) && @@ -2524,7 +2325,7 @@ bool Compiler::fgTryMorphStructArg(CallArg* arg) unsigned lclNum = lclNode->GetLclNum(); LclVarDsc* varDsc = lvaGetDesc(lclNum); - if (!arg->NewAbiInfo.HasExactlyOneRegisterSegment()) + if (!arg->AbiInfo.HasExactlyOneRegisterSegment()) { varDsc->lvIsMultiRegArg = true; } @@ -2534,11 +2335,11 @@ bool Compiler::fgTryMorphStructArg(CallArg* arg) // Try to see if we can use the promoted fields to pass this argument. // - if (varDsc->lvPromoted && (varDsc->lvFieldCnt == arg->NewAbiInfo.CountRegsAndStackSlots())) + if (varDsc->lvPromoted && (varDsc->lvFieldCnt == arg->AbiInfo.CountRegsAndStackSlots())) { bool fieldsMatch = true; - for (const ABIPassingSegment& seg : arg->NewAbiInfo.Segments()) + for (const ABIPassingSegment& seg : arg->AbiInfo.Segments()) { if (seg.IsPassedInRegister()) { @@ -2589,7 +2390,7 @@ bool Compiler::fgTryMorphStructArg(CallArg* arg) (lvaGetPromotionType(argNode->AsLclVarCommon()->GetLclNum()) == PROMOTION_TYPE_INDEPENDENT); if (isUseOfIndependentlyPromotedStruct) { - if (arg->NewAbiInfo.HasExactlyOneRegisterSegment()) + if (arg->AbiInfo.HasExactlyOneRegisterSegment()) { // We already tried to use the fields above, but that failed. // Here we prefer to create a copy to avoid DNER'ing the local. @@ -2597,7 +2398,7 @@ bool Compiler::fgTryMorphStructArg(CallArg* arg) return false; } } - else if (!argNode->TypeIs(TYP_STRUCT) && arg->NewAbiInfo.HasExactlyOneRegisterSegment()) + else if (!argNode->TypeIs(TYP_STRUCT) && arg->AbiInfo.HasExactlyOneRegisterSegment()) { // This can be treated primitively. Leave it alone. return true; @@ -2633,7 +2434,7 @@ bool Compiler::fgTryMorphStructArg(CallArg* arg) GenTree* indirAddr = argNode->AsIndir()->Addr(); if (((indirAddr->gtFlags & GTF_PERSISTENT_SIDE_EFFECTS) != 0) && - (arg->NewAbiInfo.CountRegsAndStackSlots() > 1)) + (arg->AbiInfo.CountRegsAndStackSlots() > 1)) { // Cannot create multiple uses of the address. Bail. return false; @@ -2739,7 +2540,7 @@ bool Compiler::fgTryMorphStructArg(CallArg* arg) newArg = new (this, GT_FIELD_LIST) GenTreeFieldList(); newArg->SetMorphed(this); - for (const ABIPassingSegment& seg : arg->NewAbiInfo.Segments()) + for (const ABIPassingSegment& seg : arg->AbiInfo.Segments()) { if (seg.IsPassedInRegister()) { @@ -2824,7 +2625,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) // // We don't need a copy if this is the last use of the local. // - if (opts.OptimizationEnabled() && arg->NewAbiInfo.IsPassedByReference()) + if (opts.OptimizationEnabled() && arg->AbiInfo.IsPassedByReference()) { GenTree* implicitByRefLclAddr; target_ssize_t implicitByRefLclOffs; @@ -2912,7 +2713,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) #endif JITDUMP("making an outgoing copy for struct arg\n"); - assert(!call->IsTailCall() || !arg->NewAbiInfo.IsPassedByReference()); + assert(!call->IsTailCall() || !arg->AbiInfo.IsPassedByReference()); CORINFO_CLASS_HANDLE copyBlkClass = arg->GetSignatureClassHandle(); unsigned tmp = 0; @@ -2966,7 +2767,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) copyBlk = fgMorphCopyBlock(copyBlk); GenTree* argNode; - if (arg->NewAbiInfo.IsPassedByReference()) + if (arg->AbiInfo.IsPassedByReference()) { argNode = gtNewLclVarAddrNode(tmp); lvaSetVarAddrExposed(tmp DEBUGARG(AddressExposedReason::ESCAPE_ADDRESS)); @@ -2995,7 +2796,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg) arg->SetEarlyNode(argNode); #endif // !FEATURE_FIXED_OUT_ARGS - if (!arg->NewAbiInfo.IsPassedByReference()) + if (!arg->AbiInfo.IsPassedByReference()) { bool morphed = fgTryMorphStructArg(arg); // Should always succeed for an unpromoted local. @@ -4357,7 +4158,7 @@ bool Compiler::fgCanFastTailCall(GenTreeCall* callee, const char** failReason) #if defined(TARGET_ARM) || defined(TARGET_RISCV64) for (CallArg& arg : callee->gtArgs.Args()) { - if (arg.NewAbiInfo.IsSplitAcrossRegistersAndStack()) + if (arg.AbiInfo.IsSplitAcrossRegistersAndStack()) { reportFastTailCallDecision("Argument splitting in callee is not supported on " TARGET_READABLE_NAME); return false; @@ -4538,7 +4339,7 @@ bool Compiler::fgCallHasMustCopyByrefParameter(GenTreeCall* call) // bool Compiler::fgCallArgWillPointIntoLocalFrame(GenTreeCall* call, CallArg& arg) { - if (!arg.NewAbiInfo.IsPassedByReference()) + if (!arg.AbiInfo.IsPassedByReference()) { return false; } diff --git a/src/coreclr/jit/promotion.cpp b/src/coreclr/jit/promotion.cpp index 951fc2a6171fdc..42c2bf00821d66 100644 --- a/src/coreclr/jit/promotion.cpp +++ b/src/coreclr/jit/promotion.cpp @@ -1553,12 +1553,12 @@ class LocalsUseVisitor : public GenTreeVisitor flags |= AccessKindFlags::IsCallArg; - if (!call->gtArgs.IsNewAbiInformationDetermined()) + if (!call->gtArgs.IsAbiInformationDetermined()) { - call->gtArgs.DetermineNewABIInfo(m_compiler, call); + call->gtArgs.DetermineABIInfo(m_compiler, call); } - if (!arg.NewAbiInfo.HasAnyStackSegment() && !arg.NewAbiInfo.IsPassedByReference()) + if (!arg.AbiInfo.HasAnyStackSegment() && !arg.AbiInfo.IsPassedByReference()) { flags |= AccessKindFlags::IsRegCallArg; } @@ -2419,7 +2419,7 @@ bool ReplaceVisitor::ReplaceCallArgWithFieldList(GenTreeCall* call, GenTreeLclVa assert(layout != nullptr); StructDeaths deaths = m_liveness->GetDeathsForStructLocal(argNode); GenTreeFieldList* fieldList = m_compiler->gtNewFieldList(); - for (const ABIPassingSegment& seg : callArg->NewAbiInfo.Segments()) + for (const ABIPassingSegment& seg : callArg->AbiInfo.Segments()) { Replacement* rep = nullptr; if (agg->OverlappingReplacements(argNode->GetLclOffs() + seg.Offset, seg.Size, &rep, nullptr) && @@ -2496,9 +2496,9 @@ bool ReplaceVisitor::CanReplaceCallArgWithFieldListOfReplacements(GenTreeCall* GenTreeLclVarCommon* lcl) { // We should have computed ABI information during the costing phase. - assert(call->gtArgs.IsNewAbiInformationDetermined()); + assert(call->gtArgs.IsAbiInformationDetermined()); - if (callArg->NewAbiInfo.HasAnyStackSegment() || callArg->NewAbiInfo.IsPassedByReference()) + if (callArg->AbiInfo.HasAnyStackSegment() || callArg->AbiInfo.IsPassedByReference()) { return false; } @@ -2507,7 +2507,7 @@ bool ReplaceVisitor::CanReplaceCallArgWithFieldListOfReplacements(GenTreeCall* assert(agg != nullptr); bool anyReplacements = false; - for (const ABIPassingSegment& seg : callArg->NewAbiInfo.Segments()) + for (const ABIPassingSegment& seg : callArg->AbiInfo.Segments()) { assert(seg.IsPassedInRegister()); diff --git a/src/coreclr/jit/stacklevelsetter.cpp b/src/coreclr/jit/stacklevelsetter.cpp index 14840c65a9fe19..dc80a24d9d6413 100644 --- a/src/coreclr/jit/stacklevelsetter.cpp +++ b/src/coreclr/jit/stacklevelsetter.cpp @@ -356,14 +356,7 @@ unsigned StackLevelSetter::PopArgumentsFromCall(GenTreeCall* call) { for (CallArg& arg : call->gtArgs.Args()) { - unsigned slotCount = 0; - for (const ABIPassingSegment& segment : arg.NewAbiInfo.Segments()) - { - if (segment.IsPassedOnStack()) - { - slotCount += (segment.GetStackSize() + (TARGET_POINTER_SIZE - 1)) / TARGET_POINTER_SIZE; - } - } + unsigned slotCount = (arg.AbiInfo.StackBytesConsumed() + (TARGET_POINTER_SIZE - 1)) / TARGET_POINTER_SIZE; if (slotCount != 0) { diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 4760835c605880..2f6df6d7701e1e 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -13548,7 +13548,7 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN #ifdef DEBUG for (CallArg& arg : call->gtArgs.Args()) { - assert(!arg.NewAbiInfo.IsPassedByReference() && + assert(!arg.AbiInfo.IsPassedByReference() && "Helpers taking implicit byref arguments should not be marked as pure"); } #endif