Skip to content

Commit 9beb467

Browse files
authored
MC: Store fragment content and fixups out-of-line
Moved `Contents` and `Fixups` SmallVector storage to MCSection, enabling trivial destructors for most fragment subclasses and eliminating the need for MCFragment::destroy in ~MCSection. For appending content to the current section, use getContentsForAppending. During assembler relaxation, prefer setContents/setFixups, which may involve copying and reduce the benefits of https://reviews.llvm.org/D145791. Moving only Contents out-of-line caused a slight performance regression (Alexis Engelke's 2024 prototype). By also moving Fragments out-of-line, fragment destructors become trivial, resulting in neglgible instructions:u increase for "stage2-O0-g" and [large max-rss decrease](https://llvm-compile-time-tracker.com/compare.php?from=84e82746c3ff63ec23a8b85e9efd4f7fccf92590&to=555a28c0b2f8250a9cf86fd267a04b0460283e15&stat=max-rss&linkStats=on) for the "stage1-ReleaseLTO-g (link only)" benchmark. ( An older version using fewer inline functions: https://llvm-compile-time-tracker.com/compare.php?from=bb982e733cfcda7e4cfb0583544f68af65211ed1&to=f12d55f97c47717d438951ecddecf8ebd28c296b&linkStats=on ) Now using plain SmallVector in MCSection for storage, with potential for future allocator optimizations, such as allocating `Contents` as the trailing object of MCDataFragment. (GNU Assembler uses gnulib's obstack for fragment management.) Co-authored-by: Alexis Engelke <engelke@in.tum.de> Pull Request: #146307
1 parent 7e830f7 commit 9beb467

File tree

12 files changed

+221
-207
lines changed

12 files changed

+221
-207
lines changed

llvm/include/llvm/MC/MCSection.h

