summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaschalis Mpeis <paschalis.mpeis@arm.com>2025-10-03 09:13:09 +0100
committerGitHub <noreply@github.com>2025-10-03 09:13:09 +0100
commit224a7176dc6afaec83bfcfdb7542d30a130997cc (patch)
treef1907e02febcc0e975d6f23750dd1ffff93160bb
parent19cd5bd350b730da35629de5095764861f70ecee (diff)
[BOLT][AArch64] Refuse to run CDSplit pass (#159351)
LongJmp does not support warm blocks. On builds without assertions, this may lead to unexpected crashes. This patch exits with a clear message.
-rw-r--r--bolt/include/bolt/Passes/SplitFunctions.h19
-rw-r--r--bolt/include/bolt/Utils/CommandLineOpts.h20
-rw-r--r--bolt/lib/Passes/LongJmp.cpp4
-rw-r--r--bolt/lib/Passes/SplitFunctions.cpp35
-rw-r--r--bolt/lib/Rewrite/RewriteInstance.cpp7
-rw-r--r--bolt/lib/Utils/CommandLineOpts.cpp23
-rw-r--r--bolt/test/AArch64/unsupported-passes.test7
7 files changed, 65 insertions, 50 deletions
diff --git a/bolt/include/bolt/Passes/SplitFunctions.h b/bolt/include/bolt/Passes/SplitFunctions.h
index 8bdc48b68eb7..2c1bf1890cd9 100644
--- a/bolt/include/bolt/Passes/SplitFunctions.h
+++ b/bolt/include/bolt/Passes/SplitFunctions.h
@@ -18,25 +18,6 @@
namespace llvm {
namespace bolt {
-/// Strategy used to partition blocks into fragments.
-enum SplitFunctionsStrategy : char {
- /// Split each function into a hot and cold fragment using profiling
- /// information.
- Profile2 = 0,
- /// Split each function into a hot, warm, and cold fragment using
- /// profiling information.
- CDSplit,
- /// Split each function into a hot and cold fragment at a randomly chosen
- /// split point (ignoring any available profiling information).
- Random2,
- /// Split each function into N fragments at a randomly chosen split points
- /// (ignoring any available profiling information).
- RandomN,
- /// Split all basic blocks of each function into fragments such that each
- /// fragment contains exactly a single basic block.
- All
-};
-
class SplitStrategy {
public:
using BlockIt = BinaryFunction::BasicBlockOrderType::iterator;
diff --git a/bolt/include/bolt/Utils/CommandLineOpts.h b/bolt/include/bolt/Utils/CommandLineOpts.h
index 859d6f3bf677..0964c2c9d847 100644
--- a/bolt/include/bolt/Utils/CommandLineOpts.h
+++ b/bolt/include/bolt/Utils/CommandLineOpts.h
@@ -29,6 +29,25 @@ enum HeatmapModeKind {
HM_Optional // perf2bolt --heatmap
};
+/// Strategy used to partition blocks into fragments.
+enum SplitFunctionsStrategy : char {
+ /// Split each function into a hot and cold fragment using profiling
+ /// information.
+ Profile2 = 0,
+ /// Split each function into a hot, warm, and cold fragment using
+ /// profiling information.
+ CDSplit,
+ /// Split each function into a hot and cold fragment at a randomly chosen
+ /// split point (ignoring any available profiling information).
+ Random2,
+ /// Split each function into N fragments at a randomly chosen split points
+ /// (ignoring any available profiling information).
+ RandomN,
+ /// Split all basic blocks of each function into fragments such that each
+ /// fragment contains exactly a single basic block.
+ All
+};
+
using HeatmapBlockSizes = std::vector<unsigned>;
struct HeatmapBlockSpecParser : public llvm::cl::parser<HeatmapBlockSizes> {
explicit HeatmapBlockSpecParser(llvm::cl::Option &O)
@@ -78,6 +97,7 @@ extern llvm::cl::opt<std::string> OutputFilename;
extern llvm::cl::opt<std::string> PerfData;
extern llvm::cl::opt<bool> PrintCacheMetrics;
extern llvm::cl::opt<bool> PrintSections;
+extern llvm::cl::opt<SplitFunctionsStrategy> SplitStrategy;
// The format to use with -o in aggregation mode (perf2bolt)
enum ProfileFormatKind { PF_Fdata, PF_YAML };
diff --git a/bolt/lib/Passes/LongJmp.cpp b/bolt/lib/Passes/LongJmp.cpp
index 4dade161cc23..03c1ea9d837e 100644
--- a/bolt/lib/Passes/LongJmp.cpp
+++ b/bolt/lib/Passes/LongJmp.cpp
@@ -895,6 +895,10 @@ void LongJmpPass::relaxLocalBranches(BinaryFunction &BF) {
Error LongJmpPass::runOnFunctions(BinaryContext &BC) {
+ assert((opts::CompactCodeModel ||
+ opts::SplitStrategy != opts::SplitFunctionsStrategy::CDSplit) &&
+ "LongJmp cannot work with functions split in more than two fragments");
+
if (opts::CompactCodeModel) {
BC.outs()
<< "BOLT-INFO: relaxing branches for compact code model (<128MB)\n";
diff --git a/bolt/lib/Passes/SplitFunctions.cpp b/bolt/lib/Passes/SplitFunctions.cpp
index b21401e069bf..eab669b32b71 100644
--- a/bolt/lib/Passes/SplitFunctions.cpp
+++ b/bolt/lib/Passes/SplitFunctions.cpp
@@ -86,29 +86,6 @@ static cl::opt<unsigned> SplitThreshold(
"increase after splitting."),
cl::init(0), cl::Hidden, cl::cat(BoltOptCategory));
-static cl::opt<SplitFunctionsStrategy> SplitStrategy(
- "split-strategy", cl::init(SplitFunctionsStrategy::Profile2),
- cl::values(clEnumValN(SplitFunctionsStrategy::Profile2, "profile2",
- "split each function into a hot and cold fragment "
- "using profiling information")),
- cl::values(clEnumValN(SplitFunctionsStrategy::CDSplit, "cdsplit",
- "split each function into a hot, warm, and cold "
- "fragment using profiling information")),
- cl::values(clEnumValN(
- SplitFunctionsStrategy::Random2, "random2",
- "split each function into a hot and cold fragment at a randomly chosen "
- "split point (ignoring any available profiling information)")),
- cl::values(clEnumValN(
- SplitFunctionsStrategy::RandomN, "randomN",
- "split each function into N fragments at a randomly chosen split "
- "points (ignoring any available profiling information)")),
- cl::values(clEnumValN(
- SplitFunctionsStrategy::All, "all",
- "split all basic blocks of each function into fragments such that each "
- "fragment contains exactly a single basic block")),
- cl::desc("strategy used to partition blocks into fragments"),
- cl::cat(BoltOptCategory));
-
static cl::opt<double> CallScale(
"call-scale",
cl::desc("Call score scale coefficient (when --split-strategy=cdsplit)"),
@@ -724,14 +701,14 @@ Error SplitFunctions::runOnFunctions(BinaryContext &BC) {
// If split strategy is not CDSplit, then a second run of the pass is not
// needed after function reordering.
if (BC.HasFinalizedFunctionOrder &&
- opts::SplitStrategy != SplitFunctionsStrategy::CDSplit)
+ opts::SplitStrategy != opts::SplitFunctionsStrategy::CDSplit)
return Error::success();
std::unique_ptr<SplitStrategy> Strategy;
bool ForceSequential = false;
switch (opts::SplitStrategy) {
- case SplitFunctionsStrategy::CDSplit:
+ case opts::SplitFunctionsStrategy::CDSplit:
// CDSplit runs two splitting passes: hot-cold splitting (SplitPrfoile2)
// before function reordering and hot-warm-cold splitting
// (SplitCacheDirected) after function reordering.
@@ -742,21 +719,21 @@ Error SplitFunctions::runOnFunctions(BinaryContext &BC) {
opts::AggressiveSplitting = true;
BC.HasWarmSection = true;
break;
- case SplitFunctionsStrategy::Profile2:
+ case opts::SplitFunctionsStrategy::Profile2:
Strategy = std::make_unique<SplitProfile2>();
break;
- case SplitFunctionsStrategy::Random2:
+ case opts::SplitFunctionsStrategy::Random2:
Strategy = std::make_unique<SplitRandom2>();
// If we split functions randomly, we need to ensure that across runs with
// the same input, we generate random numbers for each function in the same
// order.
ForceSequential = true;
break;
- case SplitFunctionsStrategy::RandomN:
+ case opts::SplitFunctionsStrategy::RandomN:
Strategy = std::make_unique<SplitRandomN>();
ForceSequential = true;
break;
- case SplitFunctionsStrategy::All:
+ case opts::SplitFunctionsStrategy::All:
Strategy = std::make_unique<SplitAll>();
break;
}
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 8a25d0b90fa9..bfd03e01db98 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -2115,6 +2115,13 @@ void RewriteInstance::adjustCommandLineOptions() {
opts::SplitEH = false;
}
+ if (BC->isAArch64() && !opts::CompactCodeModel &&
+ opts::SplitStrategy == opts::SplitFunctionsStrategy::CDSplit) {
+ BC->errs() << "BOLT-ERROR: CDSplit is not supported with LongJmp. Try with "
+ "'--compact-code-model'\n";
+ exit(1);
+ }
+
if (opts::StrictMode && !BC->HasRelocations) {
BC->errs()
<< "BOLT-WARNING: disabling strict mode (-strict) in non-relocation "
diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp
index 5635da476451..095612ac3a4a 100644
--- a/bolt/lib/Utils/CommandLineOpts.cpp
+++ b/bolt/lib/Utils/CommandLineOpts.cpp
@@ -104,6 +104,29 @@ ExecutionCountThreshold("execution-count-threshold",
cl::Hidden,
cl::cat(BoltOptCategory));
+cl::opt<SplitFunctionsStrategy> SplitStrategy(
+ "split-strategy", cl::init(SplitFunctionsStrategy::Profile2),
+ cl::values(clEnumValN(SplitFunctionsStrategy::Profile2, "profile2",
+ "split each function into a hot and cold fragment "
+ "using profiling information")),
+ cl::values(clEnumValN(SplitFunctionsStrategy::CDSplit, "cdsplit",
+ "split each function into a hot, warm, and cold "
+ "fragment using profiling information")),
+ cl::values(clEnumValN(
+ SplitFunctionsStrategy::Random2, "random2",
+ "split each function into a hot and cold fragment at a randomly chosen "
+ "split point (ignoring any available profiling information)")),
+ cl::values(clEnumValN(
+ SplitFunctionsStrategy::RandomN, "randomN",
+ "split each function into N fragments at a randomly chosen split "
+ "points (ignoring any available profiling information)")),
+ cl::values(clEnumValN(
+ SplitFunctionsStrategy::All, "all",
+ "split all basic blocks of each function into fragments such that each "
+ "fragment contains exactly a single basic block")),
+ cl::desc("strategy used to partition blocks into fragments"),
+ cl::cat(BoltOptCategory));
+
bool HeatmapBlockSpecParser::parse(cl::Option &O, StringRef ArgName,
StringRef Arg, HeatmapBlockSizes &Val) {
// Parses a human-readable suffix into a shift amount or nullopt on error.
diff --git a/bolt/test/AArch64/unsupported-passes.test b/bolt/test/AArch64/unsupported-passes.test
index 886fc1c574dc..5b12d86500ee 100644
--- a/bolt/test/AArch64/unsupported-passes.test
+++ b/bolt/test/AArch64/unsupported-passes.test
@@ -3,6 +3,9 @@
// REQUIRES: system-linux,asserts,target=aarch64{{.*}}
RUN: %clang %cflags %p/../Inputs/hello.c -o %t -Wl,-q
-RUN: not llvm-bolt %t -o %t.bolt --frame-opt=all 2>&1 | FileCheck %s
+RUN: not llvm-bolt %t -o %t.bolt --frame-opt=all 2>&1 | FileCheck %s --check-prefix=CHECK-FRAME-OPT
-CHECK: BOLT-ERROR: frame-optimizer is supported only on X86
+CHECK-FRAME-OPT: BOLT-ERROR: frame-optimizer is supported only on X86
+
+RUN: not llvm-bolt %t -o %t.bolt split-functions --split-strategy=cdsplit 2>&1 | FileCheck %s --check-prefix=CHECK-CDSPLIT
+CHECK-CDSPLIT: BOLT-ERROR: CDSplit is not supported with LongJmp. Try with '--compact-code-model'