diff options
Diffstat (limited to 'lib/LTO/LTOCodeGenerator.cpp')
-rw-r--r-- | lib/LTO/LTOCodeGenerator.cpp | 329 |
1 files changed, 141 insertions, 188 deletions
diff --git a/lib/LTO/LTOCodeGenerator.cpp b/lib/LTO/LTOCodeGenerator.cpp index 25ae4ac76e3c..6baaaa4b1395 100644 --- a/lib/LTO/LTOCodeGenerator.cpp +++ b/lib/LTO/LTOCodeGenerator.cpp @@ -18,6 +18,7 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/CodeGen/ParallelCG.h" #include "llvm/CodeGen/RuntimeLibcalls.h" #include "llvm/Config/config.h" #include "llvm/IR/Constants.h" @@ -63,47 +64,15 @@ const char* LTOCodeGenerator::getVersionString() { #endif } -static void handleLTODiagnostic(const DiagnosticInfo &DI) { - DiagnosticPrinterRawOStream DP(errs()); - DI.print(DP); - errs() << "\n"; -} - -LTOCodeGenerator::LTOCodeGenerator() - : Context(getGlobalContext()), IRLinker(new Module("ld-temp.o", Context), - handleLTODiagnostic) { - initializeLTOPasses(); -} - -LTOCodeGenerator::LTOCodeGenerator(std::unique_ptr<LLVMContext> Context) - : OwnedContext(std::move(Context)), Context(*OwnedContext), - IRLinker(new Module("ld-temp.o", *OwnedContext), handleLTODiagnostic) { +LTOCodeGenerator::LTOCodeGenerator(LLVMContext &Context) + : Context(Context), MergedModule(new Module("ld-temp.o", Context)), + TheLinker(new Linker(*MergedModule)) { initializeLTOPasses(); } -void LTOCodeGenerator::destroyMergedModule() { - if (OwnedModule) { - assert(IRLinker.getModule() == &OwnedModule->getModule() && - "The linker's module should be the same as the owned module"); - delete OwnedModule; - OwnedModule = nullptr; - } else if (IRLinker.getModule()) - IRLinker.deleteModule(); -} - -LTOCodeGenerator::~LTOCodeGenerator() { - destroyMergedModule(); +LTOCodeGenerator::~LTOCodeGenerator() {} - delete TargetMach; - TargetMach = nullptr; - - for (std::vector<char *>::iterator I = CodegenOptions.begin(), - E = CodegenOptions.end(); - I != E; ++I) - free(*I); -} - -// Initialize LTO passes. Please keep this funciton in sync with +// Initialize LTO passes. Please keep this function in sync with // PassManagerBuilder::populateLTOPassManager(), and make sure all LTO // passes are initialized. void LTOCodeGenerator::initializeLTOPasses() { @@ -120,11 +89,11 @@ void LTOCodeGenerator::initializeLTOPasses() { initializeGlobalDCEPass(R); initializeArgPromotionPass(R); initializeJumpThreadingPass(R); - initializeSROAPass(R); + initializeSROALegacyPassPass(R); initializeSROA_DTPass(R); initializeSROA_SSAUpPass(R); initializeFunctionAttrsPass(R); - initializeGlobalsModRefPass(R); + initializeGlobalsAAWrapperPassPass(R); initializeLICMPass(R); initializeMergedLoadStoreMotionPass(R); initializeGVNPass(R); @@ -133,41 +102,39 @@ void LTOCodeGenerator::initializeLTOPasses() { initializeCFGSimplifyPassPass(R); } -bool LTOCodeGenerator::addModule(LTOModule *mod) { - assert(&mod->getModule().getContext() == &Context && +bool LTOCodeGenerator::addModule(LTOModule *Mod) { + assert(&Mod->getModule().getContext() == &Context && "Expected module in same context"); - bool ret = IRLinker.linkInModule(&mod->getModule()); + bool ret = TheLinker->linkInModule(Mod->takeModule()); - const std::vector<const char*> &undefs = mod->getAsmUndefinedRefs(); + const std::vector<const char *> &undefs = Mod->getAsmUndefinedRefs(); for (int i = 0, e = undefs.size(); i != e; ++i) AsmUndefinedRefs[undefs[i]] = 1; return !ret; } -void LTOCodeGenerator::setModule(LTOModule *Mod) { +void LTOCodeGenerator::setModule(std::unique_ptr<LTOModule> Mod) { assert(&Mod->getModule().getContext() == &Context && "Expected module in same context"); - // Delete the old merged module. - destroyMergedModule(); AsmUndefinedRefs.clear(); - OwnedModule = Mod; - IRLinker.setModule(&Mod->getModule()); + MergedModule = Mod->takeModule(); + TheLinker = make_unique<Linker>(*MergedModule); const std::vector<const char*> &Undefs = Mod->getAsmUndefinedRefs(); for (int I = 0, E = Undefs.size(); I != E; ++I) AsmUndefinedRefs[Undefs[I]] = 1; } -void LTOCodeGenerator::setTargetOptions(TargetOptions options) { - Options = options; +void LTOCodeGenerator::setTargetOptions(TargetOptions Options) { + this->Options = Options; } -void LTOCodeGenerator::setDebugInfo(lto_debug_model debug) { - switch (debug) { +void LTOCodeGenerator::setDebugInfo(lto_debug_model Debug) { + switch (Debug) { case LTO_DEBUG_MODEL_NONE: EmitDwarfDebugInfo = false; return; @@ -179,21 +146,26 @@ void LTOCodeGenerator::setDebugInfo(lto_debug_model debug) { llvm_unreachable("Unknown debug format!"); } -void LTOCodeGenerator::setCodePICModel(lto_codegen_model model) { - switch (model) { - case LTO_CODEGEN_PIC_MODEL_STATIC: - case LTO_CODEGEN_PIC_MODEL_DYNAMIC: - case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: - case LTO_CODEGEN_PIC_MODEL_DEFAULT: - CodeModel = model; - return; +void LTOCodeGenerator::setOptLevel(unsigned Level) { + OptLevel = Level; + switch (OptLevel) { + case 0: + CGOptLevel = CodeGenOpt::None; + break; + case 1: + CGOptLevel = CodeGenOpt::Less; + break; + case 2: + CGOptLevel = CodeGenOpt::Default; + break; + case 3: + CGOptLevel = CodeGenOpt::Aggressive; + break; } - llvm_unreachable("Unknown PIC model!"); } -bool LTOCodeGenerator::writeMergedModules(const char *path, - std::string &errMsg) { - if (!determineTarget(errMsg)) +bool LTOCodeGenerator::writeMergedModules(const char *Path) { + if (!determineTarget()) return false; // mark which symbols can not be internalized @@ -201,20 +173,22 @@ bool LTOCodeGenerator::writeMergedModules(const char *path, // create output file std::error_code EC; - tool_output_file Out(path, EC, sys::fs::F_None); + tool_output_file Out(Path, EC, sys::fs::F_None); if (EC) { - errMsg = "could not open bitcode file for writing: "; - errMsg += path; + std::string ErrMsg = "could not open bitcode file for writing: "; + ErrMsg += Path; + emitError(ErrMsg); return false; } // write bitcode to it - WriteBitcodeToFile(IRLinker.getModule(), Out.os(), ShouldEmbedUselists); + WriteBitcodeToFile(MergedModule.get(), Out.os(), ShouldEmbedUselists); Out.os().close(); if (Out.os().has_error()) { - errMsg = "could not write bitcode file: "; - errMsg += path; + std::string ErrMsg = "could not write bitcode file: "; + ErrMsg += Path; + emitError(ErrMsg); Out.os().clear_error(); return false; } @@ -223,22 +197,25 @@ bool LTOCodeGenerator::writeMergedModules(const char *path, return true; } -bool LTOCodeGenerator::compileOptimizedToFile(const char **name, - std::string &errMsg) { - // make unique temp .o file to put generated object file +bool LTOCodeGenerator::compileOptimizedToFile(const char **Name) { + // make unique temp output file to put generated code SmallString<128> Filename; int FD; + + const char *Extension = + (FileType == TargetMachine::CGFT_AssemblyFile ? "s" : "o"); + std::error_code EC = - sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename); + sys::fs::createTemporaryFile("lto-llvm", Extension, FD, Filename); if (EC) { - errMsg = EC.message(); + emitError(EC.message()); return false; } // generate object file tool_output_file objFile(Filename.c_str(), FD); - bool genResult = compileOptimized(objFile.os(), errMsg); + bool genResult = compileOptimized(&objFile.os()); objFile.os().close(); if (objFile.os().has_error()) { objFile.os().clear_error(); @@ -253,21 +230,21 @@ bool LTOCodeGenerator::compileOptimizedToFile(const char **name, } NativeObjectPath = Filename.c_str(); - *name = NativeObjectPath.c_str(); + *Name = NativeObjectPath.c_str(); return true; } std::unique_ptr<MemoryBuffer> -LTOCodeGenerator::compileOptimized(std::string &errMsg) { +LTOCodeGenerator::compileOptimized() { const char *name; - if (!compileOptimizedToFile(&name, errMsg)) + if (!compileOptimizedToFile(&name)) return nullptr; // read .o file into memory buffer ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = MemoryBuffer::getFile(name, -1, false); if (std::error_code EC = BufferOrErr.getError()) { - errMsg = EC.message(); + emitError(EC.message()); sys::fs::remove(NativeObjectPath); return nullptr; } @@ -278,66 +255,51 @@ LTOCodeGenerator::compileOptimized(std::string &errMsg) { return std::move(*BufferOrErr); } - -bool LTOCodeGenerator::compile_to_file(const char **name, - bool disableInline, - bool disableGVNLoadPRE, - bool disableVectorization, - std::string &errMsg) { - if (!optimize(disableInline, disableGVNLoadPRE, - disableVectorization, errMsg)) +bool LTOCodeGenerator::compile_to_file(const char **Name, bool DisableVerify, + bool DisableInline, + bool DisableGVNLoadPRE, + bool DisableVectorization) { + if (!optimize(DisableVerify, DisableInline, DisableGVNLoadPRE, + DisableVectorization)) return false; - return compileOptimizedToFile(name, errMsg); + return compileOptimizedToFile(Name); } std::unique_ptr<MemoryBuffer> -LTOCodeGenerator::compile(bool disableInline, bool disableGVNLoadPRE, - bool disableVectorization, std::string &errMsg) { - if (!optimize(disableInline, disableGVNLoadPRE, - disableVectorization, errMsg)) +LTOCodeGenerator::compile(bool DisableVerify, bool DisableInline, + bool DisableGVNLoadPRE, bool DisableVectorization) { + if (!optimize(DisableVerify, DisableInline, DisableGVNLoadPRE, + DisableVectorization)) return nullptr; - return compileOptimized(errMsg); + return compileOptimized(); } -bool LTOCodeGenerator::determineTarget(std::string &errMsg) { +bool LTOCodeGenerator::determineTarget() { if (TargetMach) return true; - std::string TripleStr = IRLinker.getModule()->getTargetTriple(); - if (TripleStr.empty()) + std::string TripleStr = MergedModule->getTargetTriple(); + if (TripleStr.empty()) { TripleStr = sys::getDefaultTargetTriple(); + MergedModule->setTargetTriple(TripleStr); + } llvm::Triple Triple(TripleStr); // create target machine from info for merged modules - const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); - if (!march) + std::string ErrMsg; + const Target *march = TargetRegistry::lookupTarget(TripleStr, ErrMsg); + if (!march) { + emitError(ErrMsg); return false; - - // The relocation model is actually a static member of TargetMachine and - // needs to be set before the TargetMachine is instantiated. - Reloc::Model RelocModel = Reloc::Default; - switch (CodeModel) { - case LTO_CODEGEN_PIC_MODEL_STATIC: - RelocModel = Reloc::Static; - break; - case LTO_CODEGEN_PIC_MODEL_DYNAMIC: - RelocModel = Reloc::PIC_; - break; - case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: - RelocModel = Reloc::DynamicNoPIC; - break; - case LTO_CODEGEN_PIC_MODEL_DEFAULT: - // RelocModel is already the default, so leave it that way. - break; } // Construct LTOModule, hand over ownership of module and target. Use MAttr as // the default set of features. SubtargetFeatures Features(MAttr); Features.getDefaultSubtargetFeatures(Triple); - std::string FeatureStr = Features.getString(); + FeatureStr = Features.getString(); // Set a default CPU for Darwin triples. if (MCpu.empty() && Triple.isOSDarwin()) { if (Triple.getArch() == llvm::Triple::x86_64) @@ -348,25 +310,9 @@ bool LTOCodeGenerator::determineTarget(std::string &errMsg) { MCpu = "cyclone"; } - CodeGenOpt::Level CGOptLevel; - switch (OptLevel) { - case 0: - CGOptLevel = CodeGenOpt::None; - break; - case 1: - CGOptLevel = CodeGenOpt::Less; - break; - case 2: - CGOptLevel = CodeGenOpt::Default; - break; - case 3: - CGOptLevel = CodeGenOpt::Aggressive; - break; - } - - TargetMach = march->createTargetMachine(TripleStr, MCpu, FeatureStr, Options, - RelocModel, CodeModel::Default, - CGOptLevel); + TargetMach.reset(march->createTargetMachine(TripleStr, MCpu, FeatureStr, + Options, RelocModel, + CodeModel::Default, CGOptLevel)); return true; } @@ -453,7 +399,6 @@ static void accumulateAndSortLibcalls(std::vector<StringRef> &Libcalls, void LTOCodeGenerator::applyScopeRestrictions() { if (ScopeRestrictionsDone || !ShouldInternalize) return; - Module *mergedModule = IRLinker.getModule(); // Start off with a verification pass. legacy::PassManager passes; @@ -467,20 +412,17 @@ void LTOCodeGenerator::applyScopeRestrictions() { TargetLibraryInfoImpl TLII(Triple(TargetMach->getTargetTriple())); TargetLibraryInfo TLI(TLII); - accumulateAndSortLibcalls(Libcalls, TLI, *mergedModule, *TargetMach); + accumulateAndSortLibcalls(Libcalls, TLI, *MergedModule, *TargetMach); - for (Module::iterator f = mergedModule->begin(), - e = mergedModule->end(); f != e; ++f) - applyRestriction(*f, Libcalls, MustPreserveList, AsmUsed, Mangler); - for (Module::global_iterator v = mergedModule->global_begin(), - e = mergedModule->global_end(); v != e; ++v) - applyRestriction(*v, Libcalls, MustPreserveList, AsmUsed, Mangler); - for (Module::alias_iterator a = mergedModule->alias_begin(), - e = mergedModule->alias_end(); a != e; ++a) - applyRestriction(*a, Libcalls, MustPreserveList, AsmUsed, Mangler); + for (Function &f : *MergedModule) + applyRestriction(f, Libcalls, MustPreserveList, AsmUsed, Mangler); + for (GlobalVariable &v : MergedModule->globals()) + applyRestriction(v, Libcalls, MustPreserveList, AsmUsed, Mangler); + for (GlobalAlias &a : MergedModule->aliases()) + applyRestriction(a, Libcalls, MustPreserveList, AsmUsed, Mangler); GlobalVariable *LLVMCompilerUsed = - mergedModule->getGlobalVariable("llvm.compiler.used"); + MergedModule->getGlobalVariable("llvm.compiler.used"); findUsedValues(LLVMCompilerUsed, AsmUsed); if (LLVMCompilerUsed) LLVMCompilerUsed->eraseFromParent(); @@ -495,7 +437,7 @@ void LTOCodeGenerator::applyScopeRestrictions() { llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size()); LLVMCompilerUsed = - new llvm::GlobalVariable(*mergedModule, ATy, false, + new llvm::GlobalVariable(*MergedModule, ATy, false, llvm::GlobalValue::AppendingLinkage, llvm::ConstantArray::get(ATy, asmUsed2), "llvm.compiler.used"); @@ -506,21 +448,18 @@ void LTOCodeGenerator::applyScopeRestrictions() { passes.add(createInternalizePass(MustPreserveList)); // apply scope restrictions - passes.run(*mergedModule); + passes.run(*MergedModule); ScopeRestrictionsDone = true; } /// Optimize merged modules using various IPO passes -bool LTOCodeGenerator::optimize(bool DisableInline, +bool LTOCodeGenerator::optimize(bool DisableVerify, bool DisableInline, bool DisableGVNLoadPRE, - bool DisableVectorization, - std::string &errMsg) { - if (!this->determineTarget(errMsg)) + bool DisableVectorization) { + if (!this->determineTarget()) return false; - Module *mergedModule = IRLinker.getModule(); - // Mark which symbols can not be internalized this->applyScopeRestrictions(); @@ -528,7 +467,7 @@ bool LTOCodeGenerator::optimize(bool DisableInline, legacy::PassManager passes; // Add an appropriate DataLayout instance for this module... - mergedModule->setDataLayout(*TargetMach->getDataLayout()); + MergedModule->setDataLayout(TargetMach->createDataLayout()); passes.add( createTargetTransformInfoWrapperPass(TargetMach->getTargetIRAnalysis())); @@ -542,60 +481,57 @@ bool LTOCodeGenerator::optimize(bool DisableInline, PMB.Inliner = createFunctionInliningPass(); PMB.LibraryInfo = new TargetLibraryInfoImpl(TargetTriple); PMB.OptLevel = OptLevel; - PMB.VerifyInput = true; - PMB.VerifyOutput = true; + PMB.VerifyInput = !DisableVerify; + PMB.VerifyOutput = !DisableVerify; PMB.populateLTOPassManager(passes); // Run our queue of passes all at once now, efficiently. - passes.run(*mergedModule); + passes.run(*MergedModule); return true; } -bool LTOCodeGenerator::compileOptimized(raw_pwrite_stream &out, - std::string &errMsg) { - if (!this->determineTarget(errMsg)) +bool LTOCodeGenerator::compileOptimized(ArrayRef<raw_pwrite_stream *> Out) { + if (!this->determineTarget()) return false; - Module *mergedModule = IRLinker.getModule(); - - legacy::PassManager codeGenPasses; + legacy::PassManager preCodeGenPasses; // If the bitcode files contain ARC code and were compiled with optimization, // the ObjCARCContractPass must be run, so do it unconditionally here. - codeGenPasses.add(createObjCARCContractPass()); - - if (TargetMach->addPassesToEmitFile(codeGenPasses, out, - TargetMachine::CGFT_ObjectFile)) { - errMsg = "target file type not supported"; - return false; - } - - // Run the code generator, and write assembly file - codeGenPasses.run(*mergedModule); + preCodeGenPasses.add(createObjCARCContractPass()); + preCodeGenPasses.run(*MergedModule); + + // Do code generation. We need to preserve the module in case the client calls + // writeMergedModules() after compilation, but we only need to allow this at + // parallelism level 1. This is achieved by having splitCodeGen return the + // original module at parallelism level 1 which we then assign back to + // MergedModule. + MergedModule = + splitCodeGen(std::move(MergedModule), Out, MCpu, FeatureStr, Options, + RelocModel, CodeModel::Default, CGOptLevel, FileType); return true; } /// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging /// LTO problems. -void LTOCodeGenerator::setCodeGenDebugOptions(const char *options) { - for (std::pair<StringRef, StringRef> o = getToken(options); - !o.first.empty(); o = getToken(o.second)) { - // ParseCommandLineOptions() expects argv[0] to be program name. Lazily add - // that. - if (CodegenOptions.empty()) - CodegenOptions.push_back(strdup("libLLVMLTO")); - CodegenOptions.push_back(strdup(o.first.str().c_str())); - } +void LTOCodeGenerator::setCodeGenDebugOptions(const char *Options) { + for (std::pair<StringRef, StringRef> o = getToken(Options); !o.first.empty(); + o = getToken(o.second)) + CodegenOptions.push_back(o.first); } void LTOCodeGenerator::parseCodeGenDebugOptions() { // if options were requested, set them - if (!CodegenOptions.empty()) - cl::ParseCommandLineOptions(CodegenOptions.size(), - const_cast<char **>(&CodegenOptions[0])); + if (!CodegenOptions.empty()) { + // ParseCommandLineOptions() expects argv[0] to be program name. + std::vector<const char *> CodegenArgv(1, "libLLVMLTO"); + for (std::string &Arg : CodegenOptions) + CodegenArgv.push_back(Arg.c_str()); + cl::ParseCommandLineOptions(CodegenArgv.size(), CodegenArgv.data()); + } } void LTOCodeGenerator::DiagnosticHandler(const DiagnosticInfo &DI, @@ -645,3 +581,20 @@ LTOCodeGenerator::setDiagnosticHandler(lto_diagnostic_handler_t DiagHandler, Context.setDiagnosticHandler(LTOCodeGenerator::DiagnosticHandler, this, /* RespectFilters */ true); } + +namespace { +class LTODiagnosticInfo : public DiagnosticInfo { + const Twine &Msg; +public: + LTODiagnosticInfo(const Twine &DiagMsg, DiagnosticSeverity Severity=DS_Error) + : DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {} + void print(DiagnosticPrinter &DP) const override { DP << Msg; } +}; +} + +void LTOCodeGenerator::emitError(const std::string &ErrMsg) { + if (DiagHandler) + (*DiagHandler)(LTO_DS_ERROR, ErrMsg.c_str(), DiagContext); + else + Context.diagnose(LTODiagnosticInfo(ErrMsg)); +} |