Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions src/coreclr/jit/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,95 @@ bool ABIPassingInformation::IsSplitAcrossRegistersAndStack() const
}
return anyReg && anyStack;
}

//-----------------------------------------------------------------------------
// FromSegment:
// Create ABIPassingInformation from a single segment.
//
// Parameters:
// comp - Compiler instance
// segment - The single segment that represents the passing information
//
// Return Value:
// An instance of ABIPassingInformation.
//
ABIPassingInformation ABIPassingInformation::FromSegment(Compiler* comp, const ABIPassingSegment& segment)
{
ABIPassingInformation info;
info.NumSegments = 1;
info.Segments = new (comp, CMK_ABI) ABIPassingSegment(segment);
return info;
}

//-----------------------------------------------------------------------------
// RegisterQueue::Dequeue:
// Dequeue a register from the queue.
//
// Return Value:
// The dequeued register.
//
regNumber RegisterQueue::Dequeue()
{
assert(Count() > 0);
return static_cast<regNumber>(m_regs[m_index++]);
}

//-----------------------------------------------------------------------------
// RegisterQueue::Peek:
// Peek at the head of the queue.
//
// Return Value:
// The head register in the queue.
//
regNumber RegisterQueue::Peek()
{
assert(Count() > 0);
return static_cast<regNumber>(m_regs[m_index]);
}

//-----------------------------------------------------------------------------
// RegisterQueue::Clear:
// Clear the register queue.
//
void RegisterQueue::Clear()
{
m_index = m_numRegs;
}

#ifdef SWIFT_SUPPORT
//-----------------------------------------------------------------------------
// Classify:
// Classify a parameter for the Swift ABI.
//
// Parameters:
// comp - Compiler instance
// type - The type of the parameter
// structLayout - The layout of the struct. Expected to be non-null if
// varTypeIsStruct(type) is true.
// wellKnownParam - Well known type of the parameter (if it may affect its ABI classification)
//
// Returns:
// Classification information for the parameter.
//
ABIPassingInformation SwiftABIClassifier::Classify(Compiler* comp,
var_types type,
ClassLayout* structLayout,
WellKnownArg wellKnownParam)
{
#ifdef TARGET_AMD64
if (wellKnownParam == WellKnownArg::RetBuffer)
{
return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(REG_SWIFT_ARG_RET_BUFF, 0,
TARGET_POINTER_SIZE));
}
#endif

if (wellKnownParam == WellKnownArg::SwiftSelf)
{
return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(REG_SWIFT_SELF, 0,
TARGET_POINTER_SIZE));
}

return m_classifier.Classify(comp, type, structLayout, wellKnownParam);
}
#endif
124 changes: 120 additions & 4 deletions src/coreclr/jit/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,134 @@ class ABIPassingSegment
struct ABIPassingInformation
{
// The number of segments used to pass the value. Examples:
// - On x86, TYP_LONG can be passed in two registers, resulting in two
// register segments
// - On SysV x64, structs can be passed in two registers, resulting in two
// register segments
// - On arm64/arm32, HFAs can be passed in up to four registers, giving
// four register segments
// - On arm32, structs can be split out over register and stack, giving
// multiple register segments and a struct segment.
// - On Windows x64, all parameters always belong into one stack slot or register,
// and thus always have NumSegments == 1
// - On Windows x64, all parameters always fit into one stack slot or
// register, and thus always have NumSegments == 1
unsigned NumSegments = 0;
ABIPassingSegment* Segments = nullptr;

bool IsSplitAcrossRegistersAndStack() const;

static ABIPassingInformation FromSegment(Compiler* comp, const ABIPassingSegment& segment);
};

class RegisterQueue
{
const regNumber* m_regs;
unsigned int m_numRegs;
unsigned int m_index = 0;

public:
RegisterQueue(const regNumber* regs, unsigned int numRegs) : m_regs(regs), m_numRegs(numRegs)
{
}

unsigned Count()
{
return m_numRegs - m_index;
}

regNumber Dequeue();
regNumber Peek();
void Clear();
};

struct ClassifierInfo
{
CorInfoCallConvExtension CallConv = CorInfoCallConvExtension::Managed;
bool IsVarArgs = false;
bool HasThis = false;
bool HasRetBuff = false;
};

class X86Classifier
Copy link
Contributor

@SingleAccretion SingleAccretion Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about having target-specific classifiers in target-specific files (targetXYZ.cpp, which we already have but don't really use)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that idea. They'll probably have to stay as being defined in abi.h, but I'll try moving the classification Implementation into those target specific files.

{
RegisterQueue m_regs;
unsigned m_stackArgSize = 0;

public:
X86Classifier(const ClassifierInfo& info);

ABIPassingInformation Classify(Compiler* comp,
var_types type,
ClassLayout* structLayout,
WellKnownArg wellKnownParam);
};

class WinX64Classifier
{
RegisterQueue m_intRegs;
RegisterQueue m_floatRegs;
unsigned m_stackArgSize = 0;

public:
WinX64Classifier(const ClassifierInfo& info);

ABIPassingInformation Classify(Compiler* comp,
var_types type,
ClassLayout* structLayout,
WellKnownArg wellKnownParam);
};

class SysVX64Classifier
{
RegisterQueue m_intRegs;
RegisterQueue m_floatRegs;
unsigned m_stackArgSize = 0;

public:
SysVX64Classifier(const ClassifierInfo& info);

ABIPassingInformation Classify(Compiler* comp,
var_types type,
ClassLayout* structLayout,
WellKnownArg wellKnownParam);
};

class Arm64Classifier
{
const ClassifierInfo& m_info;
RegisterQueue m_intRegs;
RegisterQueue m_floatRegs;
unsigned m_stackArgSize = 0;

public:
Arm64Classifier(const ClassifierInfo& info);

ABIPassingInformation Classify(Compiler* comp,
var_types type,
ClassLayout* structLayout,
WellKnownArg wellKnownParam);
};

#if defined(TARGET_X86)
typedef X86Classifier PlatformClassifier;
#elif defined(WINDOWS_AMD64_ABI)
typedef WinX64Classifier PlatformClassifier;
#elif defined(UNIX_AMD64_ABI)
typedef SysVX64Classifier PlatformClassifier;
#elif defined(TARGET_ARM64)
typedef Arm64Classifier PlatformClassifier;
#endif

#ifdef SWIFT_SUPPORT
class SwiftABIClassifier
{
PlatformClassifier m_classifier;

public:
SwiftABIClassifier(const ClassifierInfo& info) : m_classifier(info)
{
}

ABIPassingInformation Classify(Compiler* comp,
var_types type,
ClassLayout* structLayout,
WellKnownArg wellKnownParam);
};
#endif
5 changes: 5 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3994,6 +3994,11 @@ class Compiler
CORINFO_ARG_LIST_HANDLE varList,
CORINFO_SIG_INFO* varSig);

template <typename Classifier>
void lvaClassifyParameterABI(Classifier& classifier);

void lvaClassifyParameterABI();

bool lvaInitSpecialSwiftParam(InitVarDscInfo* varDscInfo, CorInfoType type, CORINFO_CLASS_HANDLE typeHnd);

var_types lvaGetActualType(unsigned lclNum);
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compmemkind.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// and the corresponding array of string names for these enum members.

// clang-format off
CompMemKindMacro(ABI)
CompMemKindMacro(AssertionProp)
CompMemKindMacro(ASTNode)
CompMemKindMacro(InstDesc)
Expand Down
Loading