diff options
-rw-r--r-- | include/llvm-c/lto.h | 234 | ||||
-rw-r--r-- | tools/lto2/LTOCodeGenerator.cpp | 465 | ||||
-rw-r--r-- | tools/lto2/LTOCodeGenerator.h | 59 | ||||
-rw-r--r-- | tools/lto2/LTOModule.cpp | 329 | ||||
-rw-r--r-- | tools/lto2/LTOModule.h | 83 | ||||
-rw-r--r-- | tools/lto2/Makefile | 45 | ||||
-rw-r--r-- | tools/lto2/lto.cpp | 240 | ||||
-rw-r--r-- | tools/lto2/lto.exports | 22 |
8 files changed, 1477 insertions, 0 deletions
diff --git a/include/llvm-c/lto.h b/include/llvm-c/lto.h new file mode 100644 index 0000000000..8d4590b675 --- /dev/null +++ b/include/llvm-c/lto.h @@ -0,0 +1,234 @@ +/*===-- llvm-c/lto.h - LTO Public C Interface ---------------------*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides public interface to an abstract link time optimization*| +|* library. LLVM provides an implementation of this interface for use with *| +|* llvm bitcode files. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LTO_H +#define LTO_H 1 + +#include <stdbool.h> +#include <stddef.h> + +typedef enum { + LTO_SYMBOL_ALIGNMENT_MASK = 0x0000001F, /* log2 of alignment */ + LTO_SYMBOL_PERMISSIONS_MASK = 0x000000E0, + LTO_SYMBOL_PERMISSIONS_CODE = 0x000000A0, + LTO_SYMBOL_PERMISSIONS_DATA = 0x000000C0, + LTO_SYMBOL_PERMISSIONS_RODATA = 0x00000080, + LTO_SYMBOL_DEFINITION_MASK = 0x00000700, + LTO_SYMBOL_DEFINITION_REGULAR = 0x00000100, + LTO_SYMBOL_DEFINITION_TENTATIVE = 0x00000200, + LTO_SYMBOL_DEFINITION_WEAK = 0x00000300, + LTO_SYMBOL_DEFINITION_UNDEFINED = 0x00000400, + LTO_SYMBOL_SCOPE_MASK = 0x00001800, + LTO_SYMBOL_SCOPE_INTERNAL = 0x00000800, + LTO_SYMBOL_SCOPE_HIDDEN = 0x00001000, + LTO_SYMBOL_SCOPE_DEFAULT = 0x00001800 +} lto_symbol_attributes; + +typedef enum { + LTO_DEBUG_MODEL_NONE = 0, + LTO_DEBUG_MODEL_DWARF = 1 +} lto_debug_model; + +typedef enum { + LTO_CODEGEN_PIC_MODEL_STATIC = 0, + LTO_CODEGEN_PIC_MODEL_DYNAMIC = 1, + LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC = 2 +} lto_codegen_model; + + +/** opaque reference to a loaded object module */ +typedef struct LTOModule* lto_module_t; + +/** opaque reference to a code generator */ +typedef struct LTOCodeGenerator* lto_code_gen_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Returns a printable string. + */ +extern const char* +lto_get_version(); + + +/** + * Returns the last error string or NULL if last operation was sucessful. + */ +extern const char* +lto_get_error_message(); + + +/** + * Checks if a file is a loadable object file. + */ +extern bool +lto_module_is_object_file(const char* path); + + +/** + * Checks if a file is a loadable object compiled for requested target. + */ +extern bool +lto_module_is_object_file_for_target(const char* path, + const char* target_triple_prefix); + + +/** + * Checks if a buffer is a loadable object file. + */ +extern bool +lto_module_is_object_file_in_memory(const void* mem, size_t length); + + +/** + * Checks if a buffer is a loadable object compiled for requested target. + */ +extern bool +lto_module_is_object_file_in_memory_for_target(const void* mem, size_t length, + const char* target_triple_prefix); + + +/** + * Loads an object file from disk. + * Returns NULL on error (check lto_get_error_message() for details). + */ +extern lto_module_t +lto_module_create(const char* path); + + +/** + * Loads an object file from memory. + * Returns NULL on error (check lto_get_error_message() for details). + */ +extern lto_module_t +lto_module_create_from_memory(const void* mem, size_t length); + + +/** + * Frees all memory internally allocated by the module. + * Upon return the lto_module_t is no longer valid. + */ +extern void +lto_module_dispose(lto_module_t mod); + + +/** + * Returns triple string which the object module was compiled under. + */ +extern const char* +lto_module_get_target_triple(lto_module_t mod); + + +/** + * Returns the number of symbols in the object module. + */ +extern unsigned int +lto_module_get_num_symbols(lto_module_t mod); + + +/** + * Returns the name of the ith symbol in the object module. + */ +extern const char* +lto_module_get_symbol_name(lto_module_t mod, unsigned int index); + + +/** + * Returns the attributes of the ith symbol in the object module. + */ +extern lto_symbol_attributes +lto_module_get_symbol_attribute(lto_module_t mod, unsigned int index); + + +/** + * Instantiates a code generator. + * Returns NULL on error (check lto_get_error_message() for details). + */ +extern lto_code_gen_t +lto_codegen_create(); + + +/** + * Frees all code generator and all memory it internally allocated. + * Upon return the lto_code_gen_t is no longer valid. + */ +extern void +lto_codegen_dispose(lto_code_gen_t); + + + +/** + * Add an object module to the set of modules for which code will be generated. + * Returns true on error (check lto_get_error_message() for details). + */ +extern bool +lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod); + + + +/** + * Sets if debug info should be generated. + * Returns true on error (check lto_get_error_message() for details). + */ +extern bool +lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model); + + +/** + * Sets which PIC code model to generated. + * Returns true on error (check lto_get_error_message() for details). + */ +extern bool +lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model); + + +/** + * Adds to a list of all global symbols that must exist in the final + * generated code. If a function is not listed, it might be + * inlined into every usage and optimized away. + */ +extern void +lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char* symbol); + + +/** + * Writes a new object file at the specified path that contains the + * merged contents of all modules added so far. + * Returns true on error (check lto_get_error_message() for details). + */ +extern bool +lto_codegen_write_merged_modules(lto_code_gen_t cg, const char* path); + + +/** + * Generates code for all added modules into one native object file. + * On sucess returns a pointer to a generated mach-o/ELF buffer and + * length set to the buffer size. Client owns the buffer and should + * free() it when done. + * On failure, returns NULL (check lto_get_error_message() for details). + */ +extern void* +lto_codegen_compile(lto_code_gen_t cg, size_t* length); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/tools/lto2/LTOCodeGenerator.cpp b/tools/lto2/LTOCodeGenerator.cpp new file mode 100644 index 0000000000..795aca01f5 --- /dev/null +++ b/tools/lto2/LTOCodeGenerator.cpp @@ -0,0 +1,465 @@ +//===-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/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Linker.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/ModuleProvider.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/Mangler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Program.h" +#include "llvm/System/Signals.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/Analysis/LoopPass.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/CodeGen/FileWriters.h" +#include "llvm/Target/SubtargetFeature.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetMachineRegistry.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Analysis/LoadValueNumbering.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Config/config.h" + +#include "LTOModule.h" +#include "LTOCodeGenerator.h" + +#include <fstream> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> + + +using namespace llvm; + + + +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() + : _linker("LinkTimeOptimizer", "ld-temp.o"), _target(NULL), + _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false), + _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC) +{ + +} + +LTOCodeGenerator::~LTOCodeGenerator() +{ + // FIXME +} + + + +bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) +{ + return _linker.LinkInModule(mod->getLLVVMModule(), &errMsg); +} + + +bool LTOCodeGenerator::setDebugInfo(lto_debug_model debug, std::string& errMsg) +{ + switch (debug) { + case LTO_DEBUG_MODEL_NONE: + _emitDwarfDebugInfo = false; + return false; + + case LTO_DEBUG_MODEL_DWARF: + _emitDwarfDebugInfo = true; + return false; + } + errMsg = "unknown debug format"; + return true; +} + + +bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model, + std::string& errMsg) +{ + 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 false; + } + errMsg = "unknown pic model"; + return true; +} + + +void LTOCodeGenerator::addMustPreserveSymbol(const char* sym) +{ + _mustPreserveSymbols[sym] = 1; +} + + +bool LTOCodeGenerator::writeMergedModules(const char* path, std::string& errMsg) +{ + if ( this->determineTarget(errMsg) ) + return true; + + // mark which symbols can not be internalized + this->applyScopeRestrictions(); + + // create output file + std::ofstream out(path, std::ios_base::out|std::ios::trunc|std::ios::binary); + if ( out.fail() ) { + errMsg = "could not open bitcode file for writing: "; + errMsg += path; + return true; + } + + // write bitcode to it + WriteBitcodeToFile(_linker.getModule(), out); + if ( out.fail() ) { + errMsg = "could not write bitcode file: "; + errMsg += path; + return true; + } + + return false; +} + + +void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) +{ + // make unqiue temp .s file to put generated assembly code + sys::Path uniqueAsmPath("lto-llvm.s"); + if ( uniqueAsmPath.createTemporaryFileOnDisk(true, &errMsg) ) + return NULL; + sys::RemoveFileOnSignal(uniqueAsmPath); + + // generate assembly code + std::ofstream asmFile(uniqueAsmPath.c_str()); + bool genResult = this->generateAssemblyCode(asmFile, errMsg); + asmFile.close(); + if ( genResult ) { + if ( uniqueAsmPath.exists() ) + uniqueAsmPath.eraseFromDisk(); + return NULL; + } + + // make unqiue temp .o file to put generated object file + sys::PathWithStatus uniqueObjPath("lto-llvm.o"); + if ( uniqueObjPath.createTemporaryFileOnDisk(true, &errMsg) ) { + if ( uniqueAsmPath.exists() ) + uniqueAsmPath.eraseFromDisk(); + return NULL; + } + sys::RemoveFileOnSignal(uniqueObjPath); + + // assemble the assembly code + void* buffer = NULL; + bool asmResult = this->assemble(uniqueAsmPath.toString(), + uniqueObjPath.toString(), errMsg); + if ( !asmResult ) { + // read .o file into memory buffer + const sys::FileStatus* objStatus; + objStatus = uniqueObjPath.getFileStatus(false, &errMsg); + if ( objStatus != NULL ) { + *length = objStatus->getSize(); + // use malloc() because caller will own this buffer and free() it + buffer = ::malloc(*length); + if ( buffer != NULL ) { + int fd = ::open(uniqueObjPath.c_str(), O_RDONLY, 0); + if ( fd != -1 ) { + // read object file contents into buffer + if ( ::read(fd, buffer, *length) != (ssize_t)*length ) { + errMsg = "error reading object file"; + free(buffer); + buffer = NULL; + } + close(fd); + } + else { + errMsg = "error opening object file"; + free(buffer); + buffer = NULL; + } + } + else { + errMsg = "error mallocing space for object file"; + } + } + else { + errMsg = "error stat'ing object file"; + } + } + // clean up temp files + uniqueAsmPath.eraseFromDisk(); + uniqueObjPath.eraseFromDisk(); + return buffer; +} + + +bool LTOCodeGenerator::assemble(const std::string& asmPath, + const std::string& objPath, std::string& errMsg) +{ + // find compiler driver + const sys::Path gcc = sys::Program::FindProgramByName("gcc"); + if ( gcc.isEmpty() ) { + errMsg = "can't locate gcc"; + return true; + } + + // build argument list + std::vector<const char*> args; + std::string targetTriple = _linker.getModule()->getTargetTriple(); + args.push_back(gcc.c_str()); + if ( targetTriple.find("darwin") != targetTriple.size() ) { + if (strncmp(targetTriple.c_str(), "i686-apple-", 11) == 0) { + args.push_back("-arch"); + args.push_back("i386"); + } + else if (strncmp(targetTriple.c_str(), "x86_64-apple-", 13) == 0) { + args.push_back("-arch"); + args.push_back("x86_64"); + } + else if (strncmp(targetTriple.c_str(), "powerpc-apple-", 14) == 0) { + args.push_back("-arch"); + args.push_back("ppc"); + } + else if (strncmp(targetTriple.c_str(), "powerpc64-apple-", 16) == 0) { + args.push_back("-arch"); + args.push_back("ppc64"); + } + } + args.push_back("-c"); + args.push_back("-x"); + args.push_back("assembler"); + args.push_back("-o"); + args.push_back(objPath.c_str()); + args.push_back(asmPath.c_str()); + args.push_back(0); + + // invoke assembler + if ( sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 0, 0, &errMsg) ) { + errMsg = "error in assembly"; + return true; + } + return false; // success +} + + + +bool LTOCodeGenerator::determineTarget(std::string& errMsg) +{ + if ( _target == NULL ) { + // create target machine from info for merged modules + Module* mergedModule = _linker.getModule(); + const TargetMachineRegistry::entry* march = + TargetMachineRegistry::getClosestStaticTargetForModule( + *mergedModule, errMsg); + if ( march == NULL ) + return true; + std::string features; + _target = march->CtorFn(*mergedModule, features); + } + return false; +} + +void LTOCodeGenerator::applyScopeRestrictions() +{ + if ( !_scopeRestrictionsDone ) { + Module* mergedModule = _linker.getModule(); + + // Start off with a verification pass. + PassManager passes; + passes.add(createVerifierPass()); + + // mark which symbols can not be internalized + if ( !_mustPreserveSymbols.empty() ) { + Mangler mangler(*mergedModule, + _target->getTargetAsmInfo()->getGlobalPrefix()); + std::vector<const char*> mustPreserveList; + for (Module::iterator f = mergedModule->begin(), + e = mergedModule->end(); f != e; ++f) { + if ( !f->isDeclaration() + && _mustPreserveSymbols.count(mangler.getValueName(f)) ) + mustPreserveList.push_back(::strdup(f->getName().c_str())); + } + for (Module::global_iterator v = mergedModule->global_begin(), + e = mergedModule->global_end(); v != e; ++v) { + if ( !v->isDeclaration() + && _mustPreserveSymbols.count(mangler.getValueName(v)) ) + mustPreserveList.push_back(::strdup(v->getName().c_str())); + } + passes.add(createInternalizePass(mustPreserveList)); + } + // apply scope restrictions + passes.run(*mergedModule); + + _scopeRestrictionsDone = true; + } +} + + +/// Optimize merged modules using various IPO passes +bool LTOCodeGenerator::generateAssemblyCode(std::ostream& out, std::string& errMsg) +{ + if ( this->determineTarget(errMsg) ) + return true; + + // mark which symbols can not be internalized + this->applyScopeRestrictions(); + + Module* mergedModule = _linker.getModule(); + + // If target supports exception handling then enable it now. + if ( _target->getTargetAsmInfo()->doesSupportExceptionHandling() ) + llvm::ExceptionHandling = true; + + // set codegen model + switch( _codeModel ) { + case LTO_CODEGEN_PIC_MODEL_STATIC: + _target->setRelocationModel(Reloc::Static); + break; + case LTO_CODEGEN_PIC_MODEL_DYNAMIC: + _target->setRelocationModel(Reloc::PIC_); + break; + case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: + _target->setRelocationModel(Reloc::DynamicNoPIC); + break; + } + + // Instantiate the pass manager to organize the passes. + PassManager passes; + + // Start off with a verification pass. + passes.add(createVerifierPass()); + + // Add an appropriate TargetData instance for this module... + passes.add(new TargetData(*_target->getTargetData())); + + // Now that we internalized some globals, see if we can hack on them! + passes.add(createGlobalOptimizerPass()); + + // Linking modules together can lead to duplicated global constants, only + // keep one copy of each constant... + passes.add(createConstantMergePass()); + + // If the -s command line option was specified, strip the symbols out of the + // resulting program to make it smaller. -s is a GLD option that we are + // supporting. + if( !llvm::ExceptionHandling ) { + // FIXME : This causes multiple nameless _.eh symbols on + // darwin when EH is ON. + passes.add(createStripSymbolsPass()); + } + + // Propagate constants at call sites into the functions they call. + passes.add(createIPConstantPropagationPass()); + + // Remove unused arguments from functions... + passes.add(createDeadArgEliminationPass()); + + passes.add(createFunctionInliningPass()); // Inline small functions + + passes.add(createPruneEHPass()); // Remove dead EH info + + passes.add(createGlobalDCEPass()); // Remove dead functions + + // If we didn't decide to inline a function, check to see if we can + // transform it to pass arguments by value instead of by reference. + passes.add(createArgumentPromotionPass()); + + // The IPO passes may leave cruft around. Clean up after them. + passes.add(createInstructionCombiningPass()); + + passes.add(createScalarReplAggregatesPass()); // Break up allocas + + // Run a few AA driven optimizations here and now, to cleanup the code. + passes.add(createGlobalsModRefPass()); // IP alias analysis + + passes.add(createLICMPass()); // Hoist loop invariants + passes.add(createLoadValueNumberingPass()); // GVN for load instrs + passes.add(createGCSEPass()); // Remove common subexprs + passes.add(createDeadStoreEliminationPass()); // Nuke dead stores + + // Cleanup and simplify the code after the scalar optimizations. + passes.add(createInstructionCombiningPass()); + + // Delete basic blocks, which optimization passes may have killed... + passes.add(createCFGSimplificationPass()); + + // Now that we have optimized the program, discard unreachable functions... + passes.add(createGlobalDCEPass()); + + // Make sure everything is still good. + passes.add(createVerifierPass()); + + FunctionPassManager* codeGenPasses = + new FunctionPassManager(new ExistingModuleProvider(mergedModule)); + + codeGenPasses->add(new TargetData(*_target->getTargetData())); + + MachineCodeEmitter* mce = NULL; + + switch (_target->addPassesToEmitFile(*codeGenPasses, out, + TargetMachine::AssemblyFile, true)) { + case FileModel::MachOFile: + mce = AddMachOWriter(*codeGenPasses, out, *_target); + break; + case FileModel::ElfFile: + mce = AddELFWriter(*codeGenPasses, out, *_target); + break; + case FileModel::AsmFile: + break; + case FileModel::Error: + case FileModel::None: + errMsg = "target file type not supported"; + return true; + } + + if (_target->addPassesToEmitFileFinish(*codeGenPasses, mce, true)) { + errMsg = "target does not support generation of this file type"; + return true; + } + + // Run our queue of passes all at once now, efficiently. + passes.run(*mergedModule); + + // Run the code generator, and write assembly file + codeGenPasses->doInitialization(); + for (Module::iterator it = mergedModule->begin(), + e = mergedModule->end(); it != e; ++it) { + if (!it->isDeclaration()) + codeGenPasses->run(*it); + } + codeGenPasses->doFinalization(); + + return false; // success +} + + + diff --git a/tools/lto2/LTOCodeGenerator.h b/tools/lto2/LTOCodeGenerator.h new file mode 100644 index 0000000000..e9c1f7822a --- /dev/null +++ b/tools/lto2/LTOCodeGenerator.h @@ -0,0 +1,59 @@ +//===-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. +// +//===----------------------------------------------------------------------===// + + +#ifndef LTO_CODE_GENERATOR_H +#define LTO_CODE_GENERATOR_H + +#include "llvm/Linker.h" +#include "llvm/ADT/StringMap.h" + + + +// +// C++ class which implements the opaque lto_code_gen_t +// +class LTOCodeGenerator { +public: + static const char* getVersionString(); + + LTOCodeGenerator(); + ~LTOCodeGenerator(); + + bool addModule(class LTOModule*, std::string& errMsg); + bool setDebugInfo(lto_debug_model, std::string& errMsg); + bool setCodePICModel(lto_codegen_model, std::string& errMsg); + void addMustPreserveSymbol(const char* sym); + bool writeMergedModules(const char* path, std::string& errMsg); + void* compile(size_t* length, std::string& errMsg); + +private: + bool generateAssemblyCode(std::ostream& out, + std::string& errMsg); + bool assemble(const std::string& asmPath, + const std::string& objPath, std::string& errMsg); + void applyScopeRestrictions(); + bool determineTarget(std::string& errMsg); + + typedef llvm::StringMap<uint8_t> StringSet; + + llvm::Linker _linker; + llvm::TargetMachine* _target; + bool _emitDwarfDebugInfo; + bool _scopeRestrictionsDone; + lto_codegen_model _codeModel; + StringSet _mustPreserveSymbols; +}; + +#endif // LTO_CODE_GENERATOR_H + diff --git a/tools/lto2/LTOModule.cpp b/tools/lto2/LTOModule.cpp new file mode 100644 index 0000000000..e10ea5f925 --- /dev/null +++ b/tools/lto2/LTOModule.cpp @@ -0,0 +1,329 @@ +//===-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/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Linker.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/ModuleProvider.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/Mangler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Program.h" +#include "llvm/System/Path.h" +#include "llvm/System/Signals.h" +#include "llvm/Target/SubtargetFeature.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetMachineRegistry.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Analysis/LoadValueNumbering.h" +#include "llvm/Support/MathExtras.h" + +#include "LTOModule.h" + +#include <fstream> + +using namespace llvm; + +bool LTOModule::isBitcodeFile(const void* mem, size_t length) +{ + return ( llvm::sys::IdentifyFileType((char*)mem, length) + == llvm::sys::Bitcode_FileType ); +} + +bool LTOModule::isBitcodeFile(const char* path) +{ + return llvm::sys::Path(path).isBitcodeFile(); +} + +bool LTOModule::isBitcodeFileForTarget(const void* mem, + size_t length, const char* triplePrefix) +{ + bool result = false; + MemoryBuffer* buffer; + buffer = MemoryBuffer::getMemBuffer((char*)mem, (char*)mem+length); + if ( buffer != NULL ) { + ModuleProvider* mp = getBitcodeModuleProvider(buffer); + if ( mp != NULL ) { + std::string actualTarget = mp->getModule()->getTargetTriple(); + if ( strncmp(actualTarget.c_str(), triplePrefix, + strlen(triplePrefix)) == 0) { + result = true; + } + // mp destructor will delete buffer + delete mp; + } + else { + // if getBitcodeModuleProvider failed, we need to delete buffer + delete buffer; + } + } + return result; +} + +bool LTOModule::isBitcodeFileForTarget(const char* path, + const char* triplePrefix) +{ + bool result = false; + MemoryBuffer* buffer; + buffer = MemoryBuffer::getFile(path, strlen(path)); + if ( buffer != NULL ) { + ModuleProvider* mp = getBitcodeModuleProvider(buffer); + if ( mp != NULL ) { + std::string actualTarget = mp->getModule()->getTargetTriple(); + if ( strncmp(actualTarget.c_str(), triplePrefix, + strlen(triplePrefix)) == 0) { + result = true; + } + // mp destructor will delete buffer + delete mp; + } + else { + // if getBitcodeModuleProvider failed, we need to delete buffer + delete buffer; + } + } + return result; +} + + +LTOModule::LTOModule(Module* m, TargetMachine* t) + : _module(m), _target(t), _symbolsParsed(false) +{ +} + +LTOModule::~LTOModule() +{ + delete _module; + if ( _target != NULL ) + delete _target; +} + + +LTOModule* LTOModule::makeLTOModule(const char* path, std::string& errMsg) +{ + MemoryBuffer* buffer = MemoryBuffer::getFile(path, strlen(path)); + if ( buffer != NULL ) { + Module* m = ParseBitcodeFile(buffer, &errMsg); + delete buffer; + if ( m != NULL ) { + const TargetMachineRegistry::entry* march = + TargetMachineRegistry::getClosestStaticTargetForModule(*m, errMsg); + if ( march != NULL ) { + std::string features; + TargetMachine* target = march->CtorFn(*m, features); + return new LTOModule(m, target); + } + } + } + return NULL; +} + +LTOModule* LTOModule::makeLTOModule(const void* mem, size_t length, + std::string& errMsg) +{ + MemoryBuffer* buffer; + buffer = MemoryBuffer::getMemBuffer((char*)mem, (char*)mem+length); + if ( buffer != NULL ) { + Module* m = ParseBitcodeFile(buffer, &errMsg); + delete buffer; + if ( m != NULL ) { + const TargetMachineRegistry::entry* march = + TargetMachineRegistry::getClosestStaticTargetForModule(*m, errMsg); + if ( march != NULL ) { + std::string features; + TargetMachine* target = march->CtorFn(*m, features); + return new LTOModule(m, target); + } + } + } + return NULL; +} + + +const char* LTOModule::getTargetTriple() +{ + return _module->getTargetTriple().c_str(); +} + +void LTOModule::addDefinedSymbol(GlobalValue* def, Mangler &mangler, + bool isFunction) +{ + const char* symbolName = ::strdup(mangler.getValueName(def).c_str()); + + // set alignment part log2() can have rounding errors + uint32_t align = def->getAlignment(); + uint32_t attr = align ? __builtin_ctz(def->getAlignment()) : 0; + + // set permissions part + if ( isFunction ) + attr |= LTO_SYMBOL_PERMISSIONS_CODE; + else { + GlobalVariable* gv = dyn_cast<GlobalVariable>(def); + if ( (gv != NULL) && gv->isConstant() ) + attr |= LTO_SYMBOL_PERMISSIONS_RODATA; + else + attr |= LTO_SYMBOL_PERMISSIONS_DATA; + } + + // set definition part + if ( def->hasWeakLinkage() || def->hasLinkOnceLinkage() ) { + // lvm bitcode does not differenciate between weak def data + // and tentative definitions! + // HACK HACK HACK + // C++ does not use tentative definitions, but does use weak symbols + // so guess that anything that looks like a C++ symbol is weak and others + // are tentative definitions + if ( (strncmp(symbolName, "__Z", 3) == 0) ) + attr |= LTO_SYMBOL_DEFINITION_WEAK; + else { + 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->hasExternalLinkage() || def->hasWeakLinkage() ) + attr |= LTO_SYMBOL_SCOPE_DEFAULT; + else + attr |= LTO_SYMBOL_SCOPE_INTERNAL; + + // add to table of symbols + NameAndAttributes info; + info.name = symbolName; + info.attributes = (lto_symbol_attributes)attr; + _symbols.push_back(info); + _defines[info.name] = 1; +} + + +void LTOModule::addUndefinedSymbol(const char* name) +{ + // ignore all llvm.* symbols + if ( strncmp(nam |