1//===- llvm/IR/OptBisect/Bisect.cpp - LLVM Bisect support -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// This file implements support for a bisecting optimizations based on a
11/// command line option.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/IR/OptBisect.h"
16#include "llvm/ADT/StringExtras.h"
17#include "llvm/Pass.h"
18#include "llvm/Support/CommandLine.h"
19#include "llvm/Support/IntegerInclusiveInterval.h"
20#include "llvm/Support/raw_ostream.h"
21#include <cassert>
22#include <cstdlib>
23
24using namespace llvm;
25
26static OptBisect &getOptBisector() {
27 static OptBisect OptBisector;
28 return OptBisector;
29}
30
31static cl::opt<int> OptBisectLimit(
32 "opt-bisect-limit", cl::Hidden, cl::init(Val: -1), cl::Optional,
33 cl::cb<void, int>([](int Limit) {
34 if (Limit == -1)
35 // -1 means run all passes.
36 getOptBisector().setIntervals({{1, std::numeric_limits<int>::max()}});
37 else if (Limit == 0)
38 // 0 means run no passes.
39 getOptBisector().setIntervals({{0, 0}});
40 else if (Limit > 0)
41 // Convert limit to interval 1-Limit.
42 getOptBisector().setIntervals({{1, Limit}});
43 else
44 llvm_unreachable(
45 ("Invalid limit for -opt-bisect-limit: " + llvm::utostr(Limit))
46 .c_str());
47 }),
48 cl::desc(
49 "Maximum optimization to perform (equivalent to -opt-bisect=1-N)"));
50
51static cl::opt<std::string> OptBisectIntervals(
52 "opt-bisect", cl::Hidden, cl::Optional,
53 cl::cb<void, const std::string &>([](const std::string &IntervalStr) {
54 if (IntervalStr == "-1") {
55 // -1 means run all passes.
56 getOptBisector().setIntervals({{1, std::numeric_limits<int>::max()}});
57 return;
58 }
59
60 auto Intervals =
61 IntegerInclusiveIntervalUtils::parseIntervals(IntervalStr);
62 if (!Intervals) {
63 handleAllErrors(E: Intervals.takeError(), Handlers: [&](const StringError &E) {
64 errs() << "Error: Invalid interval specification for -opt-bisect: "
65 << IntervalStr << " (" << E.getMessage() << ")\n";
66 });
67 exit(status: 1);
68 }
69 getOptBisector().setIntervals(std::move(*Intervals));
70 }),
71 cl::desc("Run optimization passes only for the specified intervals. "
72 "Format: '1-10,20-30,45' runs passes 1-10, 20-30, and 45, where "
73 "index 1 is the first pass. Supply '0' to run no passes and -1 to "
74 "run all passes."));
75
76static cl::opt<bool> OptBisectVerbose(
77 "opt-bisect-verbose",
78 cl::desc(
79 "Show verbose output when opt-bisect-limit and/or opt-disable are set"),
80 cl::Hidden, cl::init(Val: true), cl::Optional);
81
82static cl::list<std::string> OptDisablePasses(
83 "opt-disable", cl::Hidden, cl::CommaSeparated, cl::Optional,
84 cl::cb<void, std::string>([](const std::string &Pass) {
85 getOptBisector().setDisabled(Pass);
86 }),
87 cl::desc("Optimization pass(es) to disable (comma-separated list)"));
88
89static void printPassMessage(StringRef Name, int PassNum, StringRef TargetDesc,
90 bool Running) {
91 StringRef Status = Running ? "" : "NOT ";
92 errs() << "BISECT: " << Status << "running pass (" << PassNum << ") " << Name
93 << " on " << TargetDesc << '\n';
94}
95
96bool OptBisect::shouldRunPass(StringRef PassName,
97 StringRef IRDescription) const {
98 assert(isEnabled());
99
100 int CurBisectNum = ++LastBisectNum;
101
102 // Check if current pass number falls within any of the specified intervals.
103 // Since the bisector may be enabled by opt-disable, we also need to check if
104 // the BisectIntervals are empty.
105 bool ShouldRun =
106 BisectIntervals.empty() ||
107 IntegerInclusiveIntervalUtils::contains(Intervals: BisectIntervals, Value: CurBisectNum);
108
109 // Also check if the pass is disabled via -opt-disable.
110 ShouldRun = ShouldRun && !DisabledPasses.contains(key: PassName);
111
112 if (OptBisectVerbose)
113 printPassMessage(Name: PassName, PassNum: CurBisectNum, TargetDesc: IRDescription, Running: ShouldRun);
114 return ShouldRun;
115}
116
117OptPassGate &llvm::getGlobalPassGate() { return getOptBisector(); }
118