ldc/runtime/jit-rt/cpp-so/optimizer.cpp
2023-12-03 19:07:31 +01:00

263 lines
8.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- optimizer.cpp -----------------------------------------------------===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the Boost Software License. See the LICENSE
// file for details.
// Uses some parts from gen/optimizer.cpp which is under the BSD-style LDC
// license.
//
//===----------------------------------------------------------------------===//
#include "optimizer.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#if LDC_LLVM_VER < 1700
#include "llvm/ADT/Triple.h"
#else
#include "llvm/TargetParser/Triple.h"
#endif
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/Inliner.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "context.h"
#include "utils.h"
#include "valueparser.h"
#ifdef LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES
#include "Passes.h"
#endif
namespace {
namespace cl = llvm::cl;
cl::opt<bool>
verifyEach("verify-each", cl::ZeroOrMore, cl::Hidden,
cl::desc("Run verifier after D-specific and explicitly "
"specified optimization passes"));
/// LDC LICENSE START
#ifdef LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES
cl::opt<bool>
disableLangSpecificPasses("disable-d-passes", cl::ZeroOrMore,
cl::desc("Disable all D-specific passes"));
cl::opt<bool> disableSimplifyDruntimeCalls(
"disable-simplify-drtcalls", cl::ZeroOrMore,
cl::desc("Disable simplification of druntime calls"));
cl::opt<bool> disableSimplifyLibCalls(
"disable-simplify-libcalls", cl::ZeroOrMore,
cl::desc("Disable simplification of well-known C runtime calls"));
cl::opt<bool> disableGCToStack(
"disable-gc2stack", cl::ZeroOrMore,
cl::desc("Disable promotion of GC allocations to stack memory"));
#endif
/// LDC LICENSE END
cl::opt<bool> stripDebug(
"strip-debug", cl::ZeroOrMore,
cl::desc("Strip symbolic debug information before optimization"));
cl::opt<bool> disableLoopUnrolling(
"disable-loop-unrolling", cl::ZeroOrMore,
cl::desc("Disable loop unrolling in all relevant passes"));
cl::opt<bool>
disableLoopVectorization("disable-loop-vectorization", cl::ZeroOrMore,
cl::desc("Disable the loop vectorization pass"));
cl::opt<bool>
disableSLPVectorization("disable-slp-vectorization", cl::ZeroOrMore,
cl::desc("Disable the slp vectorization pass"));
/// LDC LICENSE START
#ifdef LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES
void addPass(llvm::PassManagerBase &pm, llvm::Pass *pass) {
pm.add(pass);
if (verifyEach) {
pm.add(llvm::createVerifierPass());
}
}
void addStripExternalsPass(const llvm::PassManagerBuilder &builder,
llvm::PassManagerBase &pm) {
if (builder.OptLevel >= 1) {
addPass(pm, createStripExternalsPass());
addPass(pm, llvm::createGlobalDCEPass());
}
}
void addSimplifyDRuntimeCallsPass(const llvm::PassManagerBuilder &builder,
llvm::PassManagerBase &pm) {
if (builder.OptLevel >= 2 && builder.SizeLevel == 0) {
addPass(pm, createSimplifyDRuntimeCalls());
}
}
void addGarbageCollect2StackPass(const llvm::PassManagerBuilder &builder,
llvm::PassManagerBase &pm) {
if (builder.OptLevel >= 2 && builder.SizeLevel == 0) {
addPass(pm, createGarbageCollect2Stack());
}
}
#endif
/// LDC LICENSE END
// TODO: share this function with compiler
void addOptimizationPasses(llvm::legacy::PassManagerBase &mpm,
llvm::legacy::FunctionPassManager &fpm,
unsigned optLevel, unsigned sizeLevel) {
llvm::PassManagerBuilder builder;
builder.OptLevel = optLevel;
builder.SizeLevel = sizeLevel;
// TODO: expose this option from jit
if (/*willInline()*/ true) {
auto params = llvm::getInlineParams(optLevel, sizeLevel);
builder.Inliner = llvm::createFunctionInliningPass(params);
} else {
builder.Inliner = llvm::createAlwaysInlinerLegacyPass();
}
builder.DisableUnrollLoops = (disableLoopUnrolling.getNumOccurrences() > 0)
? disableLoopUnrolling
: optLevel == 0;
if (disableLoopVectorization) {
builder.LoopVectorize = false;
// If option wasn't forced via cmd line (-vectorize-loops, -loop-vectorize)
} else if (!builder.LoopVectorize) {
builder.LoopVectorize = optLevel > 1 && sizeLevel < 2;
}
builder.SLPVectorize =
disableSLPVectorization ? false : optLevel > 1 && sizeLevel < 2;
// TODO: sanitizers support in jit?
// TODO: PGO support in jit?
/// LDC LICENSE START
#ifdef LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES
if (!disableLangSpecificPasses) {
if (!disableSimplifyDruntimeCalls) {
builder.addExtension(llvm::PassManagerBuilder::EP_LoopOptimizerEnd,
addSimplifyDRuntimeCallsPass);
}
if (!disableGCToStack) {
builder.addExtension(llvm::PassManagerBuilder::EP_LoopOptimizerEnd,
addGarbageCollect2StackPass);
}
}
// EP_OptimizerLast does not exist in LLVM 3.0, add it manually below.
builder.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast,
addStripExternalsPass);
#endif
/// LDC LICENSE END
builder.populateFunctionPassManager(fpm);
builder.populateModulePassManager(mpm);
}
void setupPasses(llvm::TargetMachine &targetMachine,
const OptimizerSettings &settings,
llvm::legacy::PassManager &mpm,
llvm::legacy::FunctionPassManager &fpm) {
mpm.add(
new llvm::TargetLibraryInfoWrapperPass(targetMachine.getTargetTriple()));
mpm.add(llvm::createTargetTransformInfoWrapperPass(
targetMachine.getTargetIRAnalysis()));
fpm.add(llvm::createTargetTransformInfoWrapperPass(
targetMachine.getTargetIRAnalysis()));
if (stripDebug) {
mpm.add(llvm::createStripSymbolsPass(true));
}
mpm.add(llvm::createStripDeadPrototypesPass());
mpm.add(llvm::createStripDeadDebugInfoPass());
addOptimizationPasses(mpm, fpm, settings.optLevel, settings.sizeLevel);
}
struct FuncFinalizer final {
llvm::legacy::FunctionPassManager &fpm;
explicit FuncFinalizer(llvm::legacy::FunctionPassManager &_fpm) : fpm(_fpm) {
fpm.doInitialization();
}
~FuncFinalizer() { fpm.doFinalization(); }
};
void stripComdat(llvm::Module &module) {
for (auto &&func : module.functions()) {
func.setComdat(nullptr);
}
for (auto &&var : module.globals()) {
var.setComdat(nullptr);
}
module.getComdatSymbolTable().clear();
}
} // anon namespace
void optimizeModule(const Context &context, llvm::TargetMachine &targetMachine,
const OptimizerSettings &settings, llvm::Module &module) {
// There is llvm bug related tp comdat and IR based pgo
// and anyway comdat is useless at this stage
stripComdat(module);
llvm::legacy::PassManager mpm;
llvm::legacy::FunctionPassManager fpm(&module);
const auto name = module.getName();
interruptPoint(context, "Setup passes for module", name.data());
setupPasses(targetMachine, settings, mpm, fpm);
// Run per-function passes.
{
FuncFinalizer finalizer(fpm);
for (auto &fun : module) {
if (fun.isDeclaration()) {
interruptPoint(context, "Func decl", fun.getName().data());
} else {
interruptPoint(context, "Run passes for function",
fun.getName().data());
}
fpm.run(fun);
}
}
// Run per-module passes.
interruptPoint(context, "Run passes for module", name.data());
mpm.run(module);
}
void setRtCompileVar(const Context &context, llvm::Module &module,
const char *name, const void *init) {
assert(nullptr != name);
assert(nullptr != init);
auto var = module.getGlobalVariable(name);
if (nullptr != var) {
auto type = var->getValueType();
auto initializer =
parseInitializer(module.getDataLayout(), *type, init,
[&](const std::string &str) { fatal(context, str); });
var->setConstant(true);
var->setInitializer(initializer);
var->setLinkage(llvm::GlobalValue::PrivateLinkage);
}
}