Skip to content

Commit 43a18c7

Browse files
committed
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 minor instructions:u increase and [large max-rss decrease](https://llvm-compile-time-tracker.com/compare.php?from=bb982e733cfcda7e4cfb0583544f68af65211ed1&to=f12d55f97c47717d438951ecddecf8ebd28c296b&stat=max-rss&linkStats=on) for the "stage1-ReleaseLTO-g (link only)" benchmark. 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 <[email protected]> Pull Request: llvm#146307
1 parent 393aebf commit 43a18c7

File tree

12 files changed

+224
-210
lines changed

12 files changed

+224
-210
lines changed

llvm/include/llvm/MC/MCSection.h

Lines changed: 82 additions & 65 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,10 +301,7 @@ class LLVM_ABI MCSection {
296301

297302
/// Interface implemented by fragments that contain encoded instructions and/or
298303
/// data.
299-
///
300304
class MCEncodedFragment : public MCFragment {
301-
uint8_t BundlePadding = 0;
302-
303305
protected:
304306
MCEncodedFragment(MCFragment::FragmentType FType, bool HasInstructions)
305307
: MCFragment(FType, HasInstructions) {}
@@ -308,6 +310,13 @@ class MCEncodedFragment : public MCFragment {
308310
/// It must be non-null for instructions.
309311
const MCSubtargetInfo *STI = nullptr;
310312

313+
private:
314+
uint32_t ContentStart = 0;
315+
uint32_t ContentEnd = 0;
316+
uint32_t FixupStart = 0;
317+
uint32_t FixupEnd = 0;
318+
uint8_t BundlePadding = 0;
319+
311320
public:
312321
static bool classof(const MCFragment *F) {
313322
MCFragment::FragmentType Kind = F->getKind();
@@ -318,7 +327,10 @@ class MCEncodedFragment : public MCFragment {
318327
case MCFragment::FT_Data:
319328
case MCFragment::FT_Dwarf:
320329
case MCFragment::FT_DwarfFrame:
330+
case MCFragment::FT_LEB:
321331
case MCFragment::FT_PseudoProbe:
332+
case MCFragment::FT_CVInlineLines:
333+
case MCFragment::FT_CVDefRange:
322334
return true;
323335
}
324336
}
@@ -348,48 +360,64 @@ class MCEncodedFragment : public MCFragment {
348360
HasInstructions = true;
349361
this->STI = &STI;
350362
}
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;
362-
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; }
371363

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

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;
400+
// Fixup-related functions manage parent's storage using FixupStart and
401+
// FixupSize.
402+
void clearFixups() { FixupEnd = FixupStart; }
403+
void addFixup(MCFixup Fixup);
404+
void appendFixups(ArrayRef<MCFixup> Fixups);
405+
void setFixups(ArrayRef<MCFixup> Fixups);
406+
MutableArrayRef<MCFixup> getFixups() {
407+
return MutableArrayRef(getParent()->FixupStorage)
408+
.slice(FixupStart, FixupEnd - FixupStart);
409+
}
410+
ArrayRef<MCFixup> getFixups() const {
411+
return ArrayRef(getParent()->FixupStorage)
412+
.slice(FixupStart, FixupEnd - FixupStart);
385413
}
386414
};
387415

388416
/// Fragment for data and encoded instructions.
389417
///
390-
class MCDataFragment : public MCEncodedFragmentWithFixups<32, 4> {
418+
class MCDataFragment : public MCEncodedFragment {
391419
public:
392-
MCDataFragment() : MCEncodedFragmentWithFixups<32, 4>(FT_Data, false) {}
420+
MCDataFragment() : MCEncodedFragment(FT_Data, false) {}
393421

394422
static bool classof(const MCFragment *F) {
395423
return F->getKind() == MCFragment::FT_Data;
@@ -402,13 +430,13 @@ class MCDataFragment : public MCEncodedFragmentWithFixups<32, 4> {
402430
/// A relaxable fragment holds on to its MCInst, since it may need to be
403431
/// relaxed during the assembler layout and relaxation stage.
404432
///
405-
class MCRelaxableFragment : public MCEncodedFragmentWithFixups<8, 1> {
433+
class MCRelaxableFragment : public MCEncodedFragment {
406434
/// The instruction this is a fragment for.
407435
MCInst Inst;
408436

409437
public:
410438
MCRelaxableFragment(const MCInst &Inst, const MCSubtargetInfo &STI)
411-
: MCEncodedFragmentWithFixups(FT_Relaxable, true), Inst(Inst) {
439+
: MCEncodedFragment(FT_Relaxable, true), Inst(Inst) {
412440
this->STI = &STI;
413441
}
414442

@@ -557,7 +585,7 @@ class MCOrgFragment : public MCFragment {
557585
}
558586
};
559587

560-
class MCLEBFragment final : public MCEncodedFragmentWithFixups<8, 0> {
588+
class MCLEBFragment final : public MCEncodedFragment {
561589
/// True if this is a sleb128, false if uleb128.
562590
bool IsSigned;
563591

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

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

574599
const MCExpr &getValue() const { return *Value; }
575600
void setValue(const MCExpr *Expr) { Value = Expr; }
576601

577602
bool isSigned() const { return IsSigned; }
578603

579-
/// @}
580-
581604
static bool classof(const MCFragment *F) {
582605
return F->getKind() == MCFragment::FT_LEB;
583606
}
584607
};
585608

586-
class MCDwarfLineAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
609+
class MCDwarfLineAddrFragment : public MCEncodedFragment {
587610
/// The value of the difference between the two line numbers
588611
/// between two .loc dwarf directives.
589612
int64_t LineDelta;
@@ -594,8 +617,8 @@ class MCDwarfLineAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
594617

595618
public:
596619
MCDwarfLineAddrFragment(int64_t LineDelta, const MCExpr &AddrDelta)
597-
: MCEncodedFragmentWithFixups<8, 1>(FT_Dwarf, false),
598-
LineDelta(LineDelta), AddrDelta(&AddrDelta) {}
620+
: MCEncodedFragment(FT_Dwarf, false), LineDelta(LineDelta),
621+
AddrDelta(&AddrDelta) {}
599622

600623
int64_t getLineDelta() const { return LineDelta; }
601624

@@ -606,15 +629,14 @@ class MCDwarfLineAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
606629
}
607630
};
608631

609-
class MCDwarfCallFrameFragment : public MCEncodedFragmentWithFixups<8, 1> {
632+
class MCDwarfCallFrameFragment : public MCEncodedFragment {
610633
/// The expression for the difference of the two symbols that
611634
/// make up the address delta between two .cfi_* dwarf directives.
612635
const MCExpr *AddrDelta;
613636

614637
public:
615638
MCDwarfCallFrameFragment(const MCExpr &AddrDelta)
616-
: MCEncodedFragmentWithFixups<8, 1>(FT_DwarfFrame, false),
617-
AddrDelta(&AddrDelta) {}
639+
: MCEncodedFragment(FT_DwarfFrame, false), AddrDelta(&AddrDelta) {}
618640

619641
const MCExpr &getAddrDelta() const { return *AddrDelta; }
620642
void setAddrDelta(const MCExpr *E) { AddrDelta = E; }
@@ -642,13 +664,12 @@ class MCSymbolIdFragment : public MCFragment {
642664

643665
/// Fragment representing the binary annotations produced by the
644666
/// .cv_inline_linetable directive.
645-
class MCCVInlineLineTableFragment : public MCFragment {
667+
class MCCVInlineLineTableFragment : public MCEncodedFragment {
646668
unsigned SiteFuncId;
647669
unsigned StartFileId;
648670
unsigned StartLineNum;
649671
const MCSymbol *FnStartSym;
650672
const MCSymbol *FnEndSym;
651-
SmallString<8> Contents;
652673

653674
/// CodeViewContext has the real knowledge about this format, so let it access
654675
/// our members.
@@ -658,23 +679,20 @@ class MCCVInlineLineTableFragment : public MCFragment {
658679
MCCVInlineLineTableFragment(unsigned SiteFuncId, unsigned StartFileId,
659680
unsigned StartLineNum, const MCSymbol *FnStartSym,
660681
const MCSymbol *FnEndSym)
661-
: MCFragment(FT_CVInlineLines, false), SiteFuncId(SiteFuncId),
682+
: MCEncodedFragment(FT_CVInlineLines, false), SiteFuncId(SiteFuncId),
662683
StartFileId(StartFileId), StartLineNum(StartLineNum),
663684
FnStartSym(FnStartSym), FnEndSym(FnEndSym) {}
664685

665686
const MCSymbol *getFnStartSym() const { return FnStartSym; }
666687
const MCSymbol *getFnEndSym() const { return FnEndSym; }
667688

668-
SmallString<8> &getContents() { return Contents; }
669-
const SmallString<8> &getContents() const { return Contents; }
670-
671689
static bool classof(const MCFragment *F) {
672690
return F->getKind() == MCFragment::FT_CVInlineLines;
673691
}
674692
};
675693

676694
/// Fragment representing the .cv_def_range directive.
677-
class MCCVDefRangeFragment : public MCEncodedFragmentWithFixups<32, 4> {
695+
class MCCVDefRangeFragment : public MCEncodedFragment {
678696
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges;
679697
StringRef FixedSizePortion;
680698

@@ -686,8 +704,9 @@ class MCCVDefRangeFragment : public MCEncodedFragmentWithFixups<32, 4> {
686704
MCCVDefRangeFragment(
687705
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
688706
StringRef FixedSizePortion)
689-
: MCEncodedFragmentWithFixups<32, 4>(FT_CVDefRange, false),
690-
Ranges(Ranges), FixedSizePortion(FixedSizePortion) {}
707+
: MCEncodedFragment(FT_CVDefRange, false),
708+
Ranges(Ranges.begin(), Ranges.end()),
709+
FixedSizePortion(FixedSizePortion) {}
691710

692711
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> getRanges() const {
693712
return Ranges;
@@ -739,23 +758,21 @@ class MCBoundaryAlignFragment : public MCFragment {
739758
}
740759
};
741760

742-
class MCPseudoProbeAddrFragment : public MCEncodedFragmentWithFixups<8, 1> {
761+
class MCPseudoProbeAddrFragment : public MCEncodedFragment {
743762
/// The expression for the difference of the two symbols that
744763
/// make up the address delta between two .pseudoprobe directives.
745764
const MCExpr *AddrDelta;
746765

747766
public:
748767
MCPseudoProbeAddrFragment(const MCExpr *AddrDelta)
749-
: MCEncodedFragmentWithFixups<8, 1>(FT_PseudoProbe, false),
750-
AddrDelta(AddrDelta) {}
768+
: MCEncodedFragment(FT_PseudoProbe, false), AddrDelta(AddrDelta) {}
751769

752770
const MCExpr &getAddrDelta() const { return *AddrDelta; }
753771

754772
static bool classof(const MCFragment *F) {
755773
return F->getKind() == MCFragment::FT_PseudoProbe;
756774
}
757775
};
758-
759776
} // end namespace llvm
760777

761778
#endif // LLVM_MC_MCSECTION_H

0 commit comments

Comments
 (0)