Skip to content

Commit

Permalink
JIT: Store padding information in ClassLayout/ClassLayoutBuilder (dot…
Browse files Browse the repository at this point in the history
…net#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()`
  • Loading branch information
jakobbotsch authored Feb 6, 2025
1 parent fc8b63c commit 6d0eae5
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 115 deletions.
4 changes: 2 additions & 2 deletions src/coreclr/jit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,14 @@ set( JIT_SOURCES
regset.cpp
scev.cpp
scopeinfo.cpp
segmentlist.cpp
sideeffects.cpp
sm.cpp
smdata.cpp
smweights.cpp
ssabuilder.cpp
ssarenamestate.cpp
stacklevelsetter.cpp
structsegments.cpp
switchrecognition.cpp
treelifeupdater.cpp
unwind.cpp
Expand Down Expand Up @@ -362,6 +362,7 @@ set( JIT_HEADERS
register.h
regset.h
scev.h
segmentlist.h
sideeffects.h
simd.h
sm.h
Expand All @@ -372,7 +373,6 @@ set( JIT_HEADERS
ssaconfig.h
ssarenamestate.h
stacklevelsetter.h
structsegments.h
target.h
targetx86.h
targetamd64.h
Expand Down
61 changes: 0 additions & 61 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8269,67 +8269,6 @@ void Compiler::TransferTestDataToNode(GenTree* from, GenTree* to)

#endif // DEBUG

//------------------------------------------------------------------------
// GetSignificantSegments:
// Compute a segment tree containing all significant (non-padding) segments
// for the specified class layout.
//
// Parameters:
// layout - The layout
//
// Returns:
// Segment tree containing all significant parts of the layout.
//
const StructSegments& Compiler::GetSignificantSegments(ClassLayout* layout)
{
StructSegments* cached;
if ((m_significantSegmentsMap != nullptr) && m_significantSegmentsMap->Lookup(layout, &cached))
{
return *cached;
}

COMP_HANDLE compHnd = info.compCompHnd;

StructSegments* newSegments = new (this, CMK_Promotion) StructSegments(getAllocator(CMK_Promotion));

if (layout->IsCustomLayout())
{
newSegments->Add(StructSegments::Segment(0, layout->GetSize()));
}
else
{
CORINFO_TYPE_LAYOUT_NODE nodes[256];
size_t numNodes = ArrLen(nodes);
GetTypeLayoutResult result = compHnd->getTypeLayout(layout->GetClassHandle(), nodes, &numNodes);

if (result != GetTypeLayoutResult::Success)
{
newSegments->Add(StructSegments::Segment(0, layout->GetSize()));
}
else
{
for (size_t i = 0; i < numNodes; i++)
{
const CORINFO_TYPE_LAYOUT_NODE& node = nodes[i];
if ((node.type != CORINFO_TYPE_VALUECLASS) || (node.simdTypeHnd != NO_CLASS_HANDLE) ||
node.hasSignificantPadding)
{
newSegments->Add(StructSegments::Segment(node.offset, node.offset + node.size));
}
}
}
}

if (m_significantSegmentsMap == nullptr)
{
m_significantSegmentsMap = new (this, CMK_Promotion) ClassLayoutStructSegmentsMap(getAllocator(CMK_Promotion));
}

m_significantSegmentsMap->Set(layout, newSegments);

return *newSegments;
}

/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Expand Down
7 changes: 1 addition & 6 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#include "valuenum.h"
#include "scev.h"
#include "namedintrinsiclist.h"
#include "structsegments.h"
#include "segmentlist.h"
#ifdef LATE_DISASM
#include "disasm.h"
#endif
Expand Down Expand Up @@ -5783,11 +5783,6 @@ class Compiler
return m_signatureToLookupInfoMap;
}

const StructSegments& GetSignificantSegments(ClassLayout* layout);

typedef JitHashTable<ClassLayout*, JitPtrKeyFuncs<ClassLayout>, class StructSegments*> ClassLayoutStructSegmentsMap;
ClassLayoutStructSegmentsMap* m_significantSegmentsMap = nullptr;

#ifdef SWIFT_SUPPORT
typedef JitHashTable<CORINFO_CLASS_HANDLE, JitPtrKeyFuncs<struct CORINFO_CLASS_STRUCT_>, CORINFO_SWIFT_LOWERING*> SwiftLoweringMap;
SwiftLoweringMap* m_swiftLoweringCache = nullptr;
Expand Down
127 changes: 122 additions & 5 deletions src/coreclr/jit/layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ ClassLayout* ClassLayout::Create(Compiler* compiler, const ClassLayoutBuilder& b
{
ClassLayout* newLayout = new (compiler, CMK_ClassLayout) ClassLayout(builder.m_size);
newLayout->m_gcPtrCount = builder.m_gcPtrCount;
newLayout->m_nonPadding = builder.m_nonPadding;

#ifdef DEBUG
newLayout->m_name = builder.m_name;
Expand Down Expand Up @@ -575,6 +576,60 @@ bool ClassLayout::IntersectsGCPtr(unsigned offset, unsigned size) const
return false;
}

//------------------------------------------------------------------------
// GetNonPadding:
// Get a SegmentList containing segments for all the non-padding in the
// layout. This is generally the areas of the layout covered by fields, but
// in some cases may also include other parts.
//
// Parameters:
// comp - Compiler instance
//
// Return value:
// A segment list.
//
const SegmentList& ClassLayout::GetNonPadding(Compiler* comp)
{
if (m_nonPadding != nullptr)
{
return *m_nonPadding;
}

m_nonPadding = new (comp, CMK_ClassLayout) SegmentList(comp->getAllocator(CMK_ClassLayout));
if (IsCustomLayout())
{
if (m_size > 0)
{
m_nonPadding->Add(SegmentList::Segment(0, GetSize()));
}

return *m_nonPadding;
}

CORINFO_TYPE_LAYOUT_NODE nodes[256];
size_t numNodes = ArrLen(nodes);
GetTypeLayoutResult result = comp->info.compCompHnd->getTypeLayout(GetClassHandle(), nodes, &numNodes);

if (result != GetTypeLayoutResult::Success)
{
m_nonPadding->Add(SegmentList::Segment(0, GetSize()));
}
else
{
for (size_t i = 0; i < numNodes; i++)
{
const CORINFO_TYPE_LAYOUT_NODE& node = nodes[i];
if ((node.type != CORINFO_TYPE_VALUECLASS) || (node.simdTypeHnd != NO_CLASS_HANDLE) ||
node.hasSignificantPadding)
{
m_nonPadding->Add(SegmentList::Segment(node.offset, node.offset + node.size));
}
}
}

return *m_nonPadding;
}

//------------------------------------------------------------------------
// AreCompatible: check if 2 layouts are the same for copying.
//
Expand Down Expand Up @@ -663,7 +718,7 @@ bool ClassLayout::AreCompatible(const ClassLayout* layout1, const ClassLayout* l

//------------------------------------------------------------------------
// ClassLayoutbuilder: Construct a new builder for a class layout of the
// specified size.
// specified size, with all data being considered as non-padding.
//
// Arguments:
// compiler - Compiler instance
Expand Down Expand Up @@ -754,13 +809,14 @@ void ClassLayoutBuilder::SetGCPtrType(unsigned slot, var_types type)
}

//------------------------------------------------------------------------
// CopyInfoFrom: Copy GC pointers from another layout.
// CopyInfoFrom: Copy GC pointers and padding information from another layout.
//
// Arguments:
// offset - Offset in this builder to start copy information into.
// layout - Layout to get information from.
// offset - Offset in this builder to start copy information into.
// layout - Layout to get information from.
// copyPadding - Whether padding info should also be copied from the layout.
//
void ClassLayoutBuilder::CopyInfoFrom(unsigned offset, ClassLayout* layout)
void ClassLayoutBuilder::CopyInfoFrom(unsigned offset, ClassLayout* layout, bool copyPadding)
{
assert(offset + layout->GetSize() <= m_size);

Expand All @@ -773,6 +829,67 @@ void ClassLayoutBuilder::CopyInfoFrom(unsigned offset, ClassLayout* layout)
SetGCPtr(startSlot + slot, layout->GetGCPtr(slot));
}
}

if (copyPadding)
{
AddPadding(SegmentList::Segment(offset, offset + layout->GetSize()));

for (const SegmentList::Segment& nonPadding : layout->GetNonPadding(m_compiler))
{
RemovePadding(SegmentList::Segment(offset + nonPadding.Start, offset + nonPadding.End));
}
}
}

//------------------------------------------------------------------------
// GetOrCreateNonPadding: Get the non padding segment list, or create it if it
// does not exist.
//
// Remarks:
// The ClassLayoutBuilder starts out with the entire layout being considered
// to NOT be padding.
//
SegmentList* ClassLayoutBuilder::GetOrCreateNonPadding()
{
if (m_nonPadding == nullptr)
{
m_nonPadding = new (m_compiler, CMK_ClassLayout) SegmentList(m_compiler->getAllocator(CMK_ClassLayout));
m_nonPadding->Add(SegmentList::Segment(0, m_size));
}

return m_nonPadding;
}

//------------------------------------------------------------------------
// AddPadding: Mark that part of the layout has padding.
//
// Arguments:
// padding - The segment to mark as being padding.
//
// Remarks:
// The ClassLayoutBuilder starts out with the entire layout being considered
// to NOT be padding.
//
void ClassLayoutBuilder::AddPadding(const SegmentList::Segment& padding)
{
assert((padding.Start <= padding.End) && (padding.End <= m_size));
GetOrCreateNonPadding()->Subtract(padding);
}

//------------------------------------------------------------------------
// RemovePadding: Mark that part of the layout does not have padding.
//
// Arguments:
// nonPadding - The segment to mark as having significant data.
//
// Remarks:
// The ClassLayoutBuilder starts out with the entire layout being considered
// to NOT be padding.
//
void ClassLayoutBuilder::RemovePadding(const SegmentList::Segment& nonPadding)
{
assert((nonPadding.Start <= nonPadding.End) && (nonPadding.End <= m_size));
GetOrCreateNonPadding()->Add(nonPadding);
}

#ifdef DEBUG
Expand Down
23 changes: 16 additions & 7 deletions src/coreclr/jit/layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#define LAYOUT_H

#include "jit.h"
#include "segmentlist.h"

// Builder for class layouts
//
Expand All @@ -14,24 +15,28 @@ class ClassLayoutBuilder
friend class ClassLayoutTable;
friend struct CustomLayoutKey;

Compiler* m_compiler;
BYTE* m_gcPtrs = nullptr;
unsigned m_size;
unsigned m_gcPtrCount = 0;
Compiler* m_compiler;
BYTE* m_gcPtrs = nullptr;
unsigned m_size;
unsigned m_gcPtrCount = 0;
SegmentList* m_nonPadding = nullptr;
#ifdef DEBUG
const char* m_name = "UNNAMED";
const char* m_shortName = "UNNAMED";
#endif

BYTE* GetOrCreateGCPtrs();
void SetGCPtr(unsigned slot, CorInfoGCType type);
BYTE* GetOrCreateGCPtrs();
void SetGCPtr(unsigned slot, CorInfoGCType type);
SegmentList* GetOrCreateNonPadding();
public:
// Create a class layout builder.
//
ClassLayoutBuilder(Compiler* compiler, unsigned size);

void SetGCPtrType(unsigned slot, var_types type);
void CopyInfoFrom(unsigned offset, ClassLayout* layout);
void CopyInfoFrom(unsigned offset, ClassLayout* layout, bool copyPadding);
void AddPadding(const SegmentList::Segment& padding);
void RemovePadding(const SegmentList::Segment& nonPadding);

#ifdef DEBUG
void SetName(const char* name, const char* shortName);
Expand Down Expand Up @@ -68,6 +73,8 @@ class ClassLayout
BYTE m_gcPtrsArray[sizeof(BYTE*)];
};

class SegmentList* m_nonPadding = nullptr;

// The normalized type to use in IR for block nodes with this layout.
const var_types m_type;

Expand Down Expand Up @@ -247,6 +254,8 @@ class ClassLayout

bool IntersectsGCPtr(unsigned offset, unsigned size) const;

const SegmentList& GetNonPadding(Compiler* comp);

static bool AreCompatible(const ClassLayout* layout1, const ClassLayout* layout2);

private:
Expand Down
12 changes: 6 additions & 6 deletions src/coreclr/jit/promotion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -720,9 +720,9 @@ class LocalUses
return true;
}

