diff options
Diffstat (limited to 'contrib/llvm/tools/lto')
-rw-r--r-- | contrib/llvm/tools/lto/LTOCodeGenerator.cpp | 416 | ||||
-rw-r--r-- | contrib/llvm/tools/lto/LTOCodeGenerator.h | 68 | ||||
-rw-r--r-- | contrib/llvm/tools/lto/LTOModule.cpp | 525 | ||||
-rw-r--r-- | contrib/llvm/tools/lto/LTOModule.h | 110 | ||||
-rw-r--r-- | contrib/llvm/tools/lto/Makefile | 47 | ||||
-rw-r--r-- | contrib/llvm/tools/lto/lto.cpp | 257 | ||||
-rw-r--r-- | contrib/llvm/tools/lto/lto.exports | 23 |
7 files changed, 1446 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lto/LTOCodeGenerator.cpp b/contrib/llvm/tools/lto/LTOCodeGenerator.cpp new file mode 100644 index 0000000..59e8405 --- /dev/null +++ b/contrib/llvm/tools/lto/LTOCodeGenerator.cpp @@ -0,0 +1,416 @@ +//===-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 "LTOModule.h" +#include "LTOCodeGenerator.h" + +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Linker.h" +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/SubtargetFeature.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetSelect.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/StandardPasses.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/System/Host.h" +#include "llvm/System/Program.h" +#include "llvm/System/Signals.h" +#include "llvm/Config/config.h" +#include <cstdlib> +#include <unistd.h> +#include <fcntl.h> + + +using namespace llvm; + +static cl::opt<bool> DisableInline("disable-inlining", + cl::desc("Do not run the inliner 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("LinkTimeOptimizer", "ld-temp.o", _context), _target(NULL), + _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false), + _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC), + _nativeObjectFile(NULL), _assemblerPath(NULL) +{ + InitializeAllTargets(); + InitializeAllAsmPrinters(); +} + +LTOCodeGenerator::~LTOCodeGenerator() +{ + delete _target; + delete _nativeObjectFile; +} + + + +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::setAssemblerPath(const char* path) +{ + if ( _assemblerPath ) + delete _assemblerPath; + _assemblerPath = new sys::Path(path); +} + +void LTOCodeGenerator::addMustPreserveSymbol(const char* sym) +{ + _mustPreserveSymbols[sym] = 1; +} + + +bool LTOCodeGenerator::writeMergedModules(const char *path, + std::string &errMsg) { + if (determineTarget(errMsg)) + return true; + + // mark which symbols can not be internalized + applyScopeRestrictions(); + + // create output file + std::string ErrInfo; + raw_fd_ostream Out(path, ErrInfo, + raw_fd_ostream::F_Binary); + if (!ErrInfo.empty()) { + errMsg = "could not open bitcode file for writing: "; + errMsg += path; + return true; + } + + // write bitcode to it + WriteBitcodeToFile(_linker.getModule(), Out); + + if (Out.has_error()) { + errMsg = "could not write bitcode file: "; + errMsg += path; + return true; + } + + return false; +} + + +const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) +{ + // make unique 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 + bool genResult = false; + { + raw_fd_ostream asmFD(uniqueAsmPath.c_str(), errMsg); + formatted_raw_ostream asmFile(asmFD); + if (!errMsg.empty()) + return NULL; + genResult = this->generateAssemblyCode(asmFile, errMsg); + } + if ( genResult ) { + if ( uniqueAsmPath.exists() ) + uniqueAsmPath.eraseFromDisk(); + return NULL; + } + + // make unique 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 + const std::string& uniqueObjStr = uniqueObjPath.str(); + bool asmResult = this->assemble(uniqueAsmPath.str(), uniqueObjStr, errMsg); + if ( !asmResult ) { + // remove old buffer if compile() called twice + delete _nativeObjectFile; + + // read .o file into memory buffer + _nativeObjectFile = MemoryBuffer::getFile(uniqueObjStr.c_str(),&errMsg); + } + + // remove temp files + uniqueAsmPath.eraseFromDisk(); + uniqueObjPath.eraseFromDisk(); + + // return buffer, unless error + if ( _nativeObjectFile == NULL ) + return NULL; + *length = _nativeObjectFile->getBufferSize(); + return _nativeObjectFile->getBufferStart(); +} + + +bool LTOCodeGenerator::assemble(const std::string& asmPath, + const std::string& objPath, std::string& errMsg) +{ + sys::Path tool; + bool needsCompilerOptions = true; + if ( _assemblerPath ) { + tool = *_assemblerPath; + needsCompilerOptions = false; + } else { + // find compiler driver + tool = sys::Program::FindProgramByName("gcc"); + if ( tool.isEmpty() ) { + errMsg = "can't locate gcc"; + return true; + } + } + + // build argument list + std::vector<const char*> args; + llvm::Triple targetTriple(_linker.getModule()->getTargetTriple()); + const char *arch = targetTriple.getArchNameForAssembler(); + + args.push_back(tool.c_str()); + + if (targetTriple.getOS() == Triple::Darwin) { + // darwin specific command line options + if (arch != NULL) { + args.push_back("-arch"); + args.push_back(arch); + } + // add -static to assembler command line when code model requires + if ( (_assemblerPath != NULL) && + (_codeModel == LTO_CODEGEN_PIC_MODEL_STATIC) ) + args.push_back("-static"); + } + if ( needsCompilerOptions ) { + 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(tool, &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 ) { + std::string Triple = _linker.getModule()->getTargetTriple(); + if (Triple.empty()) + Triple = sys::getHostTriple(); + + // create target machine from info for merged modules + const Target *march = TargetRegistry::lookupTarget(Triple, errMsg); + if ( march == NULL ) + return true; + + // The relocation model is actually a static member of TargetMachine + // and needs to be set before the TargetMachine is instantiated. + switch( _codeModel ) { + case LTO_CODEGEN_PIC_MODEL_STATIC: + TargetMachine::setRelocationModel(Reloc::Static); + break; + case LTO_CODEGEN_PIC_MODEL_DYNAMIC: + TargetMachine::setRelocationModel(Reloc::PIC_); + break; + case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: + TargetMachine::setRelocationModel(Reloc::DynamicNoPIC); + break; + } + + // construct LTModule, hand over ownership of module and target + SubtargetFeatures Features; + Features.getDefaultSubtargetFeatures("" /* cpu */, llvm::Triple(Triple)); + std::string FeatureStr = Features.getString(); + _target = march->createTargetMachine(Triple, FeatureStr); + } + return false; +} + +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 + if (!_mustPreserveSymbols.empty()) { + MCContext Context(*_target->getMCAsmInfo()); + Mangler mangler(Context, *_target->getTargetData()); + std::vector<const char*> mustPreserveList; + for (Module::iterator f = mergedModule->begin(), + e = mergedModule->end(); f != e; ++f) { + if (!f->isDeclaration() && + _mustPreserveSymbols.count(mangler.getNameWithPrefix(f))) + mustPreserveList.push_back(::strdup(f->getNameStr().c_str())); + } + for (Module::global_iterator v = mergedModule->global_begin(), + e = mergedModule->global_end(); v != e; ++v) { + if (!v->isDeclaration() && + _mustPreserveSymbols.count(mangler.getNameWithPrefix(v))) + mustPreserveList.push_back(::strdup(v->getNameStr().c_str())); + } + passes.add(createInternalizePass(mustPreserveList)); + } + + // apply scope restrictions + passes.run(*mergedModule); + + _scopeRestrictionsDone = true; +} + +/// Optimize merged modules using various IPO passes +bool LTOCodeGenerator::generateAssemblyCode(formatted_raw_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 options were requested, set them + if ( !_codegenOptions.empty() ) + cl::ParseCommandLineOptions(_codegenOptions.size(), + const_cast<char **>(&_codegenOptions[0])); + + // 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())); + + createStandardLTOPasses(&passes, /*Internalize=*/ false, !DisableInline, + /*VerifyEach=*/ false); + + // Make sure everything is still good. + passes.add(createVerifierPass()); + + FunctionPassManager* codeGenPasses = new FunctionPassManager(mergedModule); + + codeGenPasses->add(new TargetData(*_target->getTargetData())); + + if (_target->addPassesToEmitFile(*codeGenPasses, out, + TargetMachine::CGFT_AssemblyFile, + CodeGenOpt::Aggressive)) { + errMsg = "target file type not supported"; + 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 +} + + +/// Optimize merged modules using various IPO passes +void LTOCodeGenerator::setCodeGenDebugOptions(const char* options) +{ + for (std::pair<StringRef, StringRef> o = getToken(options); + !o.first.empty(); o = getToken(o.second)) { + // ParseCommandLineOptions() expects argv[0] to be program name. + // Lazily add that. + if ( _codegenOptions.empty() ) + _codegenOptions.push_back("libLTO"); + _codegenOptions.push_back(strdup(o.first.str().c_str())); + } +} diff --git a/contrib/llvm/tools/lto/LTOCodeGenerator.h b/contrib/llvm/tools/lto/LTOCodeGenerator.h new file mode 100644 index 0000000..cac3b8c --- /dev/null +++ b/contrib/llvm/tools/lto/LTOCodeGenerator.h @@ -0,0 +1,68 @@ +//===-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/LLVMContext.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/SmallVector.h" + +#include <string> + + +// +// C++ class which implements the opaque lto_code_gen_t +// + +struct LTOCodeGenerator { + static const char* getVersionString(); + + LTOCodeGenerator(); + ~LTOCodeGenerator(); + + bool addModule(struct LTOModule*, std::string& errMsg); + bool setDebugInfo(lto_debug_model, std::string& errMsg); + bool setCodePICModel(lto_codegen_model, std::string& errMsg); + void setAssemblerPath(const char* path); + void addMustPreserveSymbol(const char* sym); + bool writeMergedModules(const char* path, + std::string& errMsg); + const void* compile(size_t* length, std::string& errMsg); + void setCodeGenDebugOptions(const char *opts); +private: + bool generateAssemblyCode(llvm::formatted_raw_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::LLVMContext& _context; + llvm::Linker _linker; + llvm::TargetMachine* _target; + bool _emitDwarfDebugInfo; + bool _scopeRestrictionsDone; + lto_codegen_model _codeModel; + StringSet _mustPreserveSymbols; + llvm::MemoryBuffer* _nativeObjectFile; + std::vector<const char*> _codegenOptions; + llvm::sys::Path* _assemblerPath; +}; + +#endif // LTO_CODE_GENERATOR_H + diff --git a/contrib/llvm/tools/lto/LTOModule.cpp b/contrib/llvm/tools/lto/LTOModule.cpp new file mode 100644 index 0000000..0870205 --- /dev/null +++ b/contrib/llvm/tools/lto/LTOModule.cpp @@ -0,0 +1,525 @@ +//===-- 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/Constants.h" +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/System/Host.h" +#include "llvm/System/Path.h" +#include "llvm/System/Process.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/SubtargetFeature.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetSelect.h" + +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) +{ + MemoryBuffer* buffer = makeBuffer(mem, length); + if (!buffer) + return false; + return isTargetMatch(buffer, triplePrefix); +} + + +bool LTOModule::isBitcodeFileForTarget(const char* path, + const char* triplePrefix) +{ + MemoryBuffer *buffer = MemoryBuffer::getFile(path); + if (buffer == NULL) + return false; + return isTargetMatch(buffer, triplePrefix); +} + +// takes ownership of buffer +bool LTOModule::isTargetMatch(MemoryBuffer* buffer, const char* triplePrefix) +{ + OwningPtr<Module> m(getLazyBitcodeModule(buffer, getGlobalContext())); + // on success, m owns buffer and both are deleted at end of this method + if (!m) { + delete buffer; + return false; + } + std::string actualTarget = m->getTargetTriple(); + return (strncmp(actualTarget.c_str(), triplePrefix, + strlen(triplePrefix)) == 0); +} + + +LTOModule::LTOModule(Module* m, TargetMachine* t) + : _module(m), _target(t), _symbolsParsed(false) +{ +} + +LTOModule* LTOModule::makeLTOModule(const char* path, + std::string& errMsg) +{ + OwningPtr<MemoryBuffer> buffer(MemoryBuffer::getFile(path, &errMsg)); + if (!buffer) + return NULL; + return makeLTOModule(buffer.get(), errMsg); +} + +/// makeBuffer - create a MemoryBuffer from a memory range. +/// MemoryBuffer requires the byte past end of the buffer to be a zero. +/// We might get lucky and already be that way, otherwise make a copy. +/// Also if next byte is on a different page, don't assume it is readable. +MemoryBuffer* LTOModule::makeBuffer(const void* mem, size_t length) +{ + const char *startPtr = (char*)mem; + const char *endPtr = startPtr+length; + if (((uintptr_t)endPtr & (sys::Process::GetPageSize()-1)) == 0 || + *endPtr != 0) + return MemoryBuffer::getMemBufferCopy(StringRef(startPtr, length)); + + return MemoryBuffer::getMemBuffer(StringRef(startPtr, length)); +} + + +LTOModule* LTOModule::makeLTOModule(const void* mem, size_t length, + std::string& errMsg) +{ + OwningPtr<MemoryBuffer> buffer(makeBuffer(mem, length)); + if (!buffer) + return NULL; + return makeLTOModule(buffer.get(), errMsg); +} + +LTOModule* LTOModule::makeLTOModule(MemoryBuffer* buffer, + std::string& errMsg) +{ + InitializeAllTargets(); + + // parse bitcode buffer + OwningPtr<Module> m(ParseBitcodeFile(buffer, getGlobalContext(), &errMsg)); + if (!m) + return NULL; + + std::string Triple = m->getTargetTriple(); + if (Triple.empty()) + Triple = sys::getHostTriple(); + + // find machine architecture for this module + const Target* march = TargetRegistry::lookupTarget(Triple, errMsg); + if (!march) + return NULL; + + // construct LTModule, hand over ownership of module and target + SubtargetFeatures Features; + Features.getDefaultSubtargetFeatures("" /* cpu */, llvm::Triple(Triple)); + std::string FeatureStr = Features.getString(); + TargetMachine* target = march->createTargetMachine(Triple, FeatureStr); + return new LTOModule(m.take(), target); +} + + +const char* LTOModule::getTargetTriple() +{ + return _module->getTargetTriple().c_str(); +} + +void LTOModule::addDefinedFunctionSymbol(Function* f, Mangler &mangler) +{ + // add to list of defined symbols + addDefinedSymbol(f, mangler, true); + + // add external symbols referenced by this function. + for (Function::iterator b = f->begin(); b != f->end(); ++b) { + for (BasicBlock::iterator i = b->begin(); i != b->end(); ++i) { + for (unsigned count = 0, total = i->getNumOperands(); + count != total; ++count) { + findExternalRefs(i->getOperand(count), mangler); + } + } + } +} + +// get string that data pointer points to +bool LTOModule::objcClassNameFromExpression(Constant* c, std::string& name) +{ + if (ConstantExpr* ce = dyn_cast<ConstantExpr>(c)) { + Constant* op = ce->getOperand(0); + if (GlobalVariable* gvn = dyn_cast<GlobalVariable>(op)) { + Constant* cn = gvn->getInitializer(); + if (ConstantArray* ca = dyn_cast<ConstantArray>(cn)) { + if (ca->isCString()) { + name = ".objc_class_name_" + ca->getAsString(); + return true; + } + } + } + } + return false; +} + +// parse i386/ppc ObjC class data structure +void LTOModule::addObjCClass(GlobalVariable* clgv) +{ + if (ConstantStruct* c = dyn_cast<ConstantStruct>(clgv->getInitializer())) { + // second slot in __OBJC,__class is pointer to superclass name + std::string superclassName; + if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { + NameAndAttributes info; + if (_undefines.find(superclassName.c_str()) == _undefines.end()) { + const char* symbolName = ::strdup(superclassName.c_str()); + info.name = ::strdup(symbolName); + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + // string is owned by _undefines + _undefines[info.name] = info; + } + } + // third slot in __OBJC,__class is pointer to class name + std::string className; + if (objcClassNameFromExpression(c->getOperand(2), className)) { + const char* symbolName = ::strdup(className.c_str()); + NameAndAttributes info; + info.name = symbolName; + info.attributes = (lto_symbol_attributes) + (LTO_SYMBOL_PERMISSIONS_DATA | + LTO_SYMBOL_DEFINITION_REGULAR | + LTO_SYMBOL_SCOPE_DEFAULT); + _symbols.push_back(info); + _defines[info.name] = 1; + } + } +} + + +// parse i386/ppc ObjC category data structure +void LTOModule::addObjCCategory(GlobalVariable* clgv) +{ + if (ConstantStruct* c = dyn_cast<ConstantStruct>(clgv->getInitializer())) { + // second slot in __OBJC,__category is pointer to target class name + std::string targetclassName; + if (objcClassNameFromExpression(c->getOperand(1), targetclassName)) { + NameAndAttributes info; + if (_undefines.find(targetclassName.c_str()) == _undefines.end()) { + const char* symbolName = ::strdup(targetclassName.c_str()); + info.name = ::strdup(symbolName); + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + // string is owned by _undefines + _undefines[info.name] = info; + } + } + } +} + + +// parse i386/ppc ObjC class list data structure +void LTOModule::addObjCClassRef(GlobalVariable* clgv) +{ + std::string targetclassName; + if (objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) { + NameAndAttributes info; + if (_undefines.find(targetclassName.c_str()) == _undefines.end()) { + const char* symbolName = ::strdup(targetclassName.c_str()); + info.name = ::strdup(symbolName); + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + // string is owned by _undefines + _undefines[info.name] = info; + } + } +} + + +void LTOModule::addDefinedDataSymbol(GlobalValue* v, Mangler& mangler) +{ + // add to list of defined symbols + addDefinedSymbol(v, mangler, false); + + // 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. + if (v->hasSection() /* && isTargetDarwin */) { + // special case if this data blob is an ObjC class definition + if (v->getSection().compare(0, 15, "__OBJC,__class,") == 0) { + if (GlobalVariable* gv = dyn_cast<GlobalVariable>(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 (GlobalVariable* gv = dyn_cast<GlobalVariable>(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 (GlobalVariable* gv = dyn_cast<GlobalVariable>(v)) { + addObjCClassRef(gv); + } + } + } + + // add external symbols referenced by this data. + for (unsigned count = 0, total = v->getNumOperands(); + count != total; ++count) { + findExternalRefs(v->getOperand(count), mangler); + } +} + + +void LTOModule::addDefinedSymbol(GlobalValue* def, Mangler &mangler, + bool isFunction) +{ + // ignore all llvm.* symbols + if (def->getName().startswith("llvm.")) + return; + + // string is owned by _defines + const char* symbolName = ::strdup(mangler.getNameWithPrefix(def).c_str()); + + // set alignment part log2() can have rounding errors + uint32_t align = def->getAlignment(); + uint32_t attr = align ? CountTrailingZeros_32(def->getAlignment()) : 0; + + // set permissions part + if (isFunction) + attr |= LTO_SYMBOL_PERMISSIONS_CODE; + else { + GlobalVariable* gv = dyn_cast<GlobalVariable>(def); + if (gv && gv->isConstant()) + attr |= LTO_SYMBOL_PERMISSIONS_RODATA; + else + attr |= LTO_SYMBOL_PERMISSIONS_DATA; + } + + // set definition part + if (def->hasWeakLinkage() || def->hasLinkOnceLinkage()) { + 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()) + 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::addAsmGlobalSymbol(const char *name) { + // only add new define if not already defined + if (_defines.count(name) == 0) + return; + + // string is owned by _defines + const char *symbolName = ::strdup(name); + uint32_t attr = LTO_SYMBOL_DEFINITION_REGULAR; + attr |= LTO_SYMBOL_SCOPE_DEFAULT; + NameAndAttributes info; + info.name = symbolName; + info.attributes = (lto_symbol_attributes)attr; + _symbols.push_back(info); + _defines[info.name] = 1; +} + +void LTOModule::addPotentialUndefinedSymbol(GlobalValue* decl, Mangler &mangler) +{ + // ignore all llvm.* symbols + if (decl->getName().startswith("llvm.")) + return; + + // ignore all aliases + if (isa<GlobalAlias>(decl)) + return; + + std::string name = mangler.getNameWithPrefix(decl); + + // we already have the symbol + if (_undefines.find(name) != _undefines.end()) + return; + + NameAndAttributes info; + // string is owned by _undefines + info.name = ::strdup(name.c_str()); + if (decl->hasExternalWeakLinkage()) + info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; + else + info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; + _undefines[name] = info; +} + + + +// Find external symbols referenced by VALUE. This is a recursive function. +void LTOModule::findExternalRefs(Value* value, Mangler &mangler) { + + if (GlobalValue* gv = dyn_cast<GlobalValue>(value)) { + if (!gv->hasExternalLinkage()) + addPotentialUndefinedSymbol(gv, mangler); + // If this is a variable definition, do not recursively process + // initializer. It might contain a reference to this variable + // and cause an infinite loop. The initializer will be + // processed in addDefinedDataSymbol(). + return; + } + + // GlobalValue, even with InternalLinkage type, may have operands with + // ExternalLinkage type. Do not ignore these operands. + if (Constant* c = dyn_cast<Constant>(value)) { + // Handle ConstantExpr, ConstantStruct, ConstantArry etc. + for (unsigned i = 0, e = c->getNumOperands(); i != e; ++i) + findExternalRefs(c->getOperand(i), mangler); + } +} + +void LTOModule::lazyParseSymbols() +{ + if (!_symbolsParsed) { + _symbolsParsed = true; + + // Use mangler to add GlobalPrefix to names to match linker names. + MCContext Context(*_target->getMCAsmInfo()); + Mangler mangler(Context, *_target->getTargetData()); + + // add functions + for (Module::iterator f = _module->begin(); f != _module->end(); ++f) { + if (f->isDeclaration()) + addPotentialUndefinedSymbol(f, mangler); + else + addDefinedFunctionSymbol(f, mangler); + } + + // add data + for (Module::global_iterator v = _module->global_begin(), + e = _module->global_end(); v != e; ++v) { + if (v->isDeclaration()) + addPotentialUndefinedSymbol(v, mangler); + else + addDefinedDataSymbol(v, mangler); + } + + // add asm globals + const std::string &inlineAsm = _module->getModuleInlineAsm(); + const std::string glbl = ".globl"; + std::string asmSymbolName; + std::string::size_type pos = inlineAsm.find(glbl, 0); + while (pos != std::string::npos) { + // eat .globl + pos = pos + 6; + + // skip white space between .globl and symbol name + std::string::size_type pbegin = inlineAsm.find_first_not_of(' ', pos); + if (pbegin == std::string::npos) + break; + + // find end-of-line + std::string::size_type pend = inlineAsm.find_first_of('\n', pbegin); + if (pend == std::string::npos) + break; + + asmSymbolName.assign(inlineAsm, pbegin, pend - pbegin); + addAsmGlobalSymbol(asmSymbolName.c_str()); + + // search next .globl + pos = inlineAsm.find(glbl, pend); + } + + // make symbols for all undefines + for (StringMap<NameAndAttributes>::iterator it=_undefines.begin(); + it != _undefines.end(); ++it) { + // if this symbol also has a definition, then don't make an undefine + // because it is a tentative definition + if (_defines.count(it->getKey()) == 0) { + NameAndAttributes info = it->getValue(); + _symbols.push_back(info); + } + } + } +} + + +uint32_t LTOModule::getSymbolCount() +{ + lazyParseSymbols(); + return _symbols.size(); +} + + +lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index) +{ + lazyParseSymbols(); + if (index < _symbols.size()) + return _symbols[index].attributes; + else + return lto_symbol_attributes(0); +} + +const char* LTOModule::getSymbolName(uint32_t index) +{ + lazyParseSymbols(); + if (index < _symbols.size()) + return _symbols[index].name; + else + return NULL; +} diff --git a/contrib/llvm/tools/lto/LTOModule.h b/contrib/llvm/tools/lto/LTOModule.h new file mode 100644 index 0000000..7f475d4 --- /dev/null +++ b/contrib/llvm/tools/lto/LTOModule.h @@ -0,0 +1,110 @@ +//===-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/Module.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/ADT/StringMap.h" + +#include "llvm-c/lto.h" + +#include <vector> +#include <string> + + +// forward references to llvm classes +namespace llvm { + class Mangler; + class MemoryBuffer; + class GlobalValue; + class Value; + class Function; +} + + +// +// C++ class which implements the opaque lto_module_t +// +struct LTOModule { + + static bool isBitcodeFile(const void* mem, size_t length); + static bool isBitcodeFile(const char* path); + + static bool isBitcodeFileForTarget(const void* mem, + size_t length, const char* triplePrefix); + + static bool isBitcodeFileForTarget(const char* path, + const char* triplePrefix); + + static LTOModule* makeLTOModule(const char* path, + std::string& errMsg); + static LTOModule* makeLTOModule(const void* mem, size_t length, + std::string& errMsg); + + const char* getTargetTriple(); + uint32_t getSymbolCount(); + lto_symbol_attributes getSymbolAttributes(uint32_t index); + const char* getSymbolName(uint32_t index); + + llvm::Module * getLLVVMModule() { return _module.get(); } + +private: + LTOModule(llvm::Module* m, llvm::TargetMachine* t); + + void lazyParseSymbols(); + void addDefinedSymbol(llvm::GlobalValue* def, + llvm::Mangler& mangler, + bool isFunction); + void addPotentialUndefinedSymbol(llvm::GlobalValue* decl, + llvm::Mangler &mangler); + void findExternalRefs(llvm::Value* value, + llvm::Mangler& mangler); + void addDefinedFunctionSymbol(llvm::Function* f, + llvm::Mangler &mangler); + void addDefinedDataSymbol(llvm::GlobalValue* v, + llvm::Mangler &mangler); + void addAsmGlobalSymbol(const char *); + void addObjCClass(llvm::GlobalVariable* clgv); + void addObjCCategory(llvm::GlobalVariable* clgv); + void addObjCClassRef(llvm::GlobalVariable* clgv); + bool objcClassNameFromExpression(llvm::Constant* c, + std::string& name); + + static bool isTargetMatch(llvm::MemoryBuffer* memBuffer, + const char* triplePrefix); + + static LTOModule* makeLTOModule(llvm::MemoryBuffer* buffer, + std::string& errMsg); + static llvm::MemoryBuffer* makeBuffer(const void* mem, size_t length); + + typedef llvm::StringMap<uint8_t> StringSet; + + struct NameAndAttributes { + const char* name; + lto_symbol_attributes attributes; + }; + + llvm::OwningPtr<llvm::Module> _module; + llvm::OwningPtr<llvm::TargetMachine> _target; + bool _symbolsParsed; + std::vector<NameAndAttributes> _symbols; + // _defines and _undefines only needed to disambiguate tentative definitions + StringSet _defines; + llvm::StringMap<NameAndAttributes> _undefines; +}; + +#endif // LTO_MODULE_H + diff --git a/contrib/llvm/tools/lto/Makefile b/contrib/llvm/tools/lto/Makefile new file mode 100644 index 0000000..8d57333 --- /dev/null +++ b/contrib/llvm/tools/lto/Makefile @@ -0,0 +1,47 @@ +##===- tools/lto/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 = LTO + +EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/lto.exports + +# Include this here so we can get the configuration of the targets +# that have been configured for construction. We have to do this +# early so we can set up LINK_COMPONENTS before including Makefile.rules +include $(LEVEL)/Makefile.config + +LINK_LIBS_IN_SHARED = 1 +SHARED_LIBRARY = 1 + +LINK_COMPONENTS := $(TARGETS_TO_BUILD) ipo scalaropts linker bitreader bitwriter + +include $(LEVEL)/Makefile.common + +ifeq ($(HOST_OS),Darwin) + # set dylib internal version number to llvmCore submission number + ifdef LLVM_SUBMIT_VERSION + LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version \ + -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) \ + -Wl,-compatibility_version -Wl,1 + endif + # extra options to override libtool defaults + LLVMLibsOptions := $(LLVMLibsOptions) \ + -avoid-version \ + -Wl,-dead_strip \ + -Wl,-seg1addr -Wl,0xE0000000 + + # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line + DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') + ifneq ($(DARWIN_VERS),8) + LLVMLibsOptions := $(LLVMLibsOptions) \ + -no-undefined -Wl,-install_name \ + -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" + endif +endif diff --git a/contrib/llvm/tools/lto/lto.cpp b/contrib/llvm/tools/lto/lto.cpp new file mode 100644 index 0000000..cc841bd --- /dev/null +++ b/contrib/llvm/tools/lto/lto.cpp @@ -0,0 +1,257 @@ +//===-lto.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-c/lto.h" +#include "llvm-c/Core.h" + +#include "LTOModule.h" +#include "LTOCodeGenerator.h" + + +// holds most recent error string +// *** not thread safe *** +static std::string sLastErrorString; + + + +// +// returns a printable string +// +extern const char* lto_get_version() +{ + return LTOCodeGenerator::getVersionString(); +} + +// +// returns the last error string or NULL if last operation was successful +// +const char* lto_get_error_message() +{ + return sLastErrorString.c_str(); +} + + + +// +// validates if a file is a loadable object file +// +bool lto_module_is_object_file(const char* path) +{ + return LTOModule::isBitcodeFile(path); +} + + +// +// validates if a file is a loadable object file compilable for requested target +// +bool lto_module_is_object_file_for_target(const char* path, + const char* target_triplet_prefix) +{ + return LTOModule::isBitcodeFileForTarget(path, target_triplet_prefix); +} + + +// +// validates if a buffer is a loadable object file +// +bool lto_module_is_object_file_in_memory(const void* mem, size_t length) +{ + return LTOModule::isBitcodeFile(mem, length); +} + + +// +// validates if a buffer is a loadable object file compilable for the target +// +bool lto_module_is_object_file_in_memory_for_target(const void* mem, + size_t length, const char* target_triplet_prefix) +{ + return LTOModule::isBitcodeFileForTarget(mem, length, target_triplet_prefix); +} + + + +// +// 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) +{ + return LTOModule::makeLTOModule(path, sLastErrorString); +} + + +// +// 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) +{ + return LTOModule::makeLTOModule(mem, length, sLastErrorString); +} + + +// +// frees all memory for a module +// upon return the lto_module_t is no longer valid +// +void lto_module_dispose(lto_module_t mod) +{ + delete mod; +} + + +// +// returns triplet string which the object module was compiled under +// +const char* lto_module_get_target_triple(lto_module_t mod) +{ + return mod->getTargetTriple(); +} + + +// +// returns the number of symbols in the object module +// +uint32_t lto_module_get_num_symbols(lto_module_t mod) +{ + return mod->getSymbolCount(); +} + +// +// returns the name of the ith symbol in the object module +// +const char* lto_module_get_symbol_name(lto_module_t mod, uint32_t index) +{ + return mod->getSymbolName(index); +} + + +// +// returns the attributes of the ith symbol in the object module +// +lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod, + uint32_t index) +{ + return mod->getSymbolAttributes(index); +} + + + + + +// +// instantiates a code generator +// returns NULL if there is an error +// +lto_code_gen_t lto_codegen_create(void) +{ + return new LTOCodeGenerator(); +} + + + +// +// frees all memory for a code generator +// upon return the lto_code_gen_t is no longer valid +// +void lto_codegen_dispose(lto_code_gen_t cg) +{ + delete cg; +} + + + +// +// 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) +// +bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod) +{ + return cg->addModule(mod, sLastErrorString); +} + + +// +// sets what if any format of debug info should be generated +// returns true on error (check lto_get_error_message() for details) +// +bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug) +{ + return cg->setDebugInfo(debug, sLastErrorString); +} + + +// +// sets what code model to generated +// returns true on error (check lto_get_error_message() for details) +// +bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model) +{ + return cg->setCodePICModel(model, sLastErrorString); +} + +// +// sets the path to the assembler tool +// +void lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path) +{ + cg->setAssemblerPath(path); +} + +// +// adds to a list of all global symbols that must exist in the final +// generated code. If a function is not listed there, it might be +// inlined into every usage and optimized away. +// +void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char* symbol) +{ + cg->addMustPreserveSymbol(symbol); +} + + +// +// writes a new 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) +// +bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char* path) +{ + return cg->writeMergedModules(path, sLastErrorString); +} + + +// +// 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. The buffer is owned by the +// lto_code_gen_t and will be freed when lto_codegen_dispose() +// is called, or lto_codegen_compile() is called again. +// On failure, returns NULL (check lto_get_error_message() for details). +// +extern const void* +lto_codegen_compile(lto_code_gen_t cg, size_t* length) +{ + return cg->compile(length, sLastErrorString); +} + + +// +// Used to pass extra options to the code generator +// +extern void +lto_codegen_debug_options(lto_code_gen_t cg, const char * opt) +{ + cg->setCodeGenDebugOptions(opt); +} diff --git a/contrib/llvm/tools/lto/lto.exports b/contrib/llvm/tools/lto/lto.exports new file mode 100644 index 0000000..9011cf6 --- /dev/null +++ b/contrib/llvm/tools/lto/lto.exports @@ -0,0 +1,23 @@ +lto_get_error_message +lto_get_version +lto_module_create +lto_module_create_from_memory +lto_module_get_num_symbols +lto_module_get_symbol_attribute +lto_module_get_symbol_name +lto_module_get_target_triple +lto_module_is_object_file +lto_module_is_object_file_for_target +lto_module_is_object_file_in_memory +lto_module_is_object_file_in_memory_for_target +lto_module_dispose +lto_codegen_add_module +lto_codegen_add_must_preserve_symbol +lto_codegen_compile +lto_codegen_create +lto_codegen_dispose +lto_codegen_set_debug_model +lto_codegen_set_pic_model +lto_codegen_write_merged_modules +lto_codegen_debug_options +lto_codegen_set_assembler_path |