mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
[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.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user