Skip to content

Commit 1a47f3f

Browse files
committed
[MC] Compute fragment offsets eagerly
This builds on top of commit 9d0754a ("[MC] Relax fragments eagerly") and relaxes fragments eagerly to eliminate MCSection::HasLayout and `getFragmentOffset` overhead. Note: The removed `#ifndef NDEBUG` code (disabled by default) in X86AsmBackend::finishLayout was problematic, as (a) !NDEBUG and NDEBUG builds evaluated fragment offsets at different times before this patch (b) one iteration might not be sufficient to converge. There might be some edge cases that it did not handle. Anyhow, this patch probably makes it work for more cases.
1 parent 0387cd0 commit 1a47f3f

File tree

7 files changed

+54
-71
lines changed

7 files changed

+54
-71
lines changed

llvm/include/llvm/MC/MCAsmBackend.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,9 @@ class MCAsmBackend {
217217
virtual bool writeNopData(raw_ostream &OS, uint64_t Count,
218218
const MCSubtargetInfo *STI) const = 0;
219219

220-
/// Give backend an opportunity to finish layout after relaxation
221-
virtual void finishLayout(MCAssembler const &Asm) const {}
220+
// Return true if fragment offsets have been adjusted and an extra layout
221+
// iteration is needed.
222+
virtual bool finishLayout(const MCAssembler &Asm) const { return false; }
222223

223224
/// Handle any target-specific assembler flags. By default, do nothing.
224225
virtual void handleAssemblerFlag(MCAssemblerFlag Flag) {}

llvm/include/llvm/MC/MCAssembler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class MCAssembler {
126126
/// Check whether the given fragment needs relaxation.
127127
bool fragmentNeedsRelaxation(const MCRelaxableFragment *IF) const;
128128

129+
void layoutSection(MCSection &Sec);
129130
/// Perform one layout iteration and return true if any offsets
130131
/// were adjusted.
131132
bool layoutOnce();
@@ -172,10 +173,9 @@ class MCAssembler {
172173
uint64_t computeFragmentSize(const MCFragment &F) const;
173174

174175
void layoutBundle(MCFragment *Prev, MCFragment *F) const;
175-
void ensureValid(MCSection &Sec) const;
176176

177177
// Get the offset of the given fragment inside its containing section.
178-
uint64_t getFragmentOffset(const MCFragment &F) const;
178+
uint64_t getFragmentOffset(const MCFragment &F) const { return F.Offset; }
179179

180180
uint64_t getSectionAddressSize(const MCSection &Sec) const;
181181
uint64_t getSectionFileSize(const MCSection &Sec) const;

llvm/include/llvm/MC/MCSection.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,6 @@ class MCSection {
9999
/// Whether this section has had instructions emitted into it.
100100
bool HasInstructions : 1;
101101

102-
bool HasLayout : 1;
103-
104102
bool IsRegistered : 1;
105103

106104
bool IsText : 1;
@@ -169,9 +167,6 @@ class MCSection {
169167
bool hasInstructions() const { return HasInstructions; }
170168
void setHasInstructions(bool Value) { HasInstructions = Value; }
171169

172-
bool hasLayout() const { return HasLayout; }
173-
void setHasLayout(bool Value) { HasLayout = Value; }
174-
175170
bool isRegistered() const { return IsRegistered; }
176171
void setIsRegistered(bool Value) { IsRegistered = Value; }
177172

llvm/lib/MC/MCAssembler.cpp

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -438,28 +438,6 @@ void MCAssembler::layoutBundle(MCFragment *Prev, MCFragment *F) const {
438438
DF->Offset = EF->Offset;
439439
}
440440

441-
void MCAssembler::ensureValid(MCSection &Sec) const {
442-
if (Sec.hasLayout())
443-
return;
444-
Sec.setHasLayout(true);
445-
MCFragment *Prev = nullptr;
446-
uint64_t Offset = 0;
447-
for (MCFragment &F : Sec) {
448-
F.Offset = Offset;
449-
if (isBundlingEnabled() && F.hasInstructions()) {
450-
layoutBundle(Prev, &F);
451-
Offset = F.Offset;
452-
}
453-
Offset += computeFragmentSize(F);
454-
Prev = &F;
455-
}
456-
}
457-
458-
uint64_t MCAssembler::getFragmentOffset(const MCFragment &F) const {
459-
ensureValid(*F.getParent());
460-
return F.Offset;
461-
}
462-
463441
// Simple getSymbolOffset helper for the non-variable case.
464442
static bool getLabelOffset(const MCAssembler &Asm, const MCSymbol &S,
465443
bool ReportError, uint64_t &Val) {
@@ -944,22 +922,20 @@ void MCAssembler::layout() {
944922

945923
// Layout until everything fits.
946924
this->HasLayout = true;
925+
for (MCSection &Sec : *this)
926+
layoutSection(Sec);
947927
while (layoutOnce()) {
948-
if (getContext().hadError())
949-
return;
950-
// Size of fragments in one section can depend on the size of fragments in
951-
// another. If any fragment has changed size, we have to re-layout (and
952-
// as a result possibly further relax) all.
953-
for (MCSection &Sec : *this)
954-
Sec.setHasLayout(false);
955928
}
956929

957930
DEBUG_WITH_TYPE("mc-dump", {
958931
errs() << "assembler backend - post-relaxation\n--\n";
959932
dump(); });
960933

961-
// Finalize the layout, including fragment lowering.
962-
getBackend().finishLayout(*this);
934+
// Some targets might want to adjust fragment offsets. If so, perform another
935+
// layout loop.
936+
if (getBackend().finishLayout(*this))
937+
for (MCSection &Sec : *this)
938+
layoutSection(Sec);
963939

964940
DEBUG_WITH_TYPE("mc-dump", {
965941
errs() << "assembler backend - final-layout\n--\n";
@@ -1312,15 +1288,42 @@ bool MCAssembler::relaxFragment(MCFragment &F) {
13121288
}
13131289
}
13141290

1291+
void MCAssembler::layoutSection(MCSection &Sec) {
1292+
MCFragment *Prev = nullptr;
1293+
uint64_t Offset = 0;
1294+
for (MCFragment &F : Sec) {
1295+
F.Offset = Offset;
1296+
if (LLVM_UNLIKELY(isBundlingEnabled())) {
1297+
if (F.hasInstructions()) {
1298+
layoutBundle(Prev, &F);
1299+
Offset = F.Offset;
1300+
}
1301+
Prev = &F;
1302+
}
1303+
Offset += computeFragmentSize(F);
1304+
}
1305+
}
1306+
13151307
bool MCAssembler::layoutOnce() {
13161308
++stats::RelaxationSteps;
13171309

1318-
bool Changed = false;
1319-
for (MCSection &Sec : *this)
1320-
for (MCFragment &Frag : Sec)
1321-
if (relaxFragment(Frag))
1322-
Changed = true;
1323-
return Changed;
1310+
// Size of fragments in one section can depend on the size of fragments in
1311+
// another. If any fragment has changed size, we have to re-layout (and
1312+
// as a result possibly further relax) all.
1313+
bool ChangedAny = false;
1314+
for (MCSection &Sec : *this) {
1315+
for (;;) {
1316+
bool Changed = false;
1317+
for (MCFragment &F : Sec)
1318+
if (relaxFragment(F))
1319+
Changed = true;
1320+
ChangedAny |= Changed;
1321+
if (!Changed)
1322+
break;
1323+
layoutSection(Sec);
1324+
}
1325+
}
1326+
return ChangedAny;
13241327
}
13251328

13261329
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

llvm/lib/MC/MCSection.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ using namespace llvm;
2323
MCSection::MCSection(SectionVariant V, StringRef Name, bool IsText,
2424
bool IsVirtual, MCSymbol *Begin)
2525
: Begin(Begin), BundleGroupBeforeFirstInst(false), HasInstructions(false),
26-
HasLayout(false), IsRegistered(false), IsText(IsText),
27-
IsVirtual(IsVirtual), Name(Name), Variant(V) {
26+
IsRegistered(false), IsText(IsText), IsVirtual(IsVirtual), Name(Name),
27+
Variant(V) {
2828
DummyFragment.setParent(this);
2929
// The initial subsection number is 0. Create a fragment list.
3030
CurFragList = &Subsections.emplace_back(0u, FragList{}).second;

llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ class HexagonAsmBackend : public MCAsmBackend {
702702
return true;
703703
}
704704

705-
void finishLayout(MCAssembler const &Asm) const override {
705+
bool finishLayout(const MCAssembler &Asm) const override {
706706
SmallVector<MCFragment *> Frags;
707707
for (MCSection &Sec : Asm) {
708708
Frags.clear();
@@ -747,7 +747,6 @@ class HexagonAsmBackend : public MCAsmBackend {
747747
//assert(!Error);
748748
(void)Error;
749749
ReplaceInstruction(Asm.getEmitter(), RF, Inst);
750-
Sec.setHasLayout(false);
751750
Size = 0; // Only look back one instruction
752751
break;
753752
}
@@ -757,6 +756,7 @@ class HexagonAsmBackend : public MCAsmBackend {
757756
}
758757
}
759758
}
759+
return true;
760760
}
761761
}; // class HexagonAsmBackend
762762

llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ class X86AsmBackend : public MCAsmBackend {
201201
bool padInstructionEncoding(MCRelaxableFragment &RF, MCCodeEmitter &Emitter,
202202
unsigned &RemainingSize) const;
203203

204-
void finishLayout(const MCAssembler &Asm) const override;
204+
bool finishLayout(const MCAssembler &Asm) const override;
205205

206206
unsigned getMaximumNopSize(const MCSubtargetInfo &STI) const override;
207207

@@ -856,15 +856,15 @@ bool X86AsmBackend::padInstructionEncoding(MCRelaxableFragment &RF,
856856
return Changed;
857857
}
858858

859-
void X86AsmBackend::finishLayout(MCAssembler const &Asm) const {
859+
bool X86AsmBackend::finishLayout(const MCAssembler &Asm) const {
860860
// See if we can further relax some instructions to cut down on the number of
861861
// nop bytes required for code alignment. The actual win is in reducing
862862
// instruction count, not number of bytes. Modern X86-64 can easily end up
863863
// decode limited. It is often better to reduce the number of instructions
864864
// (i.e. eliminate nops) even at the cost of increasing the size and
865865
// complexity of others.
866866
if (!X86PadForAlign && !X86PadForBranchAlign)
867-
return;
867+
return false;
868868

869869
// The processed regions are delimitered by LabeledFragments. -g may have more
870870
// MCSymbols and therefore different relaxation results. X86PadForAlign is
@@ -911,9 +911,6 @@ void X86AsmBackend::finishLayout(MCAssembler const &Asm) const {
911911
continue;
912912
}
913913

914-
#ifndef NDEBUG
915-
const uint64_t OrigOffset = Asm.getFragmentOffset(F);
916-
#endif
917914
const uint64_t OrigSize = Asm.computeFragmentSize(F);
918915

919916
// To keep the effects local, prefer to relax instructions closest to
@@ -926,8 +923,7 @@ void X86AsmBackend::finishLayout(MCAssembler const &Asm) const {
926923
// Give the backend a chance to play any tricks it wishes to increase
927924
// the encoding size of the given instruction. Target independent code
928925
// will try further relaxation, but target's may play further tricks.
929-
if (padInstructionEncoding(RF, Asm.getEmitter(), RemainingSize))
930-
Sec.setHasLayout(false);
926+
padInstructionEncoding(RF, Asm.getEmitter(), RemainingSize);
931927

932928
// If we have an instruction which hasn't been fully relaxed, we can't
933929
// skip past it and insert bytes before it. Changing its starting
@@ -944,14 +940,6 @@ void X86AsmBackend::finishLayout(MCAssembler const &Asm) const {
944940
if (F.getKind() == MCFragment::FT_BoundaryAlign)
945941
cast<MCBoundaryAlignFragment>(F).setSize(RemainingSize);
946942

947-
#ifndef NDEBUG
948-
const uint64_t FinalOffset = Asm.getFragmentOffset(F);
949-
const uint64_t FinalSize = Asm.computeFragmentSize(F);
950-
assert(OrigOffset + OrigSize == FinalOffset + FinalSize &&
951-
"can't move start of next fragment!");
952-
assert(FinalSize == RemainingSize && "inconsistent size computation?");
953-
#endif
954-
955943
// If we're looking at a boundary align, make sure we don't try to pad
956944
// its target instructions for some following directive. Doing so would
957945
// break the alignment of the current boundary align.
@@ -965,11 +953,7 @@ void X86AsmBackend::finishLayout(MCAssembler const &Asm) const {
965953
}
966954
}
967955

968-
// The layout is done. Mark every fragment as valid.
969-
for (MCSection &Section : Asm) {
970-
Asm.getFragmentOffset(*Section.curFragList()->Tail);
971-
Asm.computeFragmentSize(*Section.curFragList()->Tail);
972-
}
956+
return true;
973957
}
974958

975959
unsigned X86AsmBackend::getMaximumNopSize(const MCSubtargetInfo &STI) const {

0 commit comments

Comments
 (0)