Skip to content

Commit 35204dc

Browse files
committed
MCFragment: Use trailing data for fixed-size part
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`. When switching section or subsection, we cannot reuse the FragList::Tail, because it is no associated with fragment space tracked by `FragSpace`. We need to allocate a new fragment, which was 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. Pull Request: llvm#150846
1 parent 85213f2 commit 35204dc

File tree

7 files changed

+134
-68
lines changed

7 files changed

+134
-68
lines changed

llvm/include/llvm/MC/MCObjectStreamer.h

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

55+
SmallVector<std::unique_ptr<char[]>, 0> FragStorage;
56+
// Available bytes in the current block for trailing data or new fragments.
57+
size_t FragSpace = 0;
58+
5559
void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &);
5660
void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
5761
void emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;
@@ -84,9 +88,15 @@ class MCObjectStreamer : public MCStreamer {
8488
// Add a fragment with a variable-size tail and start a new empty fragment.
8589
void insert(MCFragment *F);
8690

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

98+
void ensureHeadroom(size_t Headroom);
99+
void appendContents(ArrayRef<char> Contents);
90100
void appendContents(size_t Num, char Elt);
91101
void addFixup(const MCExpr *Value, MCFixupKind Kind);
92102

llvm/include/llvm/MC/MCSection.h

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,7 @@ class MCFragment {
9393
// Track content and fixups for the fixed-size part as fragments are
9494
// appended to the section. The content remains immutable, except when
9595
// modified by applyFixup.
96-
uint32_t ContentStart = 0;
97-
uint32_t ContentEnd = 0;
96+
uint32_t FixedSize = 0;
9897
uint32_t FixupStart = 0;
9998
uint32_t FixupEnd = 0;
10099

@@ -205,18 +204,6 @@ class MCFragment {
205204
//== Content-related functions manage parent's storage using ContentStart and
206205
// ContentSize.
207206

208-
// Get a SmallVector reference. The caller should call doneAppending to update
209-
// `ContentEnd`.
210-
SmallVectorImpl<char> &getContentsForAppending();
211-
void doneAppending();
212-
void appendContents(ArrayRef<char> Contents) {
213-
getContentsForAppending().append(Contents.begin(), Contents.end());
214-
doneAppending();
215-
}
216-
void appendContents(size_t Num, char Elt) {
217-
getContentsForAppending().append(Num, Elt);
218-
doneAppending();
219-
}
220207
MutableArrayRef<char> getContents();
221208
ArrayRef<char> getContents() const;
222209

@@ -225,10 +212,10 @@ class MCFragment {
225212
MutableArrayRef<char> getVarContents();
226213
ArrayRef<char> getVarContents() const;
227214

228-
size_t getFixedSize() const { return ContentEnd - ContentStart; }
215+
size_t getFixedSize() const { return FixedSize; }
229216
size_t getVarSize() const { return VarContentEnd - VarContentStart; }
230217
size_t getSize() const {
231-
return ContentEnd - ContentStart + (VarContentEnd - VarContentStart);
218+
return FixedSize + (VarContentEnd - VarContentStart);
232219
}
233220

234221
//== Fixup-related functions manage parent's storage using FixupStart and
@@ -651,28 +638,11 @@ class LLVM_ABI MCSection {
651638
bool isBssSection() const { return IsBss; }
652639
};
653640

654-
inline SmallVectorImpl<char> &MCFragment::getContentsForAppending() {
655-
SmallVectorImpl<char> &S = getParent()->ContentStorage;
656-
if (LLVM_UNLIKELY(ContentEnd != S.size())) {
657-
// Move the elements to the end. Reserve space to avoid invalidating
658-
// S.begin()+I for `append`.
659-
auto Size = ContentEnd - ContentStart;
660-
auto I = std::exchange(ContentStart, S.size());
661-
S.reserve(S.size() + Size);
662-
S.append(S.begin() + I, S.begin() + I + Size);
663-
}
664-
return S;
665-
}
666-
inline void MCFragment::doneAppending() {
667-
ContentEnd = getParent()->ContentStorage.size();
668-
}
669641
inline MutableArrayRef<char> MCFragment::getContents() {
670-
return MutableArrayRef(getParent()->ContentStorage)
671-
.slice(ContentStart, ContentEnd - ContentStart);
642+
return {reinterpret_cast<char *>(this + 1), FixedSize};
672643
}
673644
inline ArrayRef<char> MCFragment::getContents() const {
674-
return ArrayRef(getParent()->ContentStorage)
675-
.slice(ContentStart, ContentEnd - ContentStart);
645+
return {reinterpret_cast<const char *>(this + 1), FixedSize};
676646
}
677647

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

llvm/lib/MC/MCMachOStreamer.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,8 @@ void MCMachOStreamer::finalizeCGProfile() {
484484
// For each entry, reserve space for 2 32-bit indices and a 64-bit count.
485485
size_t SectionBytes =
486486
W.getCGProfile().size() * (2 * sizeof(uint32_t) + sizeof(uint64_t));
487-
(*CGProfileSection->begin()).appendContents(SectionBytes, 0);
487+
(*CGProfileSection->begin())
488+
.setVarContents(std::vector<char>(SectionBytes, 0));
488489
}
489490

490491
MCStreamer *llvm::createMachOStreamer(MCContext &Context,
@@ -520,5 +521,5 @@ void MCMachOStreamer::createAddrSigSection() {
520521
// (instead of emitting a zero-sized section) so these relocations are
521522
// technically valid, even though we don't expect these relocations to
522523
// actually be applied by the linker.
523-
Frag->appendContents(8, 0);
524+
Frag->setVarContents(std::vector<char>(8, 0));
524525
}

llvm/lib/MC/MCObjectStreamer.cpp

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

49+
constexpr size_t FragChunkSize = 16384;
50+
// Ensure the new fragment can at least at least a few bytes.
51+
constexpr size_t NewFragHeadroom = 8;
52+
53+
static_assert(NewFragHeadroom >= alignof(MCFragment));
54+
static_assert(FragChunkSize >= sizeof(MCFragment) + NewFragHeadroom);
55+
56+
MCFragment *MCObjectStreamer::allocFragSpace(size_t Headroom) {
57+
auto Size = std::max(FragChunkSize, sizeof(MCFragment) + Headroom);
58+
FragSpace = Size - sizeof(MCFragment);
59+
auto Chunk = std::unique_ptr<char[]>(new char[Size]);
60+
auto *F = reinterpret_cast<MCFragment *>(Chunk.get());
61+
FragStorage.push_back(std::move(Chunk));
62+
return F;
63+
}
64+
4965
void MCObjectStreamer::newFragment() {
50-
addFragment(getContext().allocFragment<MCFragment>());
66+
MCFragment *F;
67+
if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
68+
auto End = 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

53-
void MCObjectStreamer::insert(MCFragment *F) {
54-
assert(F->getKind() != MCFragment::FT_Data &&
87+
void MCObjectStreamer::insert(MCFragment *Frag) {
88+
assert(Frag->getKind() != MCFragment::FT_Data &&
5589
"F should have a variable-size tail");
90+
// Allocate an empty fragment, potentially reusing the space associated with
91+
// CurFrag.
92+
MCFragment *F;
93+
if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
94+
auto End = size_t(getCurFragEnd());
95+
F = reinterpret_cast<MCFragment *>(
96+
alignToPowerOf2(End, alignof(MCFragment)));
97+
FragSpace -= size_t(F) - End + sizeof(MCFragment);
98+
} else {
99+
F = allocFragSpace(0);
100+
}
101+
102+
// Add Frag, which destroys CurFrag and the associated space.
103+
addFragment(Frag);
104+
new (F) MCFragment();
105+
// Add the empty fragment, which restores CurFrag and the associated space.
56106
addFragment(F);
57-
newFragment();
107+
}
108+
109+
void MCObjectStreamer::appendContents(ArrayRef<char> Contents) {
110+
ensureHeadroom(Contents.size());
111+
assert(FragSpace >= Contents.size());
112+
llvm::copy(Contents, getCurFragEnd());
113+
CurFrag->FixedSize += Contents.size();
114+
FragSpace -= Contents.size();
58115
}
59116

60117
void MCObjectStreamer::appendContents(size_t Num, char Elt) {
61-
CurFrag->appendContents(Num, Elt);
118+
ensureHeadroom(Num);
119+
MutableArrayRef<char> Data(getCurFragEnd(), Num);
120+
llvm::fill(Data, Elt);
121+
CurFrag->FixedSize += Num;
122+
FragSpace -= Num;
62123
}
63124

64125
void MCObjectStreamer::addFixup(const MCExpr *Value, MCFixupKind Kind) {
65-
CurFrag->addFixup(MCFixup::create(CurFrag->getFixedSize(), Value, Kind));
126+
CurFrag->addFixup(MCFixup::create(getCurFragSize(), Value, Kind));
66127
}
67128

68129
// As a compile-time optimization, avoid allocating and evaluating an MCExpr
@@ -111,6 +172,8 @@ void MCObjectStreamer::reset() {
111172
}
112173
EmitEHFrame = true;
113174
EmitDebugFrame = false;
175+
FragStorage.clear();
176+
FragSpace = 0;
114177
MCStreamer::reset();
115178
}
116179

@@ -139,7 +202,6 @@ void MCObjectStreamer::emitCFISections(bool EH, bool Debug, bool SFrame) {
139202
void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
140203
SMLoc Loc) {
141204
MCStreamer::emitValueImpl(Value, Size, Loc);
142-
MCFragment *DF = getCurrentFragment();
143205

144206
MCDwarfLineEntry::make(this, getCurrentSectionOnly());
145207

@@ -154,9 +216,9 @@ void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
154216
emitIntValue(AbsValue, Size);
155217
return;
156218
}
157-
DF->addFixup(MCFixup::create(DF->getContents().size(), Value,
158-
MCFixup::getDataKindForSize(Size)));
159-
DF->appendContents(Size, 0);
219+
ensureHeadroom(Size);
220+
addFixup(Value, MCFixup::getDataKindForSize(Size));
221+
appendContents(Size, 0);
160222
}
161223

162224
MCSymbol *MCObjectStreamer::emitCFILabel() {
@@ -190,7 +252,7 @@ void MCObjectStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
190252
// section.
191253
MCFragment *F = CurFrag;
192254
Symbol->setFragment(F);
193-
Symbol->setOffset(F->getContents().size());
255+
Symbol->setOffset(F->getFixedSize());
194256

195257
emitPendingAssignments(Symbol);
196258
}
@@ -256,20 +318,38 @@ void MCObjectStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
256318
F0 = CurFrag;
257319
}
258320

321+
// CurFrag will be changed. To ensure that FragSpace remains connected with
322+
// CurFrag, allocate an empty fragment and add it to the fragment list.
323+
// (Subsections[I].second.Tail is disconnected with FragSpace.)
324+
MCFragment *F;
325+
if (LLVM_LIKELY(sizeof(MCFragment) + NewFragHeadroom <= FragSpace)) {
326+
auto End = 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+
259336
auto &Subsections = Section->Subsections;
260337
size_t I = 0, E = Subsections.size();
261338
while (I != E && Subsections[I].first < Subsection)
262339
++I;
263340
// If the subsection number is not in the sorted Subsections list, create a
264341
// new fragment list.
265342
if (I == E || Subsections[I].first != Subsection) {
266-
auto *F = getContext().allocFragment<MCFragment>();
267-
F->setParent(Section);
268343
Subsections.insert(Subsections.begin() + I,
269344
{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);
270352
}
271-
Section->CurFragList = &Subsections[I].second;
272-
CurFrag = Section->CurFragList->Tail;
273353

274354
// Define the section symbol at subsection 0's initial fragment if required.
275355
if (!NewSec)
@@ -340,31 +420,29 @@ void MCObjectStreamer::emitInstToData(const MCInst &Inst,
340420
MCFragment *F = getCurrentFragment();
341421

342422
// Append the instruction to the data fragment.
343-
size_t CodeOffset = F->getContents().size();
423+
size_t CodeOffset = getCurFragSize();
424+
SmallString<16> Content;
344425
SmallVector<MCFixup, 1> Fixups;
345-
getAssembler().getEmitter().encodeInstruction(
346-
Inst, F->getContentsForAppending(), Fixups, STI);
347-
F->doneAppending();
426+
getAssembler().getEmitter().encodeInstruction(Inst, Content, Fixups, STI);
427+
appendContents(Content);
348428
F->setHasInstructions(STI);
349429

350430
if (Fixups.empty())
351431
return;
352432
bool MarkedLinkerRelaxable = false;
353433
for (auto &Fixup : Fixups) {
354434
Fixup.setOffset(Fixup.getOffset() + CodeOffset);
355-
if (!Fixup.isLinkerRelaxable() || MarkedLinkerRelaxable)
435+
if (!Fixup.isLinkerRelaxable())
356436
continue;
357-
MarkedLinkerRelaxable = true;
358-
// Set the fragment's order within the subsection for use by
359-
// MCAssembler::relaxAlign.
360-
auto *Sec = F->getParent();
361-
if (!Sec->isLinkerRelaxable())
362-
Sec->setLinkerRelaxable();
437+
F->setLinkerRelaxable();
363438
// Do not add data after a linker-relaxable instruction. The difference
364439
// between a new label and a label at or before the linker-relaxable
365440
// instruction cannot be resolved at assemble-time.
366-
F->setLinkerRelaxable();
367-
newFragment();
441+
if (!MarkedLinkerRelaxable) {
442+
MarkedLinkerRelaxable = true;
443+
getCurrentSectionOnly()->setLinkerRelaxable();
444+
newFragment();
445+
}
368446
}
369447
F->appendFixups(Fixups);
370448
}
@@ -538,8 +616,7 @@ void MCObjectStreamer::emitCVFileChecksumOffsetDirective(unsigned FileNo) {
538616

539617
void MCObjectStreamer::emitBytes(StringRef Data) {
540618
MCDwarfLineEntry::make(this, getCurrentSectionOnly());
541-
MCFragment *DF = getCurrentFragment();
542-
DF->appendContents(ArrayRef(Data.data(), Data.size()));
619+
appendContents(ArrayRef(Data.data(), Data.size()));
543620
}
544621

545622
void MCObjectStreamer::emitValueToAlignment(Align Alignment, int64_t Fill,

llvm/lib/MC/MCWin64EH.cpp

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

319319
// Emit the epilog instructions.
320320
if (EnableUnwindV2) {
321+
OS->ensureHeadroom(info->EpilogMap.size() * 2);
322+
321323
bool IsLast = true;
322324
for (const auto &Epilog : llvm::reverse(info->EpilogMap)) {
323325
if (IsLast) {

llvm/lib/MC/MachObjectWriter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ uint64_t MachObjectWriter::writeObject() {
806806
}
807807
MCSection *Sec = getContext().getMachOSection("__LLVM", "__cg_profile", 0,
808808
SectionKind::getMetadata());
809-
llvm::copy(OS.str(), Sec->curFragList()->Head->getContents().data());
809+
llvm::copy(OS.str(), Sec->curFragList()->Head->getVarContents().data());
810810
}
811811

812812
unsigned NumSections = Asm.end() - Asm.begin();

0 commit comments

Comments
 (0)