Skip to content

Commit a4f9ec2

Browse files
authored
JIT: Move passed-by-reference argument information to new ABI info (#112449)
1 parent 14c4743 commit a4f9ec2

14 files changed

+144
-101
lines changed

src/coreclr/jit/abi.cpp

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,19 @@ IteratorPair<ABIPassingSegmentIterator> ABIPassingInformation::Segments() const
270270
ABIPassingSegmentIterator(begin + NumSegments));
271271
}
272272

273+
//-----------------------------------------------------------------------------
274+
// IsPassedByReference:
275+
// Check if the argument is passed by (implicit) reference. If true, a single
276+
// pointer-sized segment is expected.
277+
//
278+
// Return Value:
279+
// True if so.
280+
//
281+
bool ABIPassingInformation::IsPassedByReference() const
282+
{
283+
return m_passedByRef;
284+
}
285+
273286
//-----------------------------------------------------------------------------
274287
// HasAnyRegisterSegment:
275288
// Check if any part of this value is passed in a register.
@@ -409,20 +422,50 @@ unsigned ABIPassingInformation::CountRegsAndStackSlots() const
409422
// Create ABIPassingInformation from a single segment.
410423
//
411424
// Parameters:
412-
// comp - Compiler instance
413-
// segment - The single segment that represents the passing information
425+
// comp - Compiler instance
426+
// passedByRef - If true, the argument is passed by reference and the segment is for its pointer.
427+
// segment - The single segment that represents the passing information
414428
//
415429
// Return Value:
416430
// An instance of ABIPassingInformation.
417431
//
418-
ABIPassingInformation ABIPassingInformation::FromSegment(Compiler* comp, const ABIPassingSegment& segment)
432+
ABIPassingInformation ABIPassingInformation::FromSegment(Compiler* comp,
433+
bool passedByRef,
434+
const ABIPassingSegment& segment)
419435
{
420436
ABIPassingInformation info;
437+
info.m_passedByRef = passedByRef;
421438
info.NumSegments = 1;
422439
info.m_singleSegment = segment;
440+
441+
#ifdef DEBUG
442+
if (passedByRef)
443+
{
444+
assert(segment.Size == TARGET_POINTER_SIZE);
445+
assert(!segment.IsPassedInRegister() || (segment.GetRegisterType() == TYP_I_IMPL));
446+
}
447+
#endif
448+
423449
return info;
424450
}
425451

452+
//-----------------------------------------------------------------------------
453+
// FromSegmentByValue:
454+
// Create ABIPassingInformation from a single segment passing an argument by
455+
// value.
456+
//
457+
// Parameters:
458+
// comp - Compiler instance
459+
// segment - The single segment that represents the passing information
460+
//
461+
// Return Value:
462+
// An instance of ABIPassingInformation.
463+
//
464+
ABIPassingInformation ABIPassingInformation::FromSegmentByValue(Compiler* comp, const ABIPassingSegment& segment)
465+
{
466+
return FromSegment(comp, /* passedByRef */ false, segment);
467+
}
468+
426469
//-----------------------------------------------------------------------------
427470
// FromSegments:
428471
// Create ABIPassingInformation from two segments.
@@ -466,7 +509,7 @@ void ABIPassingInformation::Dump() const
466509

467510
const ABIPassingSegment& seg = Segment(i);
468511
seg.Dump();
469-
printf("\n");
512+
printf("%s\n", IsPassedByReference() ? " (implicit by-ref)" : "");
470513
}
471514
}
472515

@@ -545,13 +588,14 @@ ABIPassingInformation SwiftABIClassifier::Classify(Compiler* comp,
545588
if (wellKnownParam == WellKnownArg::RetBuffer)
546589
{
547590
regNumber reg = theFixedRetBuffReg(CorInfoCallConvExtension::Swift);
548-
return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(reg, 0, TARGET_POINTER_SIZE));
591+
return ABIPassingInformation::FromSegmentByValue(comp,
592+
ABIPassingSegment::InRegister(reg, 0, TARGET_POINTER_SIZE));
549593
}
550594

