Skip to content

Commit e8fc808

Browse files
committed
Reapply "MCFragment: Use trailing data for fixed-size part" (llvm#150846)
The fixed-size content of the MCFragment object is now stored as trailing data, replacing ContentStart/ContentEnd with ContentSize. The available space for trailing data is tracked using `FragSpace`. If the available space is insufficient, a new block is allocated within the bump allocator `MCObjectStreamer::FragStorage`. FragList::Tail cannot be reused when switching sections or subsections, as it is not associated with the fragment space tracked by `FragSpace`. Instead, allocate a new fragment, which becomes less expensive after llvm#150574. Data can only be appended to the tail fragment of a subsection, not to fragments in the middle. Post-assembler-layout adjustments (such as .llvm_addrsig and .llvm.call-graph-profile) have been updated to use the variable-size part instead. --- This reverts commit a2fef66, which reverted the innocent f1aa605 . Commit df71243, the MCOrgFragment fix, has fixed the root cause of ClangBuiltLinux/linux#2116
1 parent b738f63 commit e8fc808

File tree

7 files changed

+142
-62
lines changed

7 files changed

+142
-62
lines changed

llvm/include/llvm/MC/MCObjectStreamer.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class MCObjectStreamer : public MCStreamer {
5252
DenseMap<const MCSymbol *, SmallVector<PendingAssignment, 1>>
5353
pendingAssignments;
5454

55+
SmallVector<std::unique_ptr<uint8_t[]>, 0> FragStorage;
56+
// Available bytes in the current block for trailing data or new fragments.
57+
size_t FragSpace = 0;
5558
// Used to allocate special fragments that do not use MCFragment's fixed-size
5659
// part.
5760
BumpPtrAllocator SpecialFragAllocator;
@@ -86,25 +89,28 @@ class MCObjectStreamer : public MCStreamer {
8689
/// \name MCStreamer Interface
8790
/// @{
8891

92+
uint8_t *getCurFragEnd() const {
93+
return reinterpret_cast<uint8_t *>(CurFrag + 1) + CurFrag->getFixedSize();
94+
}
95+
MCFragment *allocFragSpace(size_t Headroom);
8996
// Add a new fragment to the current section without a variable-size tail.
9097
void newFragment();
9198

92-
template <typename FT, typename... Args> FT *allocFragment(Args &&...args) {
93-
auto *F = new (SpecialFragAllocator.Allocate(sizeof(FT), alignof(FT)))
94-
FT(std::forward<Args>(args)...);
95-
return F;
96-
}
9799
// Add a new special fragment to the current section and start a new empty
98100
// fragment.
99101
template <typename FT, typename... Args>
100102
FT *newSpecialFragment(Args &&...args) {
101-
auto *F = allocFragment<FT, Args...>(std::forward<Args>(args)...);
103+
auto *F = new (SpecialFragAllocator.Allocate(sizeof(FT), alignof(FT)))
104+
FT(std::forward<Args>(args)...);
102105
addSpecialFragment(F);
103106
return F;
104107
}
105108

109+
void ensureHeadroom(size_t Headroom);
106110
void appendContents(ArrayRef<char> Contents);
107-
void appendContents(size_t Num, char Elt);
111+
void appendContents(size_t Num, uint8_t Elt);
112+
// Add a fixup to the current fragment. Call ensureHeadroom beforehand to
113+
// ensure the fixup and appended content apply to the same fragment.
108114
void addFixup(const MCExpr *Value, MCFixupKind Kind);
109115

110116
void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;

llvm/include/llvm/MC/MCSection.h

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ class MCFragment {
9393
bool AllowAutoPadding : 1;
9494

9595
// Track content and fixups for the fixed-size part as fragments are
96-
// appended to the section. The content remains immutable, except when
97-
// modified by applyFixup.
98-
uint32_t ContentStart = 0;
99-
uint32_t ContentEnd = 0;
96+
// appended to the section. The content is stored as trailing data of the
97+
// MCFragment. The content remains immutable, except when modified by
98+
// applyFixup.
99+
uint32_t FixedSize = 0;
100100
uint32_t FixupStart = 0;
101101
uint32_t FixupEnd = 0;
102102

@@ -189,18 +189,6 @@ class MCFragment {
189189
//== Content-related functions manage parent's storage using ContentStart and
190190
// ContentSize.
191191

192-
// Get a SmallVector reference. The caller should call doneAppending to update
193-
// `ContentEnd`.
194-
SmallVectorImpl<char> &getContentsForAppending();
195-
void doneAppending();
196-
void appendContents(ArrayRef<char> Contents) {
197-
getContentsForAppending().append(Contents.begin(), Contents.end());
198-
doneAppending();
199-
}
200-
void appendContents(size_t Num, char Elt) {
201-
getContentsForAppending().append(Num, Elt);
202-
doneAppending();
203-
}
204192
MutableArrayRef<char> getContents();
205193
ArrayRef<char> getContents() const;
206194

@@ -209,10 +197,10 @@ class MCFragment {
209197
MutableArrayRef<char> getVarContents();
210198
ArrayRef<char> getVarContents() const;
211199

212-
size_t getFixedSize() const { return ContentEnd - ContentStart; }
200+
size_t getFixedSize() const { return FixedSize; }
213201
size_t getVarSize() const { return VarContentEnd - VarContentStart; }
214202
size_t getSize() const {
215-
return ContentEnd - ContentStart + (VarContentEnd - VarContentStart);
203+
return FixedSize + (VarContentEnd - VarContentStart);
216204
}
217205

218206
//== Fixup-related functions manage parent's storage using FixupStart and
@@ -630,28 +618,11 @@ class LLVM_ABI MCSection {
630618
bool isBssSection() const { return IsBss; }
631619
};
632620

633-
inline SmallVectorImpl<char> &MCFragment::getContentsForAppending() {
634-
SmallVectorImpl<char> &S = getParent()->ContentStorage;
635-
if (LLVM_UNLIKELY(ContentEnd != S.size())) {
636-
// Move the elements to the end. Reserve space to avoid invalidating
637-
// S.begin()+I for `append`.
638-
auto Size = ContentEnd - ContentStart;
639-
auto I = std::exchange(ContentStart, S.size());
640-
S.reserve(S.size() + Size);
641-
S.append(S.begin() + I, S.begin() + I + Size);
642-
}
643-
return S;
644-
}
645-
inline void MCFragment::doneAppending() {
646-
ContentEnd = getParent()->ContentStorage.size();
647-
}
648621
inline MutableArrayRef<char> MCFragment::getContents() {
649-
return MutableArrayRef(getParent()->ContentStorage)
650-
.slice(ContentStart, ContentEnd - ContentStart);
622+
return {reinterpret_cast<char *>(this + 1), FixedSize};
651623
}
652624
inline ArrayRef<char> MCFragment::getContents() const {
653-
return ArrayRef(getParent()->ContentStorage)
654-
.slice(ContentStart, ContentEnd - ContentStart);
625+
return {reinterpret_cast<const char *>(this + 1), FixedSize};
655626
}
656627

657628
inline MutableArrayRef<char> MCFragment::getVarContents() {

llvm/lib/MC/MCObjectStreamer.cpp

Lines changed: 97 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,79 @@ MCAssembler *MCObjectStreamer::getAssemblerPtr() {
4646
return nullptr;
4747
}
4848

49+
constexpr size_t FragBlockSize = 16384;
50+
// Ensure the new fragment can at least store a few bytes.
51+
constexpr size_t NewFragHeadroom = 8;
52+
53+
static_assert(NewFragHeadroom >= alignof(MCFragment));
54+
static_assert(FragBlockSize >= sizeof(MCFragment) + NewFragHeadroom);
55+
56+
MCFragment *MCObjectStreamer::allocFragSpace(size_t Headroom) {
57+
auto Size = std::max(FragBlockSize, sizeof(MCFragment) + Headroom);
58+
FragSpace = Size - sizeof(MCFragment);
59+
auto Block = std::unique_ptr<uint8_t[]>(new uint8_t[Size]);
60+
auto *F = reinterpret_cast<MCFragment *>(Block.get());
61+
FragStorage.push_back(std::move(Block));
62+
return F;
63+
}
64+
4965
void MCObjectStreamer::newFragment() {
50-
addFragment(allocFragment<MCFragment>());
66+
MCFragment *F;
67+
if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
68+
auto End = reinterpret_cast<size_t>(getCurFragEnd());
69+
F = reinterpret_cast<MCFragment *>(
70+
alignToPowerOf2(End, alignof(MCFragment)));
71+
FragSpace -= size_t(F) - End + sizeof(MCFragment);
72+
} else {
73+
F = allocFragSpace(0);
74+
}
75+
new (F) MCFragment();
76+
addFragment(F);
77+
}
78+
79+
void MCObjectStreamer::ensureHeadroom(size_t Headroom) {
80+
if (Headroom <= FragSpace)
81+
return;
82+
auto *F = allocFragSpace(Headroom);
83+
new (F) MCFragment();
84+
addFragment(F);
5185
}
5286

5387
void MCObjectStreamer::addSpecialFragment(MCFragment *Frag) {
5488
assert(Frag->getKind() != MCFragment::FT_Data &&
5589
"Frag should have a variable-size tail");
90+
// Frag is not connected to FragSpace. Before modifying CurFrag with
91+
// addFragment(Frag), allocate an empty fragment to maintain FragSpace
92+
// connectivity, potentially reusing CurFrag's associated space.
93+
MCFragment *F;
94+
if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
95+
auto End = reinterpret_cast<size_t>(getCurFragEnd());
96+
F = reinterpret_cast<MCFragment *>(
97+
alignToPowerOf2(End, alignof(MCFragment)));
98+
FragSpace -= size_t(F) - End + sizeof(MCFragment);
99+
} else {
100+
F = allocFragSpace(0);
101+
}
102+
new (F) MCFragment();
103+
56104
addFragment(Frag);
57-
newFragment();
105+
addFragment(F);
58106
}
59107

60108
void MCObjectStreamer::appendContents(ArrayRef<char> Contents) {
61-
CurFrag->appendContents(Contents);
109+
ensureHeadroom(Contents.size());
110+
assert(FragSpace >= Contents.size());
111+
llvm::copy(Contents, getCurFragEnd());
112+
CurFrag->FixedSize += Contents.size();
113+
FragSpace -= Contents.size();
62114
}
63115

64-
void MCObjectStreamer::appendContents(size_t Num, char Elt) {
65-
CurFrag->appendContents(Num, Elt);
116+
void MCObjectStreamer::appendContents(size_t Num, uint8_t Elt) {
117+
ensureHeadroom(Num);
118+
MutableArrayRef<uint8_t> Data(getCurFragEnd(), Num);
119+
llvm::fill(Data, Elt);
120+
CurFrag->FixedSize += Num;
121+
FragSpace -= Num;
66122
}
67123

68124
void MCObjectStreamer::addFixup(const MCExpr *Value, MCFixupKind Kind) {
@@ -115,6 +171,8 @@ void MCObjectStreamer::reset() {
115171
}
116172
EmitEHFrame = true;
117173
EmitDebugFrame = false;
174+
FragStorage.clear();
175+
FragSpace = 0;
118176
SpecialFragAllocator.Reset();
119177
MCStreamer::reset();
120178
}
@@ -144,7 +202,6 @@ void MCObjectStreamer::emitCFISections(bool EH, bool Debug, bool SFrame) {
144202
void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
145203
SMLoc Loc) {
146204
MCStreamer::emitValueImpl(Value, Size, Loc);
147-
MCFragment *DF = getCurrentFragment();
148205

149206
MCDwarfLineEntry::make(this, getCurrentSectionOnly());
150207

@@ -159,9 +216,9 @@ void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
159216
emitIntValue(AbsValue, Size);
160217
return;
161218
}
162-
DF->addFixup(MCFixup::create(DF->getContents().size(), Value,
163-
MCFixup::getDataKindForSize(Size)));
164-
DF->appendContents(Size, 0);
219+
ensureHeadroom(Size);
220+
addFixup(Value, MCFixup::getDataKindForSize(Size));
221+
appendContents(Size, 0);
165222
}
166223

167224
MCSymbol *MCObjectStreamer::emitCFILabel() {
@@ -195,7 +252,7 @@ void MCObjectStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
195252
// section.
196253
MCFragment *F = CurFrag;
197254
Symbol->setFragment(F);
198-
Symbol->setOffset(F->getContents().size());
255+
Symbol->setOffset(F->getFixedSize());
199256

200257
emitPendingAssignments(Symbol);
201258
}
@@ -261,20 +318,38 @@ void MCObjectStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
261318
F0 = CurFrag;
262319
}
263320

321+
// To maintain connectivity between CurFrag and FragSpace when CurFrag is
322+
// modified, allocate an empty fragment and append it to the fragment list.
323+
// (Subsections[I].second.Tail is not connected to FragSpace.)
324+
MCFragment *F;
325+
if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
326+
auto End = reinterpret_cast<size_t>(getCurFragEnd());
327+
F = reinterpret_cast<MCFragment *>(
328+
alignToPowerOf2(End, alignof(MCFragment)));
329+
FragSpace -= size_t(F) - End + sizeof(MCFragment);
330+
} else {
331+
F = allocFragSpace(0);
332+
}
333+
new (F) MCFragment();
334+
F->setParent(Section);
335+
264336
auto &Subsections = Section->Subsections;
265337
size_t I = 0, E = Subsections.size();
266338
while (I != E && Subsections[I].first < Subsection)
267339
++I;
268340
// If the subsection number is not in the sorted Subsections list, create a
269341
// new fragment list.
270342
if (I == E || Subsections[I].first != Subsection) {
271-
auto *F = allocFragment<MCFragment>();
272-
F->setParent(Section);
273343
Subsections.insert(Subsections.begin() + I,
274344
{Subsection, MCSection::FragList{F, F}});
345+
Section->CurFragList = &Subsections[I].second;
346+
CurFrag = F;
347+
} else {
348+
Section->CurFragList = &Subsections[I].second;
349+
CurFrag = Subsections[I].second.Tail;
350+
// Ensure CurFrag is associated with FragSpace.
351+
addFragment(F);
275352
}
276-
Section->CurFragList = &Subsections[I].second;
277-
CurFrag = Section->CurFragList->Tail;
278353

279354
// Define the section symbol at subsection 0's initial fragment if required.
280355
if (!NewSec)
@@ -345,11 +420,15 @@ void MCObjectStreamer::emitInstToData(const MCInst &Inst,
345420
MCFragment *F = getCurrentFragment();
346421

347422
// Append the instruction to the data fragment.
348-
size_t CodeOffset = F->getContents().size();
423+
size_t CodeOffset = getCurFragSize();
424+
SmallString<16> Content;
349425
SmallVector<MCFixup, 1> Fixups;
350-
getAssembler().getEmitter().encodeInstruction(
351-
Inst, F->getContentsForAppending(), Fixups, STI);
352-
F->doneAppending();
426+
getAssembler().getEmitter().encodeInstruction(Inst, Content, Fixups, STI);
427+
appendContents(Content);
428+
if (CurFrag != F) {
429+
F = CurFrag;
430+
CodeOffset = 0;
431+
}
353432
F->setHasInstructions(STI);
354433

355434
if (Fixups.empty())

llvm/lib/MC/MCWin64EH.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
318318

319319
// Emit the epilog instructions.
320320
if (EnableUnwindV2) {
321+
// Ensure the fixups and appended content apply to the same fragment.
322+
OS->ensureHeadroom(info->EpilogMap.size() * 2);
323+
321324
bool IsLast = true;
322325
for (const auto &Epilog : llvm::reverse(info->EpilogMap)) {
323326
if (IsLast) {

llvm/lib/MC/MCWinCOFFStreamer.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ void MCWinCOFFStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {
279279
void MCWinCOFFStreamer::emitCOFFSectionIndex(const MCSymbol *Symbol) {
280280
visitUsedSymbol(*Symbol);
281281
const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext());
282+
ensureHeadroom(2);
282283
addFixup(SRE, FK_SecRel_2);
283284
appendContents(2, 0);
284285
}
@@ -292,6 +293,7 @@ void MCWinCOFFStreamer::emitCOFFSecRel32(const MCSymbol *Symbol,
292293
if (Offset)
293294
MCE = MCBinaryExpr::createAdd(
294295
MCE, MCConstantExpr::create(Offset, getContext()), getContext());
296+
ensureHeadroom(4);
295297
addFixup(MCE, FK_SecRel_4);
296298
// Emit 4 bytes (zeros) to the object file.
297299
appendContents(4, 0);
@@ -307,6 +309,7 @@ void MCWinCOFFStreamer::emitCOFFImgRel32(const MCSymbol *Symbol,
307309
if (Offset)
308310
MCE = MCBinaryExpr::createAdd(
309311
MCE, MCConstantExpr::create(Offset, getContext()), getContext());
312+
ensureHeadroom(4);
310313
addFixup(MCE, FK_Data_4);
311314
// Emit 4 bytes (zeros) to the object file.
312315
appendContents(4, 0);
@@ -317,6 +320,7 @@ void MCWinCOFFStreamer::emitCOFFSecNumber(MCSymbol const *Symbol) {
317320
// Create Symbol for section number.
318321
const MCExpr *MCE = MCCOFFSectionNumberTargetExpr::create(
319322
*Symbol, this->getWriter(), getContext());
323+
ensureHeadroom(4);
320324
addFixup(MCE, FK_Data_4);
321325
// Emit 4 bytes (zeros) to the object file.
322326
appendContents(4, 0);
@@ -327,6 +331,7 @@ void MCWinCOFFStreamer::emitCOFFSecOffset(MCSymbol const *Symbol) {
327331
// Create Symbol for section offset.
328332
const MCExpr *MCE =
329333
MCCOFFSectionOffsetTargetExpr::create(*Symbol, getContext());
334+
ensureHeadroom(4);
330335
addFixup(MCE, FK_Data_4);
331336
// Emit 4 bytes (zeros) to the object file.
332337
appendContents(4, 0);

0 commit comments

Comments
 (0)