
This commit adds a new pass gate that allows selective disabling of one or more passes via the clang command line using the `-opt-disable` option. Passes to be disabled should be specified as a comma-separated list of their names. The implementation resides in the same file as the bisection tool. The `getGlobalPassGate()` function returns the currently enabled gate. Example: `-opt-disable="PassA,PassB"` Pass names are matched using case-insensitive comparisons. However, note that special characters, including spaces, must be included exactly as they appear in the pass names. Additionally, a `-opt-disable-enable-verbosity` flag has been introduced to enable verbose output when this functionality is in use. When enabled, it prints the status of all passes (either running or NOT running), similar to the default behavior of `-opt-bisect-limit`. This flag is disabled by default, which is the opposite of the `-opt-bisect-verbose` flag (which defaults to enabled). To validate this functionality, a test file has also been provided. It reuses the same infrastructure as the opt-bisect test, but disables three specific passes and checks the output to ensure the expected behavior. --------- Co-authored-by: Nikita Popov <github@npopov.com>
317 lines
8.9 KiB
C++
317 lines
8.9 KiB
C++
//===- Pass.cpp - LLVM Pass Infrastructure Implementation -----------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the LLVM Pass infrastructure. It is primarily
|
|
// responsible with ensuring that passes are executed and batched together
|
|
// optimally.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Pass.h"
|
|
#include "llvm/Config/llvm-config.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/IRPrintingPasses.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/LegacyPassNameParser.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/OptBisect.h"
|
|
#include "llvm/PassInfo.h"
|
|
#include "llvm/PassRegistry.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <cassert>
|
|
|
|
#ifdef EXPENSIVE_CHECKS
|
|
#include "llvm/IR/StructuralHash.h"
|
|
#endif
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "ir"
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Pass Implementation
|
|
//
|
|
|
|
// Force out-of-line virtual method.
|
|
Pass::~Pass() {
|
|
delete Resolver;
|
|
}
|
|
|
|
// Force out-of-line virtual method.
|
|
ModulePass::~ModulePass() = default;
|
|
|
|
Pass *ModulePass::createPrinterPass(raw_ostream &OS,
|
|
const std::string &Banner) const {
|
|
return createPrintModulePass(OS, Banner);
|
|
}
|
|
|
|
PassManagerType ModulePass::getPotentialPassManagerType() const {
|
|
return PMT_ModulePassManager;
|
|
}
|
|
|
|
static std::string getDescription(const Module &M) {
|
|
return "module (" + M.getName().str() + ")";
|
|
}
|
|
|
|
bool ModulePass::skipModule(const Module &M) const {
|
|
const OptPassGate &Gate = M.getContext().getOptPassGate();
|
|
|
|
StringRef PassName = getPassArgument();
|
|
if (PassName.empty())
|
|
PassName = this->getPassName();
|
|
|
|
return Gate.isEnabled() && !Gate.shouldRunPass(PassName, getDescription(M));
|
|
}
|
|
|
|
bool Pass::mustPreserveAnalysisID(char &AID) const {
|
|
return Resolver->getAnalysisIfAvailable(&AID) != nullptr;
|
|
}
|
|
|
|
// dumpPassStructure - Implement the -debug-pass=Structure option
|
|
void Pass::dumpPassStructure(unsigned Offset) {
|
|
dbgs().indent(Offset*2) << getPassName() << "\n";
|
|
}
|
|
|
|
/// getPassName - Return a nice clean name for a pass. This usually
|
|
/// implemented in terms of the name that is registered by one of the
|
|
/// Registration templates, but can be overloaded directly.
|
|
StringRef Pass::getPassName() const {
|
|
AnalysisID AID = getPassID();
|
|
const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(AID);
|
|
if (PI)
|
|
return PI->getPassName();
|
|
return "Unnamed pass: implement Pass::getPassName()";
|
|
}
|
|
|
|
/// getPassArgument - Return a nice clean name for a pass
|
|
/// corresponding to that used to enable the pass in opt
|
|
StringRef Pass::getPassArgument() const {
|
|
AnalysisID AID = getPassID();
|
|
const PassInfo *PI = Pass::lookupPassInfo(AID);
|
|
if (PI)
|
|
return PI->getPassArgument();
|
|
return "";
|
|
}
|
|
|
|
void Pass::preparePassManager(PMStack &) {
|
|
// By default, don't do anything.
|
|
}
|
|
|
|
PassManagerType Pass::getPotentialPassManagerType() const {
|
|
// Default implementation.
|
|
return PMT_Unknown;
|
|
}
|
|
|
|
void Pass::getAnalysisUsage(AnalysisUsage &) const {
|
|
// By default, no analysis results are used, all are invalidated.
|
|
}
|
|
|
|
void Pass::releaseMemory() {
|
|
// By default, don't do anything.
|
|
}
|
|
|
|
void Pass::verifyAnalysis() const {
|
|
// By default, don't do anything.
|
|
}
|
|
|
|
ImmutablePass *Pass::getAsImmutablePass() {
|
|
return nullptr;
|
|
}
|
|
|
|
PMDataManager *Pass::getAsPMDataManager() {
|
|
return nullptr;
|
|
}
|
|
|
|
void Pass::setResolver(AnalysisResolver *AR) {
|
|
assert(!Resolver && "Resolver is already set");
|
|
Resolver = AR;
|
|
}
|
|
|
|
// print - Print out the internal state of the pass. This is called by Analyze
|
|
// to print out the contents of an analysis. Otherwise it is not necessary to
|
|
// implement this method.
|
|
void Pass::print(raw_ostream &OS, const Module *) const {
|
|
OS << "Pass::print not implemented for pass: '" << getPassName() << "'!\n";
|
|
}
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
// dump - call print(cerr);
|
|
LLVM_DUMP_METHOD void Pass::dump() const {
|
|
print(dbgs(), nullptr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef EXPENSIVE_CHECKS
|
|
uint64_t Pass::structuralHash(Module &M) const {
|
|
return StructuralHash(M, true);
|
|
}
|
|
|
|
uint64_t Pass::structuralHash(Function &F) const {
|
|
return StructuralHash(F, true);
|
|
}
|
|
#endif
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ImmutablePass Implementation
|
|
//
|
|
// Force out-of-line virtual method.
|
|
ImmutablePass::~ImmutablePass() = default;
|
|
|
|
void ImmutablePass::initializePass() {
|
|
// By default, don't do anything.
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// FunctionPass Implementation
|
|
//
|
|
|
|
Pass *FunctionPass::createPrinterPass(raw_ostream &OS,
|
|
const std::string &Banner) const {
|
|
return createPrintFunctionPass(OS, Banner);
|
|
}
|
|
|
|
PassManagerType FunctionPass::getPotentialPassManagerType() const {
|
|
return PMT_FunctionPassManager;
|
|
}
|
|
|
|
static std::string getDescription(const Function &F) {
|
|
return "function (" + F.getName().str() + ")";
|
|
}
|
|
|
|
bool FunctionPass::skipFunction(const Function &F) const {
|
|
OptPassGate &Gate = F.getContext().getOptPassGate();
|
|
|
|
StringRef PassName = getPassArgument();
|
|
if (PassName.empty())
|
|
PassName = this->getPassName();
|
|
|
|
if (Gate.isEnabled() && !Gate.shouldRunPass(PassName, getDescription(F)))
|
|
return true;
|
|
|
|
if (F.hasOptNone()) {
|
|
LLVM_DEBUG(dbgs() << "Skipping pass '" << getPassName() << "' on function "
|
|
<< F.getName() << "\n");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const PassInfo *Pass::lookupPassInfo(const void *TI) {
|
|
return PassRegistry::getPassRegistry()->getPassInfo(TI);
|
|
}
|
|
|
|
const PassInfo *Pass::lookupPassInfo(StringRef Arg) {
|
|
return PassRegistry::getPassRegistry()->getPassInfo(Arg);
|
|
}
|
|
|
|
Pass *Pass::createPass(AnalysisID ID) {
|
|
const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(ID);
|
|
if (!PI)
|
|
return nullptr;
|
|
return PI->createPass();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// PassRegistrationListener implementation
|
|
//
|
|
|
|
// enumeratePasses - Iterate over the registered passes, calling the
|
|
// passEnumerate callback on each PassInfo object.
|
|
void PassRegistrationListener::enumeratePasses() {
|
|
PassRegistry::getPassRegistry()->enumerateWith(this);
|
|
}
|
|
|
|
PassNameParser::PassNameParser(cl::Option &O)
|
|
: cl::parser<const PassInfo *>(O) {
|
|
PassRegistry::getPassRegistry()->addRegistrationListener(this);
|
|
}
|
|
|
|
// This only gets called during static destruction, in which case the
|
|
// PassRegistry will have already been destroyed by llvm_shutdown(). So
|
|
// attempting to remove the registration listener is an error.
|
|
PassNameParser::~PassNameParser() = default;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// AnalysisUsage Class Implementation
|
|
//
|
|
|
|
namespace {
|
|
|
|
struct GetCFGOnlyPasses : public PassRegistrationListener {
|
|
using VectorType = AnalysisUsage::VectorType;
|
|
|
|
VectorType &CFGOnlyList;
|
|
|
|
GetCFGOnlyPasses(VectorType &L) : CFGOnlyList(L) {}
|
|
|
|
void passEnumerate(const PassInfo *P) override {
|
|
if (P->isCFGOnlyPass())
|
|
CFGOnlyList.push_back(P->getTypeInfo());
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
// setPreservesCFG - This function should be called to by the pass, iff they do
|
|
// not:
|
|
//
|
|
// 1. Add or remove basic blocks from the function
|
|
// 2. Modify terminator instructions in any way.
|
|
//
|
|
// This function annotates the AnalysisUsage info object to say that analyses
|
|
// that only depend on the CFG are preserved by this pass.
|
|
void AnalysisUsage::setPreservesCFG() {
|
|
// Since this transformation doesn't modify the CFG, it preserves all analyses
|
|
// that only depend on the CFG (like dominators, loop info, etc...)
|
|
GetCFGOnlyPasses(Preserved).enumeratePasses();
|
|
}
|
|
|
|
AnalysisUsage &AnalysisUsage::addPreserved(StringRef Arg) {
|
|
const PassInfo *PI = Pass::lookupPassInfo(Arg);
|
|
// If the pass exists, preserve it. Otherwise silently do nothing.
|
|
if (PI)
|
|
pushUnique(Preserved, PI->getTypeInfo());
|
|
return *this;
|
|
}
|
|
|
|
AnalysisUsage &AnalysisUsage::addRequiredID(const void *ID) {
|
|
pushUnique(Required, ID);
|
|
return *this;
|
|
}
|
|
|
|
AnalysisUsage &AnalysisUsage::addRequiredID(char &ID) {
|
|
pushUnique(Required, &ID);
|
|
return *this;
|
|
}
|
|
|
|
AnalysisUsage &AnalysisUsage::addRequiredTransitiveID(char &ID) {
|
|
pushUnique(Required, &ID);
|
|
pushUnique(RequiredTransitive, &ID);
|
|
return *this;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
const char *llvm::to_string(ThinOrFullLTOPhase Phase) {
|
|
switch (Phase) {
|
|
case ThinOrFullLTOPhase::None:
|
|
return "None";
|
|
case ThinOrFullLTOPhase::ThinLTOPreLink:
|
|
return "ThinLTOPreLink";
|
|
case ThinOrFullLTOPhase::ThinLTOPostLink:
|
|
return "ThinLTOPostLink";
|
|
case ThinOrFullLTOPhase::FullLTOPreLink:
|
|
return "FullLTOPreLink";
|
|
case ThinOrFullLTOPhase::FullLTOPostLink:
|
|
return "FullLTOPostLink";
|
|
}
|
|
llvm_unreachable("invalid phase");
|
|
}
|
|
#endif
|