Skip to content

Commit

Permalink
JIT: Use new ABI classifiers for GenTreeCall arguments (dotnet#103537)
Browse files Browse the repository at this point in the history
Switch `AddFinalArgsAndDetermineABIInfo` to reuse the new-style ABI classifiers.

Does not remove the old ABI information representation in `CallArg`, but keeps both for now.

Co-authored-by: Tomasz Sowiński <tomeksowi@gmail.com>
  • Loading branch information
2 people authored and rzikm committed Jun 24, 2024
1 parent c878ec6 commit e537db7
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 978 deletions.
31 changes: 25 additions & 6 deletions src/coreclr/jit/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ ABIPassingInformation::ABIPassingInformation(Compiler* comp, unsigned numSegment

if (numSegments > 1)
{
Segments = new (comp, CMK_ABI) ABIPassingSegment[numSegments];
m_segments = new (comp, CMK_ABI) ABIPassingSegment[numSegments];
}
}

Expand All @@ -225,10 +225,10 @@ const ABIPassingSegment& ABIPassingInformation::Segment(unsigned index) const
assert(index < NumSegments);
if (NumSegments == 1)
{
return SingleSegment;
return m_singleSegment;
}

return Segments[index];
return m_segments[index];
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -265,6 +265,25 @@ bool ABIPassingInformation::HasAnyRegisterSegment() const
return false;
}

//-----------------------------------------------------------------------------
// HasAnyFloatingRegisterSegment:
// Check if any part of this value is passed in a floating-point register.
//
// Return Value:
// True if so.
//
bool ABIPassingInformation::HasAnyFloatingRegisterSegment() const
{
for (unsigned i = 0; i < NumSegments; i++)
{
if (Segment(i).IsPassedInRegister() && genIsValidFloatReg(Segment(i).GetRegister()))
{
return true;
}
}
return false;
}

//-----------------------------------------------------------------------------
// HasAnyStackSegment:
// Check if any part of this value is passed on the stack.
Expand Down Expand Up @@ -348,8 +367,8 @@ bool ABIPassingInformation::IsSplitAcrossRegistersAndStack() const
ABIPassingInformation ABIPassingInformation::FromSegment(Compiler* comp, const ABIPassingSegment& segment)
{
ABIPassingInformation info;
info.NumSegments = 1;
info.SingleSegment = segment;
info.NumSegments = 1;
info.m_singleSegment = segment;
return info;
}

Expand All @@ -371,7 +390,7 @@ ABIPassingInformation ABIPassingInformation::FromSegments(Compiler*
{
ABIPassingInformation info;
info.NumSegments = 2;
info.Segments = new (comp, CMK_ABI) ABIPassingSegment[2]{firstSegment, secondSegment};
info.m_segments = new (comp, CMK_ABI) ABIPassingSegment[2]{firstSegment, secondSegment};
return info;
}

Expand Down
8 changes: 6 additions & 2 deletions src/coreclr/jit/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#pragma once

class ClassLayout;
enum class WellKnownArg : unsigned;

class ABIPassingSegment
{
regNumber m_register = REG_NA;
Expand Down Expand Up @@ -42,8 +45,8 @@ struct ABIPassingInformation
private:
union
{
ABIPassingSegment* Segments;
ABIPassingSegment SingleSegment;
ABIPassingSegment* m_segments;
ABIPassingSegment m_singleSegment;
};

public:
Expand Down Expand Up @@ -72,6 +75,7 @@ struct ABIPassingInformation
ABIPassingSegment& Segment(unsigned index);

bool HasAnyRegisterSegment() const;
bool HasAnyFloatingRegisterSegment() const;
bool HasAnyStackSegment() const;
bool HasExactlyOneRegisterSegment() const;
bool HasExactlyOneStackSegment() const;
Expand Down
88 changes: 5 additions & 83 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1258,87 +1258,6 @@ void CallArgABIInformation::SetHfaType(var_types type, unsigned hfaSlots)
}
}

//---------------------------------------------------------------
// SetByteSize: Set information related to this argument's size and alignment.
//
// Arguments:
// byteSize - The size in bytes of the argument.
// byteAlignment - The alignment in bytes of the argument.
// isStruct - Whether this arg is a struct.
// isFloatHfa - Whether this is a float HFA.
//
// Remarks:
// This function will determine how the argument size needs to be rounded. On
// most ABIs all arguments are rounded to stack pointer size, but Apple arm64
// ABI is an exception as it allows packing some small arguments into the
// same stack slot.
//
void CallArgABIInformation::SetByteSize(unsigned byteSize, unsigned byteAlignment, bool isStruct, bool isFloatHfa)
{
unsigned roundedByteSize;
if (compAppleArm64Abi())
{
// Only struct types need extension or rounding to pointer size, but HFA<float> does not.
if (isStruct && !isFloatHfa)
{
roundedByteSize = roundUp(byteSize, TARGET_POINTER_SIZE);
}
else
{
roundedByteSize = byteSize;
}
}
else
{
roundedByteSize = roundUp(byteSize, TARGET_POINTER_SIZE);
}

#if !defined(TARGET_ARM)
// Arm32 could have a struct with 8 byte alignment
// which rounded size % 8 is not 0.
assert(byteAlignment != 0);
assert(roundedByteSize % byteAlignment == 0);
#endif // TARGET_ARM

ByteSize = roundedByteSize;
ByteAlignment = byteAlignment;
}

