Skip to content

Commit 1f3d8cb

Browse files
authored
[BOLT] Route alignment options through BinaryContext (NFC) (#204902)
Consolidate all alignment-related `cl::opt` definitions into `CommandLineOpts.cpp`, expose matching public members on `BinaryContext`, and populate them from `RewriteInstance::adjustCommandLineOptions` (and mirrored in `MachORewriteInstance`). Switch all readers in Aligner, BinaryEmitter, LongJmp, BinaryFunction and the use-old-text logs to `BC.*` instead of `opts::*`.
1 parent 60b4854 commit 1f3d8cb

9 files changed

Lines changed: 120 additions & 85 deletions

File tree

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,22 @@ class BinaryContext {
816816
std::atomic<uint16_t> MaxMainCodeAlignment{1};
817817
std::atomic<uint16_t> MaxColdCodeAlignment{1};
818818

819+
/// Alignment-related options sourced from CommandLineOpts. Populated by
820+
/// RewriteInstance::adjustCommandLineOptions() so passes and the emitter
821+
/// can read them via BinaryContext instead of touching opts::* directly.
822+
/// Defaults must stay in sync with the cl::init values in
823+
/// bolt/lib/Utils/CommandLineOpts.cpp.
824+
unsigned AlignText{0};
825+
unsigned AlignFunctions{64};
826+
unsigned AlignBlocksMinSize{0};
827+
unsigned AlignBlocksThreshold{800};
828+
unsigned AlignFunctionsMaxBytes{32};
829+
unsigned BlockAlignment{16};
830+
bool AlignBlocks{false};
831+
bool PreserveBlocksAlignment{false};
832+
bool UseCompactAligner{true};
833+
bool X86AlignBranchBoundaryHotOnly{true};
834+
819835
/// Fold \p Alignment into the running max for the main code section (when
820836
/// \p InMainSection) and/or the cold code section (when \p InColdSection),
821837
/// reflecting which output section(s) the object is emitted into. Safe to

bolt/include/bolt/Utils/CommandLineOpts.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ extern llvm::cl::OptionCategory BinaryAnalysisCategory;
7272

7373
extern llvm::cl::opt<unsigned> AlignText;
7474
extern llvm::cl::opt<unsigned> AlignFunctions;
75+
extern llvm::cl::opt<bool> AlignBlocks;
76+
extern llvm::cl::opt<unsigned> AlignBlocksMinSize;
77+
extern llvm::cl::opt<unsigned> AlignBlocksThreshold;
78+
extern llvm::cl::opt<unsigned> AlignFunctionsMaxBytes;
79+
extern llvm::cl::opt<unsigned> BlockAlignment;
80+
extern llvm::cl::opt<bool> PreserveBlocksAlignment;
81+
extern llvm::cl::opt<bool> UseCompactAligner;
82+
extern llvm::cl::opt<bool> X86AlignBranchBoundaryHotOnly;
7583
extern llvm::cl::opt<bool> AggregateOnly;
7684
extern llvm::cl::opt<bool> ArmSPE;
7785
extern llvm::cl::opt<unsigned> BucketsPerLine;

bolt/lib/Core/BinaryEmitter.cpp

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ using namespace bolt;
3333
namespace opts {
3434

3535
extern cl::opt<JumpTableSupportLevel> JumpTables;
36-
extern cl::opt<bool> PreserveBlocksAlignment;
37-
38-
cl::opt<bool> AlignBlocks("align-blocks", cl::desc("align basic blocks"),
39-
cl::cat(BoltOptCategory));
4036

4137
static cl::list<std::string>
4238
BreakFunctionNames("break-funcs",
@@ -68,12 +64,6 @@ static cl::opt<bool> PrintJumpTables("print-jump-tables",
6864
cl::desc("print jump tables"), cl::Hidden,
6965
cl::cat(BoltCategory));
7066

71-
static cl::opt<bool>
72-
X86AlignBranchBoundaryHotOnly("x86-align-branch-boundary-hot-only",
73-
cl::desc("only apply branch boundary alignment in hot code"),
74-
cl::init(true),
75-
cl::cat(BoltOptCategory));
76-
7767
size_t padFunction(std::map<std::string, size_t> &FunctionPadding,
7868
const cl::list<std::string> &Spec,
7969
const BinaryFunction &Function) {
@@ -214,7 +204,7 @@ void BinaryEmitter::emitAll(StringRef OrgSecPrefix) {
214204
if (RuntimeLibrary *RtLibrary = BC.getRuntimeLibrary())
215205
RtLibrary->emitBinary(BC, Streamer);
216206

217-
BC.getTextSection()->setAlignment(Align(opts::AlignText));
207+
BC.getTextSection()->setAlignment(Align(BC.AlignText));
218208

219209
emitFunctions();
220210

@@ -246,15 +236,15 @@ void BinaryEmitter::emitFunctions() {
246236
bool Emitted = false;
247237

248238
// Turn off Intel JCC Erratum mitigation for cold code if requested
249-
if (HasProfile && opts::X86AlignBranchBoundaryHotOnly &&
239+
if (HasProfile && BC.X86AlignBranchBoundaryHotOnly &&
250240
!Function->hasValidProfile())
251241
Streamer.setAllowAutoPadding(false);
252242

253243
FunctionLayout &Layout = Function->getLayout();
254244
Emitted |= emitFunction(*Function, Layout.getMainFragment());
255245

256246
if (Function->isSplit()) {
257-
if (opts::X86AlignBranchBoundaryHotOnly)
247+
if (BC.X86AlignBranchBoundaryHotOnly)
258248
Streamer.setAllowAutoPadding(false);
259249

260250
assert((Layout.fragment_size() == 1 || Function->isSimple()) &&
@@ -317,7 +307,7 @@ bool BinaryEmitter::emitFunction(BinaryFunction &Function,
317307
// Set section alignment to at least maximum possible object alignment.
318308
// We need this to support LongJmp and other passes that calculates
319309
// tentative layout.
320-
Section->ensureMinAlignment(Align(opts::AlignFunctions));
310+
Section->ensureMinAlignment(Align(BC.AlignFunctions));
321311

322312
Streamer.emitCodeAlignment(Function.getMinAlign(), *BC.STI);
323313
uint16_t MaxAlignBytes = FF.isSplitFragment()
@@ -457,7 +447,7 @@ void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, FunctionFragment &FF,
457447
// Track the first emitted instruction with debug info.
458448
bool FirstInstr = true;
459449
for (BinaryBasicBlock *const BB : FF) {
460-
if ((opts::AlignBlocks || opts::PreserveBlocksAlignment) &&
450+
if ((BC.AlignBlocks || BC.PreserveBlocksAlignment) &&
461451
BB->getAlignment() > 1)
462452
Streamer.emitCodeAlignment(BB->getAlign(), *BC.STI,
463453
BB->getAlignmentMaxBytes());

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,6 @@ static cl::opt<bool> NoScan(
111111
"slower binary)"),
112112
cl::Hidden, cl::cat(BoltOptCategory));
113113

114-
cl::opt<bool>
115-
PreserveBlocksAlignment("preserve-blocks-alignment",
116-
cl::desc("try to preserve basic block alignment"),
117-
cl::cat(BoltOptCategory));
118-
119114
static cl::opt<bool> PrintOutputAddressRange(
120115
"print-output-address-range",
121116
cl::desc(
@@ -2351,7 +2346,7 @@ Error BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) {
23512346
// Always create new BB at branch destination.
23522347
PrevBB = InsertBB ? InsertBB : PrevBB;
23532348
InsertBB = addBasicBlockAt(LI->first, LI->second);
2354-
if (opts::PreserveBlocksAlignment && IsLastInstrNop)
2349+
if (BC.PreserveBlocksAlignment && IsLastInstrNop)
23552350
InsertBB->setDerivedAlignment();
23562351

23572352
if (PrevBB)
@@ -2388,7 +2383,7 @@ Error BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) {
23882383
Label = BC.Ctx->createNamedTempSymbol("FT");
23892384
}
23902385
InsertBB = addBasicBlockAt(Offset, Label);
2391-
if (opts::PreserveBlocksAlignment && IsLastInstrNop)
2386+
if (BC.PreserveBlocksAlignment && IsLastInstrNop)
23922387
InsertBB->setDerivedAlignment();
23932388
updateOffset(LastInstrOffset);
23942389
}

bolt/lib/Passes/Aligner.cpp

Lines changed: 14 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -17,54 +17,16 @@
1717

1818
using namespace llvm;
1919

20-
namespace opts {
21-
22-
extern cl::OptionCategory BoltOptCategory;
23-
24-
extern cl::opt<bool> AlignBlocks;
25-
extern cl::opt<bool> PreserveBlocksAlignment;
26-
extern cl::opt<unsigned> AlignFunctions;
27-
28-
static cl::opt<unsigned> AlignBlocksMinSize(
29-
"align-blocks-min-size",
30-
cl::desc("minimal size of the basic block that should be aligned"),
31-
cl::init(0), cl::ZeroOrMore, cl::Hidden, cl::cat(BoltOptCategory));
32-
33-
static cl::opt<unsigned> AlignBlocksThreshold(
34-
"align-blocks-threshold",
35-
cl::desc(
36-
"align only blocks with frequency larger than containing function "
37-
"execution frequency specified in percent. E.g. 1000 means aligning "
38-
"blocks that are 10 times more frequently executed than the "
39-
"containing function."),
40-
cl::init(800), cl::Hidden, cl::cat(BoltOptCategory));
41-
42-
static cl::opt<unsigned> AlignFunctionsMaxBytes(
43-
"align-functions-max-bytes",
44-
cl::desc("maximum number of bytes to use to align functions"), cl::init(32),
45-
cl::cat(BoltOptCategory));
46-
47-
static cl::opt<unsigned>
48-
BlockAlignment("block-alignment",
49-
cl::desc("boundary to use for alignment of basic blocks"),
50-
cl::init(16), cl::ZeroOrMore, cl::cat(BoltOptCategory));
51-
52-
static cl::opt<bool>
53-
UseCompactAligner("use-compact-aligner",
54-
cl::desc("Use compact approach for aligning functions"),
55-
cl::init(true), cl::cat(BoltOptCategory));
56-
57-
} // end namespace opts
58-
5920
namespace llvm {
6021
namespace bolt {
6122

6223
// Align function to the specified byte-boundary (typically, 64) offsetting
6324
// the function by not more than the corresponding value
6425
static void alignMaxBytes(BinaryFunction &Function) {
65-
Function.setAlignment(opts::AlignFunctions);
66-
Function.setMaxAlignmentBytes(opts::AlignFunctionsMaxBytes);
67-
Function.setMaxColdAlignmentBytes(opts::AlignFunctionsMaxBytes);
26+
const BinaryContext &BC = Function.getBinaryContext();
27+
Function.setAlignment(BC.AlignFunctions);
28+
Function.setMaxAlignmentBytes(BC.AlignFunctionsMaxBytes);
29+
Function.setMaxColdAlignmentBytes(BC.AlignFunctionsMaxBytes);
6830
}
6931

7032
// Align function to the specified byte-boundary (typically, 64) offsetting
@@ -90,16 +52,16 @@ static void alignCompact(BinaryFunction &Function,
9052
else
9153
HotSize += BC.computeCodeSize(BB.begin(), BB.end(), Emitter);
9254

93-
Function.setAlignment(opts::AlignFunctions);
55+
Function.setAlignment(BC.AlignFunctions);
9456
if (HotSize > 0)
9557
Function.setMaxAlignmentBytes(
96-
std::min(size_t(opts::AlignFunctionsMaxBytes), HotSize));
58+
std::min(size_t(BC.AlignFunctionsMaxBytes), HotSize));
9759

9860
// using the same option, max-align-bytes, both for cold and hot parts of the
9961
// functions, as aligning cold functions typically does not affect performance
10062
if (ColdSize > 0)
10163
Function.setMaxColdAlignmentBytes(
102-
std::min(size_t(opts::AlignFunctionsMaxBytes), ColdSize));
64+
std::min(size_t(BC.AlignFunctionsMaxBytes), ColdSize));
10365
}
10466

10567
void AlignerPass::alignBlocks(BinaryFunction &Function,
@@ -115,7 +77,7 @@ void AlignerPass::alignBlocks(BinaryFunction &Function,
11577
for (BinaryBasicBlock *BB : Function.getLayout().blocks()) {
11678
uint64_t Count = BB->getKnownExecutionCount();
11779

118-
if (Count <= FuncCount * opts::AlignBlocksThreshold / 100) {
80+
if (Count <= FuncCount * BC.AlignBlocksThreshold / 100) {
11981
PrevBB = BB;
12082
continue;
12183
}
@@ -132,12 +94,12 @@ void AlignerPass::alignBlocks(BinaryFunction &Function,
13294
const uint64_t BlockSize =
13395
BC.computeCodeSize(BB->begin(), BB->end(), Emitter);
13496
const uint64_t BytesToUse =
135-
std::min<uint64_t>(opts::BlockAlignment - 1, BlockSize);
97+
std::min<uint64_t>(BC.BlockAlignment - 1, BlockSize);
13698

137-
if (opts::AlignBlocksMinSize && BlockSize < opts::AlignBlocksMinSize)
99+
if (BC.AlignBlocksMinSize && BlockSize < BC.AlignBlocksMinSize)
138100
continue;
139101

140-
BB->setAlignment(opts::BlockAlignment);
102+
BB->setAlignment(BC.BlockAlignment);
141103
BB->setAlignmentMaxBytes(BytesToUse);
142104

143105
// Update stats.
@@ -153,14 +115,14 @@ Error AlignerPass::runOnFunctions(BinaryContext &BC) {
153115
if (!BC.HasRelocations)
154116
return Error::success();
155117

156-
AlignHistogram.resize(opts::BlockAlignment);
118+
AlignHistogram.resize(BC.BlockAlignment);
157119

158120
ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
159121
// Create a separate MCCodeEmitter to allow lock free execution
160122
BinaryContext::IndependentCodeEmitter Emitter =
161123
BC.createIndependentMCCodeEmitter();
162124

163-
if (opts::UseCompactAligner)
125+
if (BC.UseCompactAligner)
164126
alignCompact(BF, Emitter.MCE.get());
165127
else
166128
alignMaxBytes(BF);
@@ -185,7 +147,7 @@ Error AlignerPass::runOnFunctions(BinaryContext &BC) {
185147
BC.getColdCodeSectionName();
186148
BC.updateMaxCodeAlignment(Align, InMainSection, InColdSection);
187149

188-
if (opts::AlignBlocks && !opts::PreserveBlocksAlignment)
150+
if (BC.AlignBlocks && !BC.PreserveBlocksAlignment)
189151
alignBlocks(BF, Emitter.MCE.get());
190152
};
191153

bolt/lib/Passes/LongJmp.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ using namespace llvm;
2222
namespace opts {
2323
extern cl::OptionCategory BoltCategory;
2424
extern cl::OptionCategory BoltOptCategory;
25-
extern llvm::cl::opt<unsigned> AlignText;
26-
extern cl::opt<unsigned> AlignFunctions;
2725
extern cl::opt<bool> UseOldText;
2826
extern cl::opt<bool> HotFunctionsAtEnd;
2927

@@ -318,7 +316,7 @@ uint64_t LongJmpPass::tentativeLayoutRelocColdPart(
318316
const BinaryContext &BC, BinaryFunctionListType &SortedFunctions,
319317
uint64_t DotAddress) {
320318
DotAddress =
321-
alignTo(DotAddress, std::max<uint64_t>(opts::AlignFunctions,
319+
alignTo(DotAddress, std::max<uint64_t>(BC.AlignFunctions,
322320
BC.MaxColdCodeAlignment.load()));
323321
for (BinaryFunction *Func : SortedFunctions) {
324322
if (!Func->isSplit())
@@ -375,11 +373,11 @@ LongJmpPass::tentativeLayoutRelocMode(const BinaryContext &BC,
375373
// after the last non-cold section. Account for it before assigning cold
376374
// fragment addresses so range checks see the hot-to-cold gap.
377375
if (opts::Hugify && !BC.HasFixedLoadAddress && !opts::HotFunctionsAtEnd)
378-
DotAddress = alignTo(DotAddress, opts::AlignText);
376+
DotAddress = alignTo(DotAddress, BC.AlignText);
379377
DotAddress = tentativeLayoutRelocColdPart(BC, SortedFunctions, DotAddress);
380378
ColdLayoutDone = true;
381379
if (opts::HotFunctionsAtEnd)
382-
DotAddress = alignTo(DotAddress, opts::AlignText);
380+
DotAddress = alignTo(DotAddress, BC.AlignText);
383381
};
384382
for (BinaryFunction *Func : SortedFunctions) {
385383
if (!BC.shouldEmit(*Func)) {
@@ -446,8 +444,7 @@ void LongJmpPass::tentativeLayout(const BinaryContext &BC,
446444
// Initial padding
447445
if (EstimatedTextSize <= BC.OldTextSectionSize) {
448446
DotAddress = BC.OldTextSectionAddress;
449-
uint64_t Pad =
450-
offsetToAlignment(DotAddress, llvm::Align(opts::AlignText));
447+
uint64_t Pad = offsetToAlignment(DotAddress, llvm::Align(BC.AlignText));
451448
if (Pad + EstimatedTextSize <= BC.OldTextSectionSize) {
452449
DotAddress += Pad;
453450
}
@@ -456,7 +453,7 @@ void LongJmpPass::tentativeLayout(const BinaryContext &BC,
456453

457454
if (!EstimatedTextSize || EstimatedTextSize > BC.OldTextSectionSize) {
458455
uint64_t TextAlign =
459-
std::max<uint64_t>(opts::AlignText, BC.MaxMainCodeAlignment.load());
456+
std::max<uint64_t>(BC.AlignText, BC.MaxMainCodeAlignment.load());
460457
DotAddress = alignTo(BC.LayoutStartAddress, TextAlign);
461458
}
462459

bolt/lib/Rewrite/MachORewriteInstance.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
namespace opts {
3333

3434
using namespace llvm;
35-
extern cl::opt<unsigned> AlignText;
3635
// FIXME! Upstream change
3736
// extern cl::opt<bool> CheckOverlappingElements;
3837
extern cl::opt<bool> Instrument;
@@ -557,6 +556,19 @@ void MachORewriteInstance::adjustCommandLineOptions() {
557556
opts::JumpTables = JTS_MOVE;
558557
opts::InstrumentCalls = false;
559558
opts::RuntimeInstrumentationLib = "libbolt_rt_instr_osx.a";
559+
560+
// Mirror alignment-related command line options onto BinaryContext so passes
561+
// and the emitter can read them via BC instead of touching opts::*.
562+
BC->AlignText = opts::AlignText;
563+
BC->AlignFunctions = opts::AlignFunctions;
564+
BC->AlignBlocks = opts::AlignBlocks;
565+
BC->AlignBlocksMinSize = opts::AlignBlocksMinSize;
566+
BC->AlignBlocksThreshold = opts::AlignBlocksThreshold;
567+
BC->AlignFunctionsMaxBytes = opts::AlignFunctionsMaxBytes;
568+
BC->BlockAlignment = opts::BlockAlignment;
569+
BC->PreserveBlocksAlignment = opts::PreserveBlocksAlignment;
570+
BC->UseCompactAligner = opts::UseCompactAligner;
571+
BC->X86AlignBranchBoundaryHotOnly = opts::X86AlignBranchBoundaryHotOnly;
560572
}
561573

562574
void MachORewriteInstance::run() {

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2447,6 +2447,19 @@ void RewriteInstance::adjustCommandLineOptions() {
24472447
if (opts::AlignText < opts::AlignFunctions)
24482448
opts::AlignText = (unsigned)opts::AlignFunctions;
24492449

2450+
// Mirror alignment-related command line options onto BinaryContext so passes
2451+
// and the emitter can read them via BC instead of touching opts::*.
2452+
BC->AlignText = opts::AlignText;
2453+
BC->AlignFunctions = opts::AlignFunctions;
2454+
BC->AlignBlocks = opts::AlignBlocks;
2455+
BC->AlignBlocksMinSize = opts::AlignBlocksMinSize;
2456+
BC->AlignBlocksThreshold = opts::AlignBlocksThreshold;
2457+
BC->AlignFunctionsMaxBytes = opts::AlignFunctionsMaxBytes;
2458+
BC->BlockAlignment = opts::BlockAlignment;
2459+
BC->PreserveBlocksAlignment = opts::PreserveBlocksAlignment;
2460+
BC->UseCompactAligner = opts::UseCompactAligner;
2461+
BC->X86AlignBranchBoundaryHotOnly = opts::X86AlignBranchBoundaryHotOnly;
2462+
24502463
if (BC->isX86() && opts::Lite.getNumOccurrences() == 0 && !opts::StrictMode &&
24512464
!opts::UseOldText)
24522465
opts::Lite = true;
@@ -4323,15 +4336,15 @@ void RewriteInstance::mapCodeSections(BOLTLinker::SectionMapper MapSection) {
43234336
const uint64_t CodeSize = EndAddress - StartAddress;
43244337
if (CodeSize <= BC->OldTextSectionSize) {
43254338
BC->outs() << "BOLT-INFO: using original .text for new code with 0x"
4326-
<< Twine::utohexstr(opts::AlignText) << " alignment";
4339+
<< Twine::utohexstr(BC->AlignText) << " alignment";
43274340
if (StartAddress != BC->OldTextSectionAddress)
43284341
BC->outs() << " at 0x" << Twine::utohexstr(StartAddress);
43294342
BC->outs() << '\n';
43304343
AllocationDone = true;
43314344
} else {
43324345
BC->errs() << "BOLT-WARNING: --use-old-text failed. The original .text "
43334346
"too small to fit the new code using 0x"
4334-
<< Twine::utohexstr(opts::AlignText) << " alignment. "
4347+
<< Twine::utohexstr(BC->AlignText) << " alignment. "
43354348
<< CodeSize << " bytes needed, have " << BC->OldTextSectionSize
43364349
<< " bytes available. Rebuilding without --use-old-text may "
43374350
"produce a smaller binary\n";

0 commit comments

Comments
 (0)