Skip to content

JIT: Store padding information in ClassLayout/ClassLayoutBuilder #112212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 6, 2025
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
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
Loading