Lines changed: 79 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class LLVM_ABI MCSection {
132132
public:
133133
friend MCAssembler;
134134
friend MCObjectStreamer;
135+
friend class MCEncodedFragment;
135136
static constexpr unsigned NonUniqueID = ~0U;
136137

137138
enum SectionVariant {
@@ -209,6 +210,10 @@ class LLVM_ABI MCSection {
209210
// subsections.
210211
SmallVector<std::pair<unsigned, FragList>, 1> Subsections;
211212

213+
// Content and fixup storage for fragments
214+
SmallVector<char, 0> ContentStorage;
215+
SmallVector<MCFixup, 0> FixupStorage;
216+
212217
protected:
213218
// TODO Make Name private when possible.
214219
StringRef Name;
@@ -296,9 +301,12 @@ class LLVM_ABI MCSection {
296301

297302
/// Interface implemented by fragments that contain encoded instructions and/or
298303
/// data.
299-
///
300304
class MCEncodedFragment : public MCFragment {
301305
uint8_t BundlePadding = 0;
306+
uint32_t ContentStart = 0;
307+
uint32_t ContentEnd = 0;
308+
uint32_t FixupStart = 0;
309+
uint32_t FixupEnd = 0;
302310

303311
protected:
304312
MCEncodedFragment(MCFragment::FragmentType FType, bool HasInstructions)
@@ -318,7 +326,10 @@ class MCEncodedFragment : public MCFragment {
318326
case MCFragment::FT_Data:
319327
case MCFragment::FT_Dwarf:
320328
case MCFragment::FT_DwarfFrame:
329+
case MCFragment::FT_LEB:
321330
case MCFragment::FT_PseudoProbe:
331+
case MCFragment::FT_CVInlineLines:
332+
case MCFragment::FT_CVDefRange:
322333
return true;
323334
}
324335
}
@@ -348,48 +359,64 @@ class MCEncodedFragment : public MCFragment {
348359
HasInstructions = true;
349360
this->STI = &STI;
350361
}
351-
};
352-
353-
/// Interface implemented by fragments that contain encoded instructions and/or
354-
/// data and also have fixups registered.
355-
///
356-
template <unsigned ContentsSize, unsigned FixupsSize>
357-
class MCEncodedFragmentWithFixups : public MCEncodedFragment {
358-
SmallVector<char, ContentsSize> Contents;
359-
360-
/// The list of fixups in this fragment.
361-
SmallVector<MCFixup, FixupsSize> Fixups;
362362

363-
protected:
364-
MCEncodedFragmentWithFixups(MCFragment::FragmentType FType,
365-
bool HasInstructions)
366-
: MCEncodedFragment(FType, HasInstructions) {}
367-
368-
public:
369-
SmallVectorImpl<char> &getContents() { return Contents; }
370-
const SmallVectorImpl<char> &getContents() const { return Contents; }
371-
372-
void appendContents(ArrayRef<char> C) { Contents.append(C.begin(), C.end()); }
373-
void appendContents(size_t Num, char Elt) { Contents.append(Num, Elt); }
374-
void setContents(ArrayRef<char> C) { Contents.assign(C.begin(), C.end()); }
375-
376-
void addFixup(MCFixup Fixup) { Fixups.push_back(Fixup); }
377-
SmallVectorImpl<MCFixup> &getFixups() { return Fixups; }
378-
const SmallVectorImpl<MCFixup> &getFixups() const { return Fixups; }
363+
// Content-related functions manage parent's storage using ContentStart and
364+
// ContentSize.
365+
void clearContents() { ContentEnd = ContentStart; }
366+
// Get a SmallVector reference. The caller should call doneAppending to update
367+
// `ContentEnd`.
368+
SmallVectorImpl<char> &getContentsForAppending() {
369+
SmallVectorImpl<char> &S = getParent()->ContentStorage;
370+
if (LLVM_UNLIKELY(ContentEnd != S.size())) {
371+
// Move the elements to the end. Reserve space to avoid invalidating
372+
// S.begin()+I for `append`.
373+
auto Size = ContentEnd - ContentStart;
374+
auto I = std::exchange(ContentStart, S.size());
375+
S.reserve(S.size() + Size);
376+
S.append(S.begin() + I, S.begin() + I + Size);
377+
}
378+
return S;
379+
}
380+
void doneAppending() { ContentEnd = getParent()->ContentStorage.size(); }
381+
void appendContents(ArrayRef<char> Contents) {
382+
getContentsForAppending().append(Contents.begin(), Contents.end());
383+
doneAppending();
384+
}
385+
void appendContents(size_t Num, char Elt) {
386+
getContentsForAppending().append(Num, Elt);
387+
doneAppending();
388+
}
389+
void setContents(ArrayRef<char> Contents);
390+
MutableArrayRef<char> getContents() {
391+
return MutableArrayRef(getParent()->ContentStorage)
392+
.slice(ContentStart, ContentEnd - ContentStart);
393+
}
394+
ArrayRef<char> getContents() const {
395+
return ArrayRef(getParent()->ContentStorage)
396+
.slice(ContentStart, ContentEnd - ContentStart);
397+
}
379398

380-
static bool classof(const MCFragment *F) {
381-
MCFragment::FragmentType Kind = F->getKind();
382-
return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data ||
383-
Kind == MCFragment::FT_CVDefRange || Kind == MCFragment::FT_Dwarf ||
384-
Kind == MCFragment::FT_DwarfFrame;
399+
// Fixup-related functions manage parent's storage using FixupStart and
400+
// FixupSize.
401+
void clearFixups() { FixupEnd = FixupStart; }
402+
void addFixup(MCFixup Fixup);
403+
void appendFixups(ArrayRef<MCFixup> Fixups);
404+
void setFixups(ArrayRef<MCFixup> Fixups);
405+
MutableArrayRef<MCFixup> getFixups() {
406+
return MutableArrayRef(getParent()->FixupStorage)
407+
.slice(FixupStart, FixupEnd - FixupStart);
408+
}
409+
ArrayRef<MCFixup> getFixups() const {
410+
return ArrayRef(getParent()->FixupStorage)
411+
.slice(FixupStart, FixupEnd - FixupStart);
385412
}
386413
};
387414

388415
/// Fragment for data and encoded instructions.
389416
///
390-
class MCDataFragment : public MCEncodedFragmentWithFixups<32, 4> {
417+
class MCDataFragment : public MCEncodedFragment {
391418
public:
392-
MCDataFragment() : MCEncodedFragmentWithFixups<32, 4>(FT_Data, false) {}
419+
MCDataFragment() : MCEncodedFragment(FT_Data, false) {}
393420

394421
static bool classof(const MCFragment *F) {
395422
return F->getKind() == MCFragment::FT_Data;
@@ -402,13 +429,13 @@ class MCDataFragment : public MCEncodedFragmentWithFixups<32, 4> {
402429
/// A relaxable fragment holds on to its MCInst, since it may need to be
403430
/// relaxed during the assembler layout and relaxation stage.
404431
///
405-
class MCRelaxableFragment : public MCEncodedFragmentWithFixups<8, 1> {
432+
class MCRelaxableFragment : public MCEncodedFragment {
406433
/// The instruction this is a fragment for.
407434
MCInst Inst;
408435

409436
public:
410437
MCRelaxableFragment(const MCInst &Inst, const MCSubtargetInfo &STI)
411-
: MCEncodedFragmentWithFixups(FT_Relaxable, true), Inst(Inst) {
438+
: MCEncodedFragment(FT_Relaxable, true), Inst(Inst) {
412439
this->STI = &STI;
413440
}
414441

@@ -557,7 +584,7 @@ class MCOrgFragment : public MCFragment {
557584
}
558585
};
559586

560-
class MCLEBFragment final : public MCEncodedFragmentWithFixups<8, 0> {
587+
class MCLEBFragment final : public MCEncodedFragment {
561588
/// True if this is a sleb128, false if uleb128.
562589
bool IsSigned;
563590

@@ -566,24 +593,19 @@ class MCLEBFragment final : public MCEncodedFragmentWithFixups<8, 0> {
566593

567594
public:
568595
MCLEBFragment(const MCExpr &Value, bool IsSigned)
569-
: MCEncodedFragmentWithFixups<8, 0>(FT_LEB, false), IsSigned(IsSigned),
570-
Value(&Value) {
571-
getContents().push_back(0);
572-
}
596+
: MCEncodedFragment(FT_LEB, false), IsSigned(IsSigned), Value(&Value) {}
573597

574598
const MCExpr &getValue() const { return *Value; }
575599
void setValue(const MCExpr *Expr) { Value = Expr; }
576600

577601
bool isSigned() const { return IsSigned; }
578602

579-
/// @}
580-
581603
static bool classof(const MCFragment *F) {
582604
return F->getKind() == MCFragment::FT_LEB;
583605
}
584606
};
585607

586-
class MCDwarfLineAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
608+
class MCDwarfLineAddrFragment : public MCEncodedFragment {
587609
/// The value of the difference between the two line numbers
588610
/// between two .loc dwarf directives.
589611
int64_t LineDelta;
@@ -594,8 +616,8 @@ class MCDwarfLineAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
594616

595617
public:
596618
MCDwarfLineAddrFragment(int64_t LineDelta, const MCExpr &AddrDelta)
597-
: MCEncodedFragmentWithFixups<8, 1>(FT_Dwarf, false),
598-
LineDelta(LineDelta), AddrDelta(&AddrDelta) {}
619+
: MCEncodedFragment(FT_Dwarf, false), LineDelta(LineDelta),
620+
AddrDelta(&AddrDelta) {}
599621

600622
int64_t getLineDelta() const { return LineDelta; }
601623

@@ -606,15 +628,14 @@ class MCDwarfLineAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
606628
}
607629
};
608630

609-
class MCDwarfCallFrameFragment : public MCEncodedFragmentWithFixups<8, 1> {
631+
class MCDwarfCallFrameFragment : public MCEncodedFragment {
610632
/// The expression for the difference of the two symbols that
611633
/// make up the address delta between two .cfi_* dwarf directives.
612634
const MCExpr *AddrDelta;
613635

614636
public:
615637
MCDwarfCallFrameFragment(const MCExpr &AddrDelta)
616-
: MCEncodedFragmentWithFixups<8, 1>(FT_DwarfFrame, false),
617-
AddrDelta(&AddrDelta) {}
638+
: MCEncodedFragment(FT_DwarfFrame, false), AddrDelta(&AddrDelta) {}
618639

619640
const MCExpr &getAddrDelta() const { return *AddrDelta; }
620641
void setAddrDelta(const MCExpr *E) { AddrDelta = E; }
@@ -642,13 +663,12 @@ class MCSymbolIdFragment : public MCFragment {
642663

643664
/// Fragment representing the binary annotations produced by the
644665
/// .cv_inline_linetable directive.
645-
class MCCVInlineLineTableFragment : public MCFragment {
666+
class MCCVInlineLineTableFragment : public MCEncodedFragment {
646667
unsigned SiteFuncId;
647668
unsigned StartFileId;
648669
unsigned StartLineNum;
649670
const MCSymbol *FnStartSym;
650671
const MCSymbol *FnEndSym;
651-
SmallString<8> Contents;
652672

653673
/// CodeViewContext has the real knowledge about this format, so let it access
654674
/// our members.
@@ -658,23 +678,20 @@ class MCCVInlineLineTableFragment : public MCFragment {
658678
MCCVInlineLineTableFragment(unsigned SiteFuncId, unsigned StartFileId,
659679
unsigned StartLineNum, const MCSymbol *FnStartSym,
660680
const MCSymbol *FnEndSym)
661-
: MCFragment(FT_CVInlineLines, false), SiteFuncId(SiteFuncId),
681+
: MCEncodedFragment(FT_CVInlineLines, false), SiteFuncId(SiteFuncId),
662682
StartFileId(StartFileId), StartLineNum(StartLineNum),
663683
FnStartSym(FnStartSym), FnEndSym(FnEndSym) {}
664684

665685
const MCSymbol *getFnStartSym() const { return FnStartSym; }
666686
const MCSymbol *getFnEndSym() const { return FnEndSym; }
667687

668-
SmallString<8> &getContents() { return Contents; }
669-
const SmallString<8> &getContents() const { return Contents; }
670-
671688
static bool classof(const MCFragment *F) {
672689
return F->getKind() == MCFragment::FT_CVInlineLines;
673690
}
674691
};
675692

676693
/// Fragment representing the .cv_def_range directive.
677-
class MCCVDefRangeFragment : public MCEncodedFragmentWithFixups<32, 4> {
694+
class MCCVDefRangeFragment : public MCEncodedFragment {
678695
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges;
679696
StringRef FixedSizePortion;
680697

@@ -686,8 +703,9 @@ class MCCVDefRangeFragment : public MCEncodedFragmentWithFixups<32, 4> {
686703
MCCVDefRangeFragment(
687704
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
688705
StringRef FixedSizePortion)
689-
: MCEncodedFragmentWithFixups<32, 4>(FT_CVDefRange, false),
690-
Ranges(Ranges), FixedSizePortion(FixedSizePortion) {}
706+
: MCEncodedFragment(FT_CVDefRange, false),
707+
Ranges(Ranges.begin(), Ranges.end()),
708+
FixedSizePortion(FixedSizePortion) {}
691709

692710
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> getRanges() const {
693711
return Ranges;
@@ -739,15 +757,14 @@ class MCBoundaryAlignFragment : public MCFragment {
739757
}
740758
};
741759

742-
class MCPseudoProbeAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
760+
class MCPseudoProbeAddrFragment : public MCEncodedFragment {
743761
/// The expression for the difference of the two symbols that
744762
/// make up the address delta between two .pseudoprobe directives.
745763
const MCExpr *AddrDelta;
746764

747765
public:
748766
MCPseudoProbeAddrFragment(const MCExpr *AddrDelta)
749-
: MCEncodedFragmentWithFixups<8, 1>(FT_PseudoProbe, false),
750-
AddrDelta(AddrDelta) {}
767+
: MCEncodedFragment(FT_PseudoProbe, false), AddrDelta(AddrDelta) {}
751768

752769
const MCExpr &getAddrDelta() const { return *AddrDelta; }
753770

0 commit comments

Comments
 (0)