From cc48854d5d51a2d7557f1040a61f160ad86c9729 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Tue, 24 Sep 2013 23:52:22 +0000 Subject: Move LTO support library to a component, allowing it to be tested more reliably across platforms. Patch by Tom Roeder! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191343 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/LTO/LTOCodeGenerator.h | 130 ++++++ include/llvm/LTO/LTOModule.h | 196 ++++++++ lib/CMakeLists.txt | 1 + lib/LLVMBuild.txt | 2 +- lib/LTO/CMakeLists.txt | 4 + lib/LTO/LLVMBuild.txt | 22 + lib/LTO/LTOCodeGenerator.cpp | 453 ++++++++++++++++++ lib/LTO/LTOModule.cpp | 900 +++++++++++++++++++++++++++++++++++ lib/LTO/Makefile | 15 + lib/Makefile | 2 +- test/LTO/cfi_endproc.ll | 20 + test/LTO/lit.local.cfg | 6 + test/tools/lto/cfi_endproc.ll | 20 - test/tools/lto/lit.local.cfg | 6 - tools/LLVMBuild.txt | 2 +- tools/llvm-lto/CMakeLists.txt | 5 +- tools/llvm-lto/LLVMBuild.txt | 22 + tools/llvm-lto/Makefile | 5 +- tools/llvm-lto/llvm-lto.cpp | 49 +- tools/lto/CMakeLists.txt | 4 +- tools/lto/LTOCodeGenerator.cpp | 458 ------------------ tools/lto/LTOCodeGenerator.h | 130 ------ tools/lto/LTOModule.cpp | 908 ------------------------------------ tools/lto/LTOModule.h | 190 -------- tools/lto/Makefile | 2 +- tools/lto/lto.cpp | 27 +- 26 files changed, 1828 insertions(+), 1751 deletions(-) create mode 100644 include/llvm/LTO/LTOCodeGenerator.h create mode 100644 include/llvm/LTO/LTOModule.h create mode 100644 lib/LTO/CMakeLists.txt create mode 100644 lib/LTO/LLVMBuild.txt create mode 100644 lib/LTO/LTOCodeGenerator.cpp create mode 100644 lib/LTO/LTOModule.cpp create mode 100644 lib/LTO/Makefile create mode 100644 test/LTO/cfi_endproc.ll create mode 100644 test/LTO/lit.local.cfg delete mode 100644 test/tools/lto/cfi_endproc.ll delete mode 100644 test/tools/lto/lit.local.cfg create mode 100644 tools/llvm-lto/LLVMBuild.txt delete mode 100644 tools/lto/LTOCodeGenerator.cpp delete mode 100644 tools/lto/LTOCodeGenerator.h delete mode 100644 tools/lto/LTOModule.cpp delete mode 100644 tools/lto/LTOModule.h diff --git a/include/llvm/LTO/LTOCodeGenerator.h b/include/llvm/LTO/LTOCodeGenerator.h new file mode 100644 index 0000000000..3d151b93af --- /dev/null +++ b/include/llvm/LTO/LTOCodeGenerator.h @@ -0,0 +1,130 @@ +//===-LTOCodeGenerator.h - 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 declares the LTOCodeGenerator class. +// +// LTO compilation consists of three phases: Pre-IPO, IPO and Post-IPO. +// +// The Pre-IPO phase compiles source code into bitcode file. The resulting +// bitcode files, along with object files and libraries, will be fed to the +// linker to through the IPO and Post-IPO phases. By using obj-file extension, +// the resulting bitcode file disguises itself as an object file, and therefore +// obviates the need of writing a special set of the make-rules only for LTO +// compilation. +// +// The IPO phase perform inter-procedural analyses and optimizations, and +// the Post-IPO consists two sub-phases: intra-procedural scalar optimizations +// (SOPT), and intra-procedural target-dependent code generator (CG). +// +// As of this writing, we don't separate IPO and the Post-IPO SOPT. They +// are intermingled together, and are driven by a single pass manager (see +// PassManagerBuilder::populateLTOPassManager()). +// +// The "LTOCodeGenerator" is the driver for the IPO and Post-IPO stages. +// The "CodeGenerator" here is bit confusing. Don't confuse the "CodeGenerator" +// with the machine specific code generator. +// +//===----------------------------------------------------------------------===// + +#ifndef LTO_CODE_GENERATOR_H +#define LTO_CODE_GENERATOR_H + +#include "llvm-c/lto.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Linker.h" +#include +#include + +namespace llvm { + class LLVMContext; + class GlobalValue; + class Mangler; + class MemoryBuffer; + class TargetMachine; + class raw_ostream; +} + +//===----------------------------------------------------------------------===// +/// LTOCodeGenerator - C++ class which implements the opaque lto_code_gen_t +/// type. +/// +struct LTOCodeGenerator { + static const char *getVersionString(); + + LTOCodeGenerator(); + ~LTOCodeGenerator(); + + // Merge given module, return true on success. + bool addModule(struct LTOModule*, std::string &errMsg); + + void setDebugInfo(lto_debug_model); + void setCodePICModel(lto_codegen_model); + + void setCpu(const char *mCpu) { MCpu = mCpu; } + + void addMustPreserveSymbol(const char *sym) { MustPreserveSymbols[sym] = 1; } + + // To pass options to the driver and optimization passes. These options are + // not necessarily for debugging purpose (The function name is misleading). + // This function should be called before LTOCodeGenerator::compilexxx(), + // and LTOCodeGenerator::writeMergedModules(). + // + void setCodeGenDebugOptions(const char *opts); + + // Write the merged module to the file specified by the given path. + // Return true on success. + bool writeMergedModules(const char *path, std::string &errMsg); + + // Compile the merged module into a *single* object file; the path to object + // file is returned to the caller via argument "name". Return true on + // success. + // + // NOTE that it is up to the linker to remove the intermediate object file. + // Do not try to remove the object file in LTOCodeGenerator's destructor + // as we don't who (LTOCodeGenerator or the obj file) will last longer. + // + bool compile_to_file(const char **name, std::string &errMsg); + + // As with compile_to_file(), this function compiles the merged module into + // single object file. Instead of returning the object-file-path to the caller + // (linker), it brings the object to a buffer, and return the buffer to the + // caller. This function should delete intermediate object file once its content + // is brought to memory. Return NULL if the compilation was not successful. + // + const void *compile(size_t *length, std::string &errMsg); + +private: + void initializeLTOPasses(); + + bool generateObjectFile(llvm::raw_ostream &out, std::string &errMsg); + void applyScopeRestrictions(); + void applyRestriction(llvm::GlobalValue &GV, + std::vector &MustPreserveList, + llvm::SmallPtrSet &AsmUsed, + llvm::Mangler &Mangler); + bool determineTarget(std::string &errMsg); + + typedef llvm::StringMap StringSet; + + llvm::LLVMContext &Context; + llvm::Linker Linker; + llvm::TargetMachine *TargetMach; + bool EmitDwarfDebugInfo; + bool ScopeRestrictionsDone; + lto_codegen_model CodeModel; + StringSet MustPreserveSymbols; + StringSet AsmUndefinedRefs; + llvm::MemoryBuffer *NativeObjectFile; + std::vector CodegenOptions; + std::string MCpu; + std::string NativeObjectPath; +}; + +#endif // LTO_CODE_GENERATOR_H diff --git a/include/llvm/LTO/LTOModule.h b/include/llvm/LTO/LTOModule.h new file mode 100644 index 0000000000..973466cc0e --- /dev/null +++ b/include/llvm/LTO/LTOModule.h @@ -0,0 +1,196 @@ +//===-LTOModule.h - 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 declares the LTOModule class. +// +//===----------------------------------------------------------------------===// + +#ifndef LTO_MODULE_H +#define LTO_MODULE_H + +#include "llvm-c/lto.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetMachine.h" +#include +#include + +// Forward references to llvm classes. +namespace llvm { + class Function; + class GlobalValue; + class MemoryBuffer; + class TargetOptions; + class Value; +} + +//===----------------------------------------------------------------------===// +/// LTOModule - C++ class which implements the opaque lto_module_t type. +/// +struct LTOModule { +private: + typedef llvm::StringMap StringSet; + + struct NameAndAttributes { + const char *name; + uint32_t attributes; + bool isFunction; + const llvm::GlobalValue *symbol; + }; + + llvm::OwningPtr _module; + llvm::OwningPtr _target; + std::vector _symbols; + + // _defines and _undefines only needed to disambiguate tentative definitions + StringSet _defines; + llvm::StringMap _undefines; + std::vector _asm_undefines; + llvm::MCContext _context; + + // Use mangler to add GlobalPrefix to names to match linker names. + llvm::Mangler _mangler; + + LTOModule(llvm::Module *m, llvm::TargetMachine *t); +public: + /// isBitcodeFile - Returns 'true' if the file or memory contents is LLVM + /// bitcode. + static bool isBitcodeFile(const void *mem, size_t length); + static bool isBitcodeFile(const char *path); + + /// isBitcodeFileForTarget - Returns 'true' if the file or memory contents + /// is LLVM bitcode for the specified triple. + static bool isBitcodeFileForTarget(const void *mem, + size_t length, + const char *triplePrefix); + static bool isBitcodeFileForTarget(const char *path, + const char *triplePrefix); + + /// makeLTOModule - Create an LTOModule. N.B. These methods take ownership + /// of the buffer. The caller must have initialized the Targets, the + /// TargetMCs, the AsmPrinters, and the AsmParsers by calling: + /// + /// InitializeAllTargets(); + /// InitializeAllTargetMCs(); + /// InitializeAllAsmPrinters(); + /// InitializeAllAsmParsers(); + static LTOModule *makeLTOModule(const char* path, + std::string &errMsg); + static LTOModule *makeLTOModule(int fd, const char *path, + size_t size, std::string &errMsg); + static LTOModule *makeLTOModule(int fd, const char *path, + size_t map_size, + off_t offset, + std::string& errMsg); + static LTOModule *makeLTOModule(const void *mem, size_t length, + std::string &errMsg); + + /// getTargetTriple - Return the Module's target triple. + const char *getTargetTriple() { + return _module->getTargetTriple().c_str(); + } + + /// setTargetTriple - Set the Module's target triple. + void setTargetTriple(const char *triple) { + _module->setTargetTriple(triple); + } + + /// getSymbolCount - Get the number of symbols + uint32_t getSymbolCount() { + return _symbols.size(); + } + + /// getSymbolAttributes - Get the attributes for a symbol at the specified + /// index. + lto_symbol_attributes getSymbolAttributes(uint32_t index) { + if (index < _symbols.size()) + return lto_symbol_attributes(_symbols[index].attributes); + return lto_symbol_attributes(0); + } + + /// getSymbolName - Get the name of the symbol at the specified index. + const char *getSymbolName(uint32_t index) { + if (index < _symbols.size()) + return _symbols[index].name; + return NULL; + } + + /// getLLVVMModule - Return the Module. + llvm::Module *getLLVVMModule() { return _module.get(); } + + /// getAsmUndefinedRefs - + const std::vector &getAsmUndefinedRefs() { + return _asm_undefines; + } + + /// getTargetOptions - Fill the TargetOptions object with the options + /// specified on the command line. + static void getTargetOptions(llvm::TargetOptions &Options); + +private: + /// parseSymbols - Parse the symbols from the module and model-level ASM and + /// add them to either the defined or undefined lists. + bool parseSymbols(std::string &errMsg); + + /// addPotentialUndefinedSymbol - Add a symbol which isn't defined just yet + /// to a list to be resolved later. + void addPotentialUndefinedSymbol(const llvm::GlobalValue *dcl, bool isFunc); + + /// addDefinedSymbol - Add a defined symbol to the list. + void addDefinedSymbol(const llvm::GlobalValue *def, bool isFunction); + + /// addDefinedFunctionSymbol - Add a function symbol as defined to the list. + void addDefinedFunctionSymbol(const llvm::Function *f); + + /// addDefinedDataSymbol - Add a data symbol as defined to the list. + void addDefinedDataSymbol(const llvm::GlobalValue *v); + + /// addAsmGlobalSymbols - Add global symbols from module-level ASM to the + /// defined or undefined lists. + bool addAsmGlobalSymbols(std::string &errMsg); + + /// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the + /// defined list. + void addAsmGlobalSymbol(const char *, lto_symbol_attributes scope); + + /// addAsmGlobalSymbolUndef - Add a global symbol from module-level ASM to + /// the undefined list. + void addAsmGlobalSymbolUndef(const char *); + + /// addObjCClass - Parse i386/ppc ObjC class data structure. + void addObjCClass(const llvm::GlobalVariable *clgv); + + /// addObjCCategory - Parse i386/ppc ObjC category data structure. + void addObjCCategory(const llvm::GlobalVariable *clgv); + + /// addObjCClassRef - Parse i386/ppc ObjC class list data structure. + void addObjCClassRef(const llvm::GlobalVariable *clgv); + + /// objcClassNameFromExpression - Get string that the data pointer points + /// to. + bool objcClassNameFromExpression(const llvm::Constant* c, std::string &name); + + /// isTargetMatch - Returns 'true' if the memory buffer is for the specified + /// target triple. + static bool isTargetMatch(llvm::MemoryBuffer *memBuffer, + const char *triplePrefix); + + /// makeLTOModule - Create an LTOModule (private version). N.B. This + /// method takes ownership of the buffer. + static LTOModule *makeLTOModule(llvm::MemoryBuffer *buffer, + std::string &errMsg); + + /// makeBuffer - Create a MemoryBuffer from a memory range. + static llvm::MemoryBuffer *makeBuffer(const void *mem, size_t length); +}; + +#endif // LTO_MODULE_H diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4d9aebcd0a..7fbf12339d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory(Bitcode) add_subdirectory(Transforms) add_subdirectory(Linker) add_subdirectory(Analysis) +add_subdirectory(LTO) add_subdirectory(MC) add_subdirectory(Object) add_subdirectory(Option) diff --git a/lib/LLVMBuild.txt b/lib/LLVMBuild.txt index ff288bc78b..00280c8603 100644 --- a/lib/LLVMBuild.txt +++ b/lib/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = Analysis AsmParser Bitcode CodeGen DebugInfo ExecutionEngine Linker IR IRReader MC Object Option Support TableGen Target Transforms +subdirectories = Analysis AsmParser Bitcode CodeGen DebugInfo ExecutionEngine Linker IR IRReader LTO MC Object Option Support TableGen Target Transforms [component_0] type = Group diff --git a/lib/LTO/CMakeLists.txt b/lib/LTO/CMakeLists.txt new file mode 100644 index 0000000000..8e00bcb655 --- /dev/null +++ b/lib/LTO/CMakeLists.txt @@ -0,0 +1,4 @@ +add_llvm_library(LLVMLTO + LTOModule.cpp + LTOCodeGenerator.cpp + ) diff --git a/lib/LTO/LLVMBuild.txt b/lib/LTO/LLVMBuild.txt new file mode 100644 index 0000000000..38c1170b9e --- /dev/null +++ b/lib/LTO/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./lib/LTO/LLVMBuild.txt ----------------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = LTO +parent = Libraries +required_libraries = Analysis BitReader BitWriter Core IPO Linker MC MCParser Scalar Support Target Vectorize \ No newline at end of file diff --git a/lib/LTO/LTOCodeGenerator.cpp b/lib/LTO/LTOCodeGenerator.cpp new file mode 100644 index 0000000000..22e9754bcf --- /dev/null +++ b/lib/LTO/LTOCodeGenerator.cpp @@ -0,0 +1,453 @@ +//===-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/LTOCodeGenerator.h" +#include "llvm/LTO/LTOModule.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Config/config.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Linker.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/PassManager.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormattedStream.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/system_error.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/ObjCARC.h" +using namespace llvm; + +static cl::opt +DisableOpt("disable-opt", cl::init(false), + cl::desc("Do not run any optimization passes")); + +static cl::opt +DisableInline("disable-inlining", cl::init(false), + cl::desc("Do not run the inliner pass")); + +static cl::opt +DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), + cl::desc("Do not run the GVN load PRE pass")); + +const char* LTOCodeGenerator::getVersionString() { +#ifdef LLVM_VERSION_INFO + return PACKAGE_NAME " version " PACKAGE_VERSION ", " LLVM_VERSION_INFO; +#else + return PACKAGE_NAME " version " PACKAGE_VERSION; +#endif +} + +LTOCodeGenerator::LTOCodeGenerator() + : Context(getGlobalContext()), Linker(new Module("ld-temp.o", Context)), + TargetMach(NULL), EmitDwarfDebugInfo(false), ScopeRestrictionsDone(false), + CodeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC), NativeObjectFile(NULL) { + initializeLTOPasses(); +} + +LTOCodeGenerator::~LTOCodeGenerator() { + delete TargetMach; + delete NativeObjectFile; + delete Linker.getModule(); + + for (std::vector::iterator I = CodegenOptions.begin(), + E = CodegenOptions.end(); + I != E; ++I) + free(*I); +} + +// Initialize LTO passes. Please keep this funciton in sync with +// PassManagerBuilder::populateLTOPassManager(), and make sure all LTO +// passes are initialized. +// +void LTOCodeGenerator::initializeLTOPasses() { + PassRegistry &R = *PassRegistry::getPassRegistry(); + + initializeInternalizePassPass(R); + initializeIPSCCPPass(R); + initializeGlobalOptPass(R); + initializeConstantMergePass(R); + initializeDAHPass(R); + initializeInstCombinerPass(R); + initializeSimpleInlinerPass(R); + initializePruneEHPass(R); + initializeGlobalDCEPass(R); + initializeArgPromotionPass(R); + initializeJumpThreadingPass(R); + initializeSROAPass(R); + initializeSROA_DTPass(R); + initializeSROA_SSAUpPass(R); + initializeFunctionAttrsPass(R); + initializeGlobalsModRefPass(R); + initializeLICMPass(R); + initializeGVNPass(R); + initializeMemCpyOptPass(R); + initializeDCEPass(R); + initializeCFGSimplifyPassPass(R); +} + +bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) { + bool ret = Linker.linkInModule(mod->getLLVVMModule(), &errMsg); + + const std::vector &undefs = mod->getAsmUndefinedRefs(); + for (int i = 0, e = undefs.size(); i != e; ++i) + AsmUndefinedRefs[undefs[i]] = 1; + + return !ret; +} + +void LTOCodeGenerator::setDebugInfo(lto_debug_model debug) { + switch (debug) { + case LTO_DEBUG_MODEL_NONE: + EmitDwarfDebugInfo = false; + return; + + case LTO_DEBUG_MODEL_DWARF: + EmitDwarfDebugInfo = true; + return; + } + 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: + CodeModel = model; + return; + } + llvm_unreachable("Unknown PIC model!"); +} + +bool LTOCodeGenerator::writeMergedModules(const char *path, + std::string &errMsg) { + if (!determineTarget(errMsg)) + return false; + + // mark which symbols can not be internalized + applyScopeRestrictions(); + + // create output file + std::string ErrInfo; + tool_output_file Out(path, ErrInfo, sys::fs::F_Binary); + if (!ErrInfo.empty()) { + errMsg = "could not open bitcode file for writing: "; + errMsg += path; + return false; + } + + // write bitcode to it + WriteBitcodeToFile(Linker.getModule(), Out.os()); + Out.os().close(); + + if (Out.os().has_error()) { + errMsg = "could not write bitcode file: "; + errMsg += path; + Out.os().clear_error(); + return false; + } + + Out.keep(); + return true; +} + +bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) { + // make unique temp .o file to put generated object file + SmallString<128> Filename; + int FD; + error_code EC = sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename); + if (EC) { + errMsg = EC.message(); + return false; + } + + // generate object file + tool_output_file objFile(Filename.c_str(), FD); + + bool genResult = generateObjectFile(objFile.os(), errMsg); + objFile.os().close(); + if (objFile.os().has_error()) { + objFile.os().clear_error(); + sys::fs::remove(Twine(Filename)); + return false; + } + + objFile.keep(); + if (!genResult) { + sys::fs::remove(Twine(Filename)); + return false; + } + + NativeObjectPath = Filename.c_str(); + *name = NativeObjectPath.c_str(); + return true; +} + +const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { + const char *name; + if (!compile_to_file(&name, errMsg)) + return NULL; + + // remove old buffer if compile() called twice + delete NativeObjectFile; + + // read .o file into memory buffer + OwningPtr BuffPtr; + if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) { + errMsg = ec.message(); + sys::fs::remove(NativeObjectPath); + return NULL; + } + NativeObjectFile = BuffPtr.take(); + + // remove temp files + sys::fs::remove(NativeObjectPath); + + // return buffer, unless error + if (NativeObjectFile == NULL) + return NULL; + *length = NativeObjectFile->getBufferSize(); + return NativeObjectFile->getBufferStart(); +} + +bool LTOCodeGenerator::determineTarget(std::string &errMsg) { + if (TargetMach != NULL) + return true; + + // if options were requested, set them + if (!CodegenOptions.empty()) + cl::ParseCommandLineOptions(CodegenOptions.size(), + const_cast(&CodegenOptions[0])); + + std::string TripleStr = Linker.getModule()->getTargetTriple(); + if (TripleStr.empty()) + TripleStr = sys::getDefaultTargetTriple(); + llvm::Triple Triple(TripleStr); + + // create target machine from info for merged modules + const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); + if (march == NULL) + 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; + } + + // construct LTOModule, hand over ownership of module and target + SubtargetFeatures Features; + Features.getDefaultSubtargetFeatures(Triple); + std::string FeatureStr = Features.getString(); + // Set a default CPU for Darwin triples. + if (MCpu.empty() && Triple.isOSDarwin()) { + if (Triple.getArch() == llvm::Triple::x86_64) + MCpu = "core2"; + else if (Triple.getArch() == llvm::Triple::x86) + MCpu = "yonah"; + } + TargetOptions Options; + LTOModule::getTargetOptions(Options); + TargetMach = march->createTargetMachine(TripleStr, MCpu, FeatureStr, Options, + RelocModel, CodeModel::Default, + CodeGenOpt::Aggressive); + return true; +} + +void LTOCodeGenerator:: +applyRestriction(GlobalValue &GV, + std::vector &MustPreserveList, + SmallPtrSet &AsmUsed, + Mangler &Mangler) { + SmallString<64> Buffer; + Mangler.getNameWithPrefix(Buffer, &GV, false); + + if (GV.isDeclaration()) + return; + if (MustPreserveSymbols.count(Buffer)) + MustPreserveList.push_back(GV.getName().data()); + if (AsmUndefinedRefs.count(Buffer)) + AsmUsed.insert(&GV); +} + +static void findUsedValues(GlobalVariable *LLVMUsed, + SmallPtrSet &UsedValues) { + if (LLVMUsed == 0) return; + + ConstantArray *Inits = cast(LLVMUsed->getInitializer()); + for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) + if (GlobalValue *GV = + dyn_cast(Inits->getOperand(i)->stripPointerCasts())) + UsedValues.insert(GV); +} + +void LTOCodeGenerator::applyScopeRestrictions() { + if (ScopeRestrictionsDone) + return; + Module *mergedModule = Linker.getModule(); + + // Start off with a verification pass. + PassManager passes; + passes.add(createVerifierPass()); + + // mark which symbols can not be internalized + MCContext MContext(TargetMach->getMCAsmInfo(), TargetMach->getRegisterInfo(), + NULL); + Mangler Mangler(MContext, TargetMach); + std::vector MustPreserveList; + SmallPtrSet AsmUsed; + + for (Module::iterator f = mergedModule->begin(), + e = mergedModule->end(); f != e; ++f) + applyRestriction(*f, MustPreserveList, AsmUsed, Mangler); + for (Module::global_iterator v = mergedModule->global_begin(), + e = mergedModule->global_end(); v != e; ++v) + applyRestriction(*v, MustPreserveList, AsmUsed, Mangler); + for (Module::alias_iterator a = mergedModule->alias_begin(), + e = mergedModule->alias_end(); a != e; ++a) + applyRestriction(*a, MustPreserveList, AsmUsed, Mangler); + + GlobalVariable *LLVMCompilerUsed = + mergedModule->getGlobalVariable("llvm.compiler.used"); + findUsedValues(LLVMCompilerUsed, AsmUsed); + if (LLVMCompilerUsed) + LLVMCompilerUsed->eraseFromParent(); + + if (!AsmUsed.empty()) { + llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(Context); + std::vector asmUsed2; + for (SmallPtrSet::const_iterator i = AsmUsed.begin(), + e = AsmUsed.end(); i !=e; ++i) { + GlobalValue *GV = *i; + Constant *c = ConstantExpr::getBitCast(GV, i8PTy); + asmUsed2.push_back(c); + } + + llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size()); + LLVMCompilerUsed = + new llvm::GlobalVariable(*mergedModule, ATy, false, + llvm::GlobalValue::AppendingLinkage, + llvm::ConstantArray::get(ATy, asmUsed2), + "llvm.compiler.used"); + + LLVMCompilerUsed->setSection("llvm.metadata"); + } + + passes.add(createInternalizePass(MustPreserveList)); + + // apply scope restrictions + passes.run(*mergedModule); + + ScopeRestrictionsDone = true; +} + +/// Optimize merged modules using various IPO passes +bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, + std::string &errMsg) { + if (!this->determineTarget(errMsg)) + return false; + + Module *mergedModule = Linker.getModule(); + + // Mark which symbols can not be internalized + this->applyScopeRestrictions(); + + // Instantiate the pass manager to organize the passes. + PassManager passes; + + // Start off with a verification pass. + passes.add(createVerifierPass()); + + // Add an appropriate DataLayout instance for this module... + passes.add(new DataLayout(*TargetMach->getDataLayout())); + TargetMach->addAnalysisPasses(passes); + + // Enabling internalize here would use its AllButMain variant. It + // keeps only main if it exists and does nothing for libraries. Instead + // we create the pass ourselves with the symbol list provided by the linker. + if (!DisableOpt) + PassManagerBuilder().populateLTOPassManager(passes, + /*Internalize=*/false, + !DisableInline, + DisableGVNLoadPRE); + + // Make sure everything is still good. + passes.add(createVerifierPass()); + + PassManager codeGenPasses; + + codeGenPasses.add(new DataLayout(*TargetMach->getDataLayout())); + TargetMach->addAnalysisPasses(codeGenPasses); + + formatted_raw_ostream Out(out); + + // 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 our queue of passes all at once now, efficiently. + passes.run(*mergedModule); + + // Run the code generator, and write assembly file + codeGenPasses.run(*mergedModule); + + return true; +} + +/// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging +/// LTO problems. +void LTOCodeGenerator::setCodeGenDebugOptions(const char *options) { + for (std::pair 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())); + } +} diff --git a/lib/LTO/LTOModule.cpp b/lib/LTO/LTOModule.cpp new file mode 100644 index 0000000000..1457f2f5a2 --- /dev/null +++ b/lib/LTO/LTOModule.cpp @@ -0,0 +1,900 @@ +//===-- LTOModule.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/LTOModule.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/system_error.h" +#include "llvm/Target/TargetRegisterInfo.h" +using namespace llvm; + +static cl::opt +EnableFPMAD("enable-fp-mad", + cl::desc("Enable less precise MAD instructions to be generated"), + cl::init(false)); + +static cl::opt +DisableFPElim("disable-fp-elim", + cl::desc("Disable frame pointer elimination optimization"), + cl::init(false)); + +static cl::opt +EnableUnsafeFPMath("enable-unsafe-fp-math", + cl::desc("Enable optimizations that may decrease FP precision"), + cl::init(false)); + +static cl::opt +EnableNoInfsFPMath("enable-no-infs-fp-math", + cl::desc("Enable FP math optimizations that assume no +-Infs"), + cl::init(false)); + +static cl::opt +EnableNoNaNsFPMath("enable-no-nans-fp-math", + cl::desc("Enable FP math optimizations that assume no NaNs"), + cl::init(false)); + +static cl::opt +EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math", + cl::Hidden, + cl::desc("Force codegen to assume rounding mode can change dynamically"), + cl::init(false)); + +static cl::opt +GenerateSoftFloatCalls("soft-float", + cl::desc("Generate software floating point library calls"), + cl::init(false)); + +static cl::opt +FloatABIForCalls("float-abi", + cl::desc("Choose float ABI type"), + cl::init(FloatABI::Default), + cl::values( + clEnumValN(FloatABI::Default, "default", + "Target default float ABI type"), + clEnumValN(FloatABI::Soft, "soft", + "Soft float ABI (implied by -soft-float)"), + clEnumValN(FloatABI::Hard, "hard", + "Hard float ABI (uses FP registers)"), + clEnumValEnd)); + +static cl::opt +FuseFPOps("fp-contract", + cl::desc("Enable aggresive formation of fused FP ops"), + cl::init(FPOpFusion::Standard), + cl::values( + clEnumValN(FPOpFusion::Fast, "fast", + "Fuse FP ops whenever profitable"), + clEnumValN(FPOpFusion::Standard, "on", + "Only fuse 'blessed' FP ops."), + clEnumValN(FPOpFusion::Strict, "off", + "Only fuse FP ops when the result won't be effected."), + clEnumValEnd)); + +static cl::opt +DontPlaceZerosInBSS("nozero-initialized-in-bss", + cl::desc("Don't place zero-initialized symbols into bss section"), + cl::init(false)); + +static cl::opt +EnableGuaranteedTailCallOpt("tailcallopt", + cl::desc("Turn fastcc calls into tail calls by (potentially) changing ABI."), + cl::init(false)); + +static cl::opt +DisableTailCalls("disable-tail-calls", + cl::desc("Never emit tail calls"), + cl::init(false)); + +static cl::opt +OverrideStackAlignment("stack-alignment", + cl::desc("Override default stack alignment"), + cl::init(0)); + +static cl::opt +TrapFuncName("trap-func", cl::Hidden, + cl::desc("Emit a call to trap function rather than a trap instruction"), + cl::init("")); + +static cl::opt +EnablePIE("enable-pie", + cl::desc("Assume the creation of a position independent executable."), + cl::init(false)); + +static cl::opt +SegmentedStacks("segmented-stacks", + cl::desc("Use segmented stacks if possible."), + cl::init(false)); + +static cl::opt +UseInitArray("use-init-array", + cl::desc("Use .init_array instead of .ctors."), + cl::init(false)); + +LTOModule::LTOModule(llvm::Module *m, llvm::TargetMachine *t) + : _module(m), _target(t), + _context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL), + _mangler(_context, t) {} + +/// isBitcodeFile - Returns 'true' if the file (or memory contents) is LLVM +/// bitcode. +bool LTOModule::isBitcodeFile(const void *mem, size_t length) { + return sys::fs::identify_magic(StringRef((const char *)mem, length)) == + sys::fs::file_magic::bitcode; +} + +bool LTOModule::isBitcodeFile(const char *path) { + sys::fs::file_magic type; + if (sys::fs::identify_magic(path, type)) + return false; + return type == sys::fs::file_magic::bitcode; +} + +/// isBitcodeFileForTarget - Returns 'true' if the file (or memory contents) is +/// LLVM bitcode for the specified triple. +bool LTOModule::isBitcodeFileForTarget(const void *mem, size_t length, + const char *triplePrefix) { + MemoryBuffer *buffer = makeBuffer(mem, length); + if (!buffer) + return false; + return isTargetMatch(buffer, triplePrefix); +} + +bool LTOModule::isBitcodeFileForTarget(const char *path, + const char *triplePrefix) { + OwningPtr buffer; + if (MemoryBuffer::getFile(path, buffer)) + return false; + return isTargetMatch(buffer.take(), triplePrefix); +} + +/// isTargetMatch - Returns 'true' if the memory buffer is for the specified +/// target triple. +bool LTOModule::isTargetMatch(MemoryBuffer *buffer, const char *triplePrefix) { + std::string Triple = getBitcodeTargetTriple(buffer, getGlobalContext()); + delete buffer; + return strncmp(Triple.c_str(), triplePrefix, strlen(triplePrefix)) == 0; +} + +/// makeLTOModule - Create an LTOModule. N.B. These methods take ownership of +/// the buffer. +LTOModule *LTOModule::makeLTOModule(const char *path, std::string &errMsg) { + OwningPtr buffer; + if (error_code ec = MemoryBuffer::getFile(path, buffer)) { + errMsg = ec.message(); + return NULL; + } + return makeLTOModule(buffer.take(), errMsg); +} + +LTOModule *LTOModule::makeLTOModule(int fd, const char *path, + size_t size, std::string &errMsg) { + return makeLTOModule(fd, path, size, 0, errMsg); +} + +LTOModule *LTOModule::makeLTOModule(int fd, const char *path, + size_t map_size, + off_t offset, + std::string &errMsg) { + OwningPtr buffer; + if (error_code ec = + MemoryBuffer::getOpenFileSlice(fd, path, buffer, map_size, offset)) { + errMsg = ec.message(); + return NULL; + } + return makeLTOModule(buffer.take(), errMsg); +} + +LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length, + std::string &errMsg) { + OwningPtr buffer(makeBuffer(mem, length)); + if (!buffer) + return NULL; + return makeLTOModule(buffer.take(), errMsg); +} + +void LTOModule::getTargetOptions(TargetOptions &Options) { + Options.LessPreciseFPMADOption = EnableFPMAD; + Options.NoFramePointerElim = DisableFPElim; + Options.AllowFPOpFusion = FuseFPOps; + Options.UnsafeFPMath = EnableUnsafeFPMath; + Options.NoInfsFPMath = EnableNoInfsFPMath; + Options.NoNaNsFPMath = EnableNoNaNsFPMath; + Options.HonorSignDependentRoundingFPMathOption = + EnableHonorSignDependentRoundingFPMath; + Options.UseSoftFloat = GenerateSoftFloatCalls; + if (FloatABIForCalls != FloatABI::Default) + Options.FloatABIType = FloatABIForCalls; + Options.NoZerosInBSS = DontPlaceZerosInBSS; + Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; + Options.DisableTailCalls = DisableTailCalls; + Options.StackAlignmentOverride = OverrideStackAlignment; + Options.TrapFuncName = TrapFuncName; + Options.PositionIndependentExecutable = EnablePIE; + Options.EnableSegmentedStacks = SegmentedStacks; + Options.UseInitArray = UseInitArray; +} + +LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, + std::string &errMsg) { + // parse bitcode buffer + OwningPtr m(getLazyBitcodeModule(buffer, getGlobalContext(), + &errMsg)); + if (!m) { + delete buffer; + return NULL; + } + + std::string TripleStr = m->getTargetTriple(); + if (TripleStr.empty()) + TripleStr = sys::getDefaultTargetTriple(); + llvm::Triple Triple(TripleStr); + + // find machine architecture for this module + const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); + if (!march) + return NULL; + + // construct LTOModule, hand over ownership of module and target + SubtargetFeatures Features; + Features.getDefaultSubtargetFeatures(Triple); + std::string FeatureStr = Features.getString(); + // Set a default CPU for Darwin triples. + std::string CPU; + if (Triple.isOSDarwin()) { + if (Triple.getArch() == llvm::Triple::x86_64) + CPU = "core2"; + else if (Triple.getArch() == llvm::Triple::x86) + CPU = "yonah"; + } + TargetOptions Options; + getTargetOptions(Options); + TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr, + Options); + LTOModule *Ret = new LTOModule(m.take(), target); + if (Ret->parseSymbols(errMsg)) { + delete Ret; + return NULL; + } + + return Ret; +} + +/// makeBuffer - Create a MemoryBuffer from a memory range. +MemoryBuffer *LTOModule::makeBuffer(const void *mem, size_t length) { + const char *startPtr = (const char*)mem; + return MemoryBuffer::getMemBuffer(StringRef(startPtr, length), "", false); +} + +/// objcClassNameFromExpression - Get string that the data pointer points to. +bool +LTOModule::objcClassNameFromExpression(const Constant *c, std::string &name) { + if (const ConstantExpr *ce = dyn_cast(c)) { + Constant *op = ce->getOperand(0); + if (GlobalVariable *gvn = dyn_cast(op)) { + Constant *cn = gvn->getInitializer(); + if (ConstantDataArray *ca = dyn_cast(cn)) { + if (ca->isCString()) { + name = ".objc_class_name_" + ca->getAsCString().str(); + return true; + } + } + } + } + return false; +} + +/// addObjCClass - Parse i386/ppc ObjC class data structure. +void LTOModule::addObjCClass(const GlobalVariable *clgv) { + const ConstantStruct *c = dyn_cast(clgv->getInitializer()); + if (!c) return; + + // second slot in __OBJC,__class is pointer to superclass name + std::string superclassName; + if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { + NameAndAttributes info; + StringMap::value_type &entry = + _undefines.GetOrCreateValue(superclassName); + if (!entry.getValue().name) { + const char *symbolName = entry.getKey().data(); + info.name = symbolName; + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + info.isFunction = false; + info.symbol = clgv; + entry.setValue(info); + } + } + + // third slot in __OBJC,__class is pointer to class name + std::string className; + if (objcClassNameFromExpression(c->getOperand(2), className)) { + StringSet::value_type &entry = _defines.GetOrCreateValue(className); + entry.setValue(1); + + NameAndAttributes info; + info.name = entry.getKey().data(); + info.attributes = LTO_SYMBOL_PERMISSIONS_DATA | + LTO_SYMBOL_DEFINITION_REGULAR | LTO_SYMBOL_SCOPE_DEFAULT; + info.isFunction = false; + info.symbol = clgv; + _symbols.push_back(info); + } +} + +/// addObjCCategory - Parse i386/ppc ObjC category data structure. +void LTOModule::addObjCCategory(const GlobalVariable *clgv) { + const ConstantStruct *c = dyn_cast(clgv->getInitializer()); + if (!c) return; + + // second slot in __OBJC,__category is pointer to target class name + std::string targetclassName; + if (!objcClassNameFromExpression(c->getOperand(1), targetclassName)) + return; + + NameAndAttributes info; + StringMap::value_type &entry = + _undefines.GetOrCreateValue(targetclassName); + + if (entry.getValue().name) + return; + + const char *symbolName = entry.getKey().data(); + info.name = symbolName; + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + info.isFunction = false; + info.symbol = clgv; + entry.setValue(info); +} + +/// addObjCClassRef - Parse i386/ppc ObjC class list data structure. +void LTOModule::addObjCClassRef(const GlobalVariable *clgv) { + std::string targetclassName; + if (!objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) + return; + + NameAndAttributes info; + StringMap::value_type &entry = + _undefines.GetOrCreateValue(targetclassName); + if (entry.getValue().name) + return; + + const char *symbolName = entry.getKey().data(); + info.name = symbolName; + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + info.isFunction = false; + info.symbol = clgv; + entry.setValue(info); +} + +/// addDefinedDataSymbol - Add a data symbol as defined to the list. +void LTOModule::addDefinedDataSymbol(const GlobalValue *v) { + // Add to list of defined symbols. + addDefinedSymbol(v, false); + + if (!v->hasSection() /* || !isTargetDarwin */) + return; + + // Special case i386/ppc ObjC data structures in magic sections: + // The issue is that the old ObjC object format did some strange + // contortions to avoid real linker symbols. For instance, the + // ObjC class data structure is allocated statically in the executable + // that defines that class. That data structures contains a pointer to + // its superclass. But instead of just initializing that part of the + // struct to the address of its superclass, and letting the static and + // dynamic linkers do the rest, the runtime works by having that field + // instead point to a C-string that is the name of the superclass. + // At runtime the objc initialization updates that pointer and sets + // it to point to the actual super class. As far as the linker + // knows it is just a pointer to a string. But then someone wanted the + // linker to issue errors at build time if the superclass was not found. + // So they figured out a way in mach-o object format to use an absolute + // symbols (.objc_class_name_Foo = 0) and a floating reference + // (.reference .objc_class_name_Bar) to cause the linker into erroring when + // a class was missing. + // The following synthesizes the implicit .objc_* symbols for the linker + // from the ObjC data structures generated by the front end. + + // special case if this data blob is an ObjC class definition + if (v->getSection().compare(0, 15, "__OBJC,__class,") == 0) { + if (const GlobalVariable *gv = dyn_cast(v)) { + addObjCClass(gv); + } + } + + // special case if this data blob is an ObjC category definition + else if (v->getSection().compare(0, 18, "__OBJC,__category,") == 0) { + if (const GlobalVariable *gv = dyn_cast(v)) { + addObjCCategory(gv); + } + } + + // special case if this data blob is the list of referenced classes + else if (v->getSection().compare(0, 18, "__OBJC,__cls_refs,") == 0) { + if (const GlobalVariable *gv = dyn_cast(v)) { + addObjCClassRef(gv); + } + } +} + +/// addDefinedFunctionSymbol - Add a function symbol as defined to the list. +void LTOModule::addDefinedFunctionSymbol(const Function *f) { + // add to list of defined symbols + addDefinedSymbol(f, true); +} + +/// addDefinedSymbol - Add a defined symbol to the list. +void LTOModule::addDefinedSymbol(const GlobalValue *def, bool isFunction) { + // ignore all llvm.* symbols + if (def->getName().startswith("llvm.")) + return; + + // string is owned by _defines + SmallString<64> Buffer; + _mangler.getNameWithPrefix(Buffer, def, false); + + // set alignment part log2() can have rounding errors + uint32_t align = def->getAlignment(); + uint32_t attr = align ? countTrailingZeros(def->getAlignment()) : 0; + + // set permissions part + if (isFunction) { + attr |= LTO_SYMBOL_PERMISSIONS_CODE; + } else { + const GlobalVariable *gv = dyn_cast(def); + if (gv && gv->isConstant()) + attr |= LTO_SYMBOL_PERMISSIONS_RODATA; + else + attr |= LTO_SYMBOL_PERMISSIONS_DATA; + } + + // set definition part + if (def->hasWeakLinkage() || def->hasLinkOnceLinkage() || + def->hasLinkerPrivateWeakLinkage()) + attr |= LTO_SYMBOL_DEFINITION_WEAK; + else if (def->hasCommonLinkage()) + attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; + else + attr |= LTO_SYMBOL_DEFINITION_REGULAR; + + // set scope part + if (def->hasHiddenVisibility()) + attr |= LTO_SYMBOL_SCOPE_HIDDEN; + else if (def->hasProtectedVisibility()) + attr |= LTO_SYMBOL_SCOPE_PROTECTED; + else if (def->hasExternalLinkage() || def->hasWeakLinkage() || + def->hasLinkOnceLinkage() || def->hasCommonLinkage() || + def->hasLinkerPrivateWeakLinkage()) + attr |= LTO_SYMBOL_SCOPE_DEFAULT; + else if (def->hasLinkOnceODRAutoHideLinkage()) + attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; + else + attr |= LTO_SYMBOL_SCOPE_INTERNAL; + + StringSet::value_type &entry = _defines.GetOrCreateValue(Buffer); + entry.setValue(1); + + // fill information structure + NameAndAttributes info; + StringRef Name = entry.getKey(); + info.name = Name.data(); + assert(info.name[Name.size()] == '\0'); + info.attributes = attr; + info.isFunction = isFunction; + info.symbol = def; + + // add to table of symbols + _symbols.push_back(info); +} + +/// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the +/// defined list. +void LTOModule::addAsmGlobalSymbol(const char *name, + lto_symbol_attributes scope) { + StringSet::value_type &entry = _defines.GetOrCreateValue(name); + + // only add new define if not already defined + if (entry.getValue()) + return; + + entry.setValue(1); + + NameAndAttributes &info = _undefines[entry.getKey().data()]; + + if (info.symbol == 0) { + // FIXME: This is trying to take care of module ASM like this: + // + // module asm ".zerofill __FOO, __foo, _bar_baz_qux, 0" + // + // but is gross and its mother dresses it funny. Have the ASM parser give us + // more details for this type of situation so that we're not guessing so + // much. + + // fill information structure + info.name = entry.getKey().data(); + info.attributes = + LTO_SYMBOL_PERMISSIONS_DATA | LTO_SYMBOL_DEFINITION_REGULAR | scope; + info.isFunction = false; + info.symbol = 0; + + // add to table of symbols + _symbols.push_back(info); + return; + } + + if (info.isFunction) + addDefinedFunctionSymbol(cast(info.symbol)); + else + addDefinedDataSymbol(info.symbol); + + _symbols.back().attributes &= ~LTO_SYMBOL_SCOPE_MASK; + _symbols.back().attributes |= scope; +} + +/// addAsmGlobalSymbolUndef - Add a global symbol from module-level ASM to the +/// undefined list. +void LTOModule::addAsmGlobalSymbolUndef(const char *name) { + StringMap::value_type &entry = + _undefines.GetOrCreateValue(name); + + _asm_undefines.push_back(entry.getKey().data()); + + // we already have the symbol + if (entry.getValue().name) + return; + + uint32_t attr = LTO_SYMBOL_DEFINITION_UNDEFINED;; + attr |= LTO_SYMBOL_SCOPE_DEFAULT; + NameAndAttributes info; + info.name = entry.getKey().data(); + info.attributes = attr; + info.isFunction = false; + info.symbol = 0; + + entry.setValue(info); +} + +/// addPotentialUndefinedSymbol - Add a symbol which isn't defined just yet to a +/// list to be resolved later. +void +LTOModule::addPotentialUndefinedSymbol(const GlobalValue *decl, bool isFunc) { + // ignore all llvm.* symbols + if (decl->getName().startswith("llvm.")) + return; + + // ignore all aliases + if (isa(decl)) + return; + + SmallString<64> name; + _mangler.getNameWithPrefix(name, decl, false); + + StringMap::value_type &entry = + _undefines.GetOrCreateValue(name); + + // we already have the symbol + if (entry.getValue().name) + return; + + NameAndAttributes info; + + info.name = entry.getKey().data(); + + if (decl->hasExternalWeakLinkage()) + info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; + else + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + + info.isFunction = isFunc; + info.symbol = decl; + + entry.setValue(info); +} + +namespace { + class RecordStreamer : public MCStreamer { + public: + enum State { NeverSeen, Global, Defined, DefinedGlobal, Used }; + + private: + StringMap Symbols; + + void markDefined(const MCSymbol &Symbol) { + State &S = Symbols[Symbol.getName()]; + switch (S) { + case DefinedGlobal: + case Global: + S = DefinedGlobal; + break; + case NeverSeen: + case Defined: + case Used: + S = Defined; + break; + } + } + void markGlobal(const MCSymbol &Symbol) { + State &S = Symbols[Symbol.getName()]; + switch (S) { + case DefinedGlobal: + case Defined: + S = DefinedGlobal; + break; + + case NeverSeen: + case Global: + case Used: + S = Global; + break; + } + } + void markUsed(const MCSymbol &Symbol) { + State &S = Symbols[Symbol.getName()]; + switch (S) { + case DefinedGlobal: + case Defined: + case Global: + break; + + case NeverSeen: + case Used: + S = Used; + break; + } + } + + // FIXME: mostly copied for the obj streamer. + void AddValueSymbols(const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Target: + // FIXME: What should we do in here? + break; + + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(Value); + AddValueSymbols(BE->getLHS()); + AddValueSymbols(BE->getRHS()); + break; + } + + case MCExpr::SymbolRef: + markUsed(cast(Value)->getSymbol()); + break; + + case MCExpr::Unary: + AddValueSymbols(cast(Value)->getSubExpr()); + break; + } + } + + public: + typedef StringMap::const_iterator const_iterator; + + const_iterator begin() { + return Symbols.begin(); + } + + const_iterator end() { + return Symbols.end(); + } + + RecordStreamer(MCContext &Context) + : MCStreamer(SK_RecordStreamer, Context) {} + + virtual void EmitInstruction(const MCInst &Inst) { + // Scan for values. + for (unsigned i = Inst.getNumOperands(); i--; ) + if (Inst.getOperand(i).isExpr()) + AddValueSymbols(Inst.getOperand(i).getExpr()); + } + virtual void EmitLabel(MCSymbol *Symbol) { + Symbol->setSection(*getCurrentSection().first); + markDefined(*Symbol); + } + virtual void EmitDebugLabel(MCSymbol *Symbol) { + EmitLabel(Symbol); + } + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // FIXME: should we handle aliases? + markDefined(*Symbol); + } + virtual bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { + if (Attribute == MCSA_Global) + markGlobal(*Symbol); + return true; + } + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size , unsigned ByteAlignment) { + markDefined(*Symbol); + } + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + markDefined(*Symbol); + } + + virtual void EmitBundleAlignMode(unsigned AlignPow2) {} + virtual void EmitBundleLock(bool AlignToEnd) {} + virtual void EmitBundleUnlock() {} + + // Noop calls. + virtual void ChangeSection(const MCSection *Section, + const MCExpr *Subsection) {} + virtual void InitToTextSection() {} + virtual void InitSections() {} + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} + virtual void EmitThumbFunc(MCSymbol *Func) {} + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {} + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) {} + virtual void EmitCOFFSymbolStorageClass(int StorageClass) {} + virtual void EmitCOFFSymbolType(int Type) {} + virtual void EndCOFFSymbolDef() {} + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) {} + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) {} + virtual void EmitBytes(StringRef Data) {} + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size) {} + virtual void EmitULEB128Value(const MCExpr *Value) {} + virtual void EmitSLEB128Value(const MCExpr *Value) {} + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, + unsigned ValueSize, + unsigned MaxBytesToEmit) {} + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) {} + virtual bool EmitValueToOffset(const MCExpr *Offset, + unsigned char Value ) { return false; } + virtual void EmitFileDirective(StringRef Filename) {} + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label, + unsigned PointerSize) {} + virtual void FinishImpl() {} + virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { + RecordProcEnd(Frame); + } + + static bool classof(const MCStreamer *S) { + return S->getKind() == SK_RecordStreamer; + } + }; +} // end anonymous namespace + +/// addAsmGlobalSymbols - Add global symbols from module-level ASM to the +/// defined or undefined lists. +bool LTOModule::addAsmGlobalSymbols(std::string &errMsg) { + const std::string &inlineAsm = _module->getModuleInlineAsm(); + if (inlineAsm.empty()) + return false; + + OwningPtr Streamer(new RecordStreamer(_context)); + MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(inlineAsm); + SourceMgr SrcMgr; + SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); + OwningPtr Parser(createMCAsmParser(SrcMgr, + _context, *Streamer, + *_target->getMCAsmInfo())); + const Target &T = _target->getTarget(); + OwningPtr MCII(T.createMCInstrInfo()); + OwningPtr + STI(T.createMCSubtargetInfo(_target->getTargetTriple(), + _target->getTargetCPU(), + _target->getTargetFeatureString())); + OwningPtr TAP(T.createMCAsmParser(*STI, *Parser.get(), *MCII)); + if (!TAP) { + errMsg = "target " + std::string(T.getName()) + + " does not define AsmParser."; + return true; + } + + Parser->setTargetParser(*TAP); + if (Parser->Run(false)) + return true; + + for (RecordStreamer::const_iterator i = Streamer->begin(), + e = Streamer->end(); i != e; ++i) { + StringRef Key = i->first(); + RecordStreamer::State Value = i->second; + if (Value == RecordStreamer::DefinedGlobal) + addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_DEFAULT); + else if (Value == RecordStreamer::Defined) + addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_INTERNAL); + else if (Value == RecordStreamer::Global || + Value == RecordStreamer::Used) + addAsmGlobalSymbolUndef(Key.data()); + } + + return false; +} + +/// isDeclaration - Return 'true' if the global value is a declaration. +static bool isDeclaration(const GlobalValue &V) { + if (V.hasAvailableExternallyLinkage()) + return true; + + if (V.isMaterializable()) + return false; + + return V.isDeclaration(); +} + +/// parseSymbols - Parse the symbols from the module and model-level ASM and add +/// them to either the defined or undefined lists. +bool LTOModule::parseSymbols(std::string &errMsg) { + // add functions + for (Module::iterator f = _module->begin(), e = _module->end(); f != e; ++f) { + if (isDeclaration(*f)) + addPotentialUndefinedSymbol(f, true); + else + addDefinedFunctionSymbol(f); + } + + // add data + for (Module::global_iterator v = _module->global_begin(), + e = _module->global_end(); v != e; ++v) { + if (isDeclaration(*v)) + addPotentialUndefinedSymbol(v, false); + else + addDefinedDataSymbol(v); + } + + // add asm globals + if (addAsmGlobalSymbols(errMsg)) + return true; + + // add aliases + for (Module::alias_iterator a = _module->alias_begin(), + e = _module->alias_end(); a != e; ++a) { + if (isDeclaration(*a->getAliasedGlobal())) + // Is an alias to a declaration. + addPotentialUndefinedSymbol(a, false); + else + addDefinedDataSymbol(a); + } + + // make symbols for all undefines + for (StringMap::iterator u =_undefines.begin(), + e = _undefines.end(); u != e; ++u) { + // If this symbol also has a definition, then don't make an undefine because + // it is a tentative definition. + if (_defines.count(u->getKey())) continue; + NameAndAttributes info = u->getValue(); + _symbols.push_back(info); + } + + return false; +} diff --git a/lib/LTO/Makefile b/lib/LTO/Makefile new file mode 100644 index 0000000000..7ca125ab14 --- /dev/null +++ b/lib/LTO/Makefile @@ -0,0 +1,15 @@ +##===- lib/Linker/Makefile ---------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +LIBRARYNAME = LLVMLTO +BUILD_ARCHIVE := 1 + +include $(LEVEL)/Makefile.common + diff --git a/lib/Makefile b/lib/Makefile index 0a4435ef64..cfe992668d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -11,7 +11,7 @@ LEVEL = .. include $(LEVEL)/Makefile.config PARALLEL_DIRS := IR AsmParser Bitcode Analysis Transforms CodeGen \ - Target ExecutionEngine Linker MC Object Option DebugInfo \ + Target ExecutionEngine Linker LTO MC Object Option DebugInfo \ IRReader include $(LEVEL)/Makefile.common diff --git a/test/LTO/cfi_endproc.ll b/test/LTO/cfi_endproc.ll new file mode 100644 index 0000000000..0a47b0225e --- /dev/null +++ b/test/LTO/cfi_endproc.ll @@ -0,0 +1,20 @@ +; RUN: llvm-as < %s >%t1 +; RUN: llvm-lto -o %t2 %t1 + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +module asm ".text" +module asm ".align 16, 0x90" +module asm ".type PR14512, @function" +module asm "PR14512:.cfi_startproc" +module asm "ret" +module asm ".cfi_endproc" + +declare void @PR14512() + +define i32 @main(i32 %argc, i8** %argv) { + call void @PR14512() + ret i32 0 +} +; XFAIL: win32 diff --git a/test/LTO/lit.local.cfg b/test/LTO/lit.local.cfg new file mode 100644 index 0000000000..f61943a77a --- /dev/null +++ b/test/LTO/lit.local.cfg @@ -0,0 +1,6 @@ +targets = set(config.root.targets_to_build.split()) +if not 'X86' in targets: + config.unsupported = True + +if config.root.host_os in ['Cygwin', 'MingW', 'Windows']: + config.unsupported = True diff --git a/test/tools/lto/cfi_endproc.ll b/test/tools/lto/cfi_endproc.ll deleted file mode 100644 index 0a47b0225e..0000000000 --- a/test/tools/lto/cfi_endproc.ll +++ /dev/null @@ -1,20 +0,0 @@ -; RUN: llvm-as < %s >%t1 -; RUN: llvm-lto -o %t2 %t1 - -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -module asm ".text" -module asm ".align 16, 0x90" -module asm ".type PR14512, @function" -module asm "PR14512:.cfi_startproc" -module asm "ret" -module asm ".cfi_endproc" - -declare void @PR14512() - -define i32 @main(i32 %argc, i8** %argv) { - call void @PR14512() - ret i32 0 -} -; XFAIL: win32 diff --git a/test/tools/lto/lit.local.cfg b/test/tools/lto/lit.local.cfg deleted file mode 100644 index f61943a77a..0000000000 --- a/test/tools/lto/lit.local.cfg +++ /dev/null @@ -1,6 +0,0 @@ -targets = set(config.root.targets_to_build.split()) -if not 'X86' in targets: - config.unsupported = True - -if config.root.host_os in ['Cygwin', 'MingW', 'Windows']: - config.unsupported = True diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt index 9ec89f3aa2..fa10b997a2 100644 --- a/tools/LLVMBuild.txt +++ b/tools/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup +subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-prof llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup [component_0] type = Group diff --git a/tools/llvm-lto/CMakeLists.txt b/tools/llvm-lto/CMakeLists.txt index b253b69c1b..348976cb81 100644 --- a/tools/llvm-lto/CMakeLists.txt +++ b/tools/llvm-lto/CMakeLists.txt @@ -1,7 +1,6 @@ +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} lto support) + add_llvm_tool(llvm-lto llvm-lto.cpp ) -target_link_libraries(llvm-lto LTO LLVMSupport) - -add_dependencies(llvm-lto lto) diff --git a/tools/llvm-lto/LLVMBuild.txt b/tools/llvm-lto/LLVMBuild.txt new file mode 100644 index 0000000000..c1613a34c0 --- /dev/null +++ b/tools/llvm-lto/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/llvm-lto/LLVMBuild.txt ----------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-lto +parent = Tools +required_libraries = LTO Support all-targets diff --git a/tools/llvm-lto/Makefile b/tools/llvm-lto/Makefile index 1b1a1f8b38..f1801b4b20 100644 --- a/tools/llvm-lto/Makefile +++ b/tools/llvm-lto/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-lto -LINK_COMPONENTS := support +LINK_COMPONENTS := lto ipo scalaropts linker bitreader bitwriter mcdisassembler support target vectorize all-targets # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 @@ -17,6 +17,3 @@ TOOL_NO_EXPORTS := 1 NO_INSTALL := 1 include $(LEVEL)/Makefile.common - -LDFLAGS += -L$(LibDir) -LIBS += -lLTO diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp index f25037c37a..82a2c8288f 100644 --- a/tools/llvm-lto/llvm-lto.cpp +++ b/tools/llvm-lto/llvm-lto.cpp @@ -12,12 +12,14 @@ // //===----------------------------------------------------------------------===// -#include "llvm-c/lto.h" +#include "llvm/LTO/LTOCodeGenerator.h" +#include "llvm/LTO/LTOModule.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TargetSelect.h" using namespace llvm; @@ -37,46 +39,48 @@ int main(int argc, char **argv) { llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n"); + // Initialize the configured targets. + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + unsigned BaseArg = 0; std::string ErrorMessage; - lto_code_gen_t code_gen = lto_codegen_create(); - if (code_gen == NULL) - errs() << argv[0] << ": error creating a code generation module: " - << lto_get_error_message() << "\n"; + LTOCodeGenerator CodeGen; - lto_codegen_set_pic_model(code_gen, LTO_CODEGEN_PIC_MODEL_DYNAMIC); - lto_codegen_set_debug_model(code_gen, LTO_DEBUG_MODEL_DWARF); + CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC); + CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF); for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) { - lto_module_t BitcodeModule = lto_module_create(InputFilenames[i].c_str()); - if (BitcodeModule == NULL) { + std::string error; + OwningPtr Module(LTOModule::makeLTOModule(InputFilenames[i].c_str(), + error)); + if (!error.empty()) { errs() << argv[0] << ": error loading file '" << InputFilenames[i] - << "': " << lto_get_error_message() << "\n"; + << "': " << error << "\n"; return 1; } - if (lto_codegen_add_module(code_gen, BitcodeModule)) { + + if (!CodeGen.addModule(Module.get(), error)) { errs() << argv[0] << ": error adding file '" << InputFilenames[i] - << "': " << lto_get_error_message() << "\n"; - lto_module_dispose(BitcodeModule); + << "': " << error << "\n"; return 1; } - - lto_module_dispose(BitcodeModule); } if (!OutputFilename.empty()) { size_t len = 0; - const void *Code = lto_codegen_compile(code_gen, &len); + std::string ErrorInfo; + const void *Code = CodeGen.compile(&len, ErrorInfo); if (Code == NULL) { errs() << argv[0] - << ": error compiling the code: " << lto_get_error_message() - << "\n"; + << ": error compiling the code: " << ErrorInfo << "\n"; return 1; } - std::string ErrorInfo; raw_fd_ostream FileStream(OutputFilename.c_str(), ErrorInfo); if (!ErrorInfo.empty()) { errs() << argv[0] << ": error opening the file '" << OutputFilename @@ -86,10 +90,11 @@ int main(int argc, char **argv) { FileStream.write(reinterpret_cast(Code), len); } else { + std::string ErrorInfo; const char *OutputName = NULL; - if (lto_codegen_compile_to_file(code_gen, &OutputName)) { + if (!CodeGen.compile_to_file(&OutputName, ErrorInfo)) { errs() << argv[0] - << ": error compiling the code: " << lto_get_error_message() + << ": error compiling the code: " << ErrorInfo << "\n"; return 1; } @@ -97,7 +102,5 @@ int main(int argc, char **argv) { outs() << "Wrote native object file '" << OutputName << "'\n"; } - lto_codegen_dispose(code_gen); - return 0; } diff --git a/tools/lto/CMakeLists.txt b/tools/lto/CMakeLists.txt index c71aac1eec..8b26ddd57e 100644 --- a/tools/lto/CMakeLists.txt +++ b/tools/lto/CMakeLists.txt @@ -1,14 +1,12 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - ipo scalaropts linker bitreader bitwriter mcdisassembler vectorize) + ipo scalaropts linker bitreader bitwriter lto mcdisassembler vectorize) add_definitions( -DLLVM_VERSION_INFO=\"${PACKAGE_VERSION}\" ) set(SOURCES - LTOCodeGenerator.cpp LTODisassembler.cpp lto.cpp - LTOModule.cpp ) if( NOT WIN32 AND LLVM_ENABLE_PIC ) diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp deleted file mode 100644 index 19e8c4c149..0000000000 --- a/tools/lto/LTOCodeGenerator.cpp +++ /dev/null @@ -1,458 +0,0 @@ -//===-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 "LTOCodeGenerator.h" -#include "LTOModule.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Config/config.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/InitializePasses.h" -#include "llvm/Linker.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/SubtargetFeature.h" -#include "llvm/PassManager.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/FormattedStream.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/system_error.h" -#include "llvm/Target/Mangler.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include "llvm/Transforms/ObjCARC.h" -using namespace llvm; - -static cl::opt -DisableOpt("disable-opt", cl::init(false), - cl::desc("Do not run any optimization passes")); - -static cl::opt -DisableInline("disable-inlining", cl::init(false), - cl::desc("Do not run the inliner pass")); - -static cl::opt -DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), - cl::desc("Do not run the GVN load PRE pass")); - -const char* LTOCodeGenerator::getVersionString() { -#ifdef LLVM_VERSION_INFO - return PACKAGE_NAME " version " PACKAGE_VERSION ", " LLVM_VERSION_INFO; -#else - return PACKAGE_NAME " version " PACKAGE_VERSION; -#endif -} - -LTOCodeGenerator::LTOCodeGenerator() - : Context(getGlobalContext()), Linker(new Module("ld-temp.o", Context)), - TargetMach(NULL), EmitDwarfDebugInfo(false), ScopeRestrictionsDone(false), - CodeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC), NativeObjectFile(NULL) { - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmPrinters(); - initializeLTOPasses(); -} - -LTOCodeGenerator::~LTOCodeGenerator() { - delete TargetMach; - delete NativeObjectFile; - delete Linker.getModule(); - - for (std::vector::iterator I = CodegenOptions.begin(), - E = CodegenOptions.end(); - I != E; ++I) - free(*I); -} - -// Initialize LTO passes. Please keep this funciton in sync with -// PassManagerBuilder::populateLTOPassManager(), and make sure all LTO -// passes are initialized. -// -void LTOCodeGenerator::initializeLTOPasses() { - PassRegistry &R = *PassRegistry::getPassRegistry(); - - initializeInternalizePassPass(R); - initializeIPSCCPPass(R); - initializeGlobalOptPass(R); - initializeConstantMergePass(R); - initializeDAHPass(R); - initializeInstCombinerPass(R); - initializeSimpleInlinerPass(R); - initializePruneEHPass(R); - initializeGlobalDCEPass(R); - initializeArgPromotionPass(R); - initializeJumpThreadingPass(R); - initializeSROAPass(R); - initializeSROA_DTPass(R); - initializeSROA_SSAUpPass(R); - initializeFunctionAttrsPass(R); - initializeGlobalsModRefPass(R); - initializeLICMPass(R); - initializeGVNPass(R); - initializeMemCpyOptPass(R); - initializeDCEPass(R); - initializeCFGSimplifyPassPass(R); -} - -bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) { - bool ret = Linker.linkInModule(mod->getLLVVMModule(), &errMsg); - - const std::vector &undefs = mod->getAsmUndefinedRefs(); - for (int i = 0, e = undefs.size(); i != e; ++i) - AsmUndefinedRefs[undefs[i]] = 1; - - return !ret; -} - -void LTOCodeGenerator::setDebugInfo(lto_debug_model debug) { - switch (debug) { - case LTO_DEBUG_MODEL_NONE: - EmitDwarfDebugInfo = false; - return; - - case LTO_DEBUG_MODEL_DWARF: - EmitDwarfDebugInfo = true; - return; - } - 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: - CodeModel = model; - return; - } - llvm_unreachable("Unknown PIC model!"); -} - -bool LTOCodeGenerator::writeMergedModules(const char *path, - std::string &errMsg) { - if (!determineTarget(errMsg)) - return false; - - // mark which symbols can not be internalized - applyScopeRestrictions(); - - // create output file - std::string ErrInfo; - tool_output_file Out(path, ErrInfo, sys::fs::F_Binary); - if (!ErrInfo.empty()) { - errMsg = "could not open bitcode file for writing: "; - errMsg += path; - return false; - } - - // write bitcode to it - WriteBitcodeToFile(Linker.getModule(), Out.os()); - Out.os().close(); - - if (Out.os().has_error()) { - errMsg = "could not write bitcode file: "; - errMsg += path; - Out.os().clear_error(); - return false; - } - - Out.keep(); - return true; -} - -bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) { - // make unique temp .o file to put generated object file - SmallString<128> Filename; - int FD; - error_code EC = sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename); - if (EC) { - errMsg = EC.message(); - return false; - } - - // generate object file - tool_output_file objFile(Filename.c_str(), FD); - - bool genResult = generateObjectFile(objFile.os(), errMsg); - objFile.os().close(); - if (objFile.os().has_error()) { - objFile.os().clear_error(); - sys::fs::remove(Twine(Filename)); - return false; - } - - objFile.keep(); - if (!genResult) { - sys::fs::remove(Twine(Filename)); - return false; - } - - NativeObjectPath = Filename.c_str(); - *name = NativeObjectPath.c_str(); - return true; -} - -const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { - const char *name; - if (!compile_to_file(&name, errMsg)) - return NULL; - - // remove old buffer if compile() called twice - delete NativeObjectFile; - - // read .o file into memory buffer - OwningPtr BuffPtr; - if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) { - errMsg = ec.message(); - sys::fs::remove(NativeObjectPath); - return NULL; - } - NativeObjectFile = BuffPtr.take(); - - // remove temp files - sys::fs::remove(NativeObjectPath); - - // return buffer, unless error - if (NativeObjectFile == NULL) - return NULL; - *length = NativeObjectFile->getBufferSize(); - return NativeObjectFile->getBufferStart(); -} - -bool LTOCodeGenerator::determineTarget(std::string &errMsg) { - if (TargetMach != NULL) - return true; - - // if options were requested, set them - if (!CodegenOptions.empty()) - cl::ParseCommandLineOptions(CodegenOptions.size(), - const_cast(&CodegenOptions[0])); - - std::string TripleStr = Linker.getModule()->getTargetTriple(); - if (TripleStr.empty()) - TripleStr = sys::getDefaultTargetTriple(); - llvm::Triple Triple(TripleStr); - - // create target machine from info for merged modules - const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); - if (march == NULL) - 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; - } - - // construct LTOModule, hand over ownership of module and target - SubtargetFeatures Features; - Features.getDefaultSubtargetFeatures(Triple); - std::string FeatureStr = Features.getString(); - // Set a default CPU for Darwin triples. - if (MCpu.empty() && Triple.isOSDarwin()) { - if (Triple.getArch() == llvm::Triple::x86_64) - MCpu = "core2"; - else if (Triple.getArch() == llvm::Triple::x86) - MCpu = "yonah"; - } - TargetOptions Options; - LTOModule::getTargetOptions(Options); - TargetMach = march->createTargetMachine(TripleStr, MCpu, FeatureStr, Options, - RelocModel, CodeModel::Default, - CodeGenOpt::Aggressive); - return true; -} - -void LTOCodeGenerator:: -applyRestriction(GlobalValue &GV, - std::vector &MustPreserveList, - SmallPtrSet &AsmUsed, - Mangler &Mangler) { - SmallString<64> Buffer; - Mangler.getNameWithPrefix(Buffer, &GV, false); - - if (GV.isDeclaration()) - return; - if (MustPreserveSymbols.count(Buffer)) - MustPreserveList.push_back(GV.getName().data()); - if (AsmUndefinedRefs.count(Buffer)) - AsmUsed.insert(&GV); -} - -static void findUsedValues(GlobalVariable *LLVMUsed, - SmallPtrSet &UsedValues) { - if (LLVMUsed == 0) return; - - ConstantArray *Inits = cast(LLVMUsed->getInitializer()); - for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) - if (GlobalValue *GV = - dyn_cast(Inits->getOperand(i)->stripPointerCasts())) - UsedValues.insert(GV); -} - -void LTOCodeGenerator::applyScopeRestrictions() { - if (ScopeRestrictionsDone) - return; - Module *mergedModule = Linker.getModule(); - - // Start off with a verification pass. - PassManager passes; - passes.add(createVerifierPass()); - - // mark which symbols can not be internalized - MCContext MContext(TargetMach->getMCAsmInfo(), TargetMach->getRegisterInfo(), - NULL); - Mangler Mangler(MContext, TargetMach); - std::vector MustPreserveList; - SmallPtrSet AsmUsed; - - for (Module::iterator f = mergedModule->begin(), - e = mergedModule->end(); f != e; ++f) - applyRestriction(*f, MustPreserveList, AsmUsed, Mangler); - for (Module::global_iterator v = mergedModule->global_begin(), - e = mergedModule->global_end(); v != e; ++v) - applyRestriction(*v, MustPreserveList, AsmUsed, Mangler); - for (Module::alias_iterator a = mergedModule->alias_begin(), - e = mergedModule->alias_end(); a != e; ++a) - applyRestriction(*a, MustPreserveList, AsmUsed, Mangler); - - GlobalVariable *LLVMCompilerUsed = - mergedModule->getGlobalVariable("llvm.compiler.used"); - findUsedValues(LLVMCompilerUsed, AsmUsed); - if (LLVMCompilerUsed) - LLVMCompilerUsed->eraseFromParent(); - - if (!AsmUsed.empty()) { - llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(Context); - std::vector asmUsed2; - for (SmallPtrSet::const_iterator i = AsmUsed.begin(), - e = AsmUsed.end(); i !=e; ++i) { - GlobalValue *GV = *i; - Constant *c = ConstantExpr::getBitCast(GV, i8PTy); - asmUsed2.push_back(c); - } - - llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size()); - LLVMCompilerUsed = - new llvm::GlobalVariable(*mergedModule, ATy, false, - llvm::GlobalValue::AppendingLinkage, - llvm::ConstantArray::get(ATy, asmUsed2), - "llvm.compiler.used"); - - LLVMCompilerUsed->setSection("llvm.metadata"); - } - - passes.add(createInternalizePass(MustPreserveList)); - - // apply scope restrictions - passes.run(*mergedModule); - - ScopeRestrictionsDone = true; -} - -/// Optimize merged modules using various IPO passes -bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, - std::string &errMsg) { - if (!this->determineTarget(errMsg)) - return false; - - Module *mergedModule = Linker.getModule(); - - // Mark which symbols can not be internalized - this->applyScopeRestrictions(); - - // Instantiate the pass manager to organize the passes. - PassManager passes; - - // Start off with a verification pass. - passes.add(createVerifierPass()); - - // Add an appropriate DataLayout instance for this module... - passes.add(new DataLayout(*TargetMach->getDataLayout())); - TargetMach->addAnalysisPasses(passes); - - // Enabling internalize here would use its AllButMain variant. It - // keeps only main if it exists and does nothing for libraries. Instead - // we create the pass ourselves with the symbol list provided by the linker. - if (!DisableOpt) - PassManagerBuilder().populateLTOPassManager(passes, - /*Internalize=*/false, - !DisableInline, - DisableGVNLoadPRE); - - // Make sure everything is still good. - passes.add(createVerifierPass()); - - PassManager codeGenPasses; - - codeGenPasses.add(new DataLayout(*TargetMach->getDataLayout())); - TargetMach->addAnalysisPasses(codeGenPasses); - - formatted_raw_ostream Out(out); - - // 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 our queue of passes all at once now, efficiently. - passes.run(*mergedModule); - - // Run the code generator, and write assembly file - codeGenPasses.run(*mergedModule); - - return true; -} - -/// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging -/// LTO problems. -void LTOCodeGenerator::setCodeGenDebugOptions(const char *options) { - for (std::pair 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("libLTO")); - CodegenOptions.push_back(strdup(o.first.str().c_str())); - } -} diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h deleted file mode 100644 index 02633629f9..0000000000 --- a/tools/lto/LTOCodeGenerator.h +++ /dev/null @@ -1,130 +0,0 @@ -//===-LTOCodeGenerator.h - 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 declares the LTOCodeGenerator class. -// -// LTO compilation consists of three phases: Pre-IPO, IPO and Post-IPO. -// -// The Pre-IPO phase compiles source code into bitcode file. The resulting -// bitcode files, along with object files and libraries, will be fed to the -// linker to through the IPO and Post-IPO phases. By using obj-file extension, -// the resulting bitcode file disguises itself as an object file, and therefore -// obviates the need of writing a special set of the make-rules only for LTO -// compilation. -// -// The IPO phase perform inter-procedural analyses and optimizations, and -// the Post-IPO consists two sub-phases: intra-procedural scalar optimizations -// (SOPT), and intra-procedural target-dependent code generator (CG). -// -// As of this writing, we don't separate IPO and the Post-IPO SOPT. They -// are intermingled together, and are driven by a single pass manager (see -// PassManagerBuilder::populateLTOPassManager()). -// -// The "LTOCodeGenerator" is the driver for the IPO and Post-IPO stages. -// The "CodeGenerator" here is bit confusing. Don't confuse the "CodeGenerator" -// with the machine specific code generator. -// -//===----------------------------------------------------------------------===// - -#ifndef LTO_CODE_GENERATOR_H -#define LTO_CODE_GENERATOR_H - -#include "llvm-c/lto.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/Linker.h" -#include -#include - -namespace llvm { - class LLVMContext; - class GlobalValue; - class Mangler; - class MemoryBuffer; - class TargetMachine; - class raw_ostream; -} - -//===----------------------------------------------------------------------===// -/// LTOCodeGenerator - C++ class which implements the opaque lto_code_gen_t -/// type. -/// -struct LTOCodeGenerator { - static const char *getVersionString(); - - LTOCodeGenerator(); - ~LTOCodeGenerator(); - - // Merge given module, return true on success. - bool addModule(struct LTOModule*, std::string &errMsg); - - void setDebugInfo(lto_debug_model); - void setCodePICModel(lto_codegen_model); - - void setCpu(const char *mCpu) { MCpu = mCpu; } - - void addMustPreserveSymbol(const char *sym) { MustPreserveSymbols[sym] = 1; } - - // To pass options to the driver and optimization passes. These options are - // not necessarily for debugging purpose (The function name is misleading). - // This function should be called before LTOCodeGenerator::compilexxx(), - // and LTOCodeGenerator::writeMergedModules(). - // - void setCodeGenDebugOptions(const char *opts); - - // Write the merged module to the file specified by the given path. - // Return true on success. - bool writeMergedModules(const char *path, std::string &errMsg); - - // Compile the merged module into a *single* object file; the path to object - // file is returned to the caller via argument "name". Return true on - // success. - // - // NOTE that it is up to the linker to remove the intermediate object file. - // Do not try to remove the object file in LTOCodeGenerator's destructor - // as we don't who (LTOCodeGenerator or the obj file) will last longer. - // - bool compile_to_file(const char **name, std::string &errMsg); - - // As with compile_to_file(), this function compiles the merged module into - // single object file. Instead of returning the object-file-path to the caller - // (linker), it brings the object to a buffer, and return the buffer to the - // caller. This function should delete intermediate object file once its content - // is brought to memory. Return NULL is the compilation was not successful. - // - const void *compile(size_t *length, std::string &errMsg); - -private: - void initializeLTOPasses(); - - bool generateObjectFile(llvm::raw_ostream &out, std::string &errMsg); - void applyScopeRestrictions(); - void applyRestriction(llvm::GlobalValue &GV, - std::vector &MustPreserveList, - llvm::SmallPtrSet &AsmUsed, - llvm::Mangler &Mangler); - bool determineTarget(std::string &errMsg); - - typedef llvm::StringMap StringSet; - - llvm::LLVMContext &Context; - llvm::Linker Linker; - llvm::TargetMachine *TargetMach; - bool EmitDwarfDebugInfo; - bool ScopeRestrictionsDone; - lto_codegen_model CodeModel; - StringSet MustPreserveSymbols; - StringSet AsmUndefinedRefs; - llvm::MemoryBuffer *NativeObjectFile; - std::vector CodegenOptions; - std::string MCpu; - std::string NativeObjectPath; -}; - -#endif // LTO_CODE_GENERATOR_H diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp deleted file mode 100644 index 87e3573de9..0000000000 --- a/tools/lto/LTOModule.cpp +++ /dev/null @@ -1,908 +0,0 @@ -//===-- LTOModule.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 "LTOModule.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCTargetAsmParser.h" -#include "llvm/MC/SubtargetFeature.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/system_error.h" -#include "llvm/Target/TargetRegisterInfo.h" -using namespace llvm; - -static cl::opt -EnableFPMAD("enable-fp-mad", - cl::desc("Enable less precise MAD instructions to be generated"), - cl::init(false)); - -static cl::opt -DisableFPElim("disable-fp-elim", - cl::desc("Disable frame pointer elimination optimization"), - cl::init(false)); - -static cl::opt -EnableUnsafeFPMath("enable-unsafe-fp-math", - cl::desc("Enable optimizations that may decrease FP precision"), - cl::init(false)); - -static cl::opt -EnableNoInfsFPMath("enable-no-infs-fp-math", - cl::desc("Enable FP math optimizations that assume no +-Infs"), - cl::init(false)); - -static cl::opt -EnableNoNaNsFPMath("enable-no-nans-fp-math", - cl::desc("Enable FP math optimizations that assume no NaNs"), - cl::init(false)); - -static cl::opt -EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math", - cl::Hidden, - cl::desc("Force codegen to assume rounding mode can change dynamically"), - cl::init(false)); - -static cl::opt -GenerateSoftFloatCalls("soft-float", - cl::desc("Generate software floating point library calls"), - cl::init(false)); - -static cl::opt -FloatABIForCalls("float-abi", - cl::desc("Choose float ABI type"), - cl::init(FloatABI::Default), - cl::values( - clEnumValN(FloatABI::Default, "default", - "Target default float ABI type"), - clEnumValN(FloatABI::Soft, "soft", - "Soft float ABI (implied by -soft-float)"), - clEnumValN(FloatABI::Hard, "hard", - "Hard float ABI (uses FP registers)"), - clEnumValEnd)); - -static cl::opt -FuseFPOps("fp-contract", - cl::desc("Enable aggresive formation of fused FP ops"), - cl::init(FPOpFusion::Standard), - cl::values( - clEnumValN(FPOpFusion::Fast, "fast", - "Fuse FP ops whenever profitable"), - clEnumValN(FPOpFusion::Standard, "on", - "Only fuse 'blessed' FP ops."), - clEnumValN(FPOpFusion::Strict, "off", - "Only fuse FP ops when the result won't be effected."), - clEnumValEnd)); - -static cl::opt -DontPlaceZerosInBSS("nozero-initialized-in-bss", - cl::desc("Don't place zero-initialized symbols into bss section"), - cl::init(false)); - -static cl::opt -EnableGuaranteedTailCallOpt("tailcallopt", - cl::desc("Turn fastcc calls into tail calls by (potentially) changing ABI."), - cl::init(false)); - -static cl::opt -DisableTailCalls("disable-tail-calls", - cl::desc("Never emit tail calls"), - cl::init(false)); - -static cl::opt -OverrideStackAlignment("stack-alignment", - cl::desc("Override default stack alignment"), - cl::init(0)); - -static cl::opt -TrapFuncName("trap-func", cl::Hidden, - cl::desc("Emit a call to trap function rather than a trap instruction"), - cl::init("")); - -static cl::opt -EnablePIE("enable-pie", - cl::desc("Assume the creation of a position independent executable."), - cl::init(false)); - -static cl::opt -SegmentedStacks("segmented-stacks", - cl::desc("Use segmented stacks if possible."), - cl::init(false)); - -static cl::opt -UseInitArray("use-init-array", - cl::desc("Use .init_array instead of .ctors."), - cl::init(false)); - -LTOModule::LTOModule(llvm::Module *m, llvm::TargetMachine *t) - : _module(m), _target(t), - _context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL), - _mangler(_context, t) {} - -/// isBitcodeFile - Returns 'true' if the file (or memory contents) is LLVM -/// bitcode. -bool LTOModule::isBitcodeFile(const void *mem, size_t length) { - return sys::fs::identify_magic(StringRef((const char *)mem, length)) == - sys::fs::file_magic::bitcode; -} - -bool LTOModule::isBitcodeFile(const char *path) { - sys::fs::file_magic type; - if (sys::fs::identify_magic(path, type)) - return false; - return type == sys::fs::file_magic::bitcode; -} - -/// isBitcodeFileForTarget - Returns 'true' if the file (or memory contents) is -/// LLVM bitcode for the specified triple. -bool LTOModule::isBitcodeFileForTarget(const void *mem, size_t length, - const char *triplePrefix) { - MemoryBuffer *buffer = makeBuffer(mem, length); - if (!buffer) - return false; - return isTargetMatch(buffer, triplePrefix); -} - -bool LTOModule::isBitcodeFileForTarget(const char *path, - const char *triplePrefix) { - OwningPtr buffer; - if (MemoryBuffer::getFile(path, buffer)) - return false; - return isTargetMatch(buffer.take(), triplePrefix); -} - -/// isTargetMatch - Returns 'true' if the memory buffer is for the specified -/// target triple. -bool LTOModule::isTargetMatch(MemoryBuffer *buffer, const char *triplePrefix) { - std::string Triple = getBitcodeTargetTriple(buffer, getGlobalContext()); - delete buffer; - return strncmp(Triple.c_str(), triplePrefix, strlen(triplePrefix)) == 0; -} - -/// makeLTOModule - Create an LTOModule. N.B. These methods take ownership of -/// the buffer. -LTOModule *LTOModule::makeLTOModule(const char *path, std::string &errMsg) { - OwningPtr buffer; - if (error_code ec = MemoryBuffer::getFile(path, buffer)) { - errMsg = ec.message(); - return NULL; - } - return makeLTOModule(buffer.take(), errMsg); -} - -LTOModule *LTOModule::makeLTOModule(int fd, const char *path, - size_t size, std::string &errMsg) { - return makeLTOModule(fd, path, size, 0, errMsg); -} - -LTOModule *LTOModule::makeLTOModule(int fd, const char *path, - size_t map_size, - off_t offset, - std::string &errMsg) { - OwningPtr buffer; - if (error_code ec = - MemoryBuffer::getOpenFileSlice(fd, path, buffer, map_size, offset)) { - errMsg = ec.message(); - return NULL; - } - return makeLTOModule(buffer.take(), errMsg); -} - -LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length, - std::string &errMsg) { - OwningPtr buffer(makeBuffer(mem, length)); - if (!buffer) - return NULL; - return makeLTOModule(buffer.take(), errMsg); -} - -void LTOModule::getTargetOptions(TargetOptions &Options) { - Options.LessPreciseFPMADOption = EnableFPMAD; - Options.NoFramePointerElim = DisableFPElim; - Options.AllowFPOpFusion = FuseFPOps; - Options.UnsafeFPMath = EnableUnsafeFPMath; - Options.NoInfsFPMath = EnableNoInfsFPMath; - Options.NoNaNsFPMath = EnableNoNaNsFPMath; - Options.HonorSignDependentRoundingFPMathOption = - EnableHonorSignDependentRoundingFPMath; - Options.UseSoftFloat = GenerateSoftFloatCalls; - if (FloatABIForCalls != FloatABI::Default) - Options.FloatABIType = FloatABIForCalls; - Options.NoZerosInBSS = DontPlaceZerosInBSS; - Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; - Options.DisableTailCalls = DisableTailCalls; - Options.StackAlignmentOverride = OverrideStackAlignment; - Options.TrapFuncName = TrapFuncName; - Options.PositionIndependentExecutable = EnablePIE; - Options.EnableSegmentedStacks = SegmentedStacks; - Options.UseInitArray = UseInitArray; -} - -LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, - std::string &errMsg) { - static bool Initialized = false; - if (!Initialized) { - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmParsers(); - Initialized = true; - } - - // parse bitcode buffer - OwningPtr m(getLazyBitcodeModule(buffer, getGlobalContext(), - &errMsg)); - if (!m) { - delete buffer; - return NULL; - } - - std::string TripleStr = m->getTargetTriple(); - if (TripleStr.empty()) - TripleStr = sys::getDefaultTargetTriple(); - llvm::Triple Triple(TripleStr); - - // find machine architecture for this module - const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); - if (!march) - return NULL; - - // construct LTOModule, hand over ownership of module and target - SubtargetFeatures Features; - Features.getDefaultSubtargetFeatures(Triple); - std::string FeatureStr = Features.getString(); - // Set a default CPU for Darwin triples. - std::string CPU; - if (Triple.isOSDarwin()) { - if (Triple.getArch() == llvm::Triple::x86_64) - CPU = "core2"; - else if (Triple.getArch() == llvm::Triple::x86) - CPU = "yonah"; - } - TargetOptions Options; - getTargetOptions(Options); - TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr, - Options); - LTOModule *Ret = new LTOModule(m.take(), target); - if (Ret->parseSymbols(errMsg)) { - delete Ret; - return NULL; - } - - return Ret; -} - -/// makeBuffer - Create a MemoryBuffer from a memory range. -MemoryBuffer *LTOModule::makeBuffer(const void *mem, size_t length) { - const char *startPtr = (const char*)mem; - return MemoryBuffer::getMemBuffer(StringRef(startPtr, length), "", false); -} - -/// objcClassNameFromExpression - Get string that the data pointer points to. -bool -LTOModule::objcClassNameFromExpression(const Constant *c, std::string &name) { - if (const ConstantExpr *ce = dyn_cast(c)) { - Constant *op = ce->getOperand(0); - if (GlobalVariable *gvn = dyn_cast(op)) { - Constant *cn = gvn->getInitializer(); - if (ConstantDataArray *ca = dyn_cast(cn)) { - if (ca->isCString()) { - name = ".objc_class_name_" + ca->getAsCString().str(); - return true; - } - } - } - } - return false; -} - -/// addObjCClass - Parse i386/ppc ObjC class data structure. -void LTOModule::addObjCClass(const GlobalVariable *clgv) { - const ConstantStruct *c = dyn_cast(clgv->getInitializer()); - if (!c) return; - - // second slot in __OBJC,__class is pointer to superclass name - std::string superclassName; - if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { - NameAndAttributes info; - StringMap::value_type &entry = - _undefines.GetOrCreateValue(superclassName); - if (!entry.getValue().name) { - const char *symbolName = entry.getKey().data(); - info.name = symbolName; - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; - entry.setValue(info); - } - } - - // third slot in __OBJC,__class is pointer to class name - std::string className; - if (objcClassNameFromExpression(c->getOperand(2), className)) { - StringSet::value_type &entry = _defines.GetOrCreateValue(className); - entry.setValue(1); - - NameAndAttributes info; - info.name = entry.getKey().data(); - info.attributes = LTO_SYMBOL_PERMISSIONS_DATA | - LTO_SYMBOL_DEFINITION_REGULAR | LTO_SYMBOL_SCOPE_DEFAULT; - info.isFunction = false; - info.symbol = clgv; - _symbols.push_back(info); - } -} - -/// addObjCCategory - Parse i386/ppc ObjC category data structure. -void LTOModule::addObjCCategory(const GlobalVariable *clgv) { - const ConstantStruct *c = dyn_cast(clgv->getInitializer()); - if (!c) return; - - // second slot in __OBJC,__category is pointer to target class name - std::string targetclassName; - if (!objcClassNameFromExpression(c->getOperand(1), targetclassName)) - return; - - NameAndAttributes info; - StringMap::value_type &entry = - _undefines.GetOrCreateValue(targetclassName); - - if (entry.getValue().name) - return; - - const char *symbolName = entry.getKey().data(); - info.name = symbolName; - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; - entry.setValue(info); -} - -/// addObjCClassRef - Parse i386/ppc ObjC class list data structure. -void LTOModule::addObjCClassRef(const GlobalVariable *clgv) { - std::string targetclassName; - if (!objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) - return; - - NameAndAttributes info; - StringMap::value_type &entry = - _undefines.GetOrCreateValue(targetclassName); - if (entry.getValue().name) - return; - - const char *symbolName = entry.getKey().data(); - info.name = symbolName; - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; - entry.setValue(info); -} - -/// addDefinedDataSymbol - Add a data symbol as defined to the list. -void LTOModule::addDefinedDataSymbol(const GlobalValue *v) { - // Add to list of defined symbols. - addDefinedSymbol(v, false); - - if (!v->hasSection() /* || !isTargetDarwin */) - return; - - // Special case i386/ppc ObjC data structures in magic sections: - // The issue is that the old ObjC object format did some strange - // contortions to avoid real linker symbols. For instance, the - // ObjC class data structure is allocated statically in the executable - // that defines that class. That data structures contains a pointer to - // its superclass. But instead of just initializing that part of the - // struct to the address of its superclass, and letting the static and - // dynamic linkers do the rest, the runtime works by having that field - // instead point to a C-string that is the name of the superclass. - // At runtime the objc initialization updates that pointer and sets - // it to point to the actual super class. As far as the linker - // knows it is just a pointer to a string. But then someone wanted the - // linker to issue errors at build time if the superclass was not found. - // So they figured out a way in mach-o object format to use an absolute - // symbols (.objc_class_name_Foo = 0) and a floating reference - // (.reference .objc_class_name_Bar) to cause the linker into erroring when - // a class was missing. - // The following synthesizes the implicit .objc_* symbols for the linker - // from the ObjC data structures generated by the front end. - - // special case if this data blob is an ObjC class definition - if (v->getSection().compare(0, 15, "__OBJC,__class,") == 0) { - if (const GlobalVariable *gv = dyn_cast(v)) { - addObjCClass(gv); - } - } - - // special case if this data blob is an ObjC category definition - else if (v->getSection().compare(0, 18, "__OBJC,__category,") == 0) { - if (const GlobalVariable *gv = dyn_cast(v)) { - addObjCCategory(gv); - } - } - - // special case if this data blob is the list of referenced classes - else if (v->getSection().compare(0, 18, "__OBJC,__cls_refs,") == 0) { - if (const GlobalVariable *gv = dyn_cast(v)) { - addObjCClassRef(gv); - } - } -} - -/// addDefinedFunctionSymbol - Add a function symbol as defined to the list. -void LTOModule::addDefinedFunctionSymbol(const Function *f) { - // add to list of defined symbols - addDefinedSymbol(f, true); -} - -/// addDefinedSymbol - Add a defined symbol to the list. -void LTOModule::addDefinedSymbol(const GlobalValue *def, bool isFunction) { - // ignore all llvm.* symbols - if (def->getName().startswith("llvm.")) - return; - - // string is owned by _defines - SmallString<64> Buffer; - _mangler.getNameWithPrefix(Buffer, def, false); - - // set alignment part log2() can have rounding errors - uint32_t align = def->getAlignment(); - uint32_t attr = align ? countTrailingZeros(def->getAlignment()) : 0; - - // set permissions part - if (isFunction) { - attr |= LTO_SYMBOL_PERMISSIONS_CODE; - } else { - const GlobalVariable *gv = dyn_cast(def); - if (gv && gv->isConstant()) - attr |= LTO_SYMBOL_PERMISSIONS_RODATA; - else - attr |= LTO_SYMBOL_PERMISSIONS_DATA; - } - - // set definition part - if (def->hasWeakLinkage() || def->hasLinkOnceLinkage() || - def->hasLinkerPrivateWeakLinkage()) - attr |= LTO_SYMBOL_DEFINITION_WEAK; - else if (def->hasCommonLinkage()) - attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; - else - attr |= LTO_SYMBOL_DEFINITION_REGULAR; - - // set scope part - if (def->hasHiddenVisibility()) - attr |= LTO_SYMBOL_SCOPE_HIDDEN; - else if (def->hasProtectedVisibility()) - attr |= LTO_SYMBOL_SCOPE_PROTECTED; - else if (def->hasExternalLinkage() || def->hasWeakLinkage() || - def->hasLinkOnceLinkage() || def->hasCommonLinkage() || - def->hasLinkerPrivateWeakLinkage()) - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - else if (def->hasLinkOnceODRAutoHideLinkage()) - attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; - else - attr |= LTO_SYMBOL_SCOPE_INTERNAL; - - StringSet::value_type &entry = _defines.GetOrCreateValue(Buffer); - entry.setValue(1); - - // fill information structure - NameAndAttributes info; - StringRef Name = entry.getKey(); - info.name = Name.data(); - assert(info.name[Name.size()] == '\0'); - info.attributes = attr; - info.isFunction = isFunction; - info.symbol = def; - - // add to table of symbols - _symbols.push_back(info); -} - -/// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the -/// defined list. -void LTOModule::addAsmGlobalSymbol(const char *name, - lto_symbol_attributes scope) { - StringSet::value_type &entry = _defines.GetOrCreateValue(name); - - // only add new define if not already defined - if (entry.getValue()) - return; - - entry.setValue(1); - - NameAndAttributes &info = _undefines[entry.getKey().data()]; - - if (info.symbol == 0) { - // FIXME: This is trying to take care of module ASM like this: - // - // module asm ".zerofill __FOO, __foo, _bar_baz_qux, 0" - // - // but is gross and its mother dresses it funny. Have the ASM parser give us - // more details for this type of situation so that we're not guessing so - // much. - - // fill information structure - info.name = entry.getKey().data(); - info.attributes = - LTO_SYMBOL_PERMISSIONS_DATA | LTO_SYMBOL_DEFINITION_REGULAR | scope; - info.isFunction = false; - info.symbol = 0; - - // add to table of symbols - _symbols.push_back(info); - return; - } - - if (info.isFunction) - addDefinedFunctionSymbol(cast(info.symbol)); - else - addDefinedDataSymbol(info.symbol); - - _symbols.back().attributes &= ~LTO_SYMBOL_SCOPE_MASK; - _symbols.back().attributes |= scope; -} - -/// addAsmGlobalSymbolUndef - Add a global symbol from module-level ASM to the -/// undefined list. -void LTOModule::addAsmGlobalSymbolUndef(const char *name) { - StringMap::value_type &entry = - _undefines.GetOrCreateValue(name); - - _asm_undefines.push_back(entry.getKey().data()); - - // we already have the symbol - if (entry.getValue().name) - return; - - uint32_t attr = LTO_SYMBOL_DEFINITION_UNDEFINED;; - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - NameAndAttributes info; - info.name = entry.getKey().data(); - info.attributes = attr; - info.isFunction = false; - info.symbol = 0; - - entry.setValue(info); -} - -/// addPotentialUndefinedSymbol - Add a symbol which isn't defined just yet to a -/// list to be resolved later. -void -LTOModule::addPotentialUndefinedSymbol(const GlobalValue *decl, bool isFunc) { - // ignore all llvm.* symbols - if (decl->getName().startswith("llvm.")) - return; - - // ignore all aliases - if (isa(decl)) - return; - - SmallString<64> name; - _mangler.getNameWithPrefix(name, decl, false); - - StringMap::value_type &entry = - _undefines.GetOrCreateValue(name); - - // we already have the symbol - if (entry.getValue().name) - return; - - NameAndAttributes info; - - info.name = entry.getKey().data(); - - if (decl->hasExternalWeakLinkage()) - info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; - else - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - - info.isFunction = isFunc; - info.symbol = decl; - - entry.setValue(info); -} - -namespace { - class RecordStreamer : public MCStreamer { - public: - enum State { NeverSeen, Global, Defined, DefinedGlobal, Used }; - - private: - StringMap Symbols; - - void markDefined(const MCSymbol &Symbol) { - State &S = Symbols[Symbol.getName()]; - switch (S) { - case DefinedGlobal: - case Global: - S = DefinedGlobal; - break; - case NeverSeen: - case Defined: - case Used: - S = Defined; - break; - } - } - void markGlobal(const MCSymbol &Symbol) { - State &S = Symbols[Symbol.getName()]; - switch (S) { - case DefinedGlobal: - case Defined: - S = DefinedGlobal; - break; - - case NeverSeen: - case Global: - case Used: - S = Global; - break; - } - } - void markUsed(const MCSymbol &Symbol) { - State &S = Symbols[Symbol.getName()]; - switch (S) { - case DefinedGlobal: - case Defined: - case Global: - break; - - case NeverSeen: - case Used: - S = Used; - break; - } - } - - // FIXME: mostly copied for the obj streamer. - void AddValueSymbols(const MCExpr *Value) { - switch (Value->getKind()) { - case MCExpr::Target: - // FIXME: What should we do in here? - break; - - case MCExpr::Constant: - break; - - case MCExpr::Binary: { - const MCBinaryExpr *BE = cast(Value); - AddValueSymbols(BE->getLHS()); - AddValueSymbols(BE->getRHS()); - break; - } - - case MCExpr::SymbolRef: - markUsed(cast(Value)->getSymbol()); - break; - - case MCExpr::Unary: - AddValueSymbols(cast(Value)->getSubExpr()); - break; - } - } - - public: - typedef StringMap::const_iterator const_iterator; - - const_iterator begin() { - return Symbols.begin(); - } - - const_iterator end() { - return Symbols.end(); - } - - RecordStreamer(MCContext &Context) - : MCStreamer(SK_RecordStreamer, Context) {} - - virtual void EmitInstruction(const MCInst &Inst) { - // Scan for values. - for (unsigned i = Inst.getNumOperands(); i--; ) - if (Inst.getOperand(i).isExpr()) - AddValueSymbols(Inst.getOperand(i).getExpr()); - } - virtual void EmitLabel(MCSymbol *Symbol) { - Symbol->setSection(*getCurrentSection().first); - markDefined(*Symbol); - } - virtual void EmitDebugLabel(MCSymbol *Symbol) { - EmitLabel(Symbol); - } - virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { - // FIXME: should we handle aliases? - markDefined(*Symbol); - } - virtual bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { - if (Attribute == MCSA_Global) - markGlobal(*Symbol); - return true; - } - virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size , unsigned ByteAlignment) { - markDefined(*Symbol); - } - virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment) { - markDefined(*Symbol); - } - - virtual void EmitBundleAlignMode(unsigned AlignPow2) {} - virtual void EmitBundleLock(bool AlignToEnd) {} - virtual void EmitBundleUnlock() {} - - // Noop calls. - virtual void ChangeSection(const MCSection *Section, - const MCExpr *Subsection) {} - virtual void InitToTextSection() {} - virtual void InitSections() {} - virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} - virtual void EmitThumbFunc(MCSymbol *Func) {} - virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} - virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {} - virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) {} - virtual void EmitCOFFSymbolStorageClass(int StorageClass) {} - virtual void EmitCOFFSymbolType(int Type) {} - virtual void EndCOFFSymbolDef() {} - virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment) {} - virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment) {} - virtual void EmitBytes(StringRef Data) {} - virtual void EmitValueImpl(const MCExpr *Value, unsigned Size) {} - virtual void EmitULEB128Value(const MCExpr *Value) {} - virtual void EmitSLEB128Value(const MCExpr *Value) {} - virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, - unsigned ValueSize, - unsigned MaxBytesToEmit) {} - virtual void EmitCodeAlignment(unsigned ByteAlignment, - unsigned MaxBytesToEmit) {} - virtual bool EmitValueToOffset(const MCExpr *Offset, - unsigned char Value ) { return false; } - virtual void EmitFileDirective(StringRef Filename) {} - virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, - const MCSymbol *LastLabel, - const MCSymbol *Label, - unsigned PointerSize) {} - virtual void FinishImpl() {} - virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { - RecordProcEnd(Frame); - } - - static bool classof(const MCStreamer *S) { - return S->getKind() == SK_RecordStreamer; - } - }; -} // end anonymous namespace - -/// addAsmGlobalSymbols - Add global symbols from module-level ASM to the -/// defined or undefined lists. -bool LTOModule::addAsmGlobalSymbols(std::string &errMsg) { - const std::string &inlineAsm = _module->getModuleInlineAsm(); - if (inlineAsm.empty()) - return false; - - OwningPtr Streamer(new RecordStreamer(_context)); - MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(inlineAsm); - SourceMgr SrcMgr; - SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); - OwningPtr Parser(createMCAsmParser(SrcMgr, - _context, *Streamer, - *_target->getMCAsmInfo())); - const Target &T = _target->getTarget(); - OwningPtr MCII(T.createMCInstrInfo()); - OwningPtr - STI(T.createMCSubtargetInfo(_target->getTargetTriple(), - _target->getTargetCPU(), - _target->getTargetFeatureString())); - OwningPtr TAP(T.createMCAsmParser(*STI, *Parser.get(), *MCII)); - if (!TAP) { - errMsg = "target " + std::string(T.getName()) + - " does not define AsmParser."; - return true; - } - - Parser->setTargetParser(*TAP); - if (Parser->Run(false)) - return true; - - for (RecordStreamer::const_iterator i = Streamer->begin(), - e = Streamer->end(); i != e; ++i) { - StringRef Key = i->first(); - RecordStreamer::State Value = i->second; - if (Value == RecordStreamer::DefinedGlobal) - addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_DEFAULT); - else if (Value == RecordStreamer::Defined) - addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_INTERNAL); - else if (Value == RecordStreamer::Global || - Value == RecordStreamer::Used) - addAsmGlobalSymbolUndef(Key.data()); - } - - return false; -} - -/// isDeclaration - Return 'true' if the global value is a declaration. -static bool isDeclaration(const GlobalValue &V) { - if (V.hasAvailableExternallyLinkage()) - return true; - - if (V.isMaterializable()) - return false; - - return V.isDeclaration(); -} - -/// parseSymbols - Parse the symbols from the module and model-level ASM and add -/// them to either the defined or undefined lists. -bool LTOModule::parseSymbols(std::string &errMsg) { - // add functions - for (Module::iterator f = _module->begin(), e = _module->end(); f != e; ++f) { - if (isDeclaration(*f)) - addPotentialUndefinedSymbol(f, true); - else - addDefinedFunctionSymbol(f); - } - - // add data - for (Module::global_iterator v = _module->global_begin(), - e = _module->global_end(); v != e; ++v) { - if (isDeclaration(*v)) - addPotentialUndefinedSymbol(v, false); - else - addDefinedDataSymbol(v); - } - - // add asm globals - if (addAsmGlobalSymbols(errMsg)) - return true; - - // add aliases - for (Module::alias_iterator a = _module->alias_begin(), - e = _module->alias_end(); a != e; ++a) { - if (isDeclaration(*a->getAliasedGlobal())) - // Is an alias to a declaration. - addPotentialUndefinedSymbol(a, false); - else - addDefinedDataSymbol(a); - } - - // make symbols for all undefines - for (StringMap::iterator u =_undefines.begin(), - e = _undefines.end(); u != e; ++u) { - // If this symbol also has a definition, then don't make an undefine because - // it is a tentative definition. - if (_defines.count(u->getKey())) continue; - NameAndAttributes info = u->getValue(); - _symbols.push_back(info); - } - - return false; -} diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h deleted file mode 100644 index 902e9c5438..0000000000 --- a/tools/lto/LTOModule.h +++ /dev/null @@ -1,190 +0,0 @@ -//===-LTOModule.h - 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 declares the LTOModule class. -// -//===----------------------------------------------------------------------===// - -#ifndef LTO_MODULE_H -#define LTO_MODULE_H - -#include "llvm-c/lto.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/IR/Module.h" -#include "llvm/MC/MCContext.h" -#include "llvm/Target/Mangler.h" -#include "llvm/Target/TargetMachine.h" -#include -#include - -// Forward references to llvm classes. -namespace llvm { - class Function; - class GlobalValue; - class MemoryBuffer; - class TargetOptions; - class Value; -} - -//===----------------------------------------------------------------------===// -/// LTOModule - C++ class which implements the opaque lto_module_t type. -/// -struct LTOModule { -private: - typedef llvm::StringMap StringSet; - - struct NameAndAttributes { - const char *name; - uint32_t attributes; - bool isFunction; - const llvm::GlobalValue *symbol; - }; - - llvm::OwningPtr _module; - llvm::OwningPtr _target; - std::vector _symbols; - - // _defines and _undefines only needed to disambiguate tentative definitions - StringSet _defines; - llvm::StringMap _undefines; - std::vector _asm_undefines; - llvm::MCContext _context; - - // Use mangler to add GlobalPrefix to names to match linker names. - llvm::Mangler _mangler; - - LTOModule(llvm::Module *m, llvm::TargetMachine *t); -public: - /// isBitcodeFile - Returns 'true' if the file or memory contents is LLVM - /// bitcode. - static bool isBitcodeFile(const void *mem, size_t length); - static bool isBitcodeFile(const char *path); - - /// isBitcodeFileForTarget - Returns 'true' if the file or memory contents - /// is LLVM bitcode for the specified triple. - static bool isBitcodeFileForTarget(const void *mem, - size_t length, - const char *triplePrefix); - static bool isBitcodeFileForTarget(const char *path, - const char *triplePrefix); - - /// makeLTOModule - Create an LTOModule. N.B. These methods take ownership - /// of the buffer. - static LTOModule *makeLTOModule(const char* path, - std::string &errMsg); - static LTOModule *makeLTOModule(int fd, const char *path, - size_t size, std::string &errMsg); - static LTOModule *makeLTOModule(int fd, const char *path, - size_t map_size, - off_t offset, - std::string& errMsg); - static LTOModule *makeLTOModule(const void *mem, size_t length, - std::string &errMsg); - - /// getTargetTriple - Return the Module's target triple. - const char *getTargetTriple() { - return _module->getTargetTriple().c_str(); - } - - /// setTargetTriple - Set the Module's target triple. - void setTargetTriple(const char *triple) { - _module->setTargetTriple(triple); - } - - /// getSymbolCount - Get the number of symbols - uint32_t getSymbolCount() { - return _symbols.size(); - } - - /// getSymbolAttributes - Get the attributes for a symbol at the specified - /// index. - lto_symbol_attributes getSymbolAttributes(uint32_t index) { - if (index < _symbols.size()) - return lto_symbol_attributes(_symbols[index].attributes); - return lto_symbol_attributes(0); - } - - /// getSymbolName - Get the name of the symbol at the specified index. - const char *getSymbolName(uint32_t index) { - if (index < _symbols.size()) - return _symbols[index].name; - return NULL; - } - - /// getLLVVMModule - Return the Module. - llvm::Module *getLLVVMModule() { return _module.get(); } - - /// getAsmUndefinedRefs - - const std::vector &getAsmUndefinedRefs() { - return _asm_undefines; - } - - /// getTargetOptions - Fill the TargetOptions object with the options - /// specified on the command line. - static void getTargetOptions(llvm::TargetOptions &Options); - -private: - /// parseSymbols - Parse the symbols from the module and model-level ASM and - /// add them to either the defined or undefined lists. - bool parseSymbols(std::string &errMsg); - - /// addPotentialUndefinedSymbol - Add a symbol which isn't defined just yet - /// to a list to be resolved later. - void addPotentialUndefinedSymbol(const llvm::GlobalValue *dcl, bool isFunc); - - /// addDefinedSymbol - Add a defined symbol to the list. - void addDefinedSymbol(const llvm::GlobalValue *def, bool isFunction); - - /// addDefinedFunctionSymbol - Add a function symbol as defined to the list. - void addDefinedFunctionSymbol(const llvm::Function *f); - - /// addDefinedDataSymbol - Add a data symbol as defined to the list. - void addDefinedDataSymbol(const llvm::GlobalValue *v); - - /// addAsmGlobalSymbols - Add global symbols from module-level ASM to the - /// defined or undefined lists. - bool addAsmGlobalSymbols(std::string &errMsg); - - /// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the - /// defined list. - void addAsmGlobalSymbol(const char *, lto_symbol_attributes scope); - - /// addAsmGlobalSymbolUndef - Add a global symbol from module-level ASM to - /// the undefined list. - void addAsmGlobalSymbolUndef(const char *); - - /// addObjCClass - Parse i386/ppc ObjC class data structure. - void addObjCClass(const llvm::GlobalVariable *clgv); - - /// addObjCCategory - Parse i386/ppc ObjC category data structure. - void addObjCCategory(const llvm::GlobalVariable *clgv); - - /// addObjCClassRef - Parse i386/ppc ObjC class list data structure. - void addObjCClassRef(const llvm::GlobalVariable *clgv); - - /// objcClassNameFromExpression - Get string that the data pointer points - /// to. - bool objcClassNameFromExpression(const llvm::Constant* c, std::string &name); - - /// isTargetMatch - Returns 'true' if the memory buffer is for the specified - /// target triple. - static bool isTargetMatch(llvm::MemoryBuffer *memBuffer, - const char *triplePrefix); - - /// makeLTOModule - Create an LTOModule (private version). N.B. This - /// method takes ownership of the buffer. - static LTOModule *makeLTOModule(llvm::MemoryBuffer *buffer, - std::string &errMsg); - - /// makeBuffer - Create a MemoryBuffer from a memory range. - static llvm::MemoryBuffer *makeBuffer(const void *mem, size_t length); -}; - -#endif // LTO_MODULE_H diff --git a/tools/lto/Makefile b/tools/lto/Makefile index 56c67df373..672fef4c64 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -10,7 +10,7 @@ LEVEL := ../.. LIBRARYNAME := LTO LINK_COMPONENTS := all-targets ipo scalaropts linker bitreader bitwriter \ - mcdisassembler vectorize + lto mcdisassembler vectorize LINK_LIBS_IN_SHARED := 1 SHARED_LIBRARY := 1 diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index db7147c2bc..441bc77352 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -13,15 +13,33 @@ //===----------------------------------------------------------------------===// #include "llvm-c/lto.h" -#include "LTOCodeGenerator.h" -#include "LTOModule.h" +#include "llvm/LTO/LTOCodeGenerator.h" +#include "llvm/LTO/LTOModule.h" #include "llvm-c/Core.h" +#include "llvm-c/Target.h" // Holds most recent error string. // *** Not thread safe *** static std::string sLastErrorString; +// Holds the initialization state of the LTO module. +// *** Not thread safe *** +static bool initialized = false; + +// Initialize the configured targets if they have not been initialized. +static void lto_initialize() { + if (!initialized) { + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargets(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllAsmParsers(); + LLVMInitializeAllAsmPrinters(); + LLVMInitializeAllDisassemblers(); + initialized = true; + } +} + /// lto_get_version - Returns a printable string. extern const char* lto_get_version() { return LTOCodeGenerator::getVersionString(); @@ -63,12 +81,14 @@ lto_module_is_object_file_in_memory_for_target(const void* mem, /// lto_module_create - Loads an object file from disk. Returns NULL on error /// (check lto_get_error_message() for details). lto_module_t lto_module_create(const char* path) { + lto_initialize(); return LTOModule::makeLTOModule(path, sLastErrorString); } /// lto_module_create_from_fd - Loads an object file from disk. Returns NULL on /// error (check lto_get_error_message() for details). lto_module_t lto_module_create_from_fd(int fd, const char *path, size_t size) { + lto_initialize(); return LTOModule::makeLTOModule(fd, path, size, sLastErrorString); } @@ -78,12 +98,14 @@ lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path, size_t file_size, size_t map_size, off_t offset) { + lto_initialize(); return LTOModule::makeLTOModule(fd, path, map_size, offset, sLastErrorString); } /// lto_module_create_from_memory - Loads an object file from memory. Returns /// NULL on error (check lto_get_error_message() for details). lto_module_t lto_module_create_from_memory(const void* mem, size_t length) { + lto_initialize(); return LTOModule::makeLTOModule(mem, length, sLastErrorString); } @@ -127,6 +149,7 @@ lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod, /// lto_codegen_create - Instantiates a code generator. Returns NULL if there /// is an error. lto_code_gen_t lto_codegen_create(void) { + lto_initialize(); return new LTOCodeGenerator(); } -- cgit v1.2.3