//---------------------------------------------------------------
// SetMultiRegsNumw: Set the registers for a multi-reg arg using 'sequential' registers.
//
// Remarks:
// This assumes that `NumRegs` and the first reg num has already been set and
// determines how many sequential registers are necessary to pass the
// argument.
// Note that on ARM the registers set may skip odd float registers if the arg
// is a HFA of doubles, since double and float registers overlap.
void CallArgABIInformation::SetMultiRegNums()
{
#if FEATURE_MULTIREG_ARGS && !defined(UNIX_AMD64_ABI) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
if (NumRegs == 1)
{
return;
}

regNumber argReg = GetRegNum(0);
#ifdef TARGET_ARM
unsigned int regSize = (GetHfaType() == TYP_DOUBLE) ? 2 : 1;
#else
unsigned int regSize = 1;
#endif

if (NumRegs > MAX_ARG_REG_COUNT)
NO_WAY("Multireg argument exceeds the maximum length");

for (unsigned int regIndex = 1; regIndex < NumRegs; regIndex++)
{
argReg = (regNumber)(argReg + regSize);
SetRegNum(regIndex, argReg);
}
#endif // FEATURE_MULTIREG_ARGS && !defined(UNIX_AMD64_ABI) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
}

//---------------------------------------------------------------
// GetStackByteSize: Get the number of stack bytes used to pass this argument.
//
Expand Down Expand Up @@ -1468,7 +1387,7 @@ void CallArg::CheckIsStruct()
CallArgs::CallArgs()
: m_head(nullptr)
, m_lateHead(nullptr)
, m_nextStackByteOffset(0)
, m_argsStackSize(0)
#ifdef UNIX_X86_ABI
, m_stkSizeBytes(0)
, m_padStkAlign(0)
Expand Down Expand Up @@ -9817,7 +9736,7 @@ void CallArgs::InternalCopyFrom(Compiler* comp, CallArgs* other, CopyNodeFunc co
{
assert((m_head == nullptr) && (m_lateHead == nullptr));

m_nextStackByteOffset = other->m_nextStackByteOffset;
m_argsStackSize = other->m_argsStackSize;
m_hasThisPointer = other->m_hasThisPointer;
m_hasRetBuffer = other->m_hasRetBuffer;
m_isVarArgs = other->m_isVarArgs;
Expand Down Expand Up @@ -9845,6 +9764,7 @@ void CallArgs::InternalCopyFrom(Compiler* comp, CallArgs* other, CopyNodeFunc co
carg->m_isTmp = arg.m_isTmp;
carg->m_processed = arg.m_processed;
carg->AbiInfo = arg.AbiInfo;
carg->NewAbiInfo = arg.NewAbiInfo;
*tail = carg;
tail = &carg->m_next;
}
Expand Down Expand Up @@ -13174,6 +13094,8 @@ const char* Compiler::gtGetWellKnownArgNameForArgMsg(WellKnownArg arg)
return "swift error";
case WellKnownArg::SwiftSelf:
return "swift self";
case WellKnownArg::X86TailCallSpecialArg:
return "tail call";
default:
return nullptr;
}
Expand Down
19 changes: 4 additions & 15 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#define _GENTREE_H_
/*****************************************************************************/

#include "abi.h"
#include "vartype.h" // For "var_types"
#include "target.h" // For "regNumber"
#include "ssaconfig.h" // For "SsaConfig::RESERVED_SSA_NUM"
Expand Down Expand Up @@ -4480,6 +4481,7 @@ enum class WellKnownArg : unsigned
DispatchIndirectCallTarget,
SwiftError,
SwiftSelf,
X86TailCallSpecialArg,
};

#ifdef DEBUG
Expand All @@ -4492,12 +4494,10 @@ struct CallArgABIInformation
: NumRegs(0)
, ByteOffset(0)
, ByteSize(0)
, ByteAlignment(0)
#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
, StructFloatFieldType()
#endif
, ArgType(TYP_UNDEF)
, IsBackFilled(false)
, PassedByRef(false)
#if FEATURE_ARG_SPLIT
, m_isSplit(false)
Expand All @@ -4523,7 +4523,6 @@ struct CallArgABIInformation
unsigned NumRegs;
unsigned ByteOffset;
unsigned ByteSize;
unsigned ByteAlignment;
#if defined(UNIX_AMD64_ABI)
// Unix amd64 will split floating point types and integer types in structs
// between floating point and general purpose registers. Keep track of that
Expand All @@ -4541,9 +4540,6 @@ struct CallArgABIInformation
// that type. Note that if a struct is passed by reference, this will still
// be the struct type.
var_types ArgType : 5;
// True when the argument fills a register slot skipped due to alignment
// requirements of previous arguments.
bool IsBackFilled : 1;
// True iff the argument is passed by reference.
bool PassedByRef : 1;

