Skip to content

Commit be5a845

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. The approach is slightly different from 1a47f3f and has less performance benefit. The new layout algorithm also addresses the following problems: * Size change of MCFillFragment/MCOrgFragment did not influence the fixed-point iteration, which could be problematic for contrived cases. * The `invalid number of bytes` error was reported too early. Since `.zero A-B` might have temporary negative values in the first few iterations. * X86AsmBackend::finishLayout performed only one iteration, which might not converge. In addition, the removed `#ifndef NDEBUG` code (disabled by default) in X86AsmBackend::finishLayout was problematic, as !NDEBUG and NDEBUG builds evaluated fragment offsets at different times before this patch. * The computed layout for relax-recompute-align.s is optimal now. Builds with many text sections (e.g. full LTO) shall observe a decrease in compile time while the new algorithm could be slightly slower for some -O0 -g projects. Aligned bundling from the deprecated PNaCl placed constraints how we can perform iteration.
1 parent c35c4c7 commit be5a845

File tree

8 files changed

+127
-123
lines changed

8 files changed

+127
-123
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: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class MCAssembler {
6565

6666
bool HasLayout = false;
6767
bool RelaxAll = false;
68+
unsigned RelaxSteps = 0;
6869

6970
SectionListType Sections;
7071

@@ -113,19 +114,18 @@ class MCAssembler {
113114

114115
/// Perform one layout iteration and return true if any offsets
115116
/// were adjusted.
116-
bool layoutOnce();
117-
118-
/// Perform relaxation on a single fragment - returns true if the fragment
119-
/// changes as a result of relaxation.
120-
bool relaxFragment(MCFragment &F);
121-
bool relaxInstruction(MCRelaxableFragment &IF);
122-
bool relaxLEB(MCLEBFragment &IF);
123-
bool relaxBoundaryAlign(MCBoundaryAlignFragment &BF);
124-
bool relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF);
125-
bool relaxDwarfCallFrameFragment(MCDwarfCallFrameFragment &DF);
126-
bool relaxCVInlineLineTable(MCCVInlineLineTableFragment &DF);
127-
bool relaxCVDefRange(MCCVDefRangeFragment &DF);
128-
bool relaxPseudoProbeAddr(MCPseudoProbeAddrFragment &DF);
117+
bool relaxOnce();
118+
119+
/// Perform relaxation on a single fragment.
120+
void relaxFragment(MCFragment &F);
121+
void relaxInstruction(MCRelaxableFragment &IF);
122+
void relaxLEB(MCLEBFragment &IF);
123+
void relaxBoundaryAlign(MCBoundaryAlignFragment &BF);
124+
void relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF);
125+
void relaxDwarfCallFrameFragment(MCDwarfCallFrameFragment &DF);
126+
void relaxCVInlineLineTable(MCCVInlineLineTableFragment &DF);
127+
void relaxCVDefRange(MCCVDefRangeFragment &DF);
128+
void relaxPseudoProbeAddr(MCPseudoProbeAddrFragment &DF);
129129

