Move from legacy to new pass manager
It is recommended to use a new instance of analysis managers every time we perform codegen as the analyses might not be cleared. Upstream does not have any instance where populating pass/analysis managers and running passes are separated.
This commit is contained in:
parent
e5b63c66a6
commit
80b69f0737
@ -16,9 +16,11 @@
|
||||
#include "llvm/Analysis/InlineCost.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/Passes/StandardInstrumentations.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/IPO/AlwaysInliner.h"
|
||||
@ -32,15 +34,14 @@
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Basic/CodeGenOptions.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
using namespace cling;
|
||||
using namespace clang;
|
||||
using namespace llvm;
|
||||
using namespace llvm::legacy;
|
||||
|
||||
namespace {
|
||||
class KeepLocalGVPass: public ModulePass {
|
||||
static char ID;
|
||||
|
||||
class KeepLocalGVPass : public PassInfoMixin<KeepLocalGVPass> {
|
||||
bool runOnGlobal(GlobalValue& GV) {
|
||||
if (GV.isDeclaration())
|
||||
return false; // no change.
|
||||
@ -72,25 +73,19 @@ namespace {
|
||||
}
|
||||
|
||||
public:
|
||||
KeepLocalGVPass() : ModulePass(ID) {}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
bool ret = false;
|
||||
PreservedAnalyses run(llvm::Module& M, ModuleAnalysisManager& AM) {
|
||||
bool changed = false;
|
||||
for (auto &&F: M)
|
||||
ret |= runOnGlobal(F);
|
||||
changed |= runOnGlobal(F);
|
||||
for (auto &&G: M.globals())
|
||||
ret |= runOnGlobal(G);
|
||||
return ret;
|
||||
changed |= runOnGlobal(G);
|
||||
return changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char KeepLocalGVPass::ID = 0;
|
||||
|
||||
namespace {
|
||||
class PreventLocalOptPass: public ModulePass {
|
||||
static char ID;
|
||||
|
||||
class PreventLocalOptPass : public PassInfoMixin<PreventLocalOptPass> {
|
||||
bool runOnGlobal(GlobalValue& GV) {
|
||||
if (!GV.isDeclaration())
|
||||
return false; // no change.
|
||||
@ -123,25 +118,19 @@ namespace {
|
||||
}
|
||||
|
||||
public:
|
||||
PreventLocalOptPass() : ModulePass(ID) {}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
bool ret = false;
|
||||
PreservedAnalyses run(llvm::Module& M, ModuleAnalysisManager& AM) {
|
||||
bool changed = false;
|
||||
for (auto &&F: M)
|
||||
ret |= runOnGlobal(F);
|
||||
changed |= runOnGlobal(F);
|
||||
for (auto &&G: M.globals())
|
||||
ret |= runOnGlobal(G);
|
||||
return ret;
|
||||
changed |= runOnGlobal(G);
|
||||
return changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char PreventLocalOptPass::ID = 0;
|
||||
|
||||
namespace {
|
||||
class WeakTypeinfoVTablePass: public ModulePass {
|
||||
static char ID;
|
||||
|
||||
class WeakTypeinfoVTablePass : public PassInfoMixin<WeakTypeinfoVTablePass> {
|
||||
bool runOnGlobalVariable(GlobalVariable& GV) {
|
||||
// Only need to consider symbols with external linkage because only
|
||||
// these could be reported as duplicate.
|
||||
@ -164,28 +153,22 @@ namespace {
|
||||
}
|
||||
|
||||
public:
|
||||
WeakTypeinfoVTablePass() : ModulePass(ID) {}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
bool ret = false;
|
||||
PreservedAnalyses run(llvm::Module& M, ModuleAnalysisManager& AM) {
|
||||
bool changed = false;
|
||||
for (auto &&GV : M.globals())
|
||||
ret |= runOnGlobalVariable(GV);
|
||||
return ret;
|
||||
changed |= runOnGlobalVariable(GV);
|
||||
return changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char WeakTypeinfoVTablePass::ID = 0;
|
||||
|
||||
namespace {
|
||||
|
||||
// Add a suffix to the CUDA module ctor/dtor, CUDA specific functions and
|
||||
// variables to generate a unique name. This is necessary for lazy
|
||||
// compilation. Without suffix, cling cannot distinguish ctor/dtor, register
|
||||
// function and and ptx code string of subsequent modules.
|
||||
class UniqueCUDAStructorName : public ModulePass {
|
||||
static char ID;
|
||||
|
||||
class UniqueCUDAStructorName : public PassInfoMixin<UniqueCUDAStructorName> {
|
||||
// append a suffix to a symbol to make it unique
|
||||
// the suffix is "_cling_module_<module number>"
|
||||
llvm::SmallString<128> add_module_suffix(const StringRef SymbolName,
|
||||
@ -235,29 +218,24 @@ namespace {
|
||||
}
|
||||
|
||||
public:
|
||||
UniqueCUDAStructorName() : ModulePass(ID) {}
|
||||
|
||||
bool runOnModule(Module& M) override {
|
||||
bool ret = false;
|
||||
PreservedAnalyses run(llvm::Module& M, ModuleAnalysisManager& AM) {
|
||||
bool changed = false;
|
||||
const StringRef ModuleName = M.getName();
|
||||
for (auto&& F : M)
|
||||
ret |= runOnFunction(F, ModuleName);
|
||||
changed |= runOnFunction(F, ModuleName);
|
||||
for (auto&& G : M.globals())
|
||||
ret |= runOnGlobal(G, ModuleName);
|
||||
return ret;
|
||||
changed |= runOnGlobal(G, ModuleName);
|
||||
return changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
char UniqueCUDAStructorName::ID = 0;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// Replace definitions of weak symbols for which symbols already exist by
|
||||
// declarations. This reduces the amount of emitted symbols.
|
||||
class ReuseExistingWeakSymbols : public ModulePass {
|
||||
static char ID;
|
||||
class ReuseExistingWeakSymbols
|
||||
: public PassInfoMixin<ReuseExistingWeakSymbols> {
|
||||
cling::IncrementalJIT &m_JIT;
|
||||
|
||||
bool shouldRemoveGlobalDefinition(GlobalValue& GV) {
|
||||
@ -314,23 +292,43 @@ namespace {
|
||||
}
|
||||
|
||||
public:
|
||||
ReuseExistingWeakSymbols(IncrementalJIT &JIT) :
|
||||
ModulePass(ID), m_JIT(JIT) {}
|
||||
ReuseExistingWeakSymbols(IncrementalJIT& JIT) : m_JIT(JIT) {}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
bool ret = false;
|
||||
PreservedAnalyses run(llvm::Module& M, ModuleAnalysisManager& AM) {
|
||||
bool changed = false;
|
||||
// FIXME: use SymbolLookupSet, rather than looking up symbol by symbol.
|
||||
for (auto &&F: M)
|
||||
ret |= runOnFunc(F);
|
||||
changed |= runOnFunc(F);
|
||||
for (auto &&G: M.globals())
|
||||
ret |= runOnVar(G);
|
||||
return ret;
|
||||
changed |= runOnVar(G);
|
||||
return changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char ReuseExistingWeakSymbols::ID = 0;
|
||||
// From clang/lib/CodeGen/BackendUtil.cpp
|
||||
static OptimizationLevel mapToLevel(const CodeGenOptions& Opts) {
|
||||
switch (Opts.OptimizationLevel) {
|
||||
default: llvm_unreachable("Invalid optimization level!");
|
||||
|
||||
case 0: return OptimizationLevel::O0;
|
||||
|
||||
case 1: return OptimizationLevel::O1;
|
||||
|
||||
case 2:
|
||||
switch (Opts.OptimizeSize) {
|
||||
default: llvm_unreachable("Invalid optimization level for size!");
|
||||
|
||||
case 0: return OptimizationLevel::O2;
|
||||
|
||||
case 1: return OptimizationLevel::Os;
|
||||
|
||||
case 2: return OptimizationLevel::Oz;
|
||||
}
|
||||
|
||||
case 3: return OptimizationLevel::O3;
|
||||
}
|
||||
}
|
||||
|
||||
BackendPasses::BackendPasses(const clang::CodeGenOptions &CGOpts,
|
||||
IncrementalJIT &JIT, llvm::TargetMachine& TM):
|
||||
@ -344,94 +342,60 @@ BackendPasses::~BackendPasses() {
|
||||
//delete m_PMBuilder->Inliner;
|
||||
}
|
||||
|
||||
void BackendPasses::CreatePasses(llvm::Module& M, int OptLevel)
|
||||
{
|
||||
// From BackEndUtil's clang::EmitAssemblyHelper::CreatePasses().
|
||||
void BackendPasses::CreatePasses(int OptLevel, llvm::ModulePassManager& MPM,
|
||||
llvm::LoopAnalysisManager& LAM,
|
||||
llvm::FunctionAnalysisManager& FAM,
|
||||
llvm::CGSCCAnalysisManager& CGAM,
|
||||
llvm::ModuleAnalysisManager& MAM,
|
||||
PassInstrumentationCallbacks& PIC,
|
||||
StandardInstrumentations& SI) {
|
||||
|
||||
#if 0
|
||||
CodeGenOptions::InliningMethod Inlining = m_CGOpts.getInlining();
|
||||
CodeGenOptions& CGOpts_ = const_cast<CodeGenOptions&>(m_CGOpts);
|
||||
// DON'T: we will not find our symbols...
|
||||
//CGOpts_.CXXCtorDtorAliases = 1;
|
||||
MPM.addPass(KeepLocalGVPass());
|
||||
MPM.addPass(PreventLocalOptPass());
|
||||
MPM.addPass(WeakTypeinfoVTablePass());
|
||||
MPM.addPass(ReuseExistingWeakSymbols(m_JIT));
|
||||
|
||||
// Default clang -O2 on Linux 64bit also has the following, but see
|
||||
// CIFactory.cpp.
|
||||
CGOpts_.DisableFPElim = 0;
|
||||
CGOpts_.DiscardValueNames = 1;
|
||||
CGOpts_.OmitLeafFramePointer = 1;
|
||||
CGOpts_.OptimizationLevel = 2;
|
||||
CGOpts_.RelaxAll = 0;
|
||||
CGOpts_.UnrollLoops = 1;
|
||||
CGOpts_.VectorizeLoop = 1;
|
||||
CGOpts_.VectorizeSLP = 1;
|
||||
#endif
|
||||
|
||||
#if 0 // def __GNUC__
|
||||
// Better inlining is pending https://bugs.llvm.org//show_bug.cgi?id=19668
|
||||
// and its consequence https://sft.its.cern.ch/jira/browse/ROOT-7111
|
||||
// shown e.g. by roottest/cling/stl/map/badstringMap
|
||||
if (Inlining > CodeGenOptions::NormalInlining)
|
||||
Inlining = CodeGenOptions::NormalInlining;
|
||||
#endif
|
||||
// Run verifier after local passes to make sure that IR remains untouched.
|
||||
if (m_CGOpts.VerifyModule)
|
||||
MPM.addPass(VerifierPass());
|
||||
|
||||
// Handle disabling of LLVM optimization, where we want to preserve the
|
||||
// internal module before any optimization.
|
||||
if (m_CGOpts.DisableLLVMPasses) {
|
||||
OptLevel = 0;
|
||||
// Always keep at least ForceInline - NoInlining is deadly for libc++.
|
||||
// Inlining = CGOpts.NoInlining;
|
||||
MPM.addPass(AlwaysInlinerPass());
|
||||
} else if (OptLevel <= 1) {
|
||||
// At O0 and O1 we only run the always inliner which is more efficient. At
|
||||
// higher optimization levels we run the normal inliner.
|
||||
MPM.addPass(AlwaysInlinerPass());
|
||||
}
|
||||
|
||||
llvm::PassManagerBuilder PMBuilder;
|
||||
PMBuilder.OptLevel = OptLevel;
|
||||
PMBuilder.SizeLevel = m_CGOpts.OptimizeSize;
|
||||
PMBuilder.SLPVectorize = OptLevel > 1 ? 1 : 0; // m_CGOpts.VectorizeSLP
|
||||
PMBuilder.LoopVectorize = OptLevel > 1 ? 1 : 0; // m_CGOpts.VectorizeLoop
|
||||
SI.registerCallbacks(PIC, &FAM);
|
||||
|
||||
PMBuilder.DisableUnrollLoops = !m_CGOpts.UnrollLoops;
|
||||
PMBuilder.MergeFunctions = m_CGOpts.MergeFunctions;
|
||||
PipelineTuningOptions PTO;
|
||||
std::optional<PGOOptions> PGOOpt;
|
||||
PassBuilder PB(&m_TM, PTO, PGOOpt, &PIC);
|
||||
|
||||
PMBuilder.LibraryInfo = new TargetLibraryInfoImpl(m_TM.getTargetTriple());
|
||||
|
||||
// At O0 and O1 we only run the always inliner which is more efficient. At
|
||||
// higher optimization levels we run the normal inliner.
|
||||
// See also call to `CGOpts.setInlining()` in CIFactory!
|
||||
if (PMBuilder.OptLevel <= 1) {
|
||||
bool InsertLifetimeIntrinsics = PMBuilder.OptLevel != 0;
|
||||
PMBuilder.Inliner = createAlwaysInlinerLegacyPass(InsertLifetimeIntrinsics);
|
||||
} else {
|
||||
PMBuilder.Inliner = createFunctionInliningPass(OptLevel,
|
||||
PMBuilder.SizeLevel,
|
||||
(!m_CGOpts.SampleProfileFile.empty() && m_CGOpts.PrepareForThinLTO));
|
||||
if (!m_CGOpts.DisableLLVMPasses) {
|
||||
// Use the default pass pipeline. We also have to map our optimization
|
||||
// levels into one of the distinct levels used to configure the pipeline.
|
||||
OptimizationLevel Level = mapToLevel(m_CGOpts);
|
||||
MPM.addPass(PB.buildPerModuleDefaultPipeline(Level));
|
||||
}
|
||||
|
||||
// Set up the per-module pass manager.
|
||||
m_MPM[OptLevel].reset(new legacy::PassManager());
|
||||
|
||||
m_MPM[OptLevel]->add(new KeepLocalGVPass());
|
||||
m_MPM[OptLevel]->add(new PreventLocalOptPass());
|
||||
m_MPM[OptLevel]->add(new WeakTypeinfoVTablePass());
|
||||
m_MPM[OptLevel]->add(new ReuseExistingWeakSymbols(m_JIT));
|
||||
|
||||
// The function __cuda_module_ctor and __cuda_module_dtor will just generated,
|
||||
// if a CUDA fatbinary file exist. Without file path there is no need for the
|
||||
// function pass.
|
||||
if(!m_CGOpts.CudaGpuBinaryFileName.empty())
|
||||
m_MPM[OptLevel]->add(new UniqueCUDAStructorName());
|
||||
m_MPM[OptLevel]->add(createTargetTransformInfoWrapperPass(
|
||||
m_TM.getTargetIRAnalysis()));
|
||||
MPM.addPass(UniqueCUDAStructorName());
|
||||
|
||||
//if (!CGOpts.RewriteMapFiles.empty())
|
||||
// addSymbolRewriterPass(CGOpts, m_MPM);
|
||||
|
||||
PMBuilder.populateModulePassManager(*m_MPM[OptLevel]);
|
||||
|
||||
m_FPM[OptLevel].reset(new legacy::FunctionPassManager(&M));
|
||||
m_FPM[OptLevel]->add(createTargetTransformInfoWrapperPass(
|
||||
m_TM.getTargetIRAnalysis()));
|
||||
if (m_CGOpts.VerifyModule)
|
||||
m_FPM[OptLevel]->add(createVerifierPass());
|
||||
PMBuilder.populateFunctionPassManager(*m_FPM[OptLevel]);
|
||||
// Register all the basic analyses with the managers.
|
||||
PB.registerModuleAnalyses(MAM);
|
||||
PB.registerCGSCCAnalyses(CGAM);
|
||||
PB.registerFunctionAnalyses(FAM);
|
||||
PB.registerLoopAnalyses(LAM);
|
||||
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
|
||||
}
|
||||
|
||||
void BackendPasses::runOnModule(Module& M, int OptLevel) {
|
||||
@ -441,8 +405,16 @@ void BackendPasses::runOnModule(Module& M, int OptLevel) {
|
||||
if (OptLevel > 3)
|
||||
OptLevel = 3;
|
||||
|
||||
if (!m_MPM[OptLevel])
|
||||
CreatePasses(M, OptLevel);
|
||||
ModulePassManager MPM;
|
||||
LoopAnalysisManager LAM;
|
||||
FunctionAnalysisManager FAM;
|
||||
CGSCCAnalysisManager CGAM;
|
||||
ModuleAnalysisManager MAM;
|
||||
|
||||
PassInstrumentationCallbacks PIC;
|
||||
StandardInstrumentations SI(M.getContext(), m_CGOpts.DebugPassManager);
|
||||
|
||||
CreatePasses(OptLevel, MPM, LAM, FAM, CGAM, MAM, PIC, SI);
|
||||
|
||||
static constexpr std::array<llvm::CodeGenOpt::Level, 4> CGOptLevel {{
|
||||
llvm::CodeGenOpt::None,
|
||||
@ -453,12 +425,6 @@ void BackendPasses::runOnModule(Module& M, int OptLevel) {
|
||||
// TM's OptLevel is used to build orc::SimpleCompiler passes for every Module.
|
||||
m_TM.setOptLevel(CGOptLevel[OptLevel]);
|
||||
|
||||
// Run the per-function passes on the module.
|
||||
m_FPM[OptLevel]->doInitialization();
|
||||
for (auto&& I: M.functions())
|
||||
if (!I.isDeclaration())
|
||||
m_FPM[OptLevel]->run(I);
|
||||
m_FPM[OptLevel]->doFinalization();
|
||||
|
||||
m_MPM[OptLevel]->run(M);
|
||||
// Now that we have all of the passes ready, run them.
|
||||
MPM.run(M, MAM);
|
||||
}
|
||||
|
@ -10,7 +10,10 @@
|
||||
#ifndef CLING_BACKENDPASSES_H
|
||||
#define CLING_BACKENDPASSES_H
|
||||
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Analysis/CGSCCPassManager.h"
|
||||
#include "llvm/Analysis/LoopAnalysisManager.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Passes/StandardInstrumentations.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
@ -19,13 +22,7 @@ namespace llvm {
|
||||
class Function;
|
||||
class LLVMContext;
|
||||
class Module;
|
||||
class PassManagerBuilder;
|
||||
class TargetMachine;
|
||||
|
||||
namespace legacy {
|
||||
class FunctionPassManager;
|
||||
class PassManager;
|
||||
}
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -40,14 +37,17 @@ namespace cling {
|
||||
///\brief Runs passes on IR. Remove once we can migrate from ModuleBuilder to
|
||||
/// what's in clang's CodeGen/BackendUtil.
|
||||
class BackendPasses {
|
||||
std::array<std::unique_ptr<llvm::legacy::PassManager>, 4> m_MPM;
|
||||
std::array<std::unique_ptr<llvm::legacy::FunctionPassManager>, 4> m_FPM;
|
||||
|
||||
llvm::TargetMachine& m_TM;
|
||||
IncrementalJIT &m_JIT;
|
||||
const clang::CodeGenOptions &m_CGOpts;
|
||||
|
||||
void CreatePasses(llvm::Module& M, int OptLevel);
|
||||
void CreatePasses(int OptLevel, llvm::ModulePassManager& MPM,
|
||||
llvm::LoopAnalysisManager& LAM,
|
||||
llvm::FunctionAnalysisManager& FAM,
|
||||
llvm::CGSCCAnalysisManager& CGAM,
|
||||
llvm::ModuleAnalysisManager& MAM,
|
||||
llvm::PassInstrumentationCallbacks& PIC,
|
||||
llvm::StandardInstrumentations& SI);
|
||||
|
||||
public:
|
||||
BackendPasses(const clang::CodeGenOptions &CGOpts, IncrementalJIT &JIT,
|
||||
|
Loading…
Reference in New Issue
Block a user