mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-26 21:32:10 +00:00
first commit of new LTO system. It is not hooked up in the llvm/tools/Makefile, so no one will build it be default yet
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@47621 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
f4511cd8fb
commit
77595fc356
234
include/llvm-c/lto.h
Normal file
234
include/llvm-c/lto.h
Normal file
@ -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
|
465
tools/lto2/LTOCodeGenerator.cpp
Normal file
465
tools/lto2/LTOCodeGenerator.cpp
Normal file
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
59
tools/lto2/LTOCodeGenerator.h
Normal file
59
tools/lto2/LTOCodeGenerator.h
Normal file
@ -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
|
||||||
|
|
329
tools/lto2/LTOModule.cpp
Normal file
329
tools/lto2/LTOModule.cpp
Normal file
@ -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(name, "llvm.", 5) != 0 ) {
|
||||||
|
_undefines[name] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Find exeternal 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() )
|
||||||
|
addUndefinedSymbol(mangler.getValueName(gv).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t LTOModule::getSymbolCount()
|
||||||
|
{
|
||||||
|
if ( !_symbolsParsed ) {
|
||||||
|
_symbolsParsed = true;
|
||||||
|
|
||||||
|
// Use mangler to add GlobalPrefix to names to match linker names.
|
||||||
|
Mangler mangler(*_module, _target->getTargetAsmInfo()->getGlobalPrefix());
|
||||||
|
|
||||||
|
// add functions
|
||||||
|
for (Module::iterator f = _module->begin(); f != _module->end(); ++f) {
|
||||||
|
if ( f->isDeclaration() ) {
|
||||||
|
addUndefinedSymbol(mangler.getValueName(f).c_str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add data
|
||||||
|
for (Module::global_iterator v = _module->global_begin(),
|
||||||
|
e = _module->global_end(); v != e; ++v) {
|
||||||
|
if ( v->isDeclaration() ) {
|
||||||
|
addUndefinedSymbol(mangler.getValueName(v).c_str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addDefinedSymbol(v, mangler, false);
|
||||||
|
// add external symbols referenced by this data
|
||||||
|
for (unsigned count = 0, total = v->getNumOperands();
|
||||||
|
count != total; ++count) {
|
||||||
|
findExternalRefs(v->getOperand(count), mangler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make symbols for all undefines
|
||||||
|
for (StringSet::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.find(it->getKeyData(), it->getKeyData()+it->getKeyLength()) == _defines.end() ) {
|
||||||
|
NameAndAttributes info;
|
||||||
|
info.name = it->getKeyData();
|
||||||
|
info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED;
|
||||||
|
_symbols.push_back(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return _symbols.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index)
|
||||||
|
{
|
||||||
|
if ( index < _symbols.size() )
|
||||||
|
return _symbols[index].attributes;
|
||||||
|
else
|
||||||
|
return lto_symbol_attributes(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* LTOModule::getSymbolName(uint32_t index)
|
||||||
|
{
|
||||||
|
if ( index < _symbols.size() )
|
||||||
|
return _symbols[index].name;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
83
tools/lto2/LTOModule.h
Normal file
83
tools/lto2/LTOModule.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
//===-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/GlobalValue.h"
|
||||||
|
#include "llvm/Constants.h"
|
||||||
|
#include "llvm/Support/Mangler.h"
|
||||||
|
#include "llvm/Target/TargetMachine.h"
|
||||||
|
#include "llvm/ADT/StringMap.h"
|
||||||
|
|
||||||
|
#include "llvm-c/lto.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// C++ class which implements the opaque lto_module_t
|
||||||
|
//
|
||||||
|
class LTOModule {
|
||||||
|
public:
|
||||||
|
|
||||||
|
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);
|
||||||
|
~LTOModule();
|
||||||
|
|
||||||
|
const char* getTargetTriple();
|
||||||
|
uint32_t getSymbolCount();
|
||||||
|
lto_symbol_attributes getSymbolAttributes(uint32_t index);
|
||||||
|
const char* getSymbolName(uint32_t index);
|
||||||
|
|
||||||
|
llvm::Module * getLLVVMModule() { return _module; }
|
||||||
|
bool targetSupported() { return (_target != NULL); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
LTOModule(llvm::Module* m, llvm::TargetMachine* t);
|
||||||
|
|
||||||
|
void addDefinedSymbol(llvm::GlobalValue* def,
|
||||||
|
llvm::Mangler& mangler,
|
||||||
|
bool isFunction);
|
||||||
|
void addUndefinedSymbol(const char* name);
|
||||||
|
void findExternalRefs(llvm::Value* value,
|
||||||
|
llvm::Mangler& mangler);
|
||||||
|
|
||||||
|
typedef llvm::StringMap<uint8_t> StringSet;
|
||||||
|
|
||||||
|
struct NameAndAttributes {
|
||||||
|
const char* name;
|
||||||
|
lto_symbol_attributes attributes;
|
||||||
|
};
|
||||||
|
|
||||||
|
llvm::Module * _module;
|
||||||
|
llvm::TargetMachine * _target;
|
||||||
|
bool _symbolsParsed;
|
||||||
|
std::vector<NameAndAttributes> _symbols;
|
||||||
|
StringSet _defines; // only needed to disambiguate tentative definitions
|
||||||
|
StringSet _undefines; // only needed to disambiguate tentative definitions
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LTO_MODULE_H
|
||||||
|
|
45
tools/lto2/Makefile
Normal file
45
tools/lto2/Makefile
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
##===- tools/lto2/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
|
||||||
|
|
||||||
|
# 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 includeing Makefile.rules
|
||||||
|
include $(LEVEL)/Makefile.config
|
||||||
|
|
||||||
|
LINK_LIBS_IN_SHARED = 1
|
||||||
|
ifeq ($(OS),Darwin)
|
||||||
|
SHARED_LIBRARY = 1
|
||||||
|
DONT_BUILD_RELINKED = 1
|
||||||
|
else
|
||||||
|
BUILD_ARCHIVE = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
LINK_COMPONENTS := $(TARGETS_TO_BUILD) ipo scalaropts linker bitreader bitwriter
|
||||||
|
|
||||||
|
include $(LEVEL)/Makefile.common
|
||||||
|
|
||||||
|
ifeq ($(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)
|
||||||
|
endif
|
||||||
|
# extra options to override libtool defaults
|
||||||
|
LLVMLibsOptions := $(LLVMLibsOptions) \
|
||||||
|
-no-undefined -avoid-version \
|
||||||
|
-Wl,-exported_symbols_list -Wl,lto.exports \
|
||||||
|
-Wl,-dead_strip \
|
||||||
|
-Wl,-install_name \
|
||||||
|
-Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" \
|
||||||
|
-Wl,-seg1addr -Wl,0xE0000000
|
||||||
|
|
||||||
|
endif
|
240
tools/lto2/lto.cpp
Normal file
240
tools/lto2/lto.cpp
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
//===-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 "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 sucessful
|
||||||
|
//
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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 object file
|
||||||
|
// On sucess returns a pointer to a generated mach-o buffer and
|
||||||
|
// length set to the buffer size. Client must free() the buffer
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
return cg->compile(length, sLastErrorString);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
22
tools/lto2/lto.exports
Normal file
22
tools/lto2/lto.exports
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
_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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user