170 lines
5.4 KiB
C++
170 lines
5.4 KiB
C++
//------------------------------------------------------------------------------
|
|
// CLING - the C++ LLVM-based InterpreterG :)
|
|
// author: Vassil Vassilev <vvasilev@cern.ch>
|
|
//
|
|
// This file is dual-licensed: you can choose to license it under the University
|
|
// of Illinois Open Source License or the GNU Lesser General Public License. See
|
|
// LICENSE.TXT for details.
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "BackendPasses.h"
|
|
|
|
#include "llvm/Analysis/InlineCost.h"
|
|
#include "llvm/IR/DataLayout.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Verifier.h"
|
|
#include "llvm/Transforms/IPO.h"
|
|
#include "llvm/Transforms/IPO/InlinerPass.h"
|
|
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
|
#include "llvm/PassManager.h"
|
|
|
|
#include "clang/Basic/LangOptions.h"
|
|
#include "clang/Basic/TargetOptions.h"
|
|
#include "clang/Frontend/CodeGenOptions.h"
|
|
|
|
using namespace cling;
|
|
using namespace clang;
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
class InlinerKeepDeadFunc: public Inliner {
|
|
Inliner* m_Inliner; // the actual inliner
|
|
static char ID; // Pass identification, replacement for typeid
|
|
public:
|
|
InlinerKeepDeadFunc():
|
|
Inliner(ID), m_Inliner(0) { }
|
|
InlinerKeepDeadFunc(Pass* I):
|
|
Inliner(ID), m_Inliner((Inliner*)I) { }
|
|
|
|
using llvm::Pass::doInitialization;
|
|
bool doInitialization(CallGraph &CG) override {
|
|
// Forward out Resolver now that we are registered.
|
|
if (!m_Inliner->getResolver())
|
|
m_Inliner->setResolver(getResolver());
|
|
return m_Inliner->doInitialization(CG); // no Module modification
|
|
}
|
|
|
|
InlineCost getInlineCost(CallSite CS) override {
|
|
return m_Inliner->getInlineCost(CS);
|
|
}
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
m_Inliner->getAnalysisUsage(AU);
|
|
}
|
|
bool runOnSCC(CallGraphSCC &SCC) override {
|
|
return m_Inliner->runOnSCC(SCC);
|
|
}
|
|
|
|
using llvm::Pass::doFinalization;
|
|
// No-op: we need to keep the inlined functions for later use.
|
|
bool doFinalization(CallGraph& /*CG*/) override {
|
|
// Module is unchanged
|
|
return false;
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
// Pass registration. Luckily all known inliners depend on the same set
|
|
// of passes.
|
|
char InlinerKeepDeadFunc::ID = 0;
|
|
|
|
|
|
BackendPasses::BackendPasses(const CodeGenOptions &CGOpts,
|
|
const TargetOptions &TOpts,
|
|
const LangOptions &LOpts):
|
|
m_CodeGenOptsVerifyModule(CGOpts.VerifyModule)
|
|
{
|
|
CreatePasses(CGOpts, TOpts, LOpts);
|
|
}
|
|
|
|
|
|
BackendPasses::~BackendPasses() {
|
|
delete m_PMBuilder->Inliner;
|
|
}
|
|
|
|
void BackendPasses::CreatePasses(const CodeGenOptions &CGOpts,
|
|
const TargetOptions &TOpts,
|
|
const LangOptions &LOpts)
|
|
{
|
|
// From BackEndUtil's clang::EmitAssemblyHelper::CreatePasses().
|
|
|
|
unsigned OptLevel = CGOpts.OptimizationLevel;
|
|
CodeGenOptions::InliningMethod Inlining = CGOpts.getInlining();
|
|
|
|
// Handle disabling of LLVM optimization, where we want to preserve the
|
|
// internal module before any optimization.
|
|
if (CGOpts.DisableLLVMOpts) {
|
|
OptLevel = 0;
|
|
// Always keep at least ForceInline - NoInlining is deadly for libc++.
|
|
// Inlining = CGOpts.NoInlining;
|
|
}
|
|
|
|
m_PMBuilder.reset(new PassManagerBuilder());
|
|
m_PMBuilder->OptLevel = OptLevel;
|
|
m_PMBuilder->SizeLevel = CGOpts.OptimizeSize;
|
|
m_PMBuilder->BBVectorize = CGOpts.VectorizeBB;
|
|
m_PMBuilder->SLPVectorize = CGOpts.VectorizeSLP;
|
|
m_PMBuilder->LoopVectorize = CGOpts.VectorizeLoop;
|
|
|
|
m_PMBuilder->DisableTailCalls = CGOpts.DisableTailCalls;
|
|
m_PMBuilder->DisableUnitAtATime = !CGOpts.UnitAtATime;
|
|
m_PMBuilder->DisableUnrollLoops = !CGOpts.UnrollLoops;
|
|
m_PMBuilder->MergeFunctions = CGOpts.MergeFunctions;
|
|
m_PMBuilder->RerollLoops = CGOpts.RerollLoops;
|
|
|
|
|
|
switch (Inlining) {
|
|
case CodeGenOptions::NoInlining: {
|
|
assert(0 && "libc++ requires at least OnlyAlwaysInlining!");
|
|
break;
|
|
}
|
|
case CodeGenOptions::NormalInlining: {
|
|
m_PMBuilder->Inliner =
|
|
new InlinerKeepDeadFunc(createFunctionInliningPass(OptLevel,
|
|
CGOpts.OptimizeSize));
|
|
break;
|
|
}
|
|
case CodeGenOptions::OnlyAlwaysInlining:
|
|
// Respect always_inline.
|
|
if (OptLevel == 0)
|
|
// Do not insert lifetime intrinsics at -O0.
|
|
m_PMBuilder->Inliner
|
|
= new InlinerKeepDeadFunc(createAlwaysInlinerPass(false));
|
|
else
|
|
m_PMBuilder->Inliner
|
|
= new InlinerKeepDeadFunc(createAlwaysInlinerPass());
|
|
break;
|
|
}
|
|
|
|
// Set up the per-module pass manager.
|
|
m_MPM.reset(new PassManager());
|
|
m_MPM->add(new DataLayoutPass());
|
|
//m_MPM->add(createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
|
|
//if (!CGOpts.RewriteMapFiles.empty())
|
|
// addSymbolRewriterPass(CGOpts, m_MPM);
|
|
if (CGOpts.VerifyModule)
|
|
m_MPM->add(createDebugInfoVerifierPass());
|
|
|
|
m_PMBuilder->populateModulePassManager(*m_MPM);
|
|
}
|
|
|
|
void BackendPasses::runOnModule(Module& M) {
|
|
|
|
// Set up the per-function pass manager.
|
|
FunctionPassManager FPM(&M);
|
|
FPM.add(new DataLayoutPass());
|
|
//FPM.add(createTargetTransformInfoWrapperPass(getTargetIRAnalysis()));
|
|
if (m_CodeGenOptsVerifyModule)
|
|
FPM.add(createVerifierPass());
|
|
m_PMBuilder->populateFunctionPassManager(FPM);
|
|
|
|
// Run the per-function passes on the module.
|
|
FPM.doInitialization();
|
|
for (auto&& I: M.functions())
|
|
if (!I.isDeclaration())
|
|
FPM.run(I);
|
|
FPM.doFinalization();
|
|
|
|
m_MPM->run(M);
|
|
}
|