Expand Down Expand Up @@ -4641,18 +4637,11 @@ struct CallArgABIInformation
#endif // TARGET_LOONGARCH64 || TARGET_RISCV64
}

void SetByteSize(unsigned byteSize, unsigned byteAlignment, bool isStruct, bool isFloatHfa);

// 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;

// Set the register numbers for a multireg argument.
// There's nothing to do on x64/Ux because the structDesc has already been used to set the
// register numbers.
void SetMultiRegNums();

// 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.
Expand Down Expand Up @@ -4755,6 +4744,7 @@ class CallArg

public:
CallArgABIInformation AbiInfo;
ABIPassingInformation NewAbiInfo;

CallArg(const NewCallArg& arg)
: CallArg()
Expand Down Expand Up @@ -4817,7 +4807,7 @@ class CallArgs
CallArg* m_head;
CallArg* m_lateHead;

unsigned m_nextStackByteOffset;
unsigned m_argsStackSize;
#ifdef UNIX_X86_ABI
// Number of stack bytes pushed before we start pushing these arguments.
unsigned m_stkSizeBytes;
Expand Down Expand Up @@ -4846,7 +4836,6 @@ class CallArgs
void AddedWellKnownArg(WellKnownArg arg);
void RemovedWellKnownArg(WellKnownArg arg);
regNumber GetCustomRegister(Compiler* comp, CorInfoCallConvExtension cc, WellKnownArg arg);
void SplitArg(CallArg* arg, unsigned numRegs, unsigned numSlots);
void SortArgs(Compiler* comp, GenTreeCall* call, CallArg** sortedArgs);

public:
Expand Down
8 changes: 2 additions & 6 deletions src/coreclr/jit/lclvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1721,7 +1721,8 @@ void Compiler::lvaInitVarDsc(LclVarDsc* varDsc,
template <typename Classifier>
void Compiler::lvaClassifyParameterABI(Classifier& classifier)
{
lvaParameterPassingInfo = new (this, CMK_LvaTable) ABIPassingInformation[info.compArgsCount];
lvaParameterPassingInfo =
info.compArgsCount == 0 ? nullptr : new (this, CMK_LvaTable) ABIPassingInformation[info.compArgsCount];

for (unsigned i = 0; i < info.compArgsCount; i++)
{
Expand Down Expand Up @@ -1768,11 +1769,6 @@ void Compiler::lvaClassifyParameterABI(Classifier& classifier)
//
void Compiler::lvaClassifyParameterABI()
{
if (info.compArgsCount == 0)
{
return;
}

ClassifierInfo cInfo;
cInfo.CallConv = info.compCallConv;
cInfo.IsVarArgs = info.compIsVarArgs;
Expand Down
7 changes: 5 additions & 2 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3448,10 +3448,13 @@ void Lowering::LowerCFGCall(GenTreeCall* call)
call->gtArgs.PushLateBack(targetArg);

// Set up ABI information for this arg.
targetArg->NewAbiInfo =
ABIPassingInformation::FromSegment(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.SetByteSize(TARGET_POINTER_SIZE, TARGET_POINTER_SIZE, false, false);
targetArg->AbiInfo.NumRegs = 1;
targetArg->AbiInfo.ByteSize = TARGET_POINTER_SIZE;

// Lower the newly added args now that call is updated
LowerArg(call, targetArg, true /* late */);
Expand Down
7 changes: 0 additions & 7 deletions src/coreclr/jit/lsrabuild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,14 +602,7 @@ RefPosition* LinearScan::newRefPosition(Interval* theInterval,
regNumber physicalReg = genRegNumFromMask(mask, theInterval->registerType);
RefPosition* pos = newRefPosition(physicalReg, theLocation, RefTypeFixedReg, nullptr, mask);
assert(theInterval != nullptr);
#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
// The LoongArch64's ABI which the float args maybe passed by integer register
// when no float register left but free integer register.
assert((regType(theInterval->registerType) == FloatRegisterType) ||
(allRegs(theInterval->registerType) & mask) != 0);
#else
assert((allRegs(theInterval->registerType) & mask) != 0);
#endif
}

RefPosition* newRP = newRefPositionRaw(theLocation, theTreeNode, theRefType);
Expand Down
Loading

0 comments on commit e537db7

Please sign in to comment.