Skip to content

Commit 6d0eae5

Browse files
authored
JIT: Store padding information in ClassLayout/ClassLayoutBuilder (#112212)
* Rename `StructSegments` -> `SegmentList` * Add `ClassLayout::GetNonPadding` to get the non-padding of a class layout. Computed lazily for `CORINFO_CLASS_HANDLE` backed layouts and saved ahead of time for custom layouts. * Add `ClassLayoutBuilder::AddPadding` and `ClassLayoutBuilder::RemovePadding` * Remove `Compiler::GetSignificantSegments` and switch uses to `ClassLayout->GetNonPadding()`
1 parent fc8b63c commit 6d0eae5

11 files changed

+234
-115
lines changed

Diff for: src/coreclr/jit/CMakeLists.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,14 @@ set( JIT_SOURCES
167167
regset.cpp
168168
scev.cpp
169169
scopeinfo.cpp
170+
segmentlist.cpp
170171
sideeffects.cpp
171172
sm.cpp
172173
smdata.cpp
173174
smweights.cpp
174175
ssabuilder.cpp
175176
ssarenamestate.cpp
176177
stacklevelsetter.cpp
177-
structsegments.cpp
178178
switchrecognition.cpp
179179
treelifeupdater.cpp
180180
unwind.cpp
@@ -362,6 +362,7 @@ set( JIT_HEADERS
362362
register.h
363363
regset.h
364364
scev.h
365+
segmentlist.h
365366
sideeffects.h
366367
simd.h
367368
sm.h
@@ -372,7 +373,6 @@ set( JIT_HEADERS
372373
ssaconfig.h
373374
ssarenamestate.h
374375
stacklevelsetter.h
375-
structsegments.h
376376
target.h
377377
targetx86.h
378378
targetamd64.h

Diff for: src/coreclr/jit/compiler.cpp

-61
Original file line numberDiff line numberDiff line change
@@ -8269,67 +8269,6 @@ void Compiler::TransferTestDataToNode(GenTree* from, GenTree* to)
82698269

82708270
#endif // DEBUG
82718271

8272-
//------------------------------------------------------------------------
8273-
// GetSignificantSegments:
8274-
// Compute a segment tree containing all significant (non-padding) segments
8275-
// for the specified class layout.
8276-
//
8277-
// Parameters:
8278-
// layout - The layout
8279-
//
8280-
// Returns:
8281-
// Segment tree containing all significant parts of the layout.
8282-
//
8283-
const StructSegments& Compiler::GetSignificantSegments(ClassLayout* layout)
8284-
{
8285-
StructSegments* cached;
8286-
if ((m_significantSegmentsMap != nullptr) && m_significantSegmentsMap->Lookup(layout, &cached))
8287-
{
8288-
return *cached;
8289-
}
8290-
8291-
COMP_HANDLE compHnd = info.compCompHnd;
8292-
8293-
StructSegments* newSegments = new (this, CMK_Promotion) StructSegments(getAllocator(CMK_Promotion));
8294-
8295-
if (layout->IsCustomLayout())
8296-
{
8297-
newSegments->Add(StructSegments::Segment(0, layout->GetSize()));
8298-
}
8299-
else
8300-
{
8301-
CORINFO_TYPE_LAYOUT_NODE nodes[256];
8302-
size_t numNodes = ArrLen(nodes);
8303-
GetTypeLayoutResult result = compHnd->getTypeLayout(layout->GetClassHandle(), nodes, &numNodes);
8304-
8305-
if (result != GetTypeLayoutResult::Success)
8306-
{
8307-
newSegments->Add(StructSegments::Segment(0, layout->GetSize()));
8308-
}
8309-
else
8310-
{
8311-
for (size_t i = 0; i < numNodes; i++)
8312-
{
8313-
const CORINFO_TYPE_LAYOUT_NODE& node = nodes[i];
8314-
if ((node.type != CORINFO_TYPE_VALUECLASS) || (node.simdTypeHnd != NO_CLASS_HANDLE) ||
8315-
node.hasSignificantPadding)
8316-
{
8317-
newSegments->Add(StructSegments::Segment(node.offset, node.offset + node.size));
8318-
}
8319-
}
8320-
}
8321-
}
8322-
8323-
if (m_significantSegmentsMap == nullptr)
8324-
{
8325-
m_significantSegmentsMap = new (this, CMK_Promotion) ClassLayoutStructSegmentsMap(getAllocator(CMK_Promotion));
8326-
}
8327-
8328-
m_significantSegmentsMap->Set(layout, newSegments);
8329-
8330-
return *newSegments;
8331-
}
8332-
83338272
/*
83348273
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
83358274
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Diff for: src/coreclr/jit/compiler.h

+1-6
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4343
#include "valuenum.h"
4444
#include "scev.h"
4545
#include "namedintrinsiclist.h"
46-
#include "structsegments.h"
46+
#include "segmentlist.h"
4747
#ifdef LATE_DISASM
4848
#include "disasm.h"
4949
#endif
@@ -5783,11 +5783,6 @@ class Compiler
57835783
return m_signatureToLookupInfoMap;
57845784
}
57855785

5786-
const StructSegments& GetSignificantSegments(ClassLayout* layout);
5787-
5788-
typedef JitHashTable<ClassLayout*, JitPtrKeyFuncs<ClassLayout>, class StructSegments*> ClassLayoutStructSegmentsMap;
5789-
ClassLayoutStructSegmentsMap* m_significantSegmentsMap = nullptr;
5790-
57915786
#ifdef SWIFT_SUPPORT
57925787
typedef JitHashTable<CORINFO_CLASS_HANDLE, JitPtrKeyFuncs<struct CORINFO_CLASS_STRUCT_>, CORINFO_SWIFT_LOWERING*> SwiftLoweringMap;
57935788
SwiftLoweringMap* m_swiftLoweringCache = nullptr;

Diff for: src/coreclr/jit/layout.cpp

+122-5
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@ ClassLayout* ClassLayout::Create(Compiler* compiler, const ClassLayoutBuilder& b
494494
{
495495
ClassLayout* newLayout = new (compiler, CMK_ClassLayout) ClassLayout(builder.m_size);
496496
newLayout->m_gcPtrCount = builder.m_gcPtrCount;
497+
newLayout->m_nonPadding = builder.m_nonPadding;
497498

498499
#ifdef DEBUG
499500
newLayout->m_name = builder.m_name;
@@ -575,6 +576,60 @@ bool ClassLayout::IntersectsGCPtr(unsigned offset, unsigned size) const
575576
return false;
576577
}
577578

579+
//------------------------------------------------------------------------
580+
// GetNonPadding:
581+
// Get a SegmentList containing segments for all the non-padding in the
582+
// layout. This is generally the areas of the layout covered by fields, but
583+
// in some cases may also include other parts.
584+
//
585+
// Parameters:
586+
// comp - Compiler instance
587+
//
588+
// Return value:
589+
// A segment list.
590+
//
591+
const SegmentList& ClassLayout::GetNonPadding(Compiler* comp)
592+
{
593+
if (m_nonPadding != nullptr)
594+
{
595+
return *m_nonPadding;
596+
}
597+
598+
m_nonPadding = new (comp, CMK_ClassLayout) SegmentList(comp->getAllocator(CMK_ClassLayout));
599+
if (IsCustomLayout())
600+
{
601+
if (m_size > 0)
602+
{
603+
m_nonPadding->Add(SegmentList::Segment(0, GetSize()));
604+
}
605+
606+
return *m_nonPadding;
607+
}
608+
609+
CORINFO_TYPE_LAYOUT_NODE nodes[256];
610+
size_t numNodes = ArrLen(nodes);
611+
GetTypeLayoutResult result = comp->info.compCompHnd->getTypeLayout(GetClassHandle(), nodes, &numNodes);
612+
613+
if (result != GetTypeLayoutResult::Success)
614+
{
615+
m_nonPadding->Add(SegmentList::Segment(0, GetSize()));
616+
}
617+
else
618+
{
619+
for (size_t i = 0; i < numNodes; i++)
620+
{
621+
const CORINFO_TYPE_LAYOUT_NODE& node = nodes[i];
622+
if ((node.type != CORINFO_TYPE_VALUECLASS) || (node.simdTypeHnd != NO_CLASS_HANDLE) ||
623+
node.hasSignificantPadding)
624+
{
625+
m_nonPadding->Add(SegmentList::Segment(node.offset, node.offset + node.size));
626+
}
627+
}
628+
}
629+
630+
return *m_nonPadding;
631+
}
632+
578633
//------------------------------------------------------------------------
579634
// AreCompatible: check if 2 layouts are the same for copying.
580635
//
@@ -663,7 +718,7 @@ bool ClassLayout::AreCompatible(const ClassLayout* layout1, const ClassLayout* l
663718

664719
//------------------------------------------------------------------------
665720
// ClassLayoutbuilder: Construct a new builder for a class layout of the
666-
// specified size.
721+
// specified size, with all data being considered as non-padding.
667722
//
668723
// Arguments:
669724
// compiler - Compiler instance
@@ -754,13 +809,14 @@ void ClassLayoutBuilder::SetGCPtrType(unsigned slot, var_types type)
754809
}
755810

756811
//------------------------------------------------------------------------
757-
// CopyInfoFrom: Copy GC pointers from another layout.
812+
// CopyInfoFrom: Copy GC pointers and padding information from another layout.
758813
//
759814
// Arguments:
760-
// offset - Offset in this builder to start copy information into.
761-
// layout - Layout to get information from.
815+
// offset - Offset in this builder to start copy information into.
816+
// layout - Layout to get information from.
817+
// copyPadding - Whether padding info should also be copied from the layout.
762818
//
763-
void ClassLayoutBuilder::CopyInfoFrom(unsigned offset, ClassLayout* layout)
819+
void ClassLayoutBuilder::CopyInfoFrom(unsigned offset, ClassLayout* layout, bool copyPadding)
764820
{
765821
assert(offset + layout->GetSize() <= m_size);
766822

@@ -773,6 +829,67 @@ void ClassLayoutBuilder::CopyInfoFrom(unsigned offset, ClassLayout* layout)
773829
SetGCPtr(startSlot + slot, layout->GetGCPtr(slot));
774830
}
775831
}
832+
833+
if (copyPadding)
834+
{
835+
AddPadding(SegmentList::Segment(offset, offset + layout->GetSize()));
836+
837+
for (const SegmentList::Segment& nonPadding : layout->GetNonPadding(m_compiler))
838+
{
839+
RemovePadding(SegmentList::Segment(offset + nonPadding.Start, offset + nonPadding.End));
840+
}
841+
}
842+
}
843+
844+
//------------------------------------------------------------------------
845+
// GetOrCreateNonPadding: Get the non padding segment list, or create it if it
846+
// does not exist.
847+
//
848+
// Remarks:
849+
// The ClassLayoutBuilder starts out with the entire layout being considered
850+
// to NOT be padding.
851+
//
852+
SegmentList* ClassLayoutBuilder::GetOrCreateNonPadding()
853+
{
854+
if (m_nonPadding == nullptr)
855+
{
856+
m_nonPadding = new (m_compiler, CMK_ClassLayout) SegmentList(m_compiler->getAllocator(CMK_ClassLayout));
857+
m_nonPadding->Add(SegmentList::Segment(0, m_size));
858+
}
859+
860+
return m_nonPadding;
861+
}
862+
863+
//------------------------------------------------------------------------
864+
// AddPadding: Mark that part of the layout has padding.
865+
//
866+
// Arguments:
867+
// padding - The segment to mark as being padding.
868+
//
869+
// Remarks:
870+
// The ClassLayoutBuilder starts out with the entire layout being considered
871+
// to NOT be padding.
872+
//
873+
void ClassLayoutBuilder::AddPadding(const SegmentList::Segment& padding)
874+
{
875+
assert((padding.Start <= padding.End) && (padding.End <= m_size));
876+
GetOrCreateNonPadding()->Subtract(padding);
877+
}
878+
879+
//------------------------------------------------------------------------
880+
// RemovePadding: Mark that part of the layout does not have padding.
881+
//
882+
// Arguments:
883+
// nonPadding - The segment to mark as having significant data.
884+
//
885+
// Remarks:
886+
// The ClassLayoutBuilder starts out with the entire layout being considered
887+
// to NOT be padding.
888+
//
889+
void ClassLayoutBuilder::RemovePadding(const SegmentList::Segment& nonPadding)
890+
{
891+
assert((nonPadding.Start <= nonPadding.End) && (nonPadding.End <= m_size));
892+
GetOrCreateNonPadding()->Add(nonPadding);
776893
}
777894

778895
#ifdef DEBUG

Diff for: src/coreclr/jit/layout.h

+16-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define LAYOUT_H
66

77
#include "jit.h"
8+
#include "segmentlist.h"
89

910
// Builder for class layouts
1011
//
@@ -14,24 +15,28 @@ class ClassLayoutBuilder
1415
friend class ClassLayoutTable;
1516
friend struct CustomLayoutKey;
1617

17-
Compiler* m_compiler;
18-
BYTE* m_gcPtrs = nullptr;
19-
unsigned m_size;
20-
unsigned m_gcPtrCount = 0;
18+
Compiler* m_compiler;
19+
BYTE* m_gcPtrs = nullptr;
20+
unsigned m_size;
21+
unsigned m_gcPtrCount = 0;
22+
SegmentList* m_nonPadding = nullptr;
2123
#ifdef DEBUG
2224
const char* m_name = "UNNAMED";
2325
const char* m_shortName = "UNNAMED";
2426
#endif
2527

26-
BYTE* GetOrCreateGCPtrs();
27-
void SetGCPtr(unsigned slot, CorInfoGCType type);
28+
BYTE* GetOrCreateGCPtrs();
29+
void SetGCPtr(unsigned slot, CorInfoGCType type);
30+
SegmentList* GetOrCreateNonPadding();
2831
public:
2932
// Create a class layout builder.
3033
//
3134
ClassLayoutBuilder(Compiler* compiler, unsigned size);
3235

3336
void SetGCPtrType(unsigned slot, var_types type);
34-
void CopyInfoFrom(unsigned offset, ClassLayout* layout);
37+
void CopyInfoFrom(unsigned offset, ClassLayout* layout, bool copyPadding);
38+
void AddPadding(const SegmentList::Segment& padding);
39+
void RemovePadding(const SegmentList::Segment& nonPadding);
3540

3641
#ifdef DEBUG
3742
void SetName(const char* name, const char* shortName);
@@ -68,6 +73,8 @@ class ClassLayout
6873
BYTE m_gcPtrsArray[sizeof(BYTE*)];
6974
};
7075

76+
class SegmentList* m_nonPadding = nullptr;
77+
7178
// The normalized type to use in IR for block nodes with this layout.
7279
const var_types m_type;
7380

@@ -247,6 +254,8 @@ class ClassLayout
247254

248255
bool IntersectsGCPtr(unsigned offset, unsigned size) const;
249256

257+
const SegmentList& GetNonPadding(Compiler* comp);
258+
250259
static bool AreCompatible(const ClassLayout* layout1, const ClassLayout* layout2);
251260

252261
private:

Diff for: src/coreclr/jit/promotion.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -720,9 +720,9 @@ class LocalUses
720720
return true;
721721
}
722722

723-
const StructSegments& significantSegments = comp->GetSignificantSegments(otherAccess.Layout);
723+
const SegmentList& significantSegments = otherAccess.Layout->GetNonPadding(comp);
724724
if (!significantSegments.Intersects(
725-
StructSegments::Segment(layoutOffset + accessSize, layoutOffset + TARGET_POINTER_SIZE)))
725+
SegmentList::Segment(layoutOffset + accessSize, layoutOffset + TARGET_POINTER_SIZE)))
726726
{
727727
return true;
728728
}
@@ -1296,17 +1296,17 @@ class LocalsUseVisitor : public GenTreeVisitor<LocalsUseVisitor>
12961296
}
12971297
#endif
12981298

1299-
agg->Unpromoted = m_compiler->GetSignificantSegments(m_compiler->lvaGetDesc(agg->LclNum)->GetLayout());
1299+
agg->Unpromoted = m_compiler->lvaGetDesc(agg->LclNum)->GetLayout()->GetNonPadding(m_compiler);
13001300
for (Replacement& rep : reps)
13011301
{
1302-
agg->Unpromoted.Subtract(StructSegments::Segment(rep.Offset, rep.Offset + genTypeSize(rep.AccessType)));
1302+
agg->Unpromoted.Subtract(SegmentList::Segment(rep.Offset, rep.Offset + genTypeSize(rep.AccessType)));
13031303
}
13041304

13051305
JITDUMP(" Unpromoted remainder: ");
13061306
DBEXEC(m_compiler->verbose, agg->Unpromoted.Dump());
13071307
JITDUMP("\n\n");
13081308

1309-
StructSegments::Segment unpromotedSegment;
1309+
SegmentList::Segment unpromotedSegment;
13101310
if (agg->Unpromoted.CoveringSegment(&unpromotedSegment))
13111311
{
13121312
agg->UnpromotedMin = unpromotedSegment.Start;
@@ -2281,7 +2281,7 @@ bool ReplaceVisitor::CanReplaceCallArgWithFieldListOfReplacements(GenTreeCall*
22812281
// the remainder is a different promotion we will return false when
22822282
// the replacement is visited in this callback.
22832283
if ((repSize < seg.Size) &&
2284-
agg->Unpromoted.Intersects(StructSegments::Segment(rep.Offset + repSize, rep.Offset + seg.Size)))
2284+
agg->Unpromoted.Intersects(SegmentList::Segment(rep.Offset + repSize, rep.Offset + seg.Size)))
22852285
{
22862286
return false;
22872287
}

0 commit comments

Comments
 (0)