551595
if (wellKnownParam == WellKnownArg::SwiftSelf)
552596
{
553-
return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(REG_SWIFT_SELF, 0,
554-
TARGET_POINTER_SIZE));
597+
return ABIPassingInformation::FromSegmentByValue(comp, ABIPassingSegment::InRegister(REG_SWIFT_SELF, 0,
598+
TARGET_POINTER_SIZE));
555599
}
556600

557601
if (wellKnownParam == WellKnownArg::SwiftError)
@@ -561,8 +605,8 @@ ABIPassingInformation SwiftABIClassifier::Classify(Compiler* comp,
561605
// as that will mess with other args.
562606
// Quirk: To work around the JIT for now, "pass" it in REG_SWIFT_ERROR,
563607
// and let CodeGen::genFnProlog handle the rest.
564-
return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(REG_SWIFT_ERROR, 0,
565-
TARGET_POINTER_SIZE));
608+
return ABIPassingInformation::FromSegmentByValue(comp, ABIPassingSegment::InRegister(REG_SWIFT_ERROR, 0,
609+
TARGET_POINTER_SIZE));
566610
}
567611

568612
if (type == TYP_STRUCT)

src/coreclr/jit/abi.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ struct ABIPassingInformation
8888
ABIPassingSegment m_singleSegment;
8989
};
9090

91+
bool m_passedByRef = false;
92+
9193
public:
9294
// The number of segments used to pass the value. Examples:
9395
// - On SysV x64, structs can be passed in two registers, resulting in two
@@ -101,10 +103,9 @@ struct ABIPassingInformation
101103
// - On loongarch64/riscv64, structs can be passed in two registers or
102104
// can be split out over register and stack, giving
103105
// multiple register segments and a struct segment.
104-
unsigned NumSegments;
106+
unsigned NumSegments = 0;
105107

106108
ABIPassingInformation()
107-
: NumSegments(0)
108109
{
109110
}
110111

@@ -114,6 +115,7 @@ struct ABIPassingInformation
114115
ABIPassingSegment& Segment(unsigned index);
115116
IteratorPair<ABIPassingSegmentIterator> Segments() const;
116117

118+
bool IsPassedByReference() const;
117119
bool HasAnyRegisterSegment() const;
118120
bool HasAnyFloatingRegisterSegment() const;
119121
bool HasAnyStackSegment() const;
@@ -122,7 +124,8 @@ struct ABIPassingInformation
122124
bool IsSplitAcrossRegistersAndStack() const;
123125
unsigned CountRegsAndStackSlots() const;
124126

125-
static ABIPassingInformation FromSegment(Compiler* comp, const ABIPassingSegment& segment);
127+
static ABIPassingInformation FromSegment(Compiler* comp, bool passedByRef, const ABIPassingSegment& segment);
128+
static ABIPassingInformation FromSegmentByValue(Compiler* comp, const ABIPassingSegment& segment);
126129
static ABIPassingInformation FromSegments(Compiler* comp,
127130
const ABIPassingSegment& firstSegment,
128131
const ABIPassingSegment& secondSegment);

src/coreclr/jit/gentree.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4581,7 +4581,6 @@ struct CallArgABIInformation
45814581
, ByteOffset(0)
45824582
, ByteSize(0)
45834583
, ArgType(TYP_UNDEF)
4584-
, PassedByRef(false)
45854584
#if FEATURE_ARG_SPLIT
45864585
, m_isSplit(false)
45874586
#endif
@@ -4611,8 +4610,6 @@ struct CallArgABIInformation
46114610
// that type. Note that if a struct is passed by reference, this will still
46124611
// be the struct type.
46134612
var_types ArgType : 5;
4614-
// True iff the argument is passed by reference.
4615-
bool PassedByRef : 1;
46164613

