| 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 | |
| 24 | using namespace llvm; |
| 25 | |
| 26 | static OptBisect &getOptBisector() { |
| 27 | static OptBisect OptBisector; |
| 28 | return OptBisector; |
| 29 | } |
| 30 | |
| 31 | static 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 | |
| 51 | static 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 | |
| 76 | static 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 | |
| 82 | static 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 | |
| 89 | static 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 | |
| 96 | bool 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 | |
| 117 | OptPassGate &llvm::getGlobalPassGate() { return getOptBisector(); } |
| 118 | |