130130
std::tuple<MCValue, uint64_t, bool>
131131
handleFixup(MCFragment &F, const MCFixup &Fixup, const MCSubtargetInfo *STI);
@@ -147,10 +147,9 @@ class MCAssembler {
147147
uint64_t computeFragmentSize(const MCFragment &F) const;
148148

149149
void layoutBundle(MCFragment *Prev, MCFragment *F) const;
150-
void ensureValid(MCSection &Sec) const;
151150

152151
// Get the offset of the given fragment inside its containing section.
153-
uint64_t getFragmentOffset(const MCFragment &F) const;
152+
uint64_t getFragmentOffset(const MCFragment &F) const { return F.Offset; }
154153

155154
uint64_t getSectionAddressSize(const MCSection &Sec) const;
156155
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: 94 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,11 @@ uint64_t MCAssembler::computeFragmentSize(const MCFragment &F) const {
261261
}
262262
int64_t Size = NumValues * FF.getValueSize();
263263
if (Size < 0) {
264-
getContext().reportError(FF.getLoc(), "invalid number of bytes");
264+
// The expression might use symbol values which have not yet converged.
265+
// Allow the first few iterations to have temporary negative values. The
266+
// limit is somewhat arbitrary but allows contrived interdependency.
267+
if (RelaxSteps >= 2)
268+
getContext().reportError(FF.getLoc(), "invalid number of bytes");
265269
return 0;
266270
}
267271
return Size;
@@ -428,28 +432,6 @@ void MCAssembler::layoutBundle(MCFragment *Prev, MCFragment *F) const {
428432
DF->Offset = EF->Offset;
429433
}
430434

431-
void MCAssembler::ensureValid(MCSection &Sec) const {
432-
if (Sec.hasLayout())
433-
return;
434-
Sec.setHasLayout(true);
435-
MCFragment *Prev = nullptr;
436-
uint64_t Offset = 0;
437-
for (MCFragment &F : Sec) {
438-
F.Offset = Offset;
439-
if (isBundlingEnabled() && F.hasInstructions()) {
440-
layoutBundle(Prev, &F);
441-
Offset = F.Offset;
442-
}
443-
Offset += computeFragmentSize(F);
444-
Prev = &F;
445-
}
446-
}
447-
448-
uint64_t MCAssembler::getFragmentOffset(const MCFragment &F) const {
449-
ensureValid(*F.getParent());
450-
return F.Offset;
451-
}
452-
453435
// Simple getSymbolOffset helper for the non-variable case.
454436
static bool getLabelOffset(const MCAssembler &Asm, const MCSymbol &S,
455437
bool ReportError, uint64_t &Val) {
@@ -929,22 +911,38 @@ void MCAssembler::layout() {
929911

930912
// Layout until everything fits.
931913
this->HasLayout = true;
932-
while (layoutOnce()) {
914+
for (MCSection &Sec : *this) {
915+
MCFragment *Prev = nullptr;
916+
uint64_t Offset = 0;
917+
for (MCFragment &F : Sec) {
918+
F.Offset = Offset;
919+
if (LLVM_UNLIKELY(isBundlingEnabled())) {
920+
if (F.hasInstructions()) {
921+
layoutBundle(Prev, &F);
922+
Offset = F.Offset;
923+
}
924+
Prev = &F;
925+
}
926+
Offset += computeFragmentSize(F);
927+
}
928+
}
929+
while (relaxOnce())
933930
if (getContext().hadError())
934931
return;
935-
// Size of fragments in one section can depend on the size of fragments in
936-
// another. If any fragment has changed size, we have to re-layout (and
937-
// as a result possibly further relax) all.
938-
for (MCSection &Sec : *this)
939-
Sec.setHasLayout(false);
940-
}
941932

942933
DEBUG_WITH_TYPE("mc-dump", {
943934
errs() << "assembler backend - post-relaxation\n--\n";
944935
dump(); });
945936

946-
// Finalize the layout, including fragment lowering.
947-
getBackend().finishLayout(*this);
937+
// Some targets might want to adjust fragment offsets. If so, perform another
938+
// relaxation loop.
939+
if (getBackend().finishLayout(*this))
940+
while (relaxOnce())
941+
if (getContext().hadError())
942+
return;
943+
944+
// Trigger computeFragmentSize errors.
945+
RelaxSteps = UINT_MAX;
948946

949947
DEBUG_WITH_TYPE("mc-dump", {
950948
errs() << "assembler backend - final-layout\n--\n";
@@ -1073,11 +1071,11 @@ bool MCAssembler::fragmentNeedsRelaxation(const MCRelaxableFragment *F) const {
10731071
return false;
10741072
}
10751073

1076-
bool MCAssembler::relaxInstruction(MCRelaxableFragment &F) {
1074+
void MCAssembler::relaxInstruction(MCRelaxableFragment &F) {
10771075
assert(getEmitterPtr() &&
10781076
"Expected CodeEmitter defined for relaxInstruction");
10791077
if (!fragmentNeedsRelaxation(&F))
1080-
return false;
1078+
return;
10811079

10821080
++stats::RelaxedInstructions;
10831081

@@ -1095,10 +1093,9 @@ bool MCAssembler::relaxInstruction(MCRelaxableFragment &F) {
10951093
F.getContents().clear();
10961094
getEmitter().encodeInstruction(Relaxed, F.getContents(), F.getFixups(),
10971095
*F.getSubtargetInfo());
1098-
return true;
10991096
}
11001097

1101-
bool MCAssembler::relaxLEB(MCLEBFragment &LF) {
1098+
void MCAssembler::relaxLEB(MCLEBFragment &LF) {
11021099
const unsigned OldSize = static_cast<unsigned>(LF.getContents().size());
11031100
unsigned PadTo = OldSize;
11041101
int64_t Value;
@@ -1134,7 +1131,6 @@ bool MCAssembler::relaxLEB(MCLEBFragment &LF) {
11341131
encodeSLEB128(Value, OSE, PadTo);
11351132
else
11361133
encodeULEB128(Value, OSE, PadTo);
1137-
return OldSize != LF.getContents().size();
11381134
}
11391135

11401136
/// Check if the branch crosses the boundary.
@@ -1174,11 +1170,11 @@ static bool needPadding(uint64_t StartAddr, uint64_t Size,
11741170
isAgainstBoundary(StartAddr, Size, BoundaryAlignment);
11751171
}
11761172

1177-
bool MCAssembler::relaxBoundaryAlign(MCBoundaryAlignFragment &BF) {
1173+
void MCAssembler::relaxBoundaryAlign(MCBoundaryAlignFragment &BF) {
11781174
// BoundaryAlignFragment that doesn't need to align any fragment should not be
11791175
// relaxed.
11801176
if (!BF.getLastFragment())
1181-
return false;
1177+
return;
11821178

11831179
uint64_t AlignedOffset = getFragmentOffset(BF);
11841180
uint64_t AlignedSize = 0;
@@ -1192,19 +1188,15 @@ bool MCAssembler::relaxBoundaryAlign(MCBoundaryAlignFragment &BF) {
11921188
uint64_t NewSize = needPadding(AlignedOffset, AlignedSize, BoundaryAlignment)
11931189
? offsetToAlignment(AlignedOffset, BoundaryAlignment)
11941190
: 0U;
1195-
if (NewSize == BF.getSize())
1196-
return false;
11971191
BF.setSize(NewSize);
1198-
return true;
11991192
}
12001193

1201-
bool MCAssembler::relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF) {
1194+
void MCAssembler::relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF) {
12021195
bool WasRelaxed;
12031196
if (getBackend().relaxDwarfLineAddr(*this, DF, WasRelaxed))
1204-
return WasRelaxed;
1197+
return;
12051198

12061199
MCContext &Context = getContext();
1207-
uint64_t OldSize = DF.getContents().size();
12081200
int64_t AddrDelta;
12091201
bool Abs = DF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, *this);
12101202
assert(Abs && "We created a line delta with an invalid expression");
@@ -1217,13 +1209,12 @@ bool MCAssembler::relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF) {
12171209

12181210
MCDwarfLineAddr::encode(Context, getDWARFLinetableParams(), LineDelta,
12191211
AddrDelta, Data);
1220-
return OldSize != Data.size();
12211212
}
12221213

1223-
bool MCAssembler::relaxDwarfCallFrameFragment(MCDwarfCallFrameFragment &DF) {
1214+
void MCAssembler::relaxDwarfCallFrameFragment(MCDwarfCallFrameFragment &DF) {
12241215
bool WasRelaxed;
12251216
if (getBackend().relaxDwarfCFA(*this, DF, WasRelaxed))
1226-
return WasRelaxed;
1217+
return;
12271218

12281219
MCContext &Context = getContext();
12291220
int64_t Value;
@@ -1232,31 +1223,25 @@ bool MCAssembler::relaxDwarfCallFrameFragment(MCDwarfCallFrameFragment &DF) {
12321223
getContext().reportError(DF.getAddrDelta().getLoc(),
12331224
"invalid CFI advance_loc expression");
12341225
DF.setAddrDelta(MCConstantExpr::create(0, Context));
1235-
return false;
1226+
return;
12361227
}
12371228

12381229
SmallVectorImpl<char> &Data = DF.getContents();
1239-
uint64_t OldSize = Data.size();
12401230
Data.clear();
12411231
DF.getFixups().clear();
12421232

12431233
MCDwarfFrameEmitter::encodeAdvanceLoc(Context, Value, Data);
1244-
return OldSize != Data.size();
12451234
}
12461235

1247-
bool MCAssembler::relaxCVInlineLineTable(MCCVInlineLineTableFragment &F) {
1248-
unsigned OldSize = F.getContents().size();
1236+
void MCAssembler::relaxCVInlineLineTable(MCCVInlineLineTableFragment &F) {
12491237
getContext().getCVContext().encodeInlineLineTable(*this, F);
1250-
return OldSize != F.getContents().size();
12511238
}
12521239

1253-
bool MCAssembler::relaxCVDefRange(MCCVDefRangeFragment &F) {
1254-
unsigned OldSize = F.getContents().size();
1240+
void MCAssembler::relaxCVDefRange(MCCVDefRangeFragment &F) {
12551241
getContext().getCVContext().encodeDefRange(*this, F);
1256-
return OldSize != F.getContents().size();
12571242
}
12581243

1259-
bool MCAssembler::relaxPseudoProbeAddr(MCPseudoProbeAddrFragment &PF) {
1244+
void MCAssembler::relaxPseudoProbeAddr(MCPseudoProbeAddrFragment &PF) {
12601245
uint64_t OldSize = PF.getContents().size();
12611246
int64_t AddrDelta;
12621247
bool Abs = PF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, *this);
@@ -1269,13 +1254,12 @@ bool MCAssembler::relaxPseudoProbeAddr(MCPseudoProbeAddrFragment &PF) {
12691254

12701255
// AddrDelta is a signed integer
12711256
encodeSLEB128(AddrDelta, OSE, OldSize);
1272-
return OldSize != Data.size();
12731257
}
12741258

1275-
bool MCAssembler::relaxFragment(MCFragment &F) {
1259+
void MCAssembler::relaxFragment(MCFragment &F) {
12761260
switch(F.getKind()) {
12771261
default:
1278-
return false;
1262+
return;
12791263
case MCFragment::FT_Relaxable:
12801264
assert(!getRelaxAll() &&
12811265
"Did not expect a MCRelaxableFragment in RelaxAll mode");
@@ -1297,15 +1281,57 @@ bool MCAssembler::relaxFragment(MCFragment &F) {
12971281
}
12981282
}
12991283

1300-
bool MCAssembler::layoutOnce() {
1284+
bool MCAssembler::relaxOnce() {
13011285
++stats::RelaxationSteps;
1286+
++RelaxSteps;
13021287

1303-
bool Changed = false;
1304-
for (MCSection &Sec : *this)
1305-
for (MCFragment &Frag : Sec)
1306-
if (relaxFragment(Frag))
1307-
Changed = true;
1308-
return Changed;
1288+
// Size of fragments in one section can depend on the size of fragments in
1289+
// another. If any fragment has changed size, we have to re-layout (and
1290+
// as a result possibly further relax) all sections.
1291+
bool ChangedAny = false, Changed;
1292+
for (MCSection &Sec : *this) {
1293+
// Assume each iteration finalizes at least one extra fragment. If the
1294+
// layout does not converge after N+1 iterations, bail out.
1295+
auto MaxIter = Sec.curFragList()->Tail->getLayoutOrder() + 1;
1296+
uint64_t OldSize = getSectionAddressSize(Sec);
1297+
do {
1298+
uint64_t Offset = 0;
1299+
Changed = false;
1300+
if (LLVM_UNLIKELY(isBundlingEnabled())) {
1301+
MCFragment *Prev = nullptr;
1302+
for (MCFragment &F : Sec) {
1303+
F.Offset = Offset;
1304+
relaxFragment(F);
1305+
if (F.hasInstructions()) {
1306+
layoutBundle(Prev, &F);
1307+
Offset = F.Offset;
1308+
}
1309+
Prev = &F;
1310+
if (F.Offset != Offset) {
1311+
F.Offset = Offset;
1312+
Changed = true;
1313+
}
1314+
Offset += computeFragmentSize(F);
1315+
}
1316+
} else {
1317+
for (MCFragment &F : Sec) {
1318+
if (F.Offset != Offset) {
1319+
F.Offset = Offset;
1320+
Changed = true;
1321+
}
1322+
relaxFragment(F);
1323+
Offset += computeFragmentSize(F);
1324+
}
1325+
}
1326+
1327+
Changed |= OldSize != Offset;
1328+
ChangedAny |= Changed;
1329+
OldSize = Offset;
1330+
} while (Changed && --MaxIter);
1331+
if (MaxIter == 0)
1332+
return false;
1333+
}
1334+
return ChangedAny;
13091335
}
13101336

13111337
#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;

0 commit comments

Comments
 (0)