MC: Optimize getOrCreateDataFragment

... by eagerly allocating an empty fragment when adding a fragment
with a variable-size tail.

X86AsmBackend, The JCC erratum mitigation and x86-pad-for-align set a
flag for FT_Relaxable, which needs to be moved to emitInstructionBegin.
```
  if (CF->getKind() == MCFragment::FT_Relaxable)
    CF->setAllowAutoPadding(canPadInst(Inst, OS));
```

Follow-up to #148544
This commit is contained in:
Fangrui Song
2025-07-19 16:55:29 -07:00
parent 54492c231c
commit 39c8cfb70d
6 changed files with 52 additions and 40 deletions

View File

@@ -73,12 +73,14 @@ public:
MCSymbol *emitCFILabel() override;
void emitCFISections(bool EH, bool Debug) override;
/// Get a data fragment to write into, creating a new one if the current
/// fragment is not FT_Data.
MCFragment *getOrCreateDataFragment();
// TODO: Change callers to use getCurrentFragment instead.
MCFragment *getOrCreateDataFragment() { return getCurrentFragment(); }
protected:
bool changeSectionImpl(MCSection *Section, uint32_t Subsection);
MCAlignFragment *createAlignFragment(Align Alignment, int64_t Fill,
uint8_t FillLen,
unsigned MaxBytesToEmit);
public:
void visitUsedSymbol(const MCSymbol &Sym) override;

View File

@@ -270,6 +270,8 @@ protected:
/// section changes.
virtual void changeSection(MCSection *, uint32_t);
void addFragment(MCFragment *F);
virtual void emitCFIStartProcImpl(MCDwarfFrameInfo &Frame);
virtual void emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame);
@@ -456,8 +458,10 @@ public:
MCSymbol *endSection(MCSection *Section);
void insert(MCFragment *F);
/// Add a new fragment to the current section without a variable-size tail.
void newFragment();
/// Add a fragment with a variable-size tail and start a new empty fragment.
void insert(MCFragment *F);
/// Returns the mnemonic for \p MI, if the streamer has access to a
/// instruction printer and returns an empty string otherwise.

View File