const StructSegments& significantSegments = comp->GetSignificantSegments(otherAccess.Layout);
const SegmentList& significantSegments = otherAccess.Layout->GetNonPadding(comp);
if (!significantSegments.Intersects(
StructSegments::Segment(layoutOffset + accessSize, layoutOffset + TARGET_POINTER_SIZE)))
SegmentList::Segment(layoutOffset + accessSize, layoutOffset + TARGET_POINTER_SIZE)))
{
return true;
}
Expand Down Expand Up @@ -1296,17 +1296,17 @@ class LocalsUseVisitor : public GenTreeVisitor<LocalsUseVisitor>
}
#endif

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

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

StructSegments::Segment unpromotedSegment;
SegmentList::Segment unpromotedSegment;
if (agg->Unpromoted.CoveringSegment(&unpromotedSegment))
{
agg->UnpromotedMin = unpromotedSegment.Start;
Expand Down Expand Up @@ -2281,7 +2281,7 @@ bool ReplaceVisitor::CanReplaceCallArgWithFieldListOfReplacements(GenTreeCall*
// the remainder is a different promotion we will return false when
// the replacement is visited in this callback.
if ((repSize < seg.Size) &&
agg->Unpromoted.Intersects(StructSegments::Segment(rep.Offset + repSize, rep.Offset + seg.Size)))
agg->Unpromoted.Intersects(SegmentList::Segment(rep.Offset + repSize, rep.Offset + seg.Size)))
{
return false;
}
Expand Down
Loading

0 comments on commit 6d0eae5

Please sign in to comment.