//===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===////// The LLVM Compiler Infrastructure//// This file is distributed under the University of Illinois Open Source// License. See LICENSE.TXT for details.////===----------------------------------------------------------------------===////// This file implements the Link Time Optimization library. This library is// intended to be used by linker to optimize code at link time.////===----------------------------------------------------------------------===//#include"llvm/LTO/legacy/LTOCodeGenerator.h"#include"llvm/ADT/Statistic.h"#include"llvm/ADT/StringExtras.h"#include"llvm/Analysis/Passes.h"#include"llvm/Analysis/TargetLibraryInfo.h"#include"llvm/Analysis/TargetTransformInfo.h"#include"llvm/Bitcode/BitcodeWriter.h"#include"llvm/CodeGen/ParallelCG.h"#include"llvm/CodeGen/TargetSubtargetInfo.h"#include"llvm/Config/config.h"#include"llvm/IR/Constants.h"#include"llvm/IR/DataLayout.h"#include"llvm/IR/DebugInfo.h"#include"llvm/IR/DerivedTypes.h"#include"llvm/IR/DiagnosticInfo.h"#include"llvm/IR/DiagnosticPrinter.h"#include"llvm/IR/LLVMContext.h"#include"llvm/IR/LegacyPassManager.h"#include"llvm/IR/Mangler.h"#include"llvm/IR/Module.h"#include"llvm/IR/Verifier.h"#include"llvm/InitializePasses.h"#include"llvm/LTO/LTO.h"#include"llvm/LTO/legacy/LTOModule.h"#include"llvm/LTO/legacy/UpdateCompilerUsed.h"#include"llvm/Linker/Linker.h"#include"llvm/MC/MCAsmInfo.h"#include"llvm/MC/MCContext.h"#include"llvm/MC/SubtargetFeature.h"#include"llvm/Support/CommandLine.h"#include"llvm/Support/FileSystem.h"#include"llvm/Support/Host.h"#include"llvm/Support/MemoryBuffer.h"#include"llvm/Support/Signals.h"#include"llvm/Support/TargetRegistry.h"#include"llvm/Support/TargetSelect.h"#include"llvm/Support/ToolOutputFile.h"#include"llvm/Support/YAMLTraits.h"#include"llvm/Support/raw_ostream.h"#include"llvm/Target/TargetOptions.h"#include"llvm/Transforms/IPO.h"#include"llvm/Transforms/IPO/Internalize.h"#include"llvm/Transforms/IPO/PassManagerBuilder.h"#include"llvm/Transforms/ObjCARC.h"#include"llvm/Transforms/Utils/ModuleUtils.h"#include<system_error>usingnamespacellvm;constchar*LTOCodeGenerator::getVersionString(){#ifdef LLVM_VERSION_INFOreturnPACKAGE_NAME" version "PACKAGE_VERSION", "LLVM_VERSION_INFO;#elsereturnPACKAGE_NAME" version "PACKAGE_VERSION;#endif}namespacellvm{cl::opt<bool>LTODiscardValueNames("lto-discard-value-names",cl::desc("Strip names from Value during LTO (other than GlobalValue)."),#ifdef NDEBUGcl::init(true),#elsecl::init(false),#endifcl::Hidden);cl::opt<std::string>LTORemarksFilename("lto-pass-remarks-output",cl::desc("Output filename for pass remarks"),cl::value_desc("filename"));cl::opt<bool>LTOPassRemarksWithHotness("lto-pass-remarks-with-hotness",cl::desc("With PGO, include profile count in optimization remarks"),cl::Hidden);}LTOCodeGenerator::LTOCodeGenerator(LLVMContext&Context):Context(Context),MergedModule(newModule("ld-temp.o",Context)),TheLinker(newLinker(*MergedModule)){Context.setDiscardValueNames(LTODiscardValueNames);Context.enableDebugTypeODRUniquing();initializeLTOPasses();}LTOCodeGenerator::~LTOCodeGenerator(){}// Initialize LTO passes. Please keep this function in sync with// PassManagerBuilder::populateLTOPassManager(), and make sure all LTO// passes are initialized.voidLTOCodeGenerator::initializeLTOPasses(){PassRegistry&R=*PassRegistry::getPassRegistry();initializeInternalizeLegacyPassPass(R);initializeIPSCCPLegacyPassPass(R);initializeGlobalOptLegacyPassPass(R);initializeConstantMergeLegacyPassPass(R);initializeDAHPass(R);initializeInstructionCombiningPassPass(R);initializeSimpleInlinerPass(R);initializePruneEHPass(R);initializeGlobalDCELegacyPassPass(R);initializeArgPromotionPass(R);initializeJumpThreadingPass(R);initializeSROALegacyPassPass(R);initializePostOrderFunctionAttrsLegacyPassPass(R);initializeReversePostOrderFunctionAttrsLegacyPassPass(R);initializeGlobalsAAWrapperPassPass(R);initializeLegacyLICMPassPass(R);initializeMergedLoadStoreMotionLegacyPassPass(R);initializeGVNLegacyPassPass(R);initializeMemCpyOptLegacyPassPass(R);initializeDCELegacyPassPass(R);initializeCFGSimplifyPassPass(R);}voidLTOCodeGenerator::setAsmUndefinedRefs(LTOModule*Mod){conststd::vector<StringRef>&undefs=Mod->getAsmUndefinedRefs();for(inti=0,e=undefs.size();i!=e;++i)AsmUndefinedRefs[undefs[i]]=1;}boolLTOCodeGenerator::addModule(LTOModule*Mod){assert(&Mod->getModule().getContext()==&Context&&"Expected module in same context");boolret=TheLinker->linkInModule(Mod->takeModule());setAsmUndefinedRefs(Mod);// We've just changed the input, so let's make sure we verify it.HasVerifiedInput=false;return!ret;}voidLTOCodeGenerator::setModule(std::unique_ptr<LTOModule>Mod){assert(&Mod->getModule().getContext()==&Context&&"Expected module in same context");AsmUndefinedRefs.clear();MergedModule=Mod->takeModule();TheLinker=make_unique<Linker>(*MergedModule);setAsmUndefinedRefs(&*Mod);// We've just changed the input, so let's make sure we verify it.HasVerifiedInput=false;}voidLTOCodeGenerator::setTargetOptions(constTargetOptions&Options){this->Options=Options;}voidLTOCodeGenerator::setDebugInfo(lto_debug_modelDebug){switch(Debug){caseLTO_DEBUG_MODEL_NONE:EmitDwarfDebugInfo=false;return;caseLTO_DEBUG_MODEL_DWARF:EmitDwarfDebugInfo=true;return;}llvm_unreachable("Unknown debug format!");}voidLTOCodeGenerator::setOptLevel(unsignedLevel){OptLevel=Level;switch(OptLevel){case0:CGOptLevel=CodeGenOpt::None;return;case1:CGOptLevel=CodeGenOpt::Less;return;case2:CGOptLevel=CodeGenOpt::Default;return;case3:CGOptLevel=CodeGenOpt::Aggressive;return;}llvm_unreachable("Unknown optimization level!");}boolLTOCodeGenerator::writeMergedModules(StringRefPath){if(!determineTarget())returnfalse;// We always run the verifier once on the merged module.verifyMergedModuleOnce();// mark which symbols can not be internalizedapplyScopeRestrictions();// create output filestd::error_codeEC;ToolOutputFileOut(Path,EC,sys::fs::F_None);if(EC){std::stringErrMsg="could not open bitcode file for writing: ";ErrMsg+=Path.str()+": "+EC.message();emitError(ErrMsg);returnfalse;}// write bitcode to itWriteBitcodeToFile(*MergedModule,Out.os(),ShouldEmbedUselists);Out.os().close();if(Out.os().has_error()){std::stringErrMsg="could not write bitcode file: ";ErrMsg+=Path.str()+": "+Out.os().error().message();emitError(ErrMsg);Out.os().clear_error();returnfalse;}Out.keep();returntrue;}boolLTOCodeGenerator::compileOptimizedToFile(constchar**Name){// make unique temp output file to put generated codeSmallString<128>Filename;intFD;StringRefExtension(FileType==TargetMachine::CGFT_AssemblyFile?"s":"o");std::error_codeEC=sys::fs::createTemporaryFile("lto-llvm",Extension,FD,Filename);if(EC){emitError(EC.message());returnfalse;}// generate object fileToolOutputFileobjFile(Filename,FD);boolgenResult=compileOptimized(&objFile.os());objFile.os().close();if(objFile.os().has_error()){emitError((Twine("could not write object file: ")+Filename+": "+objFile.os().error().message()).str());objFile.os().clear_error();sys::fs::remove(Twine(Filename));returnfalse;}objFile.keep();if(!genResult){sys::fs::remove(Twine(Filename));returnfalse;}NativeObjectPath=Filename.c_str();*Name=NativeObjectPath.c_str();returntrue;}std::unique_ptr<MemoryBuffer>LTOCodeGenerator::compileOptimized(){constchar*name;if(!compileOptimizedToFile(&name))returnnullptr;// read .o file into memory bufferErrorOr<std::unique_ptr<MemoryBuffer>>BufferOrErr=MemoryBuffer::getFile(name,-1,false);if(std::error_codeEC=BufferOrErr.getError()){emitError(EC.message());sys::fs::remove(NativeObjectPath);returnnullptr;}// remove temp filessys::fs::remove(NativeObjectPath);returnstd::move(*BufferOrErr);}boolLTOCodeGenerator::compile_to_file(constchar**Name,boolDisableVerify,boolDisableInline,boolDisableGVNLoadPRE,boolDisableVectorization){if(!optimize(DisableVerify,DisableInline,DisableGVNLoadPRE,DisableVectorization))returnfalse;returncompileOptimizedToFile(Name);}std::unique_ptr<MemoryBuffer>LTOCodeGenerator::compile(boolDisableVerify,boolDisableInline,boolDisableGVNLoadPRE,boolDisableVectorization){if(!optimize(DisableVerify,DisableInline,DisableGVNLoadPRE,DisableVectorization))returnnullptr;returncompileOptimized();}boolLTOCodeGenerator::determineTarget(){if(TargetMach)returntrue;TripleStr=MergedModule->getTargetTriple();if(TripleStr.empty()){TripleStr=sys::getDefaultTargetTriple();MergedModule->setTargetTriple(TripleStr);}llvm::TripleTriple(TripleStr);// create target machine from info for merged modulesstd::stringErrMsg;MArch=TargetRegistry::lookupTarget(TripleStr,ErrMsg);if(!MArch){emitError(ErrMsg);returnfalse;}// Construct LTOModule, hand over ownership of module and target. Use MAttr as// the default set of features.SubtargetFeaturesFeatures(MAttr);Features.getDefaultSubtargetFeatures(Triple);FeatureStr=Features.getString();// Set a default CPU for Darwin triples.if(MCpu.empty()&&Triple.isOSDarwin()){if(Triple.getArch()==llvm::Triple::x86_64)MCpu="core2";elseif(Triple.getArch()==llvm::Triple::x86)MCpu="yonah";elseif(Triple.getArch()==llvm::Triple::aarch64)MCpu="cyclone";}TargetMach=createTargetMachine();returntrue;}std::unique_ptr<TargetMachine>LTOCodeGenerator::createTargetMachine(){returnstd::unique_ptr<TargetMachine>(MArch->createTargetMachine(TripleStr,MCpu,FeatureStr,Options,RelocModel,None,CGOptLevel));}// If a linkonce global is present in the MustPreserveSymbols, we need to make// sure we honor this. To force the compiler to not drop it, we add it to the// "llvm.compiler.used" global.voidLTOCodeGenerator::preserveDiscardableGVs(Module&TheModule,llvm::function_ref<bool(constGlobalValue&)>mustPreserveGV){std::vector<GlobalValue*>Used;automayPreserveGlobal=[&](GlobalValue&GV){if(!GV.isDiscardableIfUnused()||GV.isDeclaration()||!mustPreserveGV(GV))return;if(GV.hasAvailableExternallyLinkage())returnemitWarning((Twine("Linker asked to preserve available_externally global: '")+GV.getName()+"'").str());if(GV.hasInternalLinkage())returnemitWarning((Twine("Linker asked to preserve internal global: '")+GV.getName()+"'").str());Used.push_back(&GV);};for(auto&GV:TheModule)mayPreserveGlobal(GV);for(auto&GV:TheModule.globals())mayPreserveGlobal(GV);for(auto&GV:TheModule.aliases())mayPreserveGlobal(GV);if(Used.empty())return;appendToCompilerUsed(TheModule,Used);}voidLTOCodeGenerator::applyScopeRestrictions(){if(ScopeRestrictionsDone)return;// Declare a callback for the internalize pass that will ask for every// candidate GlobalValue if it can be internalized or not.ManglerMang;SmallString<64>MangledName;automustPreserveGV=[&](constGlobalValue&GV)->bool{// Unnamed globals can't be mangled, but they can't be preserved either.if(!GV.hasName())returnfalse;// Need to mangle the GV as the "MustPreserveSymbols" StringSet is filled// with the linker supplied name, which on Darwin includes a leading// underscore.MangledName.clear();MangledName.reserve(GV.getName().size()+1);Mang.getNameWithPrefix(MangledName,&GV,/*CannotUsePrivateLabel=*/false);returnMustPreserveSymbols.count(MangledName);};// Preserve linkonce value on linker requestpreserveDiscardableGVs(*MergedModule,mustPreserveGV);if(!ShouldInternalize)return;if(ShouldRestoreGlobalsLinkage){// Record the linkage type of non-local symbols so they can be restored// prior// to module splitting.autoRecordLinkage=[&](constGlobalValue&GV){if(!GV.hasAvailableExternallyLinkage()&&!GV.hasLocalLinkage()&&GV.hasName())ExternalSymbols.insert(std::make_pair(GV.getName(),GV.getLinkage()));};for(auto&GV:*MergedModule)RecordLinkage(GV);for(auto&GV:MergedModule->globals())RecordLinkage(GV);for(auto&GV:MergedModule->aliases())RecordLinkage(GV);}// Update the llvm.compiler_used globals to force preserving libcalls and// symbols referenced from asmupdateCompilerUsed(*MergedModule,*TargetMach,AsmUndefinedRefs);internalizeModule(*MergedModule,mustPreserveGV);ScopeRestrictionsDone=true;}/// Restore original linkage for symbols that may have been internalizedvoidLTOCodeGenerator::restoreLinkageForExternals(){if(!ShouldInternalize||!ShouldRestoreGlobalsLinkage)return;assert(ScopeRestrictionsDone&&"Cannot externalize without internalization!");if(ExternalSymbols.empty())return;autoexternalize=[this](GlobalValue&GV){if(!GV.hasLocalLinkage()||!GV.hasName())return;autoI=ExternalSymbols.find(GV.getName());if(I==ExternalSymbols.end())return;GV.setLinkage(I->second);};llvm::for_each(MergedModule->functions(),externalize);llvm::for_each(MergedModule->globals(),externalize);llvm::for_each(MergedModule->aliases(),externalize);}voidLTOCodeGenerator::verifyMergedModuleOnce(){// Only run on the first call.if(HasVerifiedInput)return;HasVerifiedInput=true;boolBrokenDebugInfo=false;if(verifyModule(*MergedModule,&dbgs(),&BrokenDebugInfo))report_fatal_error("Broken module found, compilation aborted!");if(BrokenDebugInfo){emitWarning("Invalid debug info found, debug info will be stripped");StripDebugInfo(*MergedModule);}}voidLTOCodeGenerator::finishOptimizationRemarks(){if(DiagnosticOutputFile){DiagnosticOutputFile->keep();// FIXME: LTOCodeGenerator dtor is not invoked on DarwinDiagnosticOutputFile->os().flush();}}/// Optimize merged modules using various IPO passesboolLTOCodeGenerator::optimize(boolDisableVerify,boolDisableInline,boolDisableGVNLoadPRE,boolDisableVectorization){if(!this->determineTarget())returnfalse;autoDiagFileOrErr=lto::setupOptimizationRemarks(Context,LTORemarksFilename,LTOPassRemarksWithHotness);if(!DiagFileOrErr){errs()<<"Error: "<<toString(DiagFileOrErr.takeError())<<"\n";report_fatal_error("Can't get an output file for the remarks");}DiagnosticOutputFile=std::move(*DiagFileOrErr);// We always run the verifier once on the merged module, the `DisableVerify`// parameter only applies to subsequent verify.verifyMergedModuleOnce();// Mark which symbols can not be internalizedthis->applyScopeRestrictions();// Instantiate the pass manager to organize the passes.legacy::PassManagerpasses;// Add an appropriate DataLayout instance for this module...MergedModule->setDataLayout(TargetMach->createDataLayout());passes.add(createTargetTransformInfoWrapperPass(TargetMach->getTargetIRAnalysis()));TripleTargetTriple(TargetMach->getTargetTriple());PassManagerBuilderPMB;PMB.DisableGVNLoadPRE=DisableGVNLoadPRE;PMB.LoopVectorize=!DisableVectorization;PMB.SLPVectorize=!DisableVectorization;if(!DisableInline)PMB.Inliner=createFunctionInliningPass();PMB.LibraryInfo=newTargetLibraryInfoImpl(TargetTriple);if(Freestanding)PMB.LibraryInfo->disableAllFunctions();PMB.OptLevel=OptLevel;PMB.VerifyInput=!DisableVerify;PMB.VerifyOutput=!DisableVerify;PMB.populateLTOPassManager(passes);// Run our queue of passes all at once now, efficiently.passes.run(*MergedModule);returntrue;}boolLTOCodeGenerator::compileOptimized(ArrayRef<raw_pwrite_stream*>Out){if(!this->determineTarget())returnfalse;// We always run the verifier once on the merged module. If it has already// been called in optimize(), this call will return early.verifyMergedModuleOnce();legacy::PassManagerpreCodeGenPasses;// If the bitcode files contain ARC code and were compiled with optimization,// the ObjCARCContractPass must be run, so do it unconditionally here.preCodeGenPasses.add(createObjCARCContractPass());preCodeGenPasses.run(*MergedModule);// Re-externalize globals that may have been internalized to increase scope// for splittingrestoreLinkageForExternals();// 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,{},[&](){returncreateTargetMachine();},FileType,ShouldRestoreGlobalsLinkage);// If statistics were requested, print them out after codegen.if(llvm::AreStatisticsEnabled())llvm::PrintStatistics();reportAndResetTimings();finishOptimizationRemarks();returntrue;}/// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging/// LTO problems.voidLTOCodeGenerator::setCodeGenDebugOptions(StringRefOptions){for(std::pair<StringRef,StringRef>o=getToken(Options);!o.first.empty();o=getToken(o.second))CodegenOptions.push_back(o.first);}voidLTOCodeGenerator::parseCodeGenDebugOptions(){// if options were requested, set themif(!CodegenOptions.empty()){// ParseCommandLineOptions() expects argv[0] to be program name.std::vector<constchar*>CodegenArgv(1,"libLLVMLTO");for(std::string&Arg:CodegenOptions)CodegenArgv.push_back(Arg.c_str());cl::ParseCommandLineOptions(CodegenArgv.size(),CodegenArgv.data());}}voidLTOCodeGenerator::DiagnosticHandler(constDiagnosticInfo&DI){// Map the LLVM internal diagnostic severity to the LTO diagnostic severity.lto_codegen_diagnostic_severity_tSeverity;switch(DI.getSeverity()){caseDS_Error:Severity=LTO_DS_ERROR;break;caseDS_Warning:Severity=LTO_DS_WARNING;break;caseDS_Remark:Severity=LTO_DS_REMARK;break;caseDS_Note:Severity=LTO_DS_NOTE;break;}// Create the string that will be reported to the external diagnostic handler.std::stringMsgStorage;raw_string_ostreamStream(MsgStorage);DiagnosticPrinterRawOStreamDP(Stream);DI.print(DP);Stream.flush();// If this method has been called it means someone has set up an external// diagnostic handler. Assert on that.assert(DiagHandler&&"Invalid diagnostic handler");(*DiagHandler)(Severity,MsgStorage.c_str(),DiagContext);}namespace{structLTODiagnosticHandler:publicDiagnosticHandler{LTOCodeGenerator*CodeGenerator;LTODiagnosticHandler(LTOCodeGenerator*CodeGenPtr):CodeGenerator(CodeGenPtr){}boolhandleDiagnostics(constDiagnosticInfo&DI)override{CodeGenerator->DiagnosticHandler(DI);returntrue;}};}voidLTOCodeGenerator::setDiagnosticHandler(lto_diagnostic_handler_tDiagHandler,void*Ctxt){this->DiagHandler=DiagHandler;this->DiagContext=Ctxt;if(!DiagHandler)returnContext.setDiagnosticHandler(nullptr);// Register the LTOCodeGenerator stub in the LLVMContext to forward the// diagnostic to the external DiagHandler.Context.setDiagnosticHandler(llvm::make_unique<LTODiagnosticHandler>(this),true);}namespace{classLTODiagnosticInfo:publicDiagnosticInfo{constTwine&Msg;public:LTODiagnosticInfo(constTwine&DiagMsg,DiagnosticSeveritySeverity=DS_Error):DiagnosticInfo(DK_Linker,Severity),Msg(DiagMsg){}voidprint(DiagnosticPrinter&DP)constoverride{DP<<Msg;}};}voidLTOCodeGenerator::emitError(conststd::string&ErrMsg){if(DiagHandler)(*DiagHandler)(LTO_DS_ERROR,ErrMsg.c_str(),DiagContext);elseContext.diagnose(LTODiagnosticInfo(ErrMsg));}voidLTOCodeGenerator::emitWarning(conststd::string&ErrMsg){if(DiagHandler)(*DiagHandler)(LTO_DS_WARNING,ErrMsg.c_str(),DiagContext);elseContext.diagnose(LTODiagnosticInfo(ErrMsg,DS_Warning));}