@@ -166,8 +166,8 @@ void CodeViewContext::emitStringTable(MCObjectStreamer &OS) {
// somewhere else. If somebody wants two string tables in their .s file, one
// will just be empty.
if (!StrTabFragment) {
StrTabFragment = Ctx.allocFragment<MCFragment>();
OS.insert(StrTabFragment);
OS.newFragment();
StrTabFragment = OS.getCurrentFragment();
}
OS.emitValueToAlignment(Align(4), 0);

View File

@@ -106,18 +106,6 @@ void MCObjectStreamer::emitFrames(MCAsmBackend *MAB) {
MCDwarfFrameEmitter::Emit(*this, MAB, false);
}
MCFragment *MCObjectStreamer::getOrCreateDataFragment() {
// TODO: Start a new fragment whenever finalizing the variable-size tail of a
// previous one, so that all getOrCreateDataFragment calls can be replaced
// with getCurrentFragment
auto *F = getCurrentFragment();
if (F->getKind() != MCFragment::FT_Data) {
F = getContext().allocFragment<MCFragment>();
insert(F);
}
return F;
}
void MCObjectStreamer::visitUsedSymbol(const MCSymbol &Sym) {
Assembler->registerSymbol(Sym);
}
@@ -379,6 +367,7 @@ void MCObjectStreamer::emitInstToFragment(const MCInst &Inst,
F->setVarContents(Data);
F->setVarFixups(Fixups);
F->setInst(Inst);
newFragment();
}
void MCObjectStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
@@ -444,6 +433,7 @@ void MCObjectStreamer::emitDwarfAdvanceLineAddr(int64_t LineDelta,
F->Kind = MCFragment::FT_Dwarf;
F->setDwarfAddrDelta(buildSymbolDiff(*this, Label, LastLabel, SMLoc()));
F->setDwarfLineDelta(LineDelta);
newFragment();
}
void MCObjectStreamer::emitDwarfLineEndEntry(MCSection *Section,
@@ -474,6 +464,7 @@ void MCObjectStreamer::emitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
auto *F = getOrCreateDataFragment();
F->Kind = MCFragment::FT_DwarfFrame;
F->setDwarfAddrDelta(buildSymbolDiff(*this, Label, LastLabel, Loc));
newFragment();
}
void MCObjectStreamer::emitCVLocDirective(unsigned FunctionId, unsigned FileNo,
@@ -536,32 +527,38 @@ void MCObjectStreamer::emitBytes(StringRef Data) {
DF->appendContents(ArrayRef(Data.data(), Data.size()));
}
MCAlignFragment *MCObjectStreamer::createAlignFragment(
Align Alignment, int64_t Fill, uint8_t FillLen, unsigned MaxBytesToEmit) {
if (MaxBytesToEmit == 0)
MaxBytesToEmit = Alignment.value();
return getContext().allocFragment<MCAlignFragment>(Alignment, Fill, FillLen,
MaxBytesToEmit);
}
void MCObjectStreamer::emitValueToAlignment(Align Alignment, int64_t Fill,
uint8_t FillLen,
unsigned MaxBytesToEmit) {
if (MaxBytesToEmit == 0)
MaxBytesToEmit = Alignment.value();
insert(getContext().allocFragment<MCAlignFragment>(Alignment, Fill, FillLen,
MaxBytesToEmit));
auto *F = createAlignFragment(Alignment, Fill, FillLen, MaxBytesToEmit);
insert(F);
// Update the maximum alignment on the current section if necessary.
MCSection *CurSec = getCurrentSectionOnly();
CurSec->ensureMinAlignment(Alignment);
F->getParent()->ensureMinAlignment(Alignment);
}
void MCObjectStreamer::emitCodeAlignment(Align Alignment,
const MCSubtargetInfo *STI,
unsigned MaxBytesToEmit) {
emitValueToAlignment(Alignment, 0, 1, MaxBytesToEmit);
auto *F = cast<MCAlignFragment>(getCurrentFragment());
auto *F = createAlignFragment(Alignment, 0, 1, MaxBytesToEmit);
F->setEmitNops(true, STI);
insert(F);
// Update the maximum alignment on the current section if necessary.
F->getParent()->ensureMinAlignment(Alignment);
// With RISC-V style linker relaxation, mark the section as linker-relaxable
// if the alignment is larger than the minimum NOP size.
unsigned Size;
if (getAssembler().getBackend().shouldInsertExtraNopBytesForCodeAlign(*F,
Size)) {
getCurrentSectionOnly()->setLinkerRelaxable();
newFragment();
F->getParent()->setLinkerRelaxable();
}
}

View File

@@ -1404,7 +1404,7 @@ MCSymbol *MCStreamer::endSection(MCSection *Section) {
return Sym;
}
void MCStreamer::insert(MCFragment *F) {
void MCStreamer::addFragment(MCFragment *F) {
auto *Sec = CurFrag->getParent();
F->setParent(Sec);
F->setLayoutOrder(CurFrag->getLayoutOrder() + 1);
@@ -1414,7 +1414,14 @@ void MCStreamer::insert(MCFragment *F) {
}
void MCStreamer::newFragment() {
insert(getContext().allocFragment<MCFragment>());
addFragment(getContext().allocFragment<MCFragment>());
}
void MCStreamer::insert(MCFragment *F) {
assert(F->getKind() != MCFragment::FT_Data &&
"F should have a variable-size tail");
addFragment(F);
newFragment();
}
static VersionTuple

View File

@@ -456,8 +456,6 @@ bool X86AsmBackend::canPadInst(const MCInst &Inst, MCObjectStreamer &OS) const {
}
bool X86AsmBackend::canPadBranches(MCObjectStreamer &OS) const {
if (!OS.getAllowAutoPadding())
return false;
assert(allowAutoPadding() && "incorrect initialization!");
// We only pad in text section.
@@ -491,8 +489,15 @@ void X86AsmBackend::emitInstructionBegin(MCObjectStreamer &OS,
// fragment will have changed.
IsRightAfterData =
isRightAfterData(OS.getCurrentFragment(), PrevInstPosition);
bool CanPadInst = false;
bool AutoPadding = OS.getAllowAutoPadding();
if (LLVM_UNLIKELY(AutoPadding || X86PadForAlign)) {
CanPadInst = canPadInst(Inst, OS);
if (CanPadInst)
OS.getCurrentFragment()->setAllowAutoPadding(true);
}
if (!canPadBranches(OS))
if (!AutoPadding || !canPadBranches(OS))
return;
// NB: PrevInst only valid if canPadBranches is true.
@@ -504,7 +509,7 @@ void X86AsmBackend::emitInstructionBegin(MCObjectStreamer &OS,
// we call canPadInst (not cheap) twice. However, in the common case, we can
// avoid unnecessary calls to that, as this is otherwise only used for
// relaxable fragments.
if (!canPadInst(Inst, OS))
if (!CanPadInst)
return;
if (PendingBA && PendingBA->getNext() == OS.getCurrentFragment()) {
@@ -542,15 +547,12 @@ void X86AsmBackend::emitInstructionBegin(MCObjectStreamer &OS,
/// Set the last fragment to be aligned for the BoundaryAlignFragment.
void X86AsmBackend::emitInstructionEnd(MCObjectStreamer &OS,
const MCInst &Inst) {
MCFragment *CF = OS.getCurrentFragment();
if (CF->getKind() == MCFragment::FT_Relaxable)
CF->setAllowAutoPadding(canPadInst(Inst, OS));
// Update PrevInstOpcode here, canPadInst() reads that.
MCFragment *CF = OS.getCurrentFragment();
PrevInstOpcode = Inst.getOpcode();
PrevInstPosition = std::make_pair(CF, getSizeForInstFragment(CF));
if (!canPadBranches(OS))
if (!OS.getAllowAutoPadding() || !canPadBranches(OS))
return;
// PrevInst is only needed if canPadBranches. Copying an MCInst isn't cheap.