mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-30 07:00:46 +03:00
Use llvm::PassManagerBuilder for optimization scheduling.
This commit is based on Kai's pull request #157.
This commit is contained in:
parent
2e8dac5f38
commit
2f78dc686d
2 changed files with 141 additions and 182 deletions
|
@ -1,25 +1,28 @@
|
|||
#include "gen/optimizer.h"
|
||||
#include "gen/cl_helpers.h"
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/logger.h"
|
||||
|
||||
#include "gen/passes/Passes.h"
|
||||
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/LinkAllPasses.h"
|
||||
#include "llvm/Analysis/LoopPass.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#if LDC_LLVM_VER >= 302
|
||||
#include "llvm/DataLayout.h"
|
||||
#else
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#endif
|
||||
#include "llvm/Target/TargetLibraryInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/PassNameParser.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
|
||||
#include "mars.h" // error()
|
||||
#include "root.h"
|
||||
#include <cstring> // strcmp();
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
|
@ -30,7 +33,7 @@ static cl::list<const PassInfo*, bool, PassNameParser>
|
|||
cl::Hidden // to clean up --help output
|
||||
);
|
||||
|
||||
static cl::opt<unsigned char> optimizeLevel(
|
||||
static cl::opt<signed char> optimizeLevel(
|
||||
cl::desc("Setting the optimization level:"),
|
||||
cl::ZeroOrMore,
|
||||
cl::values(
|
||||
|
@ -39,8 +42,10 @@ static cl::opt<unsigned char> optimizeLevel(
|
|||
clEnumValN(1, "O1", "Simple optimizations"),
|
||||
clEnumValN(2, "O2", "Good optimizations"),
|
||||
clEnumValN(3, "O3", "Aggressive optimizations"),
|
||||
clEnumValN(4, "O4", "Link-time optimization"), // not implemented?
|
||||
clEnumValN(5, "O5", "Link-time optimization"), // not implemented?
|
||||
clEnumValN(4, "O4", "Link-time optimization"), // Not implemented yet.
|
||||
clEnumValN(5, "O5", "Link-time optimization"), // Not implemented yet.
|
||||
clEnumValN(-1, "Os", "Like -O2 with extra optimizations for size"),
|
||||
clEnumValN(-2, "Oz", "Like -Os but reduces code size further"),
|
||||
clEnumValEnd),
|
||||
cl::init(0));
|
||||
|
||||
|
@ -75,44 +80,28 @@ enableInlining("inlining",
|
|||
cl::desc("(*) Enable function inlining in -O<N>"),
|
||||
cl::ZeroOrMore);
|
||||
|
||||
#if LDC_LLVM_VER >= 301
|
||||
static cl::opt<bool>
|
||||
runVectorization("vectorize", cl::desc("Run vectorization passes"));
|
||||
unitAtATime("unit-at-a-time",
|
||||
cl::desc("Enable basic IPO"),
|
||||
cl::init(true));
|
||||
|
||||
static cl::opt<bool>
|
||||
useGVNAfterVectorization("use-gvn-after-vectorization",
|
||||
cl::init(false), cl::Hidden,
|
||||
cl::desc("Run GVN instead of Early CSE after vectorization passes"));
|
||||
#endif
|
||||
stripDebug("strip-debug",
|
||||
cl::desc("Strip symbolic debug information before optimization"));
|
||||
|
||||
// Determine whether or not to run the inliner as part of the default list of
|
||||
// optimization passes.
|
||||
// If not explicitly specified, treat as false for -O0-2, and true for -O3.
|
||||
bool doInline() {
|
||||
return enableInlining == cl::BOU_TRUE
|
||||
|| (enableInlining == cl::BOU_UNSET && optimizeLevel >= 3);
|
||||
static unsigned optLevel() {
|
||||
// Use -O2 as a base for the size-optimization levels.
|
||||
return optimizeLevel >= 0 ? optimizeLevel : 2;
|
||||
}
|
||||
|
||||
// Determine whether the inliner will be run.
|
||||
static unsigned sizeLevel() {
|
||||
return optimizeLevel < 0 ? -optimizeLevel : 0;
|
||||
}
|
||||
|
||||
// Determines whether or not to run the normal, full inlining pass.
|
||||
bool willInline() {
|
||||
if (doInline())
|
||||
return true;
|
||||
// It may also have been specified explicitly on the command line as an explicit pass
|
||||
typedef cl::list<const PassInfo*, bool, PassNameParser> PL;
|
||||
for (PL::iterator I = passList.begin(), E = passList.end(); I != E; ++I) {
|
||||
if (!std::strcmp((*I)->getPassArgument(), "inline"))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Some extra accessors for the linker: (llvm-ld version only, currently unused?)
|
||||
int optLevel() {
|
||||
return optimizeLevel;
|
||||
}
|
||||
|
||||
bool optimize() {
|
||||
return optimizeLevel || doInline() || !passList.empty();
|
||||
return enableInlining == cl::BOU_TRUE ||
|
||||
(enableInlining != cl::BOU_UNSET && optLevel() > 1);
|
||||
}
|
||||
|
||||
llvm::CodeGenOpt::Level codeGenOptLevel() {
|
||||
|
@ -132,138 +121,84 @@ llvm::CodeGenOpt::Level codeGenOptLevel() {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void addPass(PassManager& pm, Pass* pass) {
|
||||
static inline void addPass(PassManagerBase& pm, Pass* pass) {
|
||||
pm.add(pass);
|
||||
|
||||
if (verifyEach) pm.add(createVerifierPass());
|
||||
}
|
||||
|
||||
// this function inserts some or all of the std-compile-opts passes depending on the
|
||||
// optimization level given.
|
||||
static void addPassesForOptLevel(PassManager& pm) {
|
||||
// -O1
|
||||
if (optimizeLevel >= 1)
|
||||
{
|
||||
// Add alias analysis passes.
|
||||
// This is at least required for FunctionAttrs pass.
|
||||
addPass(pm, createTypeBasedAliasAnalysisPass());
|
||||
addPass(pm, createBasicAliasAnalysisPass());
|
||||
//addPass(pm, createStripDeadPrototypesPass());
|
||||
addPass(pm, createGlobalDCEPass());
|
||||
addPass(pm, createPromoteMemoryToRegisterPass());
|
||||
addPass(pm, createCFGSimplificationPass());
|
||||
if (optimizeLevel == 1)
|
||||
addPass(pm, createPromoteMemoryToRegisterPass());
|
||||
else
|
||||
addPass(pm, createScalarReplAggregatesPass());
|
||||
addPass(pm, createGlobalOptimizerPass());
|
||||
}
|
||||
static void addStripExternalsPass(const PassManagerBuilder &builder, PassManagerBase &pm) {
|
||||
if (builder.OptLevel >= 1)
|
||||
addPass(pm, createStripExternalsPass());
|
||||
}
|
||||
|
||||
// -O2
|
||||
if (optimizeLevel >= 2)
|
||||
{
|
||||
addPass(pm, createIPConstantPropagationPass());
|
||||
addPass(pm, createDeadArgEliminationPass());
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
addPass(pm, createCFGSimplificationPass());
|
||||
addPass(pm, createPruneEHPass());
|
||||
|
||||
addPass(pm, createFunctionAttrsPass());
|
||||
|
||||
addPass(pm, createTailCallEliminationPass());
|
||||
addPass(pm, createCFGSimplificationPass());
|
||||
addPass(pm, createGVNPass());
|
||||
}
|
||||
|
||||
// -inline
|
||||
if (doInline()) {
|
||||
addPass(pm, createFunctionInliningPass());
|
||||
|
||||
if (optimizeLevel >= 2) {
|
||||
// Run some optimizations to clean up after inlining.
|
||||
addPass(pm, createScalarReplAggregatesPass());
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
// -instcombine + gvn == devirtualization :)
|
||||
addPass(pm, createGVNPass());
|
||||
|
||||
// Inline again, to catch things like now nonvirtual
|
||||
// function calls, foreach delegates passed to inlined
|
||||
// opApply's, etc. where the actual function being called
|
||||
// wasn't known during the first inliner pass.
|
||||
addPass(pm, createFunctionInliningPass());
|
||||
}
|
||||
}
|
||||
|
||||
if (optimizeLevel >= 2) {
|
||||
if (!disableLangSpecificPasses) {
|
||||
if (!disableSimplifyRuntimeCalls)
|
||||
addPass(pm, createSimplifyDRuntimeCalls());
|
||||
static void addSimplifyDRuntimeCallsPass(const PassManagerBuilder &builder, PassManagerBase &pm) {
|
||||
if (builder.OptLevel >= 2 && builder.SizeLevel == 0)
|
||||
addPass(pm, createSimplifyDRuntimeCalls());
|
||||
}
|
||||
|
||||
#if USE_METADATA
|
||||
if (!disableGCToStack)
|
||||
addPass(pm, createGarbageCollect2Stack());
|
||||
#endif // USE_METADATA
|
||||
}
|
||||
// Run some clean-up passes
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
addPass(pm, createScalarReplAggregatesPass());
|
||||
addPass(pm, createCFGSimplificationPass());
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
static void addGarbageCollect2StackPass(const PassManagerBuilder &builder, PassManagerBase &pm) {
|
||||
if (builder.OptLevel >= 2 && builder.SizeLevel == 0)
|
||||
addPass(pm, createGarbageCollect2Stack());
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Adds a set of optimization passes to the given module/function pass
|
||||
* managers based on the given optimization and size reduction levels.
|
||||
*
|
||||
* The selection mirrors Clang behavior and is based on LLVM's
|
||||
* PassManagerBuilder.
|
||||
*/
|
||||
static void addOptimizationPasses(PassManagerBase &mpm, FunctionPassManager &fpm,
|
||||
unsigned optLevel, unsigned sizeLevel) {
|
||||
fpm.add(createVerifierPass()); // Verify that input is correct
|
||||
|
||||
PassManagerBuilder builder;
|
||||
builder.OptLevel = optLevel;
|
||||
builder.SizeLevel = sizeLevel;
|
||||
|
||||
if (enableInlining == cl::BOU_FALSE) {
|
||||
// If -disable-inlining has been explictly specified, don't perform
|
||||
// any inlining at all.
|
||||
} else if (willInline()) {
|
||||
unsigned threshold = 225;
|
||||
if (sizeLevel == 1) // -Os
|
||||
threshold = 75;
|
||||
else if (sizeLevel == 2) // -Oz
|
||||
threshold = 25;
|
||||
if (optLevel > 2)
|
||||
threshold = 275;
|
||||
builder.Inliner = createFunctionInliningPass(threshold);
|
||||
} else {
|
||||
builder.Inliner = createAlwaysInlinerPass();
|
||||
}
|
||||
builder.DisableUnitAtATime = !unitAtATime;
|
||||
builder.DisableUnrollLoops = optLevel == 0;
|
||||
/* builder.Vectorize is set in ctor from command line switch */
|
||||
|
||||
// -O3
|
||||
if (optimizeLevel >= 3)
|
||||
{
|
||||
addPass(pm, createArgumentPromotionPass());
|
||||
addPass(pm, createSimplifyLibCallsPass());
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
addPass(pm, createJumpThreadingPass());
|
||||
addPass(pm, createCFGSimplificationPass());
|
||||
addPass(pm, createScalarReplAggregatesPass());
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
addPass(pm, createConstantPropagationPass());
|
||||
if (!disableLangSpecificPasses) {
|
||||
if (!disableSimplifyRuntimeCalls)
|
||||
builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, addSimplifyDRuntimeCallsPass);
|
||||
|
||||
addPass(pm, createReassociatePass());
|
||||
addPass(pm, createLoopRotatePass());
|
||||
addPass(pm, createLICMPass());
|
||||
addPass(pm, createLoopUnswitchPass());
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
addPass(pm, createIndVarSimplifyPass());
|
||||
addPass(pm, createLoopDeletionPass());
|
||||
addPass(pm, createLoopUnrollPass());
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
addPass(pm, createGVNPass());
|
||||
addPass(pm, createMemCpyOptPass());
|
||||
addPass(pm, createSCCPPass());
|
||||
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
addPass(pm, createConstantPropagationPass());
|
||||
|
||||
addPass(pm, createDeadStoreEliminationPass());
|
||||
addPass(pm, createAggressiveDCEPass());
|
||||
addPass(pm, createCFGSimplificationPass());
|
||||
addPass(pm, createConstantMergePass());
|
||||
#if USE_METADATA
|
||||
if (!disableGCToStack)
|
||||
Builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, addGarbageCollect2StackPass);
|
||||
#endif // USE_METADATA
|
||||
}
|
||||
|
||||
#if LDC_LLVM_VER >= 301
|
||||
// -vectorize
|
||||
if (runVectorization)
|
||||
{
|
||||
addPass(pm, createBBVectorizePass());
|
||||
addPass(pm, createInstructionCombiningPass());
|
||||
if (optimizeLevel > 1 && useGVNAfterVectorization)
|
||||
addPass(pm, createGVNPass()); // Remove redundancies
|
||||
else
|
||||
addPass(pm, createEarlyCSEPass()); // Catch trivial redundancies
|
||||
}
|
||||
// EP_OptimizerLast does not exist in LLVM 3.0, add it manually below.
|
||||
builder.addExtension(PassManagerBuilder::EP_OptimizerLast, addStripExternalsPass);
|
||||
#endif
|
||||
|
||||
if (optimizeLevel >= 1) {
|
||||
addPass(pm, createStripExternalsPass());
|
||||
addPass(pm, createGlobalDCEPass());
|
||||
}
|
||||
builder.populateFunctionPassManager(fpm);
|
||||
builder.populateModulePassManager(mpm);
|
||||
|
||||
// level -O4 and -O5 are linktime optimizations
|
||||
#if LDC_LLVM_VER < 301
|
||||
addStripExternalsPass(builder, mpm);
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -271,52 +206,80 @@ static void addPassesForOptLevel(PassManager& pm) {
|
|||
// Returns true if any optimization passes were invoked.
|
||||
bool ldc_optimize_module(llvm::Module* m)
|
||||
{
|
||||
if (!optimize())
|
||||
return false;
|
||||
// Create a PassManager to hold and optimize the collection of
|
||||
// per-module passes we are about to build.
|
||||
PassManager mpm;
|
||||
|
||||
PassManager pm;
|
||||
// Add an appropriate TargetLibraryInfo pass for the module's triple.
|
||||
TargetLibraryInfo *tli = new TargetLibraryInfo(Triple(m->getTargetTriple()));
|
||||
|
||||
if (verifyEach) pm.add(createVerifierPass());
|
||||
// The -disable-simplify-libcalls flag actually disables all builtin optzns.
|
||||
if (disableSimplifyRuntimeCalls)
|
||||
tli->disableAllFunctions();
|
||||
mpm.add(tli);
|
||||
|
||||
// Add an appropriate TargetData instance for this module.
|
||||
#if LDC_LLVM_VER >= 302
|
||||
addPass(pm, new DataLayout(m));
|
||||
mpm.add(new DataLayout(m));
|
||||
#else
|
||||
addPass(pm, new TargetData(m));
|
||||
mpm.add(new TargetData(m));
|
||||
#endif
|
||||
|
||||
bool optimize = optimizeLevel != 0 || doInline();
|
||||
// Also set up a manager for the per-function passes.
|
||||
FunctionPassManager fpm(m);
|
||||
#if LDC_LLVM_VER >= 302
|
||||
fpm.add(new DataLayout(m));
|
||||
#else
|
||||
fpm.add(new TargetData(m));
|
||||
#endif
|
||||
|
||||
unsigned optPos = optimizeLevel != 0
|
||||
? optimizeLevel.getPosition()
|
||||
: enableInlining.getPosition();
|
||||
// If the -strip-debug command line option was specified, add it before
|
||||
// anything else.
|
||||
if (stripDebug)
|
||||
addPass(mpm, createStripSymbolsPass(true));
|
||||
|
||||
for (size_t i = 0; i < passList.size(); i++) {
|
||||
// insert -O<N> / -enable-inlining in right position
|
||||
if (optimize && optPos < passList.getPosition(i)) {
|
||||
addPassesForOptLevel(pm);
|
||||
optimize = false;
|
||||
bool defaultsAdded = false;
|
||||
// Create a new optimization pass for each one specified on the command line
|
||||
for (unsigned i = 0; i < passList.size(); ++i) {
|
||||
if (optimizeLevel && optimizeLevel.getPosition() < passList.getPosition(i)) {
|
||||
addOptimizationPasses(mpm, fpm, optLevel(), sizeLevel());
|
||||
defaultsAdded = true;
|
||||
}
|
||||
|
||||
const PassInfo* pass = passList[i];
|
||||
if (PassInfo::NormalCtor_t ctor = pass->getNormalCtor()) {
|
||||
addPass(pm, ctor());
|
||||
} else {
|
||||
const char* arg = pass->getPassArgument(); // may return null
|
||||
const PassInfo *passInf = passList[i];
|
||||
Pass *pass = 0;
|
||||
if (passInf->getNormalCtor())
|
||||
pass = passInf->getNormalCtor()();
|
||||
else {
|
||||
const char* arg = passInf->getPassArgument(); // may return null
|
||||
if (arg)
|
||||
error("Can't create pass '-%s' (%s)", arg, pass->getPassName());
|
||||
else
|
||||
error("Can't create pass (%s)", pass->getPassName());
|
||||
assert(0); // Should be unreachable; root.h:error() calls exit()
|
||||
llvm_unreachable("pass creation failed");
|
||||
}
|
||||
if (pass) {
|
||||
addPass(mpm, pass);
|
||||
}
|
||||
}
|
||||
// insert -O<N> / -enable-inlining if specified at the end,
|
||||
if (optimize)
|
||||
addPassesForOptLevel(pm);
|
||||
|
||||
pm.run(*m);
|
||||
// Add the default passes for the specified optimization level.
|
||||
if (!defaultsAdded)
|
||||
addOptimizationPasses(mpm, fpm, optLevel(), sizeLevel());
|
||||
|
||||
// Run per-function passes.
|
||||
fpm.doInitialization();
|
||||
for (llvm::Module::iterator F = m->begin(), E = m->end(); F != E; ++F)
|
||||
fpm.run(*F);
|
||||
fpm.doFinalization();
|
||||
|
||||
// Run per-module passes.
|
||||
mpm.run(*m);
|
||||
|
||||
// Verify the resulting module.
|
||||
verifyModule(m);
|
||||
|
||||
// Report that we run some passes.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,13 +12,9 @@ namespace llvm { class Module; }
|
|||
|
||||
bool ldc_optimize_module(llvm::Module* m);
|
||||
|
||||
// Determines whether the inliner will run in the -O<N> list of passes
|
||||
bool doInline();
|
||||
// Determines whether the inliner will be run at all.
|
||||
// Returns whether the normal, full inlining pass will be run.
|
||||
bool willInline();
|
||||
|
||||
int optLevel();
|
||||
|
||||
bool optimize();
|
||||
|
||||
llvm::CodeGenOpt::Level codeGenOptLevel();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue