Skip to content

Commit 0498939

Browse files
authored
JIT: Store one segment inline in ABIPassingInformation (#103690)
By far the most common case on all platforms is that an argument takes up one segment to describe its passing behavior, so we can avoid additional allocations by storing one segment inline.
1 parent 74f7f91 commit 0498939

File tree

13 files changed

+169
-80
lines changed

13 files changed

+169
-80
lines changed

src/coreclr/jit/abi.cpp

Lines changed: 96 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,65 @@ ABIPassingSegment ABIPassingSegment::OnStack(unsigned stackOffset, unsigned offs
187187
return segment;
188188
}
189189

190+
//-----------------------------------------------------------------------------
191+
// ABIPassingInformation:
192+
// Construct an instance with the specified number of segments allocated in
193+
// the backing storage.
194+
//
195+
// Parameters:
196+
// comp - Compiler instance
197+
// numSegments - Number of segments
198+
//
199+
// Remarks:
200+
// The segments are expected to be filled out by the caller after the
201+
// allocation; they are not zeroed out by the allocation.
202+
//
203+
ABIPassingInformation::ABIPassingInformation(Compiler* comp, unsigned numSegments)
204+
{
205+
NumSegments = numSegments;
206+
207+
if (numSegments > 1)
208+
{
209+
Segments = new (comp, CMK_ABI) ABIPassingSegment[numSegments];
210+
}
211+
}
212+
213+
//-----------------------------------------------------------------------------
214+
// Segment:
215+
// Access a segment by the specified index.
216+
//
217+
// Parameters:
218+
// index - The index of the segment
219+
//
220+
// Returns:
221+
// Reference to segment.
222+
//
223+
const ABIPassingSegment& ABIPassingInformation::Segment(unsigned index) const
224+
{
225+
assert(index < NumSegments);
226+
if (NumSegments == 1)
227+
{
228+
return SingleSegment;
229+
}
230+
231+
return Segments[index];
232+
}
233+
234+
//-----------------------------------------------------------------------------
235+
// Segment:
236+
// Access a segment by the specified index.
237+
//
238+
// Parameters:
239+
// index - The index of the segment
240+
//
241+
// Returns:
242+
// Reference to segment.
243+
//
244+
ABIPassingSegment& ABIPassingInformation::Segment(unsigned index)
245+
{
246+
return const_cast<ABIPassingSegment&>(static_cast<const ABIPassingInformation&>(*this).Segment(index));
247+
}
248+
190249
//-----------------------------------------------------------------------------
191250
// HasAnyRegisterSegment:
192251
// Check if any part of this value is passed in a register.
@@ -198,7 +257,7 @@ bool ABIPassingInformation::HasAnyRegisterSegment() const
198257
{
199258
for (unsigned i = 0; i < NumSegments; i++)
200259
{
201-
if (Segments[i].IsPassedInRegister())
260+
if (Segment(i).IsPassedInRegister())
202261
{
203262
return true;
204263
}
@@ -217,7 +276,7 @@ bool ABIPassingInformation::HasAnyStackSegment() const
217276
{
218277
for (unsigned i = 0; i < NumSegments; i++)
219278
{
220-
if (Segments[i].IsPassedOnStack())
279+
if (Segment(i).IsPassedOnStack())
221280
{
222281
return true;
223282
}
@@ -234,7 +293,7 @@ bool ABIPassingInformation::HasAnyStackSegment() const
234293
//
235294
bool ABIPassingInformation::HasExactlyOneRegisterSegment() const
236295
{
237-
return (NumSegments == 1) && Segments[0].IsPassedInRegister();
296+
return (NumSegments == 1) && Segment(0).IsPassedInRegister();
238297
}
239298

240299
//-----------------------------------------------------------------------------
@@ -246,7 +305,7 @@ bool ABIPassingInformation::HasExactlyOneRegisterSegment() const
246305
//
247306
bool ABIPassingInformation::HasExactlyOneStackSegment() const
248307
{
249-
return (NumSegments == 1) && Segments[0].IsPassedOnStack();
308+
return (NumSegments == 1) && Segment(0).IsPassedOnStack();
250309
}
251310

252311
//-----------------------------------------------------------------------------
@@ -264,10 +323,10 @@ bool ABIPassingInformation::IsSplitAcrossRegistersAndStack() const
264323
return false;
265324
}
266325

267-
bool isFirstInReg = Segments[0].IsPassedInRegister();
326+
bool isFirstInReg = Segment(0).IsPassedInRegister();
268327
for (unsigned i = 1; i < NumSegments; i++)
269328
{
270-
if (isFirstInReg != Segments[i].IsPassedInRegister())
329+
if (isFirstInReg != Segment(i).IsPassedInRegister())
271330
{
272331
return true;
273332
}
@@ -288,7 +347,32 @@ bool ABIPassingInformation::IsSplitAcrossRegistersAndStack() const
288347
//
289348
ABIPassingInformation ABIPassingInformation::FromSegment(Compiler* comp, const ABIPassingSegment& segment)
290349
{
291-
return {1, new (comp, CMK_ABI) ABIPassingSegment(segment)};
350+
ABIPassingInformation info;
351+
info.NumSegments = 1;
352+
info.SingleSegment = segment;
353+
return info;
354+
}
355+
356+
//-----------------------------------------------------------------------------
357+
// FromSegments:
358+
// Create ABIPassingInformation from two segments.
359+
//
360+
// Parameters:
361+
// comp - Compiler instance
362+
// firstSegment - The first segment that represents the passing information
363+
// secondSegment - The second segment that represents the passing information
364+
//
365+
// Return Value:
366+
// An instance of ABIPassingInformation.
367+
//
368+
ABIPassingInformation ABIPassingInformation::FromSegments(Compiler* comp,
369+
const ABIPassingSegment& firstSegment,
370+
const ABIPassingSegment& secondSegment)
371+
{
372+
ABIPassingInformation info;
373+
info.NumSegments = 2;
374+
info.Segments = new (comp, CMK_ABI) ABIPassingSegment[2]{firstSegment, secondSegment};
375+
return info;
292376
}
293377

294378
#ifdef DEBUG
@@ -310,9 +394,9 @@ void ABIPassingInformation::Dump() const
310394
printf(" [%u] ", i);
311395
}
312396

313-
const ABIPassingSegment& seg = Segments[i];
397+
const ABIPassingSegment& seg = Segment(i);
314398

315-
if (Segments[i].IsPassedInRegister())
399+
if (seg.IsPassedInRegister())
316400
{
317401
printf("[%02u..%02u) reg %s\n", seg.Offset, seg.Offset + seg.Size, getRegName(seg.GetRegister()));
318402
}
@@ -418,7 +502,7 @@ ABIPassingInformation SwiftABIClassifier::Classify(Compiler* comp,
418502

419503
for (unsigned j = 0; j < elemInfo.NumSegments; j++)
420504
{
421-
ABIPassingSegment newSegment = elemInfo.Segments[j];
505+
ABIPassingSegment newSegment = elemInfo.Segment(j);
422506
newSegment.Offset += lowering->offsets[i];
423507
// Adjust the tail size if necessary; the lowered sequence can
424508
// pass the tail as a larger type than the tail size.
@@ -427,12 +511,10 @@ ABIPassingInformation SwiftABIClassifier::Classify(Compiler* comp,
427511
}
428512
}
429513

430-
ABIPassingInformation result;
431-
result.NumSegments = static_cast<unsigned>(segments.Height());
432-
result.Segments = new (comp, CMK_ABI) ABIPassingSegment[result.NumSegments];
514+
ABIPassingInformation result(comp, static_cast<unsigned>(segments.Height()));
433515
for (int i = 0; i < segments.Height(); i++)
434516
{
435-
result.Segments[i] = segments.Bottom(i);
517+
result.Segment(i) = segments.Bottom(i);
436518
}
437519

438520
return result;

src/coreclr/jit/abi.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ class ABIPassingSegment
3939

4040
struct ABIPassingInformation
4141
{
42+
private:
43+
union
44+
{
45+
ABIPassingSegment* Segments;
46+
ABIPassingSegment SingleSegment;
47+
};
48+
49+
public:
4250
// The number of segments used to pass the value. Examples:
4351
// - On SysV x64, structs can be passed in two registers, resulting in two
4452
// register segments
@@ -51,22 +59,28 @@ struct ABIPassingInformation
5159
// - On loongarch64/riscv64, structs can be passed in two registers or
5260
// can be split out over register and stack, giving
5361
// multiple register segments and a struct segment.
54-
unsigned NumSegments;
55-
ABIPassingSegment* Segments;
62+
unsigned NumSegments;
5663

57-
ABIPassingInformation(unsigned numSegments = 0, ABIPassingSegment* segments = nullptr)
58-
: NumSegments(numSegments)
59-
, Segments(segments)
64+
ABIPassingInformation()
65+
: NumSegments(0)
6066
{
6167
}
6268

69+
ABIPassingInformation(Compiler* comp, unsigned numSegments);
70+
71+
const ABIPassingSegment& Segment(unsigned index) const;
72+
ABIPassingSegment& Segment(unsigned index);
73+
6374
bool HasAnyRegisterSegment() const;
6475
bool HasAnyStackSegment() const;
6576
bool HasExactlyOneRegisterSegment() const;
6677
bool HasExactlyOneStackSegment() const;
6778
bool IsSplitAcrossRegistersAndStack() const;
6879

6980
static ABIPassingInformation FromSegment(Compiler* comp, const ABIPassingSegment& segment);
81+
static ABIPassingInformation FromSegments(Compiler* comp,
82+
const ABIPassingSegment& firstSegment,
83+
const ABIPassingSegment& secondSegment);
7084

7185
#ifdef WINDOWS_AMD64_ABI
7286
static bool GetShadowSpaceCallerOffsetForReg(regNumber reg, int* offset);

src/coreclr/jit/codegenarmarch.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3802,7 +3802,7 @@ void CodeGen::genJmpPlaceVarArgs()
38023802
const ABIPassingInformation& abiInfo = compiler->lvaGetParameterABIInfo(varNum);
38033803
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
38043804
{
3805-
const ABIPassingSegment& segment = abiInfo.Segments[i];
3805+
const ABIPassingSegment& segment = abiInfo.Segment(i);
38063806
if (segment.IsPassedInRegister())
38073807
{
38083808
potentialArgs &= ~segment.GetRegisterMask();

src/coreclr/jit/codegencommon.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3202,7 +3202,7 @@ void CodeGen::genSpillOrAddRegisterParam(unsigned lclNum, RegGraph* graph)
32023202
const ABIPassingInformation& abiInfo = compiler->lvaGetParameterABIInfo(paramLclNum);
32033203
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
32043204
{
3205-
const ABIPassingSegment& seg = abiInfo.Segments[i];
3205+
const ABIPassingSegment& seg = abiInfo.Segment(i);
32063206
if (!seg.IsPassedInRegister() || ((paramRegs & genRegMask(seg.GetRegister())) == 0))
32073207
{
32083208
continue;
@@ -3325,7 +3325,7 @@ void CodeGen::genHomeRegisterParams(regNumber initReg, bool* initRegStillZeroed)
33253325
const ABIPassingInformation& abiInfo = compiler->lvaGetParameterABIInfo(lclNum);
33263326
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
33273327
{
3328-
const ABIPassingSegment& seg = abiInfo.Segments[i];
3328+
const ABIPassingSegment& seg = abiInfo.Segment(i);
33293329
if (seg.IsPassedInRegister() && ((paramRegs & genRegMask(seg.GetRegister())) != 0))
33303330
{
33313331
var_types storeType = genParamStackType(lclDsc, seg);
@@ -4373,7 +4373,7 @@ void CodeGen::genHomeSwiftStructParameters(bool handleStack)
43734373

43744374
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
43754375
{
4376-
const ABIPassingSegment& seg = abiInfo.Segments[i];
4376+
const ABIPassingSegment& seg = abiInfo.Segment(i);
43774377
if (seg.IsPassedOnStack() != handleStack)
43784378
{
43794379
continue;
@@ -4434,9 +4434,9 @@ void CodeGen::genHomeStackPartOfSplitParameter(regNumber initReg, bool* initRegS
44344434
JITDUMP("Homing stack part of split parameter V%02u\n", lclNum);
44354435

44364436
assert(abiInfo.NumSegments == 2);
4437-
assert(abiInfo.Segments[0].GetRegister() == REG_ARG_LAST);
4438-
assert(abiInfo.Segments[1].GetStackOffset() == 0);
4439-
const ABIPassingSegment& seg = abiInfo.Segments[1];
4437+
assert(abiInfo.Segment(0).GetRegister() == REG_ARG_LAST);
4438+
assert(abiInfo.Segment(1).GetStackOffset() == 0);
4439+
const ABIPassingSegment& seg = abiInfo.Segment(1);
44404440

44414441
genHomeStackSegment(lclNum, seg, initReg, initRegStillZeroed);
44424442

@@ -7514,7 +7514,7 @@ void CodeGen::genJmpPlaceArgs(GenTree* jmp)
75147514
const ABIPassingInformation& abiInfo = compiler->lvaGetParameterABIInfo(varNum);
75157515
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
75167516
{
7517-
const ABIPassingSegment& segment = abiInfo.Segments[i];
7517+
const ABIPassingSegment& segment = abiInfo.Segment(i);
75187518
if (segment.IsPassedOnStack())
75197519
{
75207520
continue;

src/coreclr/jit/codegenxarch.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6565,7 +6565,7 @@ void CodeGen::genJmpPlaceVarArgs()
65656565
const ABIPassingInformation& abiInfo = compiler->lvaGetParameterABIInfo(varNum);
65666566
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
65676567
{
6568-
const ABIPassingSegment& segment = abiInfo.Segments[i];
6568+
const ABIPassingSegment& segment = abiInfo.Segment(i);
65696569
if (segment.IsPassedOnStack())
65706570
{
65716571
continue;

src/coreclr/jit/lclvars.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,24 +1809,24 @@ void Compiler::lvaClassifyParameterABI()
18091809
else
18101810
{
18111811
assert(abiInfo.NumSegments == 1);
1812-
if (abiInfo.Segments[0].IsPassedInRegister())
1812+
if (abiInfo.Segment(0).IsPassedInRegister())
18131813
{
18141814
dsc->lvIsRegArg = true;
1815-
dsc->SetArgReg(abiInfo.Segments[0].GetRegister());
1815+
dsc->SetArgReg(abiInfo.Segment(0).GetRegister());
18161816
dsc->SetOtherArgReg(REG_NA);
18171817
}
18181818
else
18191819
{
18201820
dsc->lvIsRegArg = false;
18211821
dsc->SetArgReg(REG_STK);
18221822
dsc->SetOtherArgReg(REG_NA);
1823-
dsc->SetStackOffset(abiInfo.Segments[0].GetStackOffset());
1823+
dsc->SetStackOffset(abiInfo.Segment(0).GetStackOffset());
18241824
}
18251825
}
18261826

18271827
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
18281828
{
1829-
const ABIPassingSegment& segment = abiInfo.Segments[i];
1829+
const ABIPassingSegment& segment = abiInfo.Segment(i);
18301830
if (segment.IsPassedInRegister())
18311831
{
18321832
argRegs |= segment.GetRegisterMask();
@@ -1887,7 +1887,7 @@ void Compiler::lvaClassifyParameterABI()
18871887

18881888
for (unsigned i = 0; i < numSegmentsToCompare; i++)
18891889
{
1890-
const ABIPassingSegment& expected = abiInfo.Segments[i];
1890+
const ABIPassingSegment& expected = abiInfo.Segment(i);
18911891
regNumber reg = REG_NA;
18921892
if (i == 0)
18931893
{
@@ -1934,19 +1934,19 @@ void Compiler::lvaClassifyParameterABI()
19341934

19351935
if (lvaIsImplicitByRefLocal(lclNum))
19361936
{
1937-
assert((abiInfo.NumSegments == 1) && (abiInfo.Segments[0].Size == TARGET_POINTER_SIZE));
1937+
assert((abiInfo.NumSegments == 1) && (abiInfo.Segment(0).Size == TARGET_POINTER_SIZE));
19381938
}
19391939
else
19401940
{
19411941
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
19421942
{
1943-
const ABIPassingSegment& segment = abiInfo.Segments[i];
1943+
const ABIPassingSegment& segment = abiInfo.Segment(i);
19441944
assert(segment.Size > 0);
19451945
assert(segment.Offset + segment.Size <= lvaLclExactSize(lclNum));
19461946

19471947
if (i > 0)
19481948
{
1949-
assert(segment.Offset > abiInfo.Segments[i - 1].Offset);
1949+
assert(segment.Offset > abiInfo.Segment(i - 1).Offset);
19501950
}
19511951

19521952
for (unsigned j = 0; j < abiInfo.NumSegments; j++)
@@ -1956,7 +1956,7 @@ void Compiler::lvaClassifyParameterABI()
19561956
continue;
19571957
}
19581958

1959-
const ABIPassingSegment& otherSegment = abiInfo.Segments[j];
1959+
const ABIPassingSegment& otherSegment = abiInfo.Segment(j);
19601960
assert((segment.Offset + segment.Size <= otherSegment.Offset) ||
19611961
(segment.Offset >= otherSegment.Offset + otherSegment.Size));
19621962
}
@@ -6054,7 +6054,7 @@ bool Compiler::lvaGetRelativeOffsetToCallerAllocatedSpaceForParameter(unsigned l
60546054

60556055
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
60566056
{
6057-
const ABIPassingSegment& segment = abiInfo.Segments[i];
6057+
const ABIPassingSegment& segment = abiInfo.Segment(i);
60586058
if (!segment.IsPassedOnStack())
60596059
{
60606060
#if defined(WINDOWS_AMD64_ABI)

src/coreclr/jit/lsrabuild.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2302,7 +2302,7 @@ void LinearScan::buildIntervals()
23022302
const ABIPassingInformation& abiInfo = compiler->lvaGetParameterABIInfo(lclNum);
23032303
for (unsigned i = 0; i < abiInfo.NumSegments; i++)
23042304
{
2305-
const ABIPassingSegment& seg = abiInfo.Segments[i];
2305+
const ABIPassingSegment& seg = abiInfo.Segment(i);
23062306
if (seg.IsPassedInRegister())
23072307
{
23082308
RegState* regState = genIsValidFloatReg(seg.GetRegister()) ? floatRegState : intRegState;

src/coreclr/jit/morph.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4598,8 +4598,8 @@ GenTree* Compiler::fgMorphExpandStackArgForVarArgs(GenTreeLclVarCommon* lclNode)
45984598
assert(abiInfo.HasExactlyOneStackSegment());
45994599

46004600
GenTree* argsBaseAddr = gtNewLclvNode(lvaVarargsBaseOfStkArgs, TYP_I_IMPL);
4601-
ssize_t offset = (ssize_t)abiInfo.Segments[0].GetStackOffset() - lclNode->GetLclOffs();
4602-
assert(abiInfo.Segments[0].GetStackOffset() ==
4601+
ssize_t offset = (ssize_t)abiInfo.Segment(0).GetStackOffset() - lclNode->GetLclOffs();
4602+
assert(abiInfo.Segment(0).GetStackOffset() ==
46034603
(varDsc->GetStackOffset() - codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES));
46044604
GenTree* offsetNode = gtNewIconNode(offset, TYP_I_IMPL);
46054605
GenTree* argAddr = gtNewOperNode(GT_SUB, TYP_I_IMPL, argsBaseAddr, offsetNode);

0 commit comments

Comments
 (0)