46174614
private:
46184615
#if FEATURE_ARG_SPLIT

src/coreclr/jit/lclvars.cpp

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,13 +1600,6 @@ void Compiler::lvaInitVarDsc(LclVarDsc* varDsc,
16001600
compFloatingPointUsed = true;
16011601
}
16021602

1603-
#if FEATURE_IMPLICIT_BYREFS
1604-
varDsc->lvIsImplicitByRef = 0;
1605-
#endif // FEATURE_IMPLICIT_BYREFS
1606-
#if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1607-
varDsc->lvIsSplit = 0;
1608-
#endif // TARGET_LOONGARCH64 || TARGET_RISCV64
1609-
16101603
// Set the lvType (before this point it is TYP_UNDEF).
16111604

16121605
if (GlobalJitOptions::compFeatureHfa)
@@ -1678,6 +1671,10 @@ void Compiler::lvaClassifyParameterABI(Classifier& classifier)
16781671

16791672
lvaParameterPassingInfo[i] = classifier.Classify(this, dsc->TypeGet(), structLayout, wellKnownArg);
16801673

1674+
#if FEATURE_IMPLICIT_BYREFS
1675+
dsc->lvIsImplicitByRef = lvaParameterPassingInfo[i].IsPassedByReference();
1676+
#endif // FEATURE_IMPLICIT_BYREFS
1677+
16811678
#ifdef DEBUG
16821679
if (verbose)
16831680
{
@@ -3327,22 +3324,6 @@ void Compiler::lvaSetStruct(unsigned varNum, ClassLayout* layout, bool unsafeVal
33273324
{
33283325
varDsc->lvType = layout->GetType();
33293326

3330-
#if FEATURE_IMPLICIT_BYREFS
3331-
// Mark implicit byref struct parameters
3332-
if (varDsc->lvIsParam && !varDsc->lvIsStructField)
3333-
{
3334-
structPassingKind howToReturnStruct;
3335-
getArgTypeForStruct(layout->GetClassHandle(), &howToReturnStruct, info.compIsVarArgs,
3336-
varDsc->lvExactSize());
3337-
3338-
if (howToReturnStruct == SPK_ByReference)
3339-
{
3340-
JITDUMP("Marking V%02i as a byref parameter\n", varNum);
3341-
varDsc->lvIsImplicitByRef = 1;
3342-
}
3343-
}
3344-
#endif // FEATURE_IMPLICIT_BYREFS
3345-
33463327
// For structs that are small enough, we check and set HFA element type
33473328
if (GlobalJitOptions::compFeatureHfa && (layout->GetSize() <= MAX_PASS_MULTIREG_BYTES))
33483329
{

src/coreclr/jit/lower.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3766,8 +3766,9 @@ void Lowering::LowerCFGCall(GenTreeCall* call)
37663766

37673767
// Set up ABI information for this arg.
37683768
targetArg->NewAbiInfo =
3769-
ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(REG_DISPATCH_INDIRECT_CALL_ADDR,
3770-
0, TARGET_POINTER_SIZE));
3769+
ABIPassingInformation::FromSegmentByValue(comp,
3770+
ABIPassingSegment::InRegister(REG_DISPATCH_INDIRECT_CALL_ADDR,
3771+
0, TARGET_POINTER_SIZE));
37713772
targetArg->AbiInfo.ArgType = callTarget->TypeGet();
37723773
targetArg->AbiInfo.SetRegNum(0, REG_DISPATCH_INDIRECT_CALL_ADDR);
37733774
targetArg->AbiInfo.NumRegs = 1;

src/coreclr/jit/morph.cpp

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ void CallArg::Dump(Compiler* comp)
748748
{
749749
printf("CallArg[[%06u].%s", comp->dspTreeID(GetNode()), GenTree::OpName(GetNode()->OperGet()));
750750
printf(" %s", varTypeName(m_signatureType));
751-
printf(" (%s)", AbiInfo.PassedByRef ? "By ref" : "By value");
751+
printf(" (%s)", NewAbiInfo.IsPassedByReference() ? "By ref" : "By value");
752752
if (AbiInfo.GetRegNum() != REG_STK)
753753
{
754754
printf(", %u reg%s:", AbiInfo.NumRegs, AbiInfo.NumRegs == 1 ? "" : "s");
@@ -1493,7 +1493,7 @@ GenTree* CallArgs::MakeTmpArgNode(Compiler* comp, CallArg* arg, unsigned lclNum)
14931493

14941494
if (varTypeIsStruct(argType))
14951495
{
1496-
if (arg->AbiInfo.PassedByRef)
1496+
if (arg->NewAbiInfo.IsPassedByReference())
14971497
{
14981498
argNode = comp->gtNewLclVarAddrNode(lclNum);
14991499
comp->lvaSetVarAddrExposed(lclNum DEBUGARG(AddressExposedReason::ESCAPE_ADDRESS));
@@ -1513,7 +1513,7 @@ GenTree* CallArgs::MakeTmpArgNode(Compiler* comp, CallArg* arg, unsigned lclNum)
15131513
}
15141514
else
15151515
{
1516-
assert(!arg->AbiInfo.PassedByRef);
1516+
assert(!arg->NewAbiInfo.IsPassedByReference());
15171517
argNode = comp->gtNewLclvNode(lclNum, argType);
15181518
}
15191519

@@ -2058,7 +2058,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call
20582058
else
20592059
{
20602060
ABIPassingSegment segment = ABIPassingSegment::InRegister(nonStdRegNum, 0, TARGET_POINTER_SIZE);
2061-
abiInfo = ABIPassingInformation::FromSegment(comp, segment);
2061+
abiInfo = ABIPassingInformation::FromSegmentByValue(comp, segment);
20622062
}
20632063

20642064
JITDUMP("Argument %u ABI info: ", GetIndex(&arg));
@@ -2096,8 +2096,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call
20962096
}
20972097
}
20982098
#endif // defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64)
2099-
arg.AbiInfo.PassedByRef = howToPassStruct == Compiler::SPK_ByReference;
2100-
arg.AbiInfo.ArgType = structBaseType == TYP_UNKNOWN ? argx->TypeGet() : structBaseType;
2099+
arg.AbiInfo.ArgType = structBaseType == TYP_UNKNOWN ? argx->TypeGet() : structBaseType;
21012100
}
21022101
else
21032102
{
@@ -2206,7 +2205,7 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call
22062205
}
22072206
}
22082207

2209-
if (arg.AbiInfo.PassedByRef)
2208+
if (arg.NewAbiInfo.IsPassedByReference())
22102209
{
22112210
arg.AbiInfo.ByteSize = TARGET_POINTER_SIZE;
22122211
}
@@ -2291,17 +2290,8 @@ void CallArgs::DetermineNewABIInfo(Compiler* comp, GenTreeCall* call)
22912290
else
22922291
{
22932292
ABIPassingSegment segment = ABIPassingSegment::InRegister(nonStdRegNum, 0, TARGET_POINTER_SIZE);
2294-
arg.NewAbiInfo = ABIPassingInformation::FromSegment(comp, segment);
2293+
arg.NewAbiInfo = ABIPassingInformation::FromSegmentByValue(comp, segment);
22952294
}
2296-
2297-
// TODO-Cleanup: This should be added to the new ABI info.
2298-
Compiler::structPassingKind passingKind = Compiler::SPK_ByValue;
2299-
if (argLayout != nullptr)
2300-
{
2301-
comp->getArgTypeForStruct(argSigClass, &passingKind, call->IsVarargs(), argLayout->GetSize());
2302-
}
2303-
2304-
arg.AbiInfo.PassedByRef = passingKind == Compiler::SPK_ByReference;
23052295
}
23062296

23072297
m_argsStackSize = classifier.StackSize();
@@ -2516,7 +2506,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
25162506
assert(originalSize == info.compCompHnd->getClassSize(arg.GetSignatureClassHandle()));
25172507

25182508
// First, handle the case where the argument is passed by reference.
2519-
if (arg.AbiInfo.PassedByRef)
2509+
if (arg.NewAbiInfo.IsPassedByReference())
25202510
{
25212511
assert(arg.AbiInfo.ByteSize == TARGET_POINTER_SIZE);
25222512
makeOutArgCopy = true;
@@ -2841,7 +2831,7 @@ void Compiler::fgMorphMultiregStructArgs(GenTreeCall* call)
28412831

28422832
for (CallArg& arg : call->gtArgs.Args())
28432833
{
2844-
if ((arg.AbiInfo.ArgType == TYP_STRUCT) && !arg.AbiInfo.PassedByRef)
2834+
if ((arg.AbiInfo.ArgType == TYP_STRUCT) && !arg.NewAbiInfo.IsPassedByReference())
28452835
{
28462836
foundStructArg = true;
28472837
GenTree*& argx = arg.NodeRef();
@@ -3195,7 +3185,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg)
31953185
//
31963186
// We don't need a copy if this is the last use of the local.
31973187
//
3198-
if (opts.OptimizationEnabled() && arg->AbiInfo.PassedByRef)
3188+
if (opts.OptimizationEnabled() && arg->NewAbiInfo.IsPassedByReference())
31993189
{
32003190
GenTree* implicitByRefLclAddr;
32013191
target_ssize_t implicitByRefLclOffs;
@@ -3283,7 +3273,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, CallArg* arg)
32833273
#endif
32843274

32853275
JITDUMP("making an outgoing copy for struct arg\n");
3286-
assert(!call->IsTailCall() || !arg->AbiInfo.PassedByRef);
3276+
assert(!call->IsTailCall() || !arg->NewAbiInfo.IsPassedByReference());
32873277

32883278
CORINFO_CLASS_HANDLE copyBlkClass = arg->GetSignatureClassHandle();
32893279
unsigned tmp = 0;
@@ -4896,7 +4886,7 @@ bool Compiler::fgCallHasMustCopyByrefParameter(GenTreeCall* call)
48964886
//
48974887
bool Compiler::fgCallArgWillPointIntoLocalFrame(GenTreeCall* call, CallArg& arg)
48984888
{
4899-
if (!arg.AbiInfo.PassedByRef)
4889+
if (!arg.NewAbiInfo.IsPassedByReference())
49004890
{
49014891
return false;
49024892
}

src/coreclr/jit/promotion.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ class LocalsUseVisitor : public GenTreeVisitor<LocalsUseVisitor>
15581558
call->gtArgs.DetermineNewABIInfo(m_compiler, call);
15591559
}
15601560

1561-
if (!arg.NewAbiInfo.HasAnyStackSegment() && !arg.AbiInfo.PassedByRef)
1561+
if (!arg.NewAbiInfo.HasAnyStackSegment() && !arg.NewAbiInfo.IsPassedByReference())
15621562
{
15631563
flags |= AccessKindFlags::IsRegCallArg;
15641564
}
@@ -2308,7 +2308,7 @@ bool ReplaceVisitor::CanReplaceCallArgWithFieldListOfReplacements(GenTreeCall*
23082308
// We should have computed ABI information during the costing phase.
23092309
assert(call->gtArgs.IsNewAbiInformationDetermined());
23102310

2311-
if (callArg->NewAbiInfo.HasAnyStackSegment() || callArg->AbiInfo.PassedByRef)
2311+
if (callArg->NewAbiInfo.HasAnyStackSegment() || callArg->NewAbiInfo.IsPassedByReference())
23122312
{
23132313
return false;
23142314
}

0 commit comments

Comments
 (0)