//===-- optimizer.cpp -----------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the Boost Software License. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #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" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "context.h" #include "utils.h" #include "valueparser.h" namespace { void addOptimizationPasses(llvm::legacy::PassManagerBase &mpm, llvm::legacy::FunctionPassManager &fpm, unsigned optLevel, unsigned sizeLevel) { // if (!noVerify) { // fpm.add(createVerifierPass()); // } llvm::PassManagerBuilder builder; builder.OptLevel = optLevel; builder.SizeLevel = sizeLevel; if (/*willInline()*/ true) { unsigned threshold = 225; if (sizeLevel == 1) { // -Os threshold = 75; } else if (sizeLevel == 2) { // -Oz threshold = 25; } if (optLevel > 2) { threshold = 275; } builder.Inliner = llvm::createFunctionInliningPass(threshold); } // builder.DisableUnitAtATime = !unitAtATime; builder.DisableUnrollLoops = optLevel == 0; // builder.DisableUnrollLoops = (disableLoopUnrolling.getNumOccurrences() > // 0) // ? disableLoopUnrolling // : optLevel == 0; // This is final, unless there is a #pragma vectorize enable if (/*disableLoopVectorization*/ false) { 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; } // When #pragma vectorize is on for SLP, do the same as above builder.SLPVectorize = /*disableSLPVectorization*/ false ? false : optLevel > 1 && sizeLevel < 2; // if (opts::sanitize == opts::AddressSanitizer) { // builder.addExtension(PassManagerBuilder::EP_OptimizerLast, // addAddressSanitizerPasses); // builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, // addAddressSanitizerPasses); // } // if (opts::sanitize == opts::MemorySanitizer) { // builder.addExtension(PassManagerBuilder::EP_OptimizerLast, // addMemorySanitizerPass); // builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, // addMemorySanitizerPass); // } // if (opts::sanitize == opts::ThreadSanitizer) { // builder.addExtension(PassManagerBuilder::EP_OptimizerLast, // addThreadSanitizerPass); // builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, // addThreadSanitizerPass); // } // if (!disableLangSpecificPasses) { // if (!disableSimplifyDruntimeCalls) { // builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, // addSimplifyDRuntimeCallsPass); // } // if (!disableGCToStack) { // builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, // addGarbageCollect2StackPass); // } // } // EP_OptimizerLast does not exist in LLVM 3.0, add it manually below. // builder.addExtension(llvm::PassManagerBuilder::EP_OptimizerLast, // addStripExternalsPass); // addInstrProfilingPass(mpm); 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*/ true) { 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(); } }; } // anon namespace void optimizeModule(const Context &context, llvm::TargetMachine &targetMachine, const OptimizerSettings &settings, llvm::Module &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->getType()->getElementType(); auto initializer = parseInitializer(context, module.getDataLayout(), type, init); var->setConstant(true); var->setInitializer(initializer); var->setLinkage(llvm::GlobalValue::PrivateLinkage); // auto tempVar = new llvm::GlobalVariable( // module, // type, // true, // llvm::GlobalValue::PrivateLinkage, // initializer, // ".str"); // llvm::Constant *idxs[] = {zero}; // auto constPtr = llvm::ConstantExpr::getGetElementPtr(nullptr, // tempVar, // idxs, // true); // for (auto&& use: var->uses()) { // use->dump(); // use->getType()->dump(); // auto i = llvm::cast(use); // i->replaceAllUsesWith(constPtr); // i->eraseFromParent(); // } // var->replaceAllUsesWith(initializer); // var->eraseFromParent(); } }