From 2b066988909948dc3d53d01760bc2d71d32f3feb Mon Sep 17 00:00:00 2001 From: dim Date: Mon, 2 May 2011 19:34:44 +0000 Subject: Vendor import of llvm trunk r130700: http://llvm.org/svn/llvm-project/llvm/trunk@130700 --- tools/CMakeLists.txt | 12 + tools/Makefile | 7 +- tools/bugpoint/BugDriver.cpp | 22 +- tools/bugpoint/ExecutionDriver.cpp | 5 +- tools/bugpoint/Miscompilation.cpp | 34 +-- tools/bugpoint/ToolRunner.cpp | 11 +- tools/edis/CMakeLists.txt | 33 ++- tools/gold/CMakeLists.txt | 43 +++ tools/gold/gold-plugin.cpp | 121 ++------- tools/llc/llc.cpp | 30 +- tools/lli/lli.cpp | 1 + tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp | 10 +- tools/llvm-config/CMakeLists.txt | 30 +- tools/llvm-diff/CMakeLists.txt | 2 + tools/llvm-diff/DiffConsumer.cpp | 209 ++++++++++++++ tools/llvm-diff/DiffConsumer.h | 92 +++++++ tools/llvm-diff/DiffLog.cpp | 53 ++++ tools/llvm-diff/DiffLog.h | 80 ++++++ tools/llvm-diff/DifferenceEngine.cpp | 27 +- tools/llvm-diff/DifferenceEngine.h | 96 +------ tools/llvm-diff/llvm-diff.cpp | 218 +-------------- tools/llvm-dis/CMakeLists.txt | 2 +- tools/llvm-dis/Makefile | 2 +- tools/llvm-dis/llvm-dis.cpp | 53 +++- tools/llvm-ld/llvm-ld.cpp | 8 +- tools/llvm-mc/Disassembler.cpp | 9 +- tools/llvm-mc/Disassembler.h | 6 +- tools/llvm-mc/llvm-mc.cpp | 39 ++- tools/llvm-objdump/llvm-objdump.cpp | 16 +- tools/llvm-rtdyld/CMakeLists.txt | 5 + tools/llvm-rtdyld/Makefile | 23 ++ tools/llvm-rtdyld/llvm-rtdyld.cpp | 151 +++++++++++ tools/llvm-stub/llvm-stub.c | 2 +- tools/llvmc/doc/LLVMC-Reference.rst | 437 ++++++++++++------------------ tools/llvmc/doc/LLVMC-Tutorial.rst | 100 ++++--- tools/llvmc/examples/Skeleton/README | 2 +- tools/llvmc/src/Base.td.in | 2 +- tools/lto/CMakeLists.txt | 27 ++ tools/lto/LTOCodeGenerator.cpp | 204 +++++++++----- tools/lto/LTOCodeGenerator.h | 8 + tools/lto/LTOModule.cpp | 356 +++++++++++++++++------- tools/lto/LTOModule.h | 21 +- tools/lto/Makefile | 3 +- tools/lto/lto.cpp | 23 +- tools/lto/lto.exports | 5 + tools/macho-dump/macho-dump.cpp | 23 +- tools/opt/GraphPrinters.cpp | 4 +- tools/opt/opt.cpp | 65 +++-- 48 files changed, 1665 insertions(+), 1067 deletions(-) create mode 100644 tools/gold/CMakeLists.txt create mode 100644 tools/llvm-diff/DiffConsumer.cpp create mode 100644 tools/llvm-diff/DiffConsumer.h create mode 100644 tools/llvm-diff/DiffLog.cpp create mode 100644 tools/llvm-diff/DiffLog.h create mode 100644 tools/llvm-rtdyld/CMakeLists.txt create mode 100644 tools/llvm-rtdyld/Makefile create mode 100644 tools/llvm-rtdyld/llvm-rtdyld.cpp create mode 100644 tools/lto/CMakeLists.txt (limited to 'tools') diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 2f37911..c9072a7 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -38,6 +38,7 @@ add_subdirectory(llvm-extract) add_subdirectory(llvm-diff) add_subdirectory(macho-dump) add_subdirectory(llvm-objdump) +add_subdirectory(llvm-rtdyld) add_subdirectory(bugpoint) add_subdirectory(bugpoint-passes) @@ -46,6 +47,17 @@ add_subdirectory(llvm-stub) add_subdirectory(edis) add_subdirectory(llvmc) +if( NOT WIN32 ) + add_subdirectory(lto) +endif() + +if( LLVM_ENABLE_PIC ) + # TODO: support other systems: + if( CMAKE_SYSTEM_NAME STREQUAL "Linux" ) + add_subdirectory(gold) + endif() +endif() + if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/clang/CMakeLists.txt ) add_subdirectory( ${CMAKE_CURRENT_SOURCE_DIR}/clang ) endif( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/clang/CMakeLists.txt ) diff --git a/tools/Makefile b/tools/Makefile index 7310247..5960433 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -13,19 +13,20 @@ LEVEL := .. OPTIONAL_PARALLEL_DIRS := clang # Build LLDB if present. Note LLDB must be built last as it depends on the -# wider LLVM infrastructure (including Clang). +# wider LLVM infrastructure (including Clang). OPTIONAL_DIRS := lldb # NOTE: The tools are organized into five groups of four consisting of one # large and three small executables. This is done to minimize memory load # in parallel builds. Please retain this ordering. -DIRS := llvm-config +DIRS := llvm-config PARALLEL_DIRS := opt llvm-as llvm-dis \ llc llvm-ranlib llvm-ar llvm-nm \ llvm-ld llvm-prof llvm-link \ lli llvm-extract llvm-mc \ bugpoint llvm-bcanalyzer llvm-stub \ - llvmc llvm-diff macho-dump llvm-objdump + llvmc llvm-diff macho-dump llvm-objdump \ + llvm-rtdyld # Let users override the set of tools to build from the command line. ifdef ONLY_TOOLS diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index 1cbf632..aa3e290 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -71,7 +71,7 @@ BugDriver::BugDriver(const char *toolname, bool find_bugs, LLVMContext& ctxt) : Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile), Program(0), Interpreter(0), SafeInterpreter(0), gcc(0), - run_find_bugs(find_bugs), Timeout(timeout), + run_find_bugs(find_bugs), Timeout(timeout), MemoryLimit(memlimit), UseValgrind(use_valgrind) {} BugDriver::~BugDriver() { @@ -97,7 +97,7 @@ Module *llvm::ParseInputFile(const std::string &Filename, if (TheTriple.getTriple().empty()) TheTriple.setTriple(sys::getHostTriple()); - + TargetTriple.setTriple(TheTriple.getTriple()); } @@ -118,7 +118,7 @@ bool BugDriver::addSources(const std::vector &Filenames) { // Load the first input file. Program = ParseInputFile(Filenames[0], Context); if (Program == 0) return true; - + outs() << "Read input file : '" << Filenames[0] << "'\n"; for (unsigned i = 1, e = Filenames.size(); i != e; ++i) { @@ -152,12 +152,12 @@ bool BugDriver::run(std::string &ErrMsg) { return runManyPasses(PassesToRun, ErrMsg); } - // If we're not running as a child, the first thing that we must do is - // determine what the problem is. Does the optimization series crash the - // compiler, or does it produce illegal code? We make the top-level - // decision by trying to run all of the passes on the the input program, - // which should generate a bitcode file. If it does generate a bitcode - // file, then we know the compiler didn't crash, so try to diagnose a + // If we're not running as a child, the first thing that we must do is + // determine what the problem is. Does the optimization series crash the + // compiler, or does it produce illegal code? We make the top-level + // decision by trying to run all of the passes on the the input program, + // which should generate a bitcode file. If it does generate a bitcode + // file, then we know the compiler didn't crash, so try to diagnose a // miscompilation. if (!PassesToRun.empty()) { outs() << "Running selected passes on program to test for crash: "; @@ -194,10 +194,10 @@ bool BugDriver::run(std::string &ErrMsg) { // Make sure the reference output file gets deleted on exit from this // function, if appropriate. sys::Path ROF(ReferenceOutputFile); - FileRemover RemoverInstance(ROF, CreatedOutput && !SaveTemps); + FileRemover RemoverInstance(ROF.str(), CreatedOutput && !SaveTemps); // Diff the output of the raw program against the reference output. If it - // matches, then we assume there is a miscompilation bug and try to + // matches, then we assume there is a miscompilation bug and try to // diagnose it. outs() << "*** Checking the code generator...\n"; bool Diff = diffProgram(Program, "", "", false, &Error); diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index f1601cd..9be9dfd 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -323,7 +323,7 @@ void BugDriver::compileProgram(Module *M, std::string *Error) const { } // Remove the temporary bitcode file when we are done. - FileRemover BitcodeFileRemover(BitcodeFile, !SaveTemps); + FileRemover BitcodeFileRemover(BitcodeFile.str(), !SaveTemps); // Actually compile the program! Interpreter->compileProgram(BitcodeFile.str(), Error, Timeout, MemoryLimit); @@ -364,7 +364,8 @@ std::string BugDriver::executeProgram(const Module *Program, // Remove the temporary bitcode file when we are done. sys::Path BitcodePath(BitcodeFile); - FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode && !SaveTemps); + FileRemover BitcodeFileRemover(BitcodePath.str(), + CreatedBitcode && !SaveTemps); if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output"; diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index 3a5f143..a9db38f 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -34,12 +34,12 @@ namespace llvm { } namespace { - static llvm::cl::opt - DisableLoopExtraction("disable-loop-extraction", + static llvm::cl::opt + DisableLoopExtraction("disable-loop-extraction", cl::desc("Don't extract loops when searching for miscompilations"), cl::init(false)); - static llvm::cl::opt - DisableBlockExtraction("disable-block-extraction", + static llvm::cl::opt + DisableBlockExtraction("disable-block-extraction", cl::desc("Don't extract blocks when searching for miscompilations"), cl::init(false)); @@ -75,7 +75,7 @@ ReduceMiscompilingPasses::doTest(std::vector &Prefix, BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false); exit(BD.debugOptimizerCrash()); } - + // Check to see if the finished program matches the reference output... bool Diff = BD.diffProgram(BD.getProgram(), BitcodeResult, "", true /*delete bitcode*/, &Error); @@ -309,7 +309,7 @@ static bool ExtractLoops(BugDriver &BD, bool MadeChange = false; while (1) { if (BugpointIsInterrupted) return MadeChange; - + ValueToValueMapTy VMap; Module *ToNotOptimize = CloneModule(BD.getProgram(), VMap); Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, @@ -354,7 +354,7 @@ static bool ExtractLoops(BugDriver &BD, BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to-le.bc", ToOptimizeLoopExtracted); - errs() << "Please submit the " + errs() << "Please submit the " << OutputPrefix << "-loop-extract-fail-*.bc files.\n"; delete ToOptimize; delete ToNotOptimize; @@ -409,9 +409,9 @@ static bool ExtractLoops(BugDriver &BD, MiscompiledFunctions.clear(); for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first); - + assert(NewF && "Function not found??"); - assert(NewF->getFunctionType() == MisCompFunctions[i].second && + assert(NewF->getFunctionType() == MisCompFunctions[i].second && "found wrong function type?"); MiscompiledFunctions.push_back(NewF); } @@ -523,7 +523,7 @@ static bool ExtractBlocks(BugDriver &BD, std::vector &MiscompiledFunctions, std::string &Error) { if (BugpointIsInterrupted) return false; - + std::vector Blocks; for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) for (Function::iterator I = MiscompiledFunctions[i]->begin(), @@ -593,7 +593,7 @@ static bool ExtractBlocks(BugDriver &BD, for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) { Function *NewF = ProgClone->getFunction(MisCompFunctions[i].first); assert(NewF && "Function not found??"); - assert(NewF->getFunctionType() == MisCompFunctions[i].second && + assert(NewF->getFunctionType() == MisCompFunctions[i].second && "Function has wrong type??"); MiscompiledFunctions.push_back(NewF); } @@ -731,7 +731,7 @@ void BugDriver::debugMiscompilation(std::string *Error) { << getPassesString(getPassesToRun()) << '\n'; EmitProgressBitcode(Program, "passinput"); - std::vector MiscompiledFunctions = + std::vector MiscompiledFunctions = DebugAMiscompilation(*this, TestOptimizer, *Error); if (!Error->empty()) return; @@ -845,7 +845,7 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, // Create a new global to hold the cached function pointer. Constant *NullPtr = ConstantPointerNull::get(F->getType()); GlobalVariable *Cache = - new GlobalVariable(*F->getParent(), F->getType(), + new GlobalVariable(*F->getParent(), F->getType(), false, GlobalValue::InternalLinkage, NullPtr,F->getName()+".fpcache"); @@ -885,7 +885,7 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, new StoreInst(CastedResolver, Cache, LookupBB); BranchInst::Create(DoCallBB, LookupBB); - PHINode *FuncPtr = PHINode::Create(NullPtr->getType(), + PHINode *FuncPtr = PHINode::Create(NullPtr->getType(), 2, "fp", DoCallBB); FuncPtr->addIncoming(CastedResolver, LookupBB); FuncPtr->addIncoming(CachedVal, EntryBB); @@ -943,7 +943,7 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, } delete Test; - FileRemover TestModuleBCRemover(TestModuleBC, !SaveTemps); + FileRemover TestModuleBCRemover(TestModuleBC.str(), !SaveTemps); // Make the shared library sys::Path SafeModuleBC("bugpoint.safe.bc"); @@ -959,14 +959,14 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, exit(1); } - FileRemover SafeModuleBCRemover(SafeModuleBC, !SaveTemps); + FileRemover SafeModuleBCRemover(SafeModuleBC.str(), !SaveTemps); std::string SharedObject = BD.compileSharedObject(SafeModuleBC.str(), Error); if (!Error.empty()) return false; delete Safe; - FileRemover SharedObjectRemover(sys::Path(SharedObject), !SaveTemps); + FileRemover SharedObjectRemover(SharedObject, !SaveTemps); // Run the code generator on the `Test' code, loading the shared library. // The function returns whether or not the new output differs from reference. diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 37cc902..6c46ef1 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -503,7 +503,7 @@ int LLC::ExecuteProgram(const std::string &Bitcode, sys::Path OutputAsmFile; GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit); - FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); + FileRemover OutFileRemover(OutputAsmFile.str(), !SaveTemps); std::vector GCCArgs(ArgsForGCC); GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); @@ -675,7 +675,7 @@ int CBE::ExecuteProgram(const std::string &Bitcode, sys::Path OutputCFile; OutputCode(Bitcode, OutputCFile, *Error, Timeout, MemoryLimit); - FileRemover CFileRemove(OutputCFile, !SaveTemps); + FileRemover CFileRemove(OutputCFile.str(), !SaveTemps); std::vector GCCArgs(ArgsForGCC); GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end()); @@ -758,8 +758,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, // For ARM architectures we don't want this flag. bugpoint isn't // explicitly told what architecture it is working on, so we get // it from gcc flags - if ((TargetTriple.getOS() == Triple::Darwin) && - !IsARMArchitecture(GCCArgs)) + if (TargetTriple.isOSDarwin() && !IsARMArchitecture(GCCArgs)) GCCArgs.push_back("-force_cpusubtype_ALL"); } } @@ -851,7 +850,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, errs() << "\n"; ); - FileRemover OutputBinaryRemover(OutputBinary, !SaveTemps); + FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps); if (RemoteClientPath.isEmpty()) { DEBUG(errs() << ""); @@ -900,7 +899,7 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, GCCArgs.push_back("none"); if (TargetTriple.getArch() == Triple::sparc) GCCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc - else if (TargetTriple.getOS() == Triple::Darwin) { + else if (TargetTriple.isOSDarwin()) { // link all source files into a single module in data segment, rather than // generating blocks. dynamic_lookup requires that you set // MACOSX_DEPLOYMENT_TARGET=10.3 in your env. FIXME: it would be better for diff --git a/tools/edis/CMakeLists.txt b/tools/edis/CMakeLists.txt index 5037f9f..9406c2a 100644 --- a/tools/edis/CMakeLists.txt +++ b/tools/edis/CMakeLists.txt @@ -1,11 +1,34 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) -add_llvm_library(EnhancedDisassembly +set(SOURCES ../../include/llvm-c/EnhancedDisassembly.h EDMain.cpp -) + ) -set_target_properties(EnhancedDisassembly - PROPERTIES - LINKER_LANGUAGE CXX) +set(LLVM_LINK_COMPONENTS mcdisassembler) +if( LLVM_TARGETS_TO_BUILD MATCHES X86 ) + list(APPEND LLVM_LINK_COMPONENTS x86asmprinter x86disassembler) +endif() +if( LLVM_TARGETS_TO_BUILD MATCHES ARM ) + list(APPEND LLVM_LINK_COMPONENTS armasmprinter armdisassembler) +endif() +# TODO: Process EnhancedDisassembly.exports + +if( NOT WIN32 AND LLVM_ENABLE_PIC ) + set(bsl ${BUILD_SHARED_LIBS}) + set(BUILD_SHARED_LIBS ON) + add_llvm_library(EnhancedDisassembly ${SOURCES}) + set_property(TARGET EnhancedDisassembly PROPERTY + OUTPUT_NAME "EnhancedDisassembly") + set(BUILD_SHARED_LIBS ${bsl}) + set(EnhancedDisassembly_STATIC_TARGET_NAME EnhancedDisassembly_static) +else() + set(EnhancedDisassembly_STATIC_TARGET_NAME EnhancedDisassembly) +endif() + +if( NOT BUILD_SHARED_LIBS ) + add_llvm_library(${EnhancedDisassembly_STATIC_TARGET_NAME} ${SOURCES}) + set_property(TARGET ${EnhancedDisassembly_STATIC_TARGET_NAME} PROPERTY + OUTPUT_NAME "EnhancedDisassembly") +endif() diff --git a/tools/gold/CMakeLists.txt b/tools/gold/CMakeLists.txt new file mode 100644 index 0000000..d8633e6 --- /dev/null +++ b/tools/gold/CMakeLists.txt @@ -0,0 +1,43 @@ +set(LLVM_BINUTILS_INCDIR "/usr/include" CACHE PATH + "PATH to binutils/include containing plugin-api.h for gold plugin.") + +if( NOT EXISTS "${LLVM_BINUTILS_INCDIR}/plugin-api.h" ) + message(STATUS "plugin-api.h not found. gold plugin excluded from the build.") +else() + include_directories( ${LLVM_BINUTILS_INCDIR} ) + + # Because off_t is used in the public API, the largefile parts are required for + # ABI compatibility. + add_definitions( -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 ) + + set(LLVM_LINK_COMPONENTS support) + + add_llvm_loadable_module(LLVMgold + gold-plugin.cpp + ) + + # Makefile.rules contains a special cases for OpenBSD, Darwin and + # Windows. We restrict ourselves to Linux for the time being. + set(srcexp ${CMAKE_CURRENT_SOURCE_DIR}/gold.exports) + add_custom_command(OUTPUT exportsfile + COMMAND echo "{" > exportsfile + COMMAND grep -q "\\<" ${srcexp} && echo " global:" >> exportsfile || : + COMMAND sed -e "s/$/;/" -e "s/^/ /" < ${srcexp} >> exportsfile + COMMAND echo " local: *;" >> exportsfile + COMMAND echo "};" >> exportsfile + DEPENDS ${srcexp} + VERBATIM + COMMENT "Creating export file for gold plugin") + add_custom_target(gold_exports DEPENDS exportsfile) + set_property(DIRECTORY APPEND + PROPERTY ADDITIONAL_MAKE_CLEAN_FILES exportsfile) + + # Force re-linking when the exports file changes. Actually, it + # forces recompilation of gold-plugin.cpp. The LINK_DEPENDS target + # property only works for makefile-based generators. + set_property(SOURCE gold-plugin.cpp APPEND PROPERTY + OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/exportsfile) + + target_link_libraries(LLVMgold LTO -Wl,--version-script,exportsfile) + add_dependencies(LLVMgold gold_exports) +endif() diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 7ce1760..dd66eae 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -50,6 +50,7 @@ namespace { ld_plugin_add_input_file add_input_file = NULL; ld_plugin_add_input_library add_input_library = NULL; ld_plugin_set_extra_library_path set_extra_library_path = NULL; + ld_plugin_get_view get_view = NULL; ld_plugin_message message = discard_message; int api_version = 0; @@ -73,7 +74,6 @@ namespace options { static generate_bc generate_bc_file = BC_NO; static std::string bc_path; static std::string obj_path; - static std::vector pass_through; static std::string extra_library_path; static std::string triple; static std::string mcpu; @@ -96,9 +96,6 @@ namespace options { mcpu = opt.substr(strlen("mcpu=")); } else if (opt.startswith("extra-library-path=")) { extra_library_path = opt.substr(strlen("extra_library_path=")); - } else if (opt.startswith("pass-through=")) { - llvm::StringRef item = opt.substr(strlen("pass-through=")); - pass_through.push_back(item.str()); } else if (opt.startswith("mtriple=")) { triple = opt.substr(strlen("mtriple=")); } else if (opt.startswith("obj-path=")) { @@ -209,6 +206,9 @@ ld_plugin_status onload(ld_plugin_tv *tv) { case LDPT_SET_EXTRA_LIBRARY_PATH: set_extra_library_path = tv->tv_u.tv_set_extra_library_path; break; + case LDPT_GET_VIEW: + get_view = tv->tv_u.tv_get_view; + break; case LDPT_MESSAGE: message = tv->tv_u.tv_message; break; @@ -236,60 +236,23 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, int *claimed) { lto_module_t M; - if (file->offset) { - // Gold has found what might be IR part-way inside of a file, such as - // an .a archive. - if (lseek(file->fd, file->offset, SEEK_SET) == -1) { - (*message)(LDPL_ERROR, - "Failed to seek to archive member of %s at offset %d: %s\n", - file->name, - file->offset, sys::StrError(errno).c_str()); - return LDPS_ERR; - } - void *buf = malloc(file->filesize); - if (!buf) { - (*message)(LDPL_ERROR, - "Failed to allocate buffer for archive member of size: %d\n", - file->filesize); - return LDPS_ERR; - } - if (read(file->fd, buf, file->filesize) != file->filesize) { - (*message)(LDPL_ERROR, - "Failed to read archive member of %s at offset %d: %s\n", - file->name, - file->offset, - sys::StrError(errno).c_str()); - free(buf); - return LDPS_ERR; - } - if (!lto_module_is_object_file_in_memory(buf, file->filesize)) { - free(buf); - return LDPS_OK; - } - M = lto_module_create_from_memory(buf, file->filesize); - if (!M) { - (*message)(LDPL_ERROR, "Failed to create LLVM module: %s", - lto_get_error_message()); + if (get_view) { + const void *view; + if (get_view(file->handle, &view) != LDPS_OK) { + (*message)(LDPL_ERROR, "Failed to get a view of %s", file->name); return LDPS_ERR; } - free(buf); + M = lto_module_create_from_memory(view, file->filesize); + } else if (file->offset) { + // Gold has found what might be IR part-way inside of a file, such as + // an .a archive. + M = lto_module_create_from_fd_at_offset(file->fd, file->name, -1, + file->filesize, file->offset); } else { - // FIXME: We should not need to pass -1 as the file size, but there - // is a bug in BFD that causes it to pass 0 to us. Remove this once - // that is fixed. - off_t size = file->filesize ? file->filesize : -1; - - // FIXME: We should not need to reset the position in the file, but there - // is a bug in BFD. Remove this once that is fixed. - off_t old_pos = lseek(file->fd, 0, SEEK_CUR); - - lseek(file->fd, 0, SEEK_SET); - M = lto_module_create_from_fd(file->fd, file->name, size); - - lseek(file->fd, old_pos, SEEK_SET); - if (!M) - return LDPS_OK; + M = lto_module_create_from_fd(file->fd, file->name, file->filesize); } + if (!M) + return LDPS_OK; *claimed = 1; Modules.resize(Modules.size() + 1); @@ -446,38 +409,10 @@ static ld_plugin_status all_symbols_read_hook(void) { exit(0); } size_t bufsize = 0; - const char *buffer = static_cast(lto_codegen_compile(code_gen, - &bufsize)); - - std::string ErrMsg; - const char *objPath; - sys::Path uniqueObjPath("/tmp/llvmgold.o"); - if (!options::obj_path.empty()) { - objPath = options::obj_path.c_str(); - } else { - if (uniqueObjPath.createTemporaryFileOnDisk(true, &ErrMsg)) { - (*message)(LDPL_ERROR, "%s", ErrMsg.c_str()); - return LDPS_ERR; - } - objPath = uniqueObjPath.c_str(); - } - tool_output_file objFile(objPath, ErrMsg, - raw_fd_ostream::F_Binary); - if (!ErrMsg.empty()) { - (*message)(LDPL_ERROR, "%s", ErrMsg.c_str()); - return LDPS_ERR; - } - - objFile.os().write(buffer, bufsize); - objFile.os().close(); - if (objFile.os().has_error()) { - (*message)(LDPL_ERROR, "Error writing output file '%s'", - objPath); - objFile.os().clear_error(); - return LDPS_ERR; + if (lto_codegen_compile_to_file(code_gen, &objPath)) { + (*message)(LDPL_ERROR, "Could not produce a combined object file\n"); } - objFile.keep(); lto_codegen_dispose(code_gen); for (std::list::iterator I = Modules.begin(), @@ -500,24 +435,6 @@ static ld_plugin_status all_symbols_read_hook(void) { return LDPS_ERR; } - for (std::vector::iterator i = options::pass_through.begin(), - e = options::pass_through.end(); - i != e; ++i) { - std::string &item = *i; - const char *item_p = item.c_str(); - if (llvm::StringRef(item).startswith("-l")) { - if (add_input_library(item_p + 2) != LDPS_OK) { - (*message)(LDPL_ERROR, "Unable to add library to the link."); - return LDPS_ERR; - } - } else { - if (add_input_file(item_p) != LDPS_OK) { - (*message)(LDPL_ERROR, "Unable to add .o file to the link."); - return LDPS_ERR; - } - } - } - if (options::obj_path.empty()) Cleanup.push_back(sys::Path(objPath)); diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index bb426a9..a36b6d7 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -99,6 +99,9 @@ cl::opt NoVerify("disable-verify", cl::Hidden, cl::opt DisableDotLoc("disable-dot-loc", cl::Hidden, cl::desc("Do not use .loc entries")); +cl::opt DisableCFI("disable-cfi", cl::Hidden, + cl::desc("Do not use .cfi_* directives")); + static cl::opt DisableRedZone("disable-red-zone", cl::desc("Do not emit code that uses the red zone."), @@ -207,7 +210,7 @@ int main(int argc, char **argv) { InitializeAllAsmParsers(); cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); - + // Load the module to be compiled... SMDiagnostic Err; std::auto_ptr M; @@ -271,25 +274,21 @@ int main(int argc, char **argv) { FeaturesStr = Features.getString(); } - std::auto_ptr + std::auto_ptr target(TheTarget->createTargetMachine(TheTriple.getTriple(), FeaturesStr)); assert(target.get() && "Could not allocate target machine!"); TargetMachine &Target = *target.get(); if (DisableDotLoc) Target.setMCUseLoc(false); - if (TheTriple.getOS() == Triple::Darwin) { - switch (TheTriple.getDarwinMajorNumber()) { - case 7: - case 8: - case 9: - // disable .loc support for older darwin OS. - Target.setMCUseLoc(false); - break; - default: - break; - } - } + + if (DisableCFI) + Target.setMCUseCFI(false); + + // Disable .loc support for older OS X versions. + if (TheTriple.isMacOSX() && + TheTriple.isMacOSXVersionLT(10, 6)) + Target.setMCUseLoc(false); // Figure out where we are going to send the output... OwningPtr Out @@ -338,6 +337,9 @@ int main(int argc, char **argv) { return 1; } + // Before executing passes, print the final values of the LLVM options. + cl::PrintOptionValues(); + PM.run(mod); } diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index a756459..014925c 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -133,6 +133,7 @@ int main(int argc, char **argv, char * const *envp) { // If we have a native target, initialize it to ensure it is linked in and // usable by the JIT. InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); cl::ParseCommandLineOptions(argc, argv, "llvm interpreter & dynamic compiler\n"); diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 980f278..9a92671 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -471,11 +471,11 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) { } static void PrintSize(double Bits) { - fprintf(stderr, "%.2f/%.2fB/%lluW", Bits, Bits/8,(unsigned long long)Bits/32); + fprintf(stderr, "%.2f/%.2fB/%luW", Bits, Bits/8,(unsigned long)(Bits/32)); } static void PrintSize(uint64_t Bits) { - fprintf(stderr, "%llub/%.2fB/%lluW", (unsigned long long)Bits, - (double)Bits/8, (unsigned long long)Bits/32); + fprintf(stderr, "%lub/%.2fB/%luW", (unsigned long)Bits, + (double)Bits/8, (unsigned long)(Bits/32)); } @@ -601,8 +601,8 @@ static int AnalyzeBitcode() { for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) { const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second]; - fprintf(stderr, "\t\t%7d %9llu ", RecStats.NumInstances, - (unsigned long long)RecStats.TotalBits); + fprintf(stderr, "\t\t%7d %9lu ", RecStats.NumInstances, + (unsigned long)RecStats.TotalBits); if (RecStats.NumAbbrev) fprintf(stderr, "%7.2f ", diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt index b6f4289..bc23a64 100644 --- a/tools/llvm-config/CMakeLists.txt +++ b/tools/llvm-config/CMakeLists.txt @@ -7,7 +7,7 @@ endif( NOT PERL_FOUND ) set(PERL ${PERL_EXECUTABLE}) set(VERSION PACKAGE_VERSION) -set(PREFIX ${LLVM_BINARY_DIR}) # TODO: Root for `make install'. +set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(abs_top_srcdir ${LLVM_MAIN_SRC_DIR}) set(abs_top_builddir ${LLVM_BINARY_DIR}) execute_process(COMMAND date @@ -27,6 +27,7 @@ endif( IS_BIG_ENDIAN ) set(SHLIBEXT ${LTDL_SHLIB_EXT}) #EXEEXT already set. set(OS "${CMAKE_SYSTEM}") +set(target "${TARGET_TRIPLE}") set(ARCH "${LLVM_NATIVE_ARCH}") get_system_libs(LLVM_SYSTEM_LIBS_LIST) @@ -54,9 +55,9 @@ configure_file( @ONLY ) -set(LIBDEPS ${CMAKE_CURRENT_BINARY_DIR}/LibDeps.txt) -set(LIBDEPS_TMP ${CMAKE_CURRENT_BINARY_DIR}/LibDeps.txt.tmp) -set(FINAL_LIBDEPS ${CMAKE_CURRENT_BINARY_DIR}/FinalLibDeps.txt) +set(LIBDEPS LibDeps.txt) +set(LIBDEPS_TMP LibDeps.txt.tmp) +set(FINAL_LIBDEPS FinalLibDeps.txt) set(LLVM_CONFIG ${LLVM_TOOLS_BINARY_DIR}/llvm-config) set(LLVM_CONFIG_IN ${CMAKE_CURRENT_BINARY_DIR}/llvm-config.in) @@ -90,9 +91,9 @@ add_custom_command(OUTPUT ${FINAL_LIBDEPS} DEPENDS ${LIBDEPS} COMMENT "Checking for cyclic dependencies between LLVM libraries.") -set(C_FLGS "${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") -set(CXX_FLGS "${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") -set(CPP_FLGS "${CMAKE_CPP_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +set(C_FLGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +set(CXX_FLGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +set(CPP_FLGS "${CMAKE_CPP_FLAGS} ${CMAKE_CPP_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") # We don't want certain flags on the output of # llvm-config --cflags --cxxflags @@ -106,17 +107,18 @@ remove_option_from_llvm_config("-Wall") remove_option_from_llvm_config("-W") add_custom_command(OUTPUT ${LLVM_CONFIG} - COMMAND echo 's!@LLVM_CPPFLAGS@!${CPP_FLGS}!' > temp.sed - COMMAND echo 's!@LLVM_CFLAGS@!${C_FLGS}!' >> temp.sed - COMMAND echo 's!@LLVM_CXXFLAGS@!${CXX_FLGS}!' >> temp.sed + COMMAND echo s!@LLVM_CPPFLAGS@!${CPP_FLGS}! > temp.sed + COMMAND echo s!@LLVM_CFLAGS@!${C_FLGS}! >> temp.sed + COMMAND echo s!@LLVM_CXXFLAGS@!${CXX_FLGS}! >> temp.sed # TODO: Use general flags for linking! not just for shared libs: - COMMAND echo 's!@LLVM_LDFLAGS@!${CMAKE_SHARED_LINKER_FLAGS}!' >> temp.sed - COMMAND echo 's!@LIBS@!${LLVM_SYSTEM_LIBS}!' >> temp.sed - COMMAND echo 's!@LLVM_BUILDMODE@!${CMAKE_BUILD_TYPE}!' >> temp.sed + COMMAND echo s!@LLVM_LDFLAGS@!${CMAKE_SHARED_LINKER_FLAGS}! >> temp.sed + COMMAND echo s!@LIBS@!${LLVM_SYSTEM_LIBS}! >> temp.sed + COMMAND echo s!@LLVM_BUILDMODE@!${CMAKE_BUILD_TYPE}! >> temp.sed COMMAND sed -f temp.sed < ${LLVM_CONFIG_IN} > ${LLVM_CONFIG} COMMAND ${CMAKE_COMMAND} -E remove -f temp.sed COMMAND cat ${FINAL_LIBDEPS} >> ${LLVM_CONFIG} COMMAND chmod +x ${LLVM_CONFIG} + VERBATIM DEPENDS ${FINAL_LIBDEPS} ${LLVM_CONFIG_IN} COMMENT "Building llvm-config script." ) @@ -140,7 +142,7 @@ install(FILES ${LLVM_CONFIG} # Regeneration of library dependencies. -# See the comments at the end of cmake/modules/LLVMConfig.cmake for +# See the comments at the end of cmake/modules/LLVM-Config.cmake for # notes and guidelines. set(LLVMLibDeps ${LLVM_MAIN_SRC_DIR}/cmake/modules/LLVMLibDeps.cmake) diff --git a/tools/llvm-diff/CMakeLists.txt b/tools/llvm-diff/CMakeLists.txt index f6d65c9..c59d69e 100644 --- a/tools/llvm-diff/CMakeLists.txt +++ b/tools/llvm-diff/CMakeLists.txt @@ -2,5 +2,7 @@ set(LLVM_LINK_COMPONENTS support asmparser bitreader) add_llvm_tool(llvm-diff llvm-diff.cpp + DiffConsumer.cpp + DiffLog.cpp DifferenceEngine.cpp ) diff --git a/tools/llvm-diff/DiffConsumer.cpp b/tools/llvm-diff/DiffConsumer.cpp new file mode 100644 index 0000000..c23e8fb --- /dev/null +++ b/tools/llvm-diff/DiffConsumer.cpp @@ -0,0 +1,209 @@ +//===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files implements the the LLVM difference Consumer +// +//===----------------------------------------------------------------------===// + +#include "DiffConsumer.h" + +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +static void ComputeNumbering(Function *F, DenseMap &Numbering){ + unsigned IN = 0; + + // Arguments get the first numbers. + for (Function::arg_iterator + AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) + if (!AI->hasName()) + Numbering[&*AI] = IN++; + + // Walk the basic blocks in order. + for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) { + if (!FI->hasName()) + Numbering[&*FI] = IN++; + + // Walk the instructions in order. + for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) + // void instructions don't get numbers. + if (!BI->hasName() && !BI->getType()->isVoidTy()) + Numbering[&*BI] = IN++; + } + + assert(!Numbering.empty() && "asked for numbering but numbering was no-op"); +} + + +void DiffConsumer::printValue(Value *V, bool isL) { + if (V->hasName()) { + out << (isa(V) ? '@' : '%') << V->getName(); + return; + } + if (V->getType()->isVoidTy()) { + if (isa(V)) { + out << "store to "; + printValue(cast(V)->getPointerOperand(), isL); + } else if (isa(V)) { + out << "call to "; + printValue(cast(V)->getCalledValue(), isL); + } else if (isa(V)) { + out << "invoke to "; + printValue(cast(V)->getCalledValue(), isL); + } else { + out << *V; + } + return; + } + + unsigned N = contexts.size(); + while (N > 0) { + --N; + DiffContext &ctxt = contexts[N]; + if (!ctxt.IsFunction) continue; + if (isL) { + if (ctxt.LNumbering.empty()) + ComputeNumbering(cast(ctxt.L), ctxt.LNumbering); + out << '%' << ctxt.LNumbering[V]; + return; + } else { + if (ctxt.RNumbering.empty()) + ComputeNumbering(cast(ctxt.R), ctxt.RNumbering); + out << '%' << ctxt.RNumbering[V]; + return; + } + } + + out << ""; +} + +void DiffConsumer::header() { + if (contexts.empty()) return; + for (SmallVectorImpl::iterator + I = contexts.begin(), E = contexts.end(); I != E; ++I) { + if (I->Differences) continue; + if (isa(I->L)) { + // Extra newline between functions. + if (Differences) out << "\n"; + + Function *L = cast(I->L); + Function *R = cast(I->R); + if (L->getName() != R->getName()) + out << "in function " << L->getName() + << " / " << R->getName() << ":\n"; + else + out << "in function " << L->getName() << ":\n"; + } else if (isa(I->L)) { + BasicBlock *L = cast(I->L); + BasicBlock *R = cast(I->R); + if (L->hasName() && R->hasName() && L->getName() == R->getName()) + out << " in block %" << L->getName() << ":\n"; + else { + out << " in block "; + printValue(L, true); + out << " / "; + printValue(R, false); + out << ":\n"; + } + } else if (isa(I->L)) { + out << " in instruction "; + printValue(I->L, true); + out << " / "; + printValue(I->R, false); + out << ":\n"; + } + + I->Differences = true; + } +} + +void DiffConsumer::indent() { + unsigned N = Indent; + while (N--) out << ' '; +} + +bool DiffConsumer::hadDifferences() const { + return Differences; +} + +void DiffConsumer::enterContext(Value *L, Value *R) { + contexts.push_back(DiffContext(L, R)); + Indent += 2; +} + +void DiffConsumer::exitContext() { + Differences |= contexts.back().Differences; + contexts.pop_back(); + Indent -= 2; +} + +void DiffConsumer::log(StringRef text) { + header(); + indent(); + out << text << '\n'; +} + +void DiffConsumer::logf(const LogBuilder &Log) { + header(); + indent(); + + unsigned arg = 0; + + StringRef format = Log.getFormat(); + while (true) { + size_t percent = format.find('%'); + if (percent == StringRef::npos) { + out << format; + break; + } + assert(format[percent] == '%'); + + if (percent > 0) out << format.substr(0, percent); + + switch (format[percent+1]) { + case '%': out << '%'; break; + case 'l': printValue(Log.getArgument(arg++), true); break; + case 'r': printValue(Log.getArgument(arg++), false); break; + default: llvm_unreachable("unknown format character"); + } + + format = format.substr(percent+2); + } + + out << '\n'; +} + +void DiffConsumer::logd(const DiffLogBuilder &Log) { + header(); + + for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) { + indent(); + switch (Log.getLineKind(I)) { + case DC_match: + out << " "; + Log.getLeft(I)->dump(); + //printValue(Log.getLeft(I), true); + break; + case DC_left: + out << "< "; + Log.getLeft(I)->dump(); + //printValue(Log.getLeft(I), true); + break; + case DC_right: + out << "> "; + Log.getRight(I)->dump(); + //printValue(Log.getRight(I), false); + break; + } + //out << "\n"; + } +} diff --git a/tools/llvm-diff/DiffConsumer.h b/tools/llvm-diff/DiffConsumer.h new file mode 100644 index 0000000..b95d427 --- /dev/null +++ b/tools/llvm-diff/DiffConsumer.h @@ -0,0 +1,92 @@ +//===-- DiffConsumer.h - Difference Consumer --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the interface to the LLVM difference Consumer +// +//===----------------------------------------------------------------------===// + +#ifndef _LLVM_DIFFCONSUMER_H_ +#define _LLVM_DIFFCONSUMER_H_ + +#include "DiffLog.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Casting.h" + +namespace llvm { + class Module; + class Value; + class Function; + + /// The interface for consumers of difference data. + class Consumer { + public: + /// Record that a local context has been entered. Left and + /// Right are IR "containers" of some sort which are being + /// considered for structural equivalence: global variables, + /// functions, blocks, instructions, etc. + virtual void enterContext(Value *Left, Value *Right) = 0; + + /// Record that a local context has been exited. + virtual void exitContext() = 0; + + /// Record a difference within the current context. + virtual void log(StringRef Text) = 0; + + /// Record a formatted difference within the current context. + virtual void logf(const LogBuilder &Log) = 0; + + /// Record a line-by-line instruction diff. + virtual void logd(const DiffLogBuilder &Log) = 0; + + protected: + virtual ~Consumer() {} + }; + + class DiffConsumer : public Consumer { + private: + struct DiffContext { + DiffContext(Value *L, Value *R) + : L(L), R(R), Differences(false), IsFunction(isa(L)) {} + Value *L; + Value *R; + bool Differences; + bool IsFunction; + DenseMap LNumbering; + DenseMap RNumbering; + }; + + raw_ostream &out; + Module *LModule; + Module *RModule; + SmallVector contexts; + bool Differences; + unsigned Indent; + + void printValue(Value *V, bool isL); + void header(); + void indent(); + + public: + DiffConsumer(Module *L, Module *R) + : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {} + + bool hadDifferences() const; + void enterContext(Value *L, Value *R); + void exitContext(); + void log(StringRef text); + void logf(const LogBuilder &Log); + void logd(const DiffLogBuilder &Log); + }; +} + +#endif diff --git a/tools/llvm-diff/DiffLog.cpp b/tools/llvm-diff/DiffLog.cpp new file mode 100644 index 0000000..9cc0c88 --- /dev/null +++ b/tools/llvm-diff/DiffLog.cpp @@ -0,0 +1,53 @@ +//===-- DiffLog.h - Difference Log Builder and accessories ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the interface to the LLVM difference log builder. +// +//===----------------------------------------------------------------------===// + +#include "DiffLog.h" +#include "DiffConsumer.h" + +#include "llvm/Instructions.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +using namespace llvm; + +LogBuilder::~LogBuilder() { + consumer.logf(*this); +} + +StringRef LogBuilder::getFormat() const { return Format; } + +unsigned LogBuilder::getNumArguments() const { return Arguments.size(); } +Value *LogBuilder::getArgument(unsigned I) const { return Arguments[I]; } + +DiffLogBuilder::~DiffLogBuilder() { consumer.logd(*this); } + +void DiffLogBuilder::addMatch(Instruction *L, Instruction *R) { + Diff.push_back(DiffRecord(L, R)); +} +void DiffLogBuilder::addLeft(Instruction *L) { + // HACK: VS 2010 has a bug in the stdlib that requires this. + Diff.push_back(DiffRecord(L, DiffRecord::second_type(0))); +} +void DiffLogBuilder::addRight(Instruction *R) { + // HACK: VS 2010 has a bug in the stdlib that requires this. + Diff.push_back(DiffRecord(DiffRecord::first_type(0), R)); +} + +unsigned DiffLogBuilder::getNumLines() const { return Diff.size(); } + +DiffChange DiffLogBuilder::getLineKind(unsigned I) const { + return (Diff[I].first ? (Diff[I].second ? DC_match : DC_left) + : DC_right); +} +Instruction *DiffLogBuilder::getLeft(unsigned I) const { return Diff[I].first; } +Instruction *DiffLogBuilder::getRight(unsigned I) const { return Diff[I].second; } diff --git a/tools/llvm-diff/DiffLog.h b/tools/llvm-diff/DiffLog.h new file mode 100644 index 0000000..43e318a --- /dev/null +++ b/tools/llvm-diff/DiffLog.h @@ -0,0 +1,80 @@ +//===-- DiffLog.h - Difference Log Builder and accessories ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the interface to the LLVM difference log builder. +// +//===----------------------------------------------------------------------===// + +#ifndef _LLVM_DIFFLOG_H_ +#define _LLVM_DIFFLOG_H_ + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { + class Instruction; + class Value; + class Consumer; + + /// Trichotomy assumption + enum DiffChange { DC_match, DC_left, DC_right }; + + /// A temporary-object class for building up log messages. + class LogBuilder { + Consumer &consumer; + + /// The use of a stored StringRef here is okay because + /// LogBuilder should be used only as a temporary, and as a + /// temporary it will be destructed before whatever temporary + /// might be initializing this format. + StringRef Format; + + SmallVector Arguments; + + public: + LogBuilder(Consumer &c, StringRef Format) + : consumer(c), Format(Format) {} + + LogBuilder &operator<<(Value *V) { + Arguments.push_back(V); + return *this; + } + + ~LogBuilder(); + + StringRef getFormat() const; + unsigned getNumArguments() const; + Value *getArgument(unsigned I) const; + }; + + /// A temporary-object class for building up diff messages. + class DiffLogBuilder { + typedef std::pair DiffRecord; + SmallVector Diff; + + Consumer &consumer; + + public: + DiffLogBuilder(Consumer &c) : consumer(c) {} + ~DiffLogBuilder(); + + void addMatch(Instruction *L, Instruction *R); + // HACK: VS 2010 has a bug in the stdlib that requires this. + void addLeft(Instruction *L); + void addRight(Instruction *R); + + unsigned getNumLines() const; + DiffChange getLineKind(unsigned I) const; + Instruction *getLeft(unsigned I) const; + Instruction *getRight(unsigned I) const; + }; + +} + +#endif diff --git a/tools/llvm-diff/DifferenceEngine.cpp b/tools/llvm-diff/DifferenceEngine.cpp index b0a24d0..ba2cec2 100644 --- a/tools/llvm-diff/DifferenceEngine.cpp +++ b/tools/llvm-diff/DifferenceEngine.cpp @@ -14,6 +14,7 @@ #include "DifferenceEngine.h" +#include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/Instructions.h" #include "llvm/Module.h" @@ -266,7 +267,7 @@ class FunctionDifferenceEngine { } else if (isa(L)) { // FIXME: implement. - // This is really wierd; type uniquing is broken? + // This is really weird; type uniquing is broken? if (L->getType() != R->getType()) { if (!L->getType()->isPointerTy() || !R->getType()->isPointerTy()) { if (Complain) Engine.log("different phi types"); @@ -506,30 +507,30 @@ void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart, for (unsigned I = 0; I != NL+1; ++I) { Cur[I].Cost = I * LeftCost; for (unsigned J = 0; J != I; ++J) - Cur[I].Path.push_back(DifferenceEngine::DC_left); + Cur[I].Path.push_back(DC_left); } for (BasicBlock::iterator RI = RStart; RI != RE; ++RI) { // Initialize the first row. Next[0] = Cur[0]; Next[0].Cost += RightCost; - Next[0].Path.push_back(DifferenceEngine::DC_right); + Next[0].Path.push_back(DC_right); unsigned Index = 1; for (BasicBlock::iterator LI = LStart; LI != LE; ++LI, ++Index) { if (matchForBlockDiff(&*LI, &*RI)) { Next[Index] = Cur[Index-1]; Next[Index].Cost += MatchCost; - Next[Index].Path.push_back(DifferenceEngine::DC_match); + Next[Index].Path.push_back(DC_match); TentativeValues.insert(std::make_pair(&*LI, &*RI)); } else if (Next[Index-1].Cost <= Cur[Index].Cost) { Next[Index] = Next[Index-1]; Next[Index].Cost += LeftCost; - Next[Index].Path.push_back(DifferenceEngine::DC_left); + Next[Index].Path.push_back(DC_left); } else { Next[Index] = Cur[Index]; Next[Index].Cost += RightCost; - Next[Index].Path.push_back(DifferenceEngine::DC_right); + Next[Index].Path.push_back(DC_right); } } @@ -543,23 +544,23 @@ void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart, SmallVectorImpl &Path = Cur[NL].Path; BasicBlock::iterator LI = LStart, RI = RStart; - DifferenceEngine::DiffLogBuilder Diff(Engine); + DiffLogBuilder Diff(Engine.getConsumer()); // Drop trailing matches. - while (Path.back() == DifferenceEngine::DC_match) + while (Path.back() == DC_match) Path.pop_back(); // Skip leading matches. SmallVectorImpl::iterator PI = Path.begin(), PE = Path.end(); - while (PI != PE && *PI == DifferenceEngine::DC_match) { + while (PI != PE && *PI == DC_match) { unify(&*LI, &*RI); ++PI, ++LI, ++RI; } for (; PI != PE; ++PI) { - switch (static_cast(*PI)) { - case DifferenceEngine::DC_match: + switch (static_cast(*PI)) { + case DC_match: assert(LI != LE && RI != RE); { Instruction *L = &*LI, *R = &*RI; @@ -569,13 +570,13 @@ void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart, ++LI; ++RI; break; - case DifferenceEngine::DC_left: + case DC_left: assert(LI != LE); Diff.addLeft(&*LI); ++LI; break; - case DifferenceEngine::DC_right: + case DC_right: assert(RI != RE); Diff.addRight(&*RI); ++RI; diff --git a/tools/llvm-diff/DifferenceEngine.h b/tools/llvm-diff/DifferenceEngine.h index 6eefb06..5b4f80b 100644 --- a/tools/llvm-diff/DifferenceEngine.h +++ b/tools/llvm-diff/DifferenceEngine.h @@ -17,6 +17,8 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "DiffLog.h" +#include "DiffConsumer.h" #include @@ -32,95 +34,6 @@ namespace llvm { /// A class for performing structural comparisons of LLVM assembly. class DifferenceEngine { public: - /// A temporary-object class for building up log messages. - class LogBuilder { - DifferenceEngine &Engine; - - /// The use of a stored StringRef here is okay because - /// LogBuilder should be used only as a temporary, and as a - /// temporary it will be destructed before whatever temporary - /// might be initializing this format. - StringRef Format; - - SmallVector Arguments; - - public: - LogBuilder(DifferenceEngine &Engine, StringRef Format) - : Engine(Engine), Format(Format) {} - - LogBuilder &operator<<(Value *V) { - Arguments.push_back(V); - return *this; - } - - ~LogBuilder() { - Engine.consumer.logf(*this); - } - - StringRef getFormat() const { return Format; } - - unsigned getNumArguments() const { return Arguments.size(); } - Value *getArgument(unsigned I) const { return Arguments[I]; } - }; - - enum DiffChange { DC_match, DC_left, DC_right }; - - /// A temporary-object class for building up diff messages. - class DiffLogBuilder { - typedef std::pair DiffRecord; - SmallVector Diff; - - DifferenceEngine &Engine; - - public: - DiffLogBuilder(DifferenceEngine &Engine) : Engine(Engine) {} - ~DiffLogBuilder() { Engine.consumer.logd(*this); } - - void addMatch(Instruction *L, Instruction *R) { - Diff.push_back(DiffRecord(L, R)); - } - void addLeft(Instruction *L) { - // HACK: VS 2010 has a bug in the stdlib that requires this. - Diff.push_back(DiffRecord(L, DiffRecord::second_type(0))); - } - void addRight(Instruction *R) { - // HACK: VS 2010 has a bug in the stdlib that requires this. - Diff.push_back(DiffRecord(DiffRecord::first_type(0), R)); - } - - unsigned getNumLines() const { return Diff.size(); } - DiffChange getLineKind(unsigned I) const { - return (Diff[I].first ? (Diff[I].second ? DC_match : DC_left) - : DC_right); - } - Instruction *getLeft(unsigned I) const { return Diff[I].first; } - Instruction *getRight(unsigned I) const { return Diff[I].second; } - }; - - /// The interface for consumers of difference data. - struct Consumer { - /// Record that a local context has been entered. Left and - /// Right are IR "containers" of some sort which are being - /// considered for structural equivalence: global variables, - /// functions, blocks, instructions, etc. - virtual void enterContext(Value *Left, Value *Right) = 0; - - /// Record that a local context has been exited. - virtual void exitContext() = 0; - - /// Record a difference within the current context. - virtual void log(StringRef Text) = 0; - - /// Record a formatted difference within the current context. - virtual void logf(const LogBuilder &Log) = 0; - - /// Record a line-by-line instruction diff. - virtual void logd(const DiffLogBuilder &Log) = 0; - - protected: - virtual ~Consumer() {} - }; - /// A RAII object for recording the current context. struct Context { Context(DifferenceEngine &Engine, Value *L, Value *R) : Engine(Engine) { @@ -149,14 +62,13 @@ namespace llvm { void diff(Module *L, Module *R); void diff(Function *L, Function *R); - void log(StringRef text) { consumer.log(text); } - LogBuilder logf(StringRef text) { - return LogBuilder(*this, text); + return LogBuilder(consumer, text); } + Consumer& getConsumer() const { return consumer; } /// Installs an oracle to decide whether two global values are /// equivalent as operands. Without an oracle, global values are diff --git a/tools/llvm-diff/llvm-diff.cpp b/tools/llvm-diff/llvm-diff.cpp index b932ccc..76853f1 100644 --- a/tools/llvm-diff/llvm-diff.cpp +++ b/tools/llvm-diff/llvm-diff.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "DiffLog.h" #include "DifferenceEngine.h" -#include "llvm/Instructions.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Type.h" @@ -21,7 +21,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/IRReader.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" @@ -43,221 +42,6 @@ static Module *ReadModule(LLVMContext &Context, StringRef Name) { return M; } -namespace { - struct DiffContext { - DiffContext(Value *L, Value *R) - : L(L), R(R), Differences(false), IsFunction(isa(L)) {} - Value *L; - Value *R; - bool Differences; - bool IsFunction; - DenseMap LNumbering; - DenseMap RNumbering; - }; -} - -static void ComputeNumbering(Function *F, DenseMap &Numbering){ - unsigned IN = 0; - - // Arguments get the first numbers. - for (Function::arg_iterator - AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI) - if (!AI->hasName()) - Numbering[&*AI] = IN++; - - // Walk the basic blocks in order. - for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) { - if (!FI->hasName()) - Numbering[&*FI] = IN++; - - // Walk the instructions in order. - for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) - // void instructions don't get numbers. - if (!BI->hasName() && !BI->getType()->isVoidTy()) - Numbering[&*BI] = IN++; - } - - assert(!Numbering.empty() && "asked for numbering but numbering was no-op"); -} - -namespace { -class DiffConsumer : public DifferenceEngine::Consumer { -private: - raw_ostream &out; - Module *LModule; - Module *RModule; - SmallVector contexts; - bool Differences; - unsigned Indent; - - void printValue(Value *V, bool isL) { - if (V->hasName()) { - out << (isa(V) ? '@' : '%') << V->getName(); - return; - } - if (V->getType()->isVoidTy()) { - if (isa(V)) { - out << "store to "; - printValue(cast(V)->getPointerOperand(), isL); - } else if (isa(V)) { - out << "call to "; - printValue(cast(V)->getCalledValue(), isL); - } else if (isa(V)) { - out << "invoke to "; - printValue(cast(V)->getCalledValue(), isL); - } else { - out << *V; - } - return; - } - - unsigned N = contexts.size(); - while (N > 0) { - --N; - DiffContext &ctxt = contexts[N]; - if (!ctxt.IsFunction) continue; - if (isL) { - if (ctxt.LNumbering.empty()) - ComputeNumbering(cast(ctxt.L), ctxt.LNumbering); - out << '%' << ctxt.LNumbering[V]; - return; - } else { - if (ctxt.RNumbering.empty()) - ComputeNumbering(cast(ctxt.R), ctxt.RNumbering); - out << '%' << ctxt.RNumbering[V]; - return; - } - } - - out << ""; - } - - void header() { - if (contexts.empty()) return; - for (SmallVectorImpl::iterator - I = contexts.begin(), E = contexts.end(); I != E; ++I) { - if (I->Differences) continue; - if (isa(I->L)) { - // Extra newline between functions. - if (Differences) out << "\n"; - - Function *L = cast(I->L); - Function *R = cast(I->R); - if (L->getName() != R->getName()) - out << "in function " << L->getName() - << " / " << R->getName() << ":\n"; - else - out << "in function " << L->getName() << ":\n"; - } else if (isa(I->L)) { - BasicBlock *L = cast(I->L); - BasicBlock *R = cast(I->R); - if (L->hasName() && R->hasName() && L->getName() == R->getName()) - out << " in block %" << L->getName() << ":\n"; - else { - out << " in block "; - printValue(L, true); - out << " / "; - printValue(R, false); - out << ":\n"; - } - } else if (isa(I->L)) { - out << " in instruction "; - printValue(I->L, true); - out << " / "; - printValue(I->R, false); - out << ":\n"; - } - - I->Differences = true; - } - } - - void indent() { - unsigned N = Indent; - while (N--) out << ' '; - } - -public: - DiffConsumer(Module *L, Module *R) - : out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {} - - bool hadDifferences() const { return Differences; } - - void enterContext(Value *L, Value *R) { - contexts.push_back(DiffContext(L, R)); - Indent += 2; - } - void exitContext() { - Differences |= contexts.back().Differences; - contexts.pop_back(); - Indent -= 2; - } - - void log(StringRef text) { - header(); - indent(); - out << text << '\n'; - } - - void logf(const DifferenceEngine::LogBuilder &Log) { - header(); - indent(); - - unsigned arg = 0; - - StringRef format = Log.getFormat(); - while (true) { - size_t percent = format.find('%'); - if (percent == StringRef::npos) { - out << format; - break; - } - assert(format[percent] == '%'); - - if (percent > 0) out << format.substr(0, percent); - - switch (format[percent+1]) { - case '%': out << '%'; break; - case 'l': printValue(Log.getArgument(arg++), true); break; - case 'r': printValue(Log.getArgument(arg++), false); break; - default: llvm_unreachable("unknown format character"); - } - - format = format.substr(percent+2); - } - - out << '\n'; - } - - void logd(const DifferenceEngine::DiffLogBuilder &Log) { - header(); - - for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) { - indent(); - switch (Log.getLineKind(I)) { - case DifferenceEngine::DC_match: - out << " "; - Log.getLeft(I)->dump(); - //printValue(Log.getLeft(I), true); - break; - case DifferenceEngine::DC_left: - out << "< "; - Log.getLeft(I)->dump(); - //printValue(Log.getLeft(I), true); - break; - case DifferenceEngine::DC_right: - out << "> "; - Log.getRight(I)->dump(); - //printValue(Log.getRight(I), false); - break; - } - //out << "\n"; - } - } - -}; -} // end anonymous namespace - static void diffGlobal(DifferenceEngine &Engine, Module *L, Module *R, StringRef Name) { // Drop leading sigils from the global name. diff --git a/tools/llvm-dis/CMakeLists.txt b/tools/llvm-dis/CMakeLists.txt index d62a6b5..3125f8a 100644 --- a/tools/llvm-dis/CMakeLists.txt +++ b/tools/llvm-dis/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS bitreader) +set(LLVM_LINK_COMPONENTS bitreader analysis) set(LLVM_REQUIRES_EH 1) add_llvm_tool(llvm-dis diff --git a/tools/llvm-dis/Makefile b/tools/llvm-dis/Makefile index 22c9ecc..be71100 100644 --- a/tools/llvm-dis/Makefile +++ b/tools/llvm-dis/Makefile @@ -9,7 +9,7 @@ LEVEL = ../.. TOOLNAME = llvm-dis -LINK_COMPONENTS := bitreader +LINK_COMPONENTS := bitreader analysis # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp index b4977ce..7453d9e 100644 --- a/tools/llvm-dis/llvm-dis.cpp +++ b/tools/llvm-dis/llvm-dis.cpp @@ -19,7 +19,9 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Type.h" +#include "llvm/IntrinsicInst.h" #include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Analysis/DebugInfo.h" #include "llvm/Assembly/AssemblyAnnotationWriter.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" @@ -50,6 +52,16 @@ ShowAnnotations("show-annotations", namespace { +static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) { + OS << DL.getLine() << ":" << DL.getCol(); + if (MDNode *N = DL.getInlinedAt(getGlobalContext())) { + DebugLoc IDL = DebugLoc::getFromDILocation(N); + if (!IDL.isUnknown()) { + OS << "@"; + printDebugLoc(IDL,OS); + } + } +} class CommentWriter : public AssemblyAnnotationWriter { public: void emitFunctionAnnot(const Function *F, @@ -58,10 +70,43 @@ public: OS << '\n'; } void printInfoComment(const Value &V, formatted_raw_ostream &OS) { - if (V.getType()->isVoidTy()) return; - - OS.PadToColumn(50); - OS << "; [#uses=" << V.getNumUses() << ']'; // Output # uses + bool Padded = false; + if (!V.getType()->isVoidTy()) { + OS.PadToColumn(50); + Padded = true; + OS << "; [#uses=" << V.getNumUses() << " type=" << V.getType()->getDescription() << "]"; // Output # uses and type + } + if (const Instruction *I = dyn_cast(&V)) { + const DebugLoc &DL = I->getDebugLoc(); + if (!DL.isUnknown()) { + if (!Padded) { + OS.PadToColumn(50); + Padded = true; + OS << ";"; + } + OS << " [debug line = "; + printDebugLoc(DL,OS); + OS << "]"; + } + if (const DbgDeclareInst *DDI = dyn_cast(I)) { + DIVariable Var(DDI->getVariable()); + if (!Padded) { + OS.PadToColumn(50); + Padded = true; + OS << ";"; + } + OS << " [debug variable = " << Var.getName() << "]"; + } + else if (const DbgValueInst *DVI = dyn_cast(I)) { + DIVariable Var(DVI->getVariable()); + if (!Padded) { + OS.PadToColumn(50); + Padded = true; + OS << ";"; + } + OS << " [debug variable = " << Var.getName() << "]"; + } + } } }; diff --git a/tools/llvm-ld/llvm-ld.cpp b/tools/llvm-ld/llvm-ld.cpp index cd6ce25..6b4c3c7 100644 --- a/tools/llvm-ld/llvm-ld.cpp +++ b/tools/llvm-ld/llvm-ld.cpp @@ -552,12 +552,12 @@ int main(int argc, char **argv, char **envp) { } // Arrange for the bitcode output file to be deleted on any errors. - BitcodeOutputRemover.setFile(sys::Path(BitcodeOutputFilename)); + BitcodeOutputRemover.setFile(BitcodeOutputFilename); sys::RemoveFileOnSignal(sys::Path(BitcodeOutputFilename)); // Arrange for the output file to be deleted on any errors. if (!LinkAsLibrary) { - OutputRemover.setFile(sys::Path(OutputFilename)); + OutputRemover.setFile(OutputFilename); sys::RemoveFileOnSignal(sys::Path(OutputFilename)); } @@ -657,7 +657,7 @@ int main(int argc, char **argv, char **envp) { AssemblyFile.appendSuffix("s"); // Mark the output files for removal. - FileRemover AssemblyFileRemover(AssemblyFile); + FileRemover AssemblyFileRemover(AssemblyFile.str()); sys::RemoveFileOnSignal(AssemblyFile); // Determine the locations of the llc and gcc programs. @@ -684,7 +684,7 @@ int main(int argc, char **argv, char **envp) { CFile.appendSuffix("cbe.c"); // Mark the output files for removal. - FileRemover CFileRemover(CFile); + FileRemover CFileRemover(CFile.str()); sys::RemoveFileOnSignal(CFile); // Determine the locations of the llc and gcc programs. diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp index d98b57e..cdd1892 100644 --- a/tools/llvm-mc/Disassembler.cpp +++ b/tools/llvm-mc/Disassembler.cpp @@ -127,7 +127,8 @@ static bool ByteArrayFromString(ByteArrayTy &ByteArray, return false; } -int Disassembler::disassemble(const Target &T, const std::string &Triple, +int Disassembler::disassemble(const Target &T, TargetMachine &TM, + const std::string &Triple, MemoryBuffer &Buffer, raw_ostream &Out) { // Set up disassembler. @@ -145,7 +146,7 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple, } int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); - OwningPtr IP(T.createMCInstPrinter(AsmPrinterVariant, + OwningPtr IP(T.createMCInstPrinter(TM, AsmPrinterVariant, *AsmInfo)); if (!IP) { errs() << "error: no instruction printer for target " << Triple << '\n'; @@ -239,12 +240,12 @@ int Disassembler::disassembleEnhanced(const std::string &TS, OwningPtr inst(disassembler->createInst(byteArrayReader, 0, &ByteArray)); - ByteArray.erase (ByteArray.begin(), ByteArray.begin() + inst->byteSize()); - if (inst == 0) { errs() << "error: Didn't get an instruction\n"; return -1; } + + ByteArray.erase (ByteArray.begin(), ByteArray.begin() + inst->byteSize()); unsigned numTokens = inst->numTokens(); if ((int)numTokens < 0) { diff --git a/tools/llvm-mc/Disassembler.h b/tools/llvm-mc/Disassembler.h index b56f2e9..aaf77b5 100644 --- a/tools/llvm-mc/Disassembler.h +++ b/tools/llvm-mc/Disassembler.h @@ -19,13 +19,15 @@ namespace llvm { -class Target; class MemoryBuffer; +class Target; +class TargetMachine; class raw_ostream; class Disassembler { public: - static int disassemble(const Target &target, + static int disassemble(const Target &target, + TargetMachine &TM, const std::string &tripleString, MemoryBuffer &buffer, raw_ostream &Out); diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index 2c22bed..24cc263 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -113,6 +113,10 @@ static cl::opt NoInitialTextSection("n", cl::desc( "Don't assume assembly file starts in the text section")); +static cl::opt +SaveTempLabels("L", cl::desc( + "Don't discard temporary labels")); + enum ActionType { AC_AsLex, AC_Assemble, @@ -327,6 +331,8 @@ static int AssembleInput(const char *ProgName) { const TargetAsmInfo *tai = new TargetAsmInfo(*TM); MCContext Ctx(*MAI, tai); + if (SaveTempLabels) + Ctx.setAllowTemporaryLabels(false); OwningPtr Out(GetOutputStream()); if (!Out) @@ -342,7 +348,7 @@ static int AssembleInput(const char *ProgName) { // FIXME: There is a bit of code duplication with addPassesToEmitFile. if (FileType == OFT_AssemblyFile) { MCInstPrinter *IP = - TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI); + TheTarget->createMCInstPrinter(*TM, OutputAsmVariant, *MAI); MCCodeEmitter *CE = 0; TargetAsmBackend *TAB = 0; if (ShowEncoding) { @@ -350,7 +356,8 @@ static int AssembleInput(const char *ProgName) { TAB = TheTarget->createAsmBackend(TripleName); } Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true, - /*useLoc*/ true, IP, CE, TAB, + /*useLoc*/ true, + /*useCFI*/ true, IP, CE, TAB, ShowInst)); } else if (FileType == OFT_Null) { Str.reset(createNullStreamer(Ctx)); @@ -403,12 +410,34 @@ static int DisassembleInput(const char *ProgName, bool Enhanced) { return 1; int Res; - if (Enhanced) + if (Enhanced) { Res = Disassembler::disassembleEnhanced(TripleName, *Buffer.take(), Out->os()); - else - Res = Disassembler::disassemble(*TheTarget, TripleName, + } else { + // Package up features to be passed to target/subtarget + std::string FeaturesStr; + if (MCPU.size()) { + SubtargetFeatures Features; + Features.setCPU(MCPU); + FeaturesStr = Features.getString(); + } + + // FIXME: We shouldn't need to do this (and link in codegen). + // When we split this out, we should do it in a way that makes + // it straightforward to switch subtargets on the fly (.e.g, + // the .cpu and .code16 directives). + OwningPtr TM(TheTarget->createTargetMachine(TripleName, + FeaturesStr)); + + if (!TM) { + errs() << ProgName << ": error: could not create target for triple '" + << TripleName << "'.\n"; + return 1; + } + + Res = Disassembler::disassemble(*TheTarget, *TM, TripleName, *Buffer.take(), Out->os()); + } // Keep output if no errors. if (Res == 0) Out->keep(); diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 1fef8b6..a17624a 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -38,13 +38,13 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetSelect.h" #include #include #include #include -#include using namespace llvm; using namespace object; @@ -182,9 +182,21 @@ static void DisassembleInput(const StringRef &Filename) { return; } + // FIXME: We shouldn't need to do this (and link in codegen). + // When we split this out, we should do it in a way that makes + // it straightforward to switch subtargets on the fly (.e.g, + // the .cpu and .code16 directives). + std::string FeaturesStr; + OwningPtr TM(TheTarget->createTargetMachine(TripleName, + FeaturesStr)); + if (!TM) { + errs() << "error: could not create target for triple " << TripleName << "\n"; + return; + } + int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); OwningPtr IP(TheTarget->createMCInstPrinter( - AsmPrinterVariant, *AsmInfo)); + *TM, AsmPrinterVariant, *AsmInfo)); if (!IP) { errs() << "error: no instruction printer for target " << TripleName << '\n'; return; diff --git a/tools/llvm-rtdyld/CMakeLists.txt b/tools/llvm-rtdyld/CMakeLists.txt new file mode 100644 index 0000000..17e2c3e --- /dev/null +++ b/tools/llvm-rtdyld/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC object RuntimeDyld JIT) + +add_llvm_tool(llvm-rtdyld + llvm-rtdyld.cpp + ) diff --git a/tools/llvm-rtdyld/Makefile b/tools/llvm-rtdyld/Makefile new file mode 100644 index 0000000..0d57277 --- /dev/null +++ b/tools/llvm-rtdyld/Makefile @@ -0,0 +1,23 @@ +##===- tools/llvm-rtdyld/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +TOOLNAME = llvm-rtdyld + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 + +# 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_COMPONENTS := $(TARGETS_TO_BUILD) support MC object RuntimeDyld JIT + +include $(LLVM_SRC_ROOT)/Makefile.rules diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp new file mode 100644 index 0000000..ec9d652 --- /dev/null +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -0,0 +1,151 @@ +//===-- llvm-rtdyld.cpp - MCJIT Testing Tool ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a testing tool for use with the MC-JIT LLVM components. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/Object/MachOObject.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Memory.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" +using namespace llvm; +using namespace llvm::object; + +static cl::list +InputFileList(cl::Positional, cl::ZeroOrMore, + cl::desc("")); + +enum ActionType { + AC_Execute +}; + +static cl::opt +Action(cl::desc("Action to perform:"), + cl::init(AC_Execute), + cl::values(clEnumValN(AC_Execute, "execute", + "Load, link, and execute the inputs."), + clEnumValEnd)); + +static cl::opt +EntryPoint("entry", + cl::desc("Function to call as entry point."), + cl::init("_main")); + +/* *** */ + +// A trivial memory manager that doesn't do anything fancy, just uses the +// support library allocation routines directly. +class TrivialMemoryManager : public RTDyldMemoryManager { +public: + SmallVector FunctionMemory; + + uint8_t *startFunctionBody(const char *Name, uintptr_t &Size); + void endFunctionBody(const char *Name, uint8_t *FunctionStart, + uint8_t *FunctionEnd); +}; + +uint8_t *TrivialMemoryManager::startFunctionBody(const char *Name, + uintptr_t &Size) { + return (uint8_t*)sys::Memory::AllocateRWX(Size, 0, 0).base(); +} + +void TrivialMemoryManager::endFunctionBody(const char *Name, + uint8_t *FunctionStart, + uint8_t *FunctionEnd) { + uintptr_t Size = FunctionEnd - FunctionStart + 1; + FunctionMemory.push_back(sys::MemoryBlock(FunctionStart, Size)); +} + +static const char *ProgramName; + +static void Message(const char *Type, const Twine &Msg) { + errs() << ProgramName << ": " << Type << ": " << Msg << "\n"; +} + +static int Error(const Twine &Msg) { + Message("error", Msg); + return 1; +} + +/* *** */ + +static int executeInput() { + // Instantiate a dynamic linker. + TrivialMemoryManager *MemMgr = new TrivialMemoryManager; + RuntimeDyld Dyld(MemMgr); + + // If we don't have any input files, read from stdin. + if (!InputFileList.size()) + InputFileList.push_back("-"); + for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { + // Load the input memory buffer. + OwningPtr InputBuffer; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i], + InputBuffer)) + return Error("unable to read input: '" + ec.message() + "'"); + + // Load the object file into it. + if (Dyld.loadObject(InputBuffer.take())) { + return Error(Dyld.getErrorString()); + } + } + + // Resolve all the relocations we can. + Dyld.resolveRelocations(); + + // FIXME: Error out if there are unresolved relocations. + + // Get the address of the entry point (_main by default). + void *MainAddress = Dyld.getSymbolAddress(EntryPoint); + if (MainAddress == 0) + return Error("no definition for '" + EntryPoint + "'"); + + // Invalidate the instruction cache for each loaded function. + for (unsigned i = 0, e = MemMgr->FunctionMemory.size(); i != e; ++i) { + sys::MemoryBlock &Data = MemMgr->FunctionMemory[i]; + // Make sure the memory is executable. + std::string ErrorStr; + sys::Memory::InvalidateInstructionCache(Data.base(), Data.size()); + if (!sys::Memory::setExecutable(Data, &ErrorStr)) + return Error("unable to mark function executable: '" + ErrorStr + "'"); + } + + // Dispatch to _main(). + errs() << "loaded '" << EntryPoint << "' at: " << (void*)MainAddress << "\n"; + + int (*Main)(int, const char**) = + (int(*)(int,const char**)) uintptr_t(MainAddress); + const char **Argv = new const char*[2]; + // Use the name of the first input object module as argv[0] for the target. + Argv[0] = InputFileList[0].c_str(); + Argv[1] = 0; + return Main(1, Argv); +} + +int main(int argc, char **argv) { + ProgramName = argv[0]; + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n"); + + switch (Action) { + default: + case AC_Execute: + return executeInput(); + } + + return 0; +} diff --git a/tools/llvm-stub/llvm-stub.c b/tools/llvm-stub/llvm-stub.c index 31c2d09..69cd6ed 100644 --- a/tools/llvm-stub/llvm-stub.c +++ b/tools/llvm-stub/llvm-stub.c @@ -64,7 +64,7 @@ int main(int argc, char** argv) { memcpy((char **)Args+2, argv+1, sizeof(char*)*argc); /* Run the JIT. */ -#ifndef _WIN32 +#if !defined(_WIN32) || defined(__MINGW64__) execvp(Interp, (char **)Args); /* POSIX execvp takes a char *const[]. */ #else execvp(Interp, Args); /* windows execvp takes a const char *const *. */ diff --git a/tools/llvmc/doc/LLVMC-Reference.rst b/tools/llvmc/doc/LLVMC-Reference.rst index ec9098b..041aedf 100644 --- a/tools/llvmc/doc/LLVMC-Reference.rst +++ b/tools/llvmc/doc/LLVMC-Reference.rst @@ -18,17 +18,16 @@ Introduction ============ LLVMC is a generic compiler driver, designed to be customizable and -extensible. It plays the same role for LLVM as the ``gcc`` program -does for GCC - LLVMC's job is essentially to transform a set of input -files into a set of targets depending on configuration rules and user -options. What makes LLVMC different is that these transformation rules -are completely customizable - in fact, LLVMC knows nothing about the -specifics of transformation (even the command-line options are mostly -not hard-coded) and regards the transformation structure as an -abstract graph. The structure of this graph is completely determined -by plugins, which can be either statically or dynamically linked. This -makes it possible to easily adapt LLVMC for other purposes - for -example, as a build tool for game resources. +extensible. It plays the same role for LLVM as the ``gcc`` program does for +GCC - LLVMC's job is essentially to transform a set of input files into a set of +targets depending on configuration rules and user options. What makes LLVMC +different is that these transformation rules are completely customizable - in +fact, LLVMC knows nothing about the specifics of transformation (even the +command-line options are mostly not hard-coded) and regards the transformation +structure as an abstract graph. The structure of this graph is described in +high-level TableGen code, from which an efficient C++ representation is +automatically derived. This makes it possible to adapt LLVMC for other +purposes - for example, as a build tool for game resources. Because LLVMC employs TableGen_ as its configuration language, you need to be familiar with it to customize LLVMC. @@ -36,8 +35,8 @@ need to be familiar with it to customize LLVMC. .. _TableGen: http://llvm.org/docs/TableGenFundamentals.html -Compiling with LLVMC -==================== +Compiling with ``llvmc`` +======================== LLVMC tries hard to be as compatible with ``gcc`` as possible, although there are some small differences. Most of the time, however, @@ -78,17 +77,13 @@ possible to choose the ``clang`` compiler with the ``-clang`` option. Predefined options ================== -LLVMC has some built-in options that can't be overridden in the -configuration libraries: +LLVMC has some built-in options that can't be overridden in the TableGen code: * ``-o FILE`` - Output file name. * ``-x LANGUAGE`` - Specify the language of the following input files until the next -x option. -* ``-load PLUGIN_NAME`` - Load the specified plugin DLL. Example: - ``-load $LLVM_DIR/Release/lib/LLVMCSimple.so``. - * ``-v`` - Enable verbose mode, i.e. print out all executed commands. * ``--save-temps`` - Write temporary files to the current directory and do not @@ -103,124 +98,90 @@ configuration libraries: precedence. * ``--check-graph`` - Check the compilation for common errors like mismatched - output/input language names, multiple default edges and cycles. Because of - plugins, these checks can't be performed at compile-time. Exit with code zero - if no errors were found, and return the number of found errors - otherwise. Hidden option, useful for debugging LLVMC plugins. + output/input language names, multiple default edges and cycles. Exit with code + zero if no errors were found, and return the number of found errors + otherwise. Hidden option, useful for debugging. * ``--view-graph`` - Show a graphical representation of the compilation graph and exit. Requires that you have ``dot`` and ``gv`` programs installed. Hidden - option, useful for debugging LLVMC plugins. + option, useful for debugging. * ``--write-graph`` - Write a ``compilation-graph.dot`` file in the current directory with the compilation graph description in Graphviz format (identical to the file used by the ``--view-graph`` option). The ``-o`` option can be - used to set the output file name. Hidden option, useful for debugging LLVMC - plugins. + used to set the output file name. Hidden option, useful for debugging. * ``--help``, ``--help-hidden``, ``--version`` - These options have their standard meaning. -Compiling LLVMC plugins -======================= +Compiling LLVMC-based drivers +============================= -It's easiest to start working on your own LLVMC plugin by copying the -skeleton project which lives under ``$LLVMC_DIR/plugins/Simple``:: +It's easiest to start working on your own LLVMC driver by copying the skeleton +project which lives under ``$LLVMC_DIR/examples/Skeleton``:: - $ cd $LLVMC_DIR/plugins - $ cp -r Simple MyPlugin - $ cd MyPlugin + $ cd $LLVMC_DIR/examples + $ cp -r Skeleton MyDriver + $ cd MyDriver $ ls - Makefile PluginMain.cpp Simple.td + AutoGenerated.td Hooks.cpp Main.cpp Makefile -As you can see, our basic plugin consists of only two files (not -counting the build script). ``Simple.td`` contains TableGen -description of the compilation graph; its format is documented in the -following sections. ``PluginMain.cpp`` is just a helper file used to -compile the auto-generated C++ code produced from TableGen source. It -can also contain hook definitions (see `below`__). +As you can see, our basic driver consists of only three files (not counting the +build script). ``AutoGenerated.td`` contains TableGen description of the +compilation graph; its format is documented in the following +sections. ``Hooks.cpp`` is an empty file that should be used for hook +definitions (see `below`__). ``Main.cpp`` is just a helper used to compile the +auto-generated C++ code produced from TableGen source. __ hooks_ -The first thing that you should do is to change the ``LLVMC_PLUGIN`` -variable in the ``Makefile`` to avoid conflicts (since this variable -is used to name the resulting library):: - - LLVMC_PLUGIN=MyPlugin - -It is also a good idea to rename ``Simple.td`` to something less -generic:: +The first thing that you should do is to change the ``LLVMC_BASED_DRIVER`` +variable in the ``Makefile``:: - $ mv Simple.td MyPlugin.td + LLVMC_BASED_DRIVER=MyDriver -To build your plugin as a dynamic library, just ``cd`` to its source -directory and run ``make``. The resulting file will be called -``plugin_llvmc_$(LLVMC_PLUGIN).$(DLL_EXTENSION)`` (in our case, -``plugin_llvmc_MyPlugin.so``). This library can be then loaded in with the -``-load`` option. Example:: +It can also be a good idea to put your TableGen code into a file with a less +generic name:: - $ cd $LLVMC_DIR/plugins/Simple - $ make - $ llvmc -load $LLVM_DIR/Release/lib/plugin_llvmc_Simple.so + $ touch MyDriver.td + $ vim AutoGenerated.td + [...] + include "MyDriver.td" -Compiling standalone LLVMC-based drivers -======================================== +If you have more than one TableGen source file, they all should be included from +``AutoGenerated.td``, since this file is used by the build system to generate +C++ code. -By default, the ``llvmc`` executable consists of a driver core plus several -statically linked plugins (``Base`` and ``Clang`` at the moment). You can -produce a standalone LLVMC-based driver executable by linking the core with your -own plugins. The recommended way to do this is by starting with the provided -``Skeleton`` example (``$LLVMC_DIR/example/Skeleton``):: - - $ cd $LLVMC_DIR/example/ - $ cp -r Skeleton mydriver - $ cd mydriver - $ vim Makefile - [...] - $ make +To build your driver, just ``cd`` to its source directory and run ``make``. The +resulting executable will be put into ``$LLVM_OBJ_DIR/$(BuildMode)/bin``. If you're compiling LLVM with different source and object directories, then you must perform the following additional steps before running ``make``:: # LLVMC_SRC_DIR = $LLVM_SRC_DIR/tools/llvmc/ # LLVMC_OBJ_DIR = $LLVM_OBJ_DIR/tools/llvmc/ - $ cp $LLVMC_SRC_DIR/example/mydriver/Makefile \ - $LLVMC_OBJ_DIR/example/mydriver/ - $ cd $LLVMC_OBJ_DIR/example/mydriver + $ mkdir $LLVMC_OBJ_DIR/examples/MyDriver/ + $ cp $LLVMC_SRC_DIR/examples/MyDriver/Makefile \ + $LLVMC_OBJ_DIR/examples/MyDriver/ + $ cd $LLVMC_OBJ_DIR/examples/MyDriver $ make -Another way to do the same thing is by using the following command:: - - $ cd $LLVMC_DIR - $ make LLVMC_BUILTIN_PLUGINS=MyPlugin LLVMC_BASED_DRIVER_NAME=mydriver - -This works with both srcdir == objdir and srcdir != objdir, but assumes that the -plugin source directory was placed under ``$LLVMC_DIR/plugins``. - -Sometimes, you will want a 'bare-bones' version of LLVMC that has no -built-in plugins. It can be compiled with the following command:: - - $ cd $LLVMC_DIR - $ make LLVMC_BUILTIN_PLUGINS="" - Customizing LLVMC: the compilation graph ======================================== -Each TableGen configuration file should include the common -definitions:: +Each TableGen configuration file should include the common definitions:: include "llvm/CompilerDriver/Common.td" -Internally, LLVMC stores information about possible source -transformations in form of a graph. Nodes in this graph represent -tools, and edges between two nodes represent a transformation path. A -special "root" node is used to mark entry points for the -transformations. LLVMC also assigns a weight to each edge (more on -this later) to choose between several alternative edges. +Internally, LLVMC stores information about possible source transformations in +form of a graph. Nodes in this graph represent tools, and edges between two +nodes represent a transformation path. A special "root" node is used to mark +entry points for the transformations. LLVMC also assigns a weight to each edge +(more on this later) to choose between several alternative edges. -The definition of the compilation graph (see file -``plugins/Base/Base.td`` for an example) is just a list of edges:: +The definition of the compilation graph (see file ``llvmc/src/Base.td`` for an +example) is just a list of edges:: def CompilationGraph : CompilationGraph<[ Edge<"root", "llvm_gcc_c">, @@ -245,43 +206,37 @@ The definition of the compilation graph (see file ]>; -As you can see, the edges can be either default or optional, where -optional edges are differentiated by an additional ``case`` expression -used to calculate the weight of this edge. Notice also that we refer -to tools via their names (as strings). This makes it possible to add -edges to an existing compilation graph in plugins without having to -know about all tool definitions used in the graph. - -The default edges are assigned a weight of 1, and optional edges get a -weight of 0 + 2*N where N is the number of tests that evaluated to -true in the ``case`` expression. It is also possible to provide an -integer parameter to ``inc_weight`` and ``dec_weight`` - in this case, -the weight is increased (or decreased) by the provided value instead -of the default 2. It is also possible to change the default weight of -an optional edge by using the ``default`` clause of the ``case`` +As you can see, the edges can be either default or optional, where optional +edges are differentiated by an additional ``case`` expression used to calculate +the weight of this edge. Notice also that we refer to tools via their names (as +strings). This makes it possible to add edges to an existing compilation graph +without having to know about all tool definitions used in the graph. + +The default edges are assigned a weight of 1, and optional edges get a weight of +0 + 2*N where N is the number of tests that evaluated to true in the ``case`` +expression. It is also possible to provide an integer parameter to +``inc_weight`` and ``dec_weight`` - in this case, the weight is increased (or +decreased) by the provided value instead of the default 2. Default weight of an +optional edge can be changed by using the ``default`` clause of the ``case`` construct. -When passing an input file through the graph, LLVMC picks the edge -with the maximum weight. To avoid ambiguity, there should be only one -default edge between two nodes (with the exception of the root node, -which gets a special treatment - there you are allowed to specify one -default edge *per language*). +When passing an input file through the graph, LLVMC picks the edge with the +maximum weight. To avoid ambiguity, there should be only one default edge +between two nodes (with the exception of the root node, which gets a special +treatment - there you are allowed to specify one default edge *per language*). -When multiple plugins are loaded, their compilation graphs are merged -together. Since multiple edges that have the same end nodes are not -allowed (i.e. the graph is not a multigraph), an edge defined in -several plugins will be replaced by the definition from the plugin -that was loaded last. Plugin load order can be controlled by using the -plugin priority feature described above. +When multiple compilation graphs are defined, they are merged together. Multiple +edges with the same end nodes are not allowed (i.e. the graph is not a +multigraph), and will lead to a compile-time error. -To get a visual representation of the compilation graph (useful for -debugging), run ``llvmc --view-graph``. You will need ``dot`` and -``gsview`` installed for this to work properly. +To get a visual representation of the compilation graph (useful for debugging), +run ``llvmc --view-graph``. You will need ``dot`` and ``gsview`` installed for +this to work properly. Describing options ================== -Command-line options that the plugin supports are defined by using an +Command-line options supported by the driver are defined by using an ``OptionList``:: def Options : OptionList<[ @@ -290,11 +245,10 @@ Command-line options that the plugin supports are defined by using an ... ]>; -As you can see, the option list is just a list of DAGs, where each DAG -is an option description consisting of the option name and some -properties. A plugin can define more than one option list (they are -all merged together in the end), which can be handy if one wants to -separate option groups syntactically. +As you can see, the option list is just a list of DAGs, where each DAG is an +option description consisting of the option name and some properties. More than +one option list can be defined (they are all merged together in the end), which +can be handy if one wants to separate option groups syntactically. * Possible option types: @@ -306,7 +260,7 @@ separate option groups syntactically. sign: ``-std c99``. At most one occurrence is allowed. - ``parameter_list_option`` - same as the above, but more than one option - occurence is allowed. + occurrence is allowed. - ``prefix_option`` - same as the parameter_option, but the option name and argument do not have to be separated. Example: ``-ofile``. This can be also @@ -314,7 +268,7 @@ separate option groups syntactically. (``=file`` will be interpreted as option value). At most one occurrence is allowed. - - ``prefix_list_option`` - same as the above, but more than one occurence of + - ``prefix_list_option`` - same as the above, but more than one occurrence of the option is allowed; example: ``-lm -lpthread``. - ``alias_option`` - a special option type for creating aliases. Unlike other @@ -380,42 +334,17 @@ separate option groups syntactically. Usage examples: ``(switch_option "foo", (init true))``; ``(prefix_option "bar", (init "baz"))``. - - ``extern`` - this option is defined in some other plugin, see `below`__. - - __ extern_ - -.. _extern: - -External options ----------------- - -Sometimes, when linking several plugins together, one plugin needs to -access options defined in some other plugin. Because of the way -options are implemented, such options must be marked as -``extern``. This is what the ``extern`` option property is -for. Example:: - - ... - (switch_option "E", (extern)) - ... - -If an external option has additional attributes besides 'extern', they are -ignored. See also the section on plugin `priorities`__. - -__ priorities_ - .. _case: Conditional evaluation ====================== -The 'case' construct is the main means by which programmability is -achieved in LLVMC. It can be used to calculate edge weights, program -actions and modify the shell commands to be executed. The 'case' -expression is designed after the similarly-named construct in -functional languages and takes the form ``(case (test_1), statement_1, -(test_2), statement_2, ... (test_N), statement_N)``. The statements -are evaluated only if the corresponding tests evaluate to true. +The 'case' construct is the main means by which programmability is achieved in +LLVMC. It can be used to calculate edge weights, program actions and modify the +shell commands to be executed. The 'case' expression is designed after the +similarly-named construct in functional languages and takes the form ``(case +(test_1), statement_1, (test_2), statement_2, ... (test_N), statement_N)``. The +statements are evaluated only if the corresponding tests evaluate to true. Examples:: @@ -439,20 +368,19 @@ Examples:: (switch_on "B"), "cmdline2", (default), "cmdline3") -Note the slight difference in 'case' expression handling in contexts -of edge weights and command line specification - in the second example -the value of the ``"B"`` switch is never checked when switch ``"A"`` is -enabled, and the whole expression always evaluates to ``"cmdline1"`` in -that case. +Note the slight difference in 'case' expression handling in contexts of edge +weights and command line specification - in the second example the value of the +``"B"`` switch is never checked when switch ``"A"`` is enabled, and the whole +expression always evaluates to ``"cmdline1"`` in that case. Case expressions can also be nested, i.e. the following is legal:: (case (switch_on "E"), (case (switch_on "o"), ..., (default), ...) (default), ...) -You should, however, try to avoid doing that because it hurts -readability. It is usually better to split tool descriptions and/or -use TableGen inheritance instead. +You should, however, try to avoid doing that because it hurts readability. It is +usually better to split tool descriptions and/or use TableGen inheritance +instead. * Possible tests are: @@ -526,72 +454,75 @@ use TableGen inheritance instead. Example: ``(not (or (test1), (test2), ... (testN)))``. - Writing a tool description ========================== -As was said earlier, nodes in the compilation graph represent tools, -which are described separately. A tool definition looks like this -(taken from the ``include/llvm/CompilerDriver/Tools.td`` file):: +As was said earlier, nodes in the compilation graph represent tools, which are +described separately. A tool definition looks like this (taken from the +``llvmc/src/Base.td`` file):: def llvm_gcc_cpp : Tool<[ (in_language "c++"), (out_language "llvm-assembler"), (output_suffix "bc"), - (cmd_line "llvm-g++ -c $INFILE -o $OUTFILE -emit-llvm"), + (command "llvm-g++ -c -emit-llvm"), (sink) ]>; This defines a new tool called ``llvm_gcc_cpp``, which is an alias for -``llvm-g++``. As you can see, a tool definition is just a list of -properties; most of them should be self-explanatory. The ``sink`` -property means that this tool should be passed all command-line -options that aren't mentioned in the option list. +``llvm-g++``. As you can see, a tool definition is just a list of properties; +most of them should be self-explanatory. The ``sink`` property means that this +tool should be passed all command-line options that aren't mentioned in the +option list. The complete list of all currently implemented tool properties follows. * Possible tool properties: - ``in_language`` - input language name. Can be given multiple arguments, in - case the tool supports multiple input languages. + case the tool supports multiple input languages. Used for typechecking and + mapping file extensions to tools. - ``out_language`` - output language name. Multiple output languages are - allowed. + allowed. Used for typechecking the compilation graph. - - ``output_suffix`` - output file suffix. Can also be changed - dynamically, see documentation on actions. + - ``output_suffix`` - output file suffix. Can also be changed dynamically, see + documentation on `actions`__. + +__ actions_ - - ``cmd_line`` - the actual command used to run the tool. You can - use ``$INFILE`` and ``$OUTFILE`` variables, output redirection - with ``>``, hook invocations (``$CALL``), environment variables + - ``command`` - the actual command used to run the tool. You can use output + redirection with ``>``, hook invocations (``$CALL``), environment variables (via ``$ENV``) and the ``case`` construct. - - ``join`` - this tool is a "join node" in the graph, i.e. it gets a - list of input files and joins them together. Used for linkers. + - ``join`` - this tool is a "join node" in the graph, i.e. it gets a list of + input files and joins them together. Used for linkers. - - ``sink`` - all command-line options that are not handled by other - tools are passed to this tool. + - ``sink`` - all command-line options that are not handled by other tools are + passed to this tool. - - ``actions`` - A single big ``case`` expression that specifies how - this tool reacts on command-line options (described in more detail - `below`__). + - ``actions`` - A single big ``case`` expression that specifies how this tool + reacts on command-line options (described in more detail `below`__). __ actions_ + - ``out_file_option``, ``in_file_option`` - Options appended to the + ``command`` string to designate output and input files. Default values are + ``"-o"`` and ``""``, respectively. + .. _actions: Actions ------- -A tool often needs to react to command-line options, and this is -precisely what the ``actions`` property is for. The next example -illustrates this feature:: +A tool often needs to react to command-line options, and this is precisely what +the ``actions`` property is for. The next example illustrates this feature:: def llvm_gcc_linker : Tool<[ (in_language "object-code"), (out_language "executable"), (output_suffix "out"), - (cmd_line "llvm-gcc $INFILE -o $OUTFILE"), + (command "llvm-gcc"), (join), (actions (case (not_empty "L"), (forward "L"), (not_empty "l"), (forward "l"), @@ -599,18 +530,17 @@ illustrates this feature:: [(append_cmd "-dummy1"), (append_cmd "-dummy2")]) ]>; -The ``actions`` tool property is implemented on top of the omnipresent -``case`` expression. It associates one or more different *actions* -with given conditions - in the example, the actions are ``forward``, -which forwards a given option unchanged, and ``append_cmd``, which -appends a given string to the tool execution command. Multiple actions -can be associated with a single condition by using a list of actions -(used in the example to append some dummy options). The same ``case`` -construct can also be used in the ``cmd_line`` property to modify the -tool command line. +The ``actions`` tool property is implemented on top of the omnipresent ``case`` +expression. It associates one or more different *actions* with given +conditions - in the example, the actions are ``forward``, which forwards a given +option unchanged, and ``append_cmd``, which appends a given string to the tool +execution command. Multiple actions can be associated with a single condition by +using a list of actions (used in the example to append some dummy options). The +same ``case`` construct can also be used in the ``cmd_line`` property to modify +the tool command line. -The "join" property used in the example means that this tool behaves -like a linker. +The "join" property used in the example means that this tool behaves like a +linker. The list of all possible actions follows. @@ -656,10 +586,10 @@ The list of all possible actions follows. Language map ============ -If you are adding support for a new language to LLVMC, you'll need to -modify the language map, which defines mappings from file extensions -to language names. It is used to choose the proper toolchain(s) for a -given input file set. Language map definition looks like this:: +If you are adding support for a new language to LLVMC, you'll need to modify the +language map, which defines mappings from file extensions to language names. It +is used to choose the proper toolchain(s) for a given input file set. Language +map definition looks like this:: def LanguageMap : LanguageMap< [LangToSuffixes<"c++", ["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]>, @@ -673,9 +603,7 @@ For example, without those definitions the following command wouldn't work:: llvmc: Unknown suffix: cpp The language map entries are needed only for the tools that are linked from the -root node. Since a tool can't have multiple output languages, for inner nodes of -the graph the input and output languages should match. This is enforced at -compile-time. +root node. A tool can have multiple output languages. Option preprocessor =================== @@ -686,7 +614,7 @@ implemented as switches, we might want to output a warning if the user invokes the driver with both of these options enabled. The ``OptionPreprocessor`` feature is reserved specially for these -occasions. Example (adapted from the built-in Base plugin):: +occasions. Example (adapted from ``llvm/src/Base.td.in``):: def Preprocess : OptionPreprocessor< @@ -705,7 +633,7 @@ that they are not forwarded to the compiler. If no optimization options are specified, ``-O2`` is enabled. ``OptionPreprocessor`` is basically a single big ``case`` expression, which is -evaluated only once right after the plugin is loaded. The only allowed actions +evaluated only once right after the driver is started. The only allowed actions in ``OptionPreprocessor`` are ``error``, ``warning``, and two special actions: ``unset_option`` and ``set_option``. As their names suggest, they can be used to set or unset a given option. To set an option with ``set_option``, use the @@ -726,30 +654,28 @@ More advanced topics Hooks and environment variables ------------------------------- -Normally, LLVMC executes programs from the system ``PATH``. Sometimes, -this is not sufficient: for example, we may want to specify tool paths -or names in the configuration file. This can be easily achieved via -the hooks mechanism. To write your own hooks, just add their -definitions to the ``PluginMain.cpp`` or drop a ``.cpp`` file into the -your plugin directory. Hooks should live in the ``hooks`` namespace -and have the signature ``std::string hooks::MyHookName ([const char* -Arg0 [ const char* Arg2 [, ...]]])``. They can be used from the -``cmd_line`` tool property:: +Normally, LLVMC searches for programs in the system ``PATH``. Sometimes, this is +not sufficient: for example, we may want to specify tool paths or names in the +configuration file. This can be achieved via the hooks mechanism. To write your +own hooks, add their definitions to the ``Hooks.cpp`` or drop a ``.cpp`` file +into your driver directory. Hooks should live in the ``hooks`` namespace and +have the signature ``std::string hooks::MyHookName ([const char* Arg0 [ const +char* Arg2 [, ...]]])``. They can be used from the ``command`` tool property:: - (cmd_line "$CALL(MyHook)/path/to/file -o $CALL(AnotherHook)") + (command "$CALL(MyHook)/path/to/file -o $CALL(AnotherHook)") To pass arguments to hooks, use the following syntax:: - (cmd_line "$CALL(MyHook, 'Arg1', 'Arg2', 'Arg # 3')/path/to/file -o1 -o2") + (command "$CALL(MyHook, 'Arg1', 'Arg2', 'Arg # 3')/path/to/file -o1 -o2") It is also possible to use environment variables in the same manner:: - (cmd_line "$ENV(VAR1)/path/to/file -o $ENV(VAR2)") + (command "$ENV(VAR1)/path/to/file -o $ENV(VAR2)") To change the command line string based on user-provided options use the ``case`` expression (documented `above`__):: - (cmd_line + (command (case (switch_on "E"), "llvm-g++ -E -x c $INFILE -o $OUTFILE", @@ -758,42 +684,21 @@ the ``case`` expression (documented `above`__):: __ case_ -.. _priorities: - -How plugins are loaded ----------------------- - -It is possible for LLVMC plugins to depend on each other. For example, -one can create edges between nodes defined in some other plugin. To -make this work, however, that plugin should be loaded first. To -achieve this, the concept of plugin priority was introduced. By -default, every plugin has priority zero; to specify the priority -explicitly, put the following line in your plugin's TableGen file:: - - def Priority : PluginPriority<$PRIORITY_VALUE>; - # Where PRIORITY_VALUE is some integer > 0 - -Plugins are loaded in order of their (increasing) priority, starting -with 0. Therefore, the plugin with the highest priority value will be -loaded last. - Debugging --------- -When writing LLVMC plugins, it can be useful to get a visual view of -the resulting compilation graph. This can be achieved via the command -line option ``--view-graph``. This command assumes that Graphviz_ and -Ghostview_ are installed. There is also a ``--write-graph`` option that -creates a Graphviz source file (``compilation-graph.dot``) in the -current directory. - -Another useful ``llvmc`` option is ``--check-graph``. It checks the -compilation graph for common errors like mismatched output/input -language names, multiple default edges and cycles. These checks can't -be performed at compile-time because the plugins can load code -dynamically. When invoked with ``--check-graph``, ``llvmc`` doesn't -perform any compilation tasks and returns the number of encountered -errors as its status code. +When writing LLVMC-based drivers, it can be useful to get a visual view of the +resulting compilation graph. This can be achieved via the command line option +``--view-graph`` (which assumes that Graphviz_ and Ghostview_ are +installed). There is also a ``--write-graph`` option that creates a Graphviz +source file (``compilation-graph.dot``) in the current directory. + +Another useful ``llvmc`` option is ``--check-graph``. It checks the compilation +graph for common errors like mismatched output/input language names, multiple +default edges and cycles. When invoked with ``--check-graph``, ``llvmc`` doesn't +perform any compilation tasks and returns the number of encountered errors as +its status code. In the future, these checks will be performed at compile-time +and this option will disappear. .. _Graphviz: http://www.graphviz.org/ .. _Ghostview: http://pages.cs.wisc.edu/~ghost/ @@ -821,7 +726,7 @@ accessible only in the C++ code (i.e. hooks). Use the following code:: In general, you're encouraged not to make the behaviour dependent on the executable file name, and use command-line switches instead. See for example how -the ``Base`` plugin behaves when it needs to choose the correct linker options +the ``llvmc`` program behaves when it needs to choose the correct linker options (think ``g++`` vs. ``gcc``). .. raw:: html diff --git a/tools/llvmc/doc/LLVMC-Tutorial.rst b/tools/llvmc/doc/LLVMC-Tutorial.rst index e7e8f08..fc4c124 100644 --- a/tools/llvmc/doc/LLVMC-Tutorial.rst +++ b/tools/llvmc/doc/LLVMC-Tutorial.rst @@ -17,59 +17,54 @@ Tutorial - Using LLVMC Introduction ============ -LLVMC is a generic compiler driver, which plays the same role for LLVM -as the ``gcc`` program does for GCC - the difference being that LLVMC -is designed to be more adaptable and easier to customize. Most of -LLVMC functionality is implemented via plugins, which can be loaded -dynamically or compiled in. This tutorial describes the basic usage -and configuration of LLVMC. +LLVMC is a generic compiler driver, which plays the same role for LLVM as the +``gcc`` program does for GCC - the difference being that LLVMC is designed to be +more adaptable and easier to customize. Most of LLVMC functionality is +implemented via high-level TableGen code, from which a corresponding C++ source +file is automatically generated. This tutorial describes the basic usage and +configuration of LLVMC. -Compiling with LLVMC -==================== +Using the ``llvmc`` program +=========================== -In general, LLVMC tries to be command-line compatible with ``gcc`` as -much as possible, so most of the familiar options work:: +In general, ``llvmc`` tries to be command-line compatible with ``gcc`` as much +as possible, so most of the familiar options work:: $ llvmc -O3 -Wall hello.cpp $ ./a.out hello -This will invoke ``llvm-g++`` under the hood (you can see which -commands are executed by using the ``-v`` option). For further help on -command-line LLVMC usage, refer to the ``llvmc --help`` output. +This will invoke ``llvm-g++`` under the hood (you can see which commands are +executed by using the ``-v`` option). For further help on command-line LLVMC +usage, refer to the ``llvmc --help`` output. Using LLVMC to generate toolchain drivers ========================================= -LLVMC plugins are written mostly using TableGen_, so you need to -be familiar with it to get anything done. +LLVMC-based drivers are written mostly using TableGen_, so you need to be +familiar with it to get anything done. .. _TableGen: http://llvm.org/docs/TableGenFundamentals.html Start by compiling ``example/Simple``, which is a primitive wrapper for ``gcc``:: - $ cd $LLVM_DIR/tools/llvmc - $ cp -r example/Simple plugins/Simple - - # NB: A less verbose way to compile standalone LLVMC-based drivers is - # described in the reference manual. - - $ make LLVMC_BASED_DRIVER_NAME=mygcc LLVMC_BUILTIN_PLUGINS=Simple + $ cd $LLVM_OBJ_DIR/tools/examples/Simple + $ make $ cat > hello.c - [...] - $ mygcc hello.c + #include + int main() { printf("Hello\n"); } + $ $LLVM_BIN_DIR/Simple -v hello.c + gcc hello.c -o hello.out $ ./hello.out Hello -Here we link our plugin with the LLVMC core statically to form an executable -file called ``mygcc``. It is also possible to build our plugin as a dynamic -library to be loaded by the ``llvmc`` executable (or any other LLVMC-based -standalone driver); this is described in the reference manual. - -Contents of the file ``Simple.td`` look like this:: +We have thus produced a simple driver called, appropriately, ``Simple``, from +the input TableGen file ``Simple.td``. The ``llvmc`` program itself is generated +using a similar process (see ``llvmc/src``). Contents of the file ``Simple.td`` +look like this:: // Include common definitions include "llvm/CompilerDriver/Common.td" @@ -79,37 +74,40 @@ Contents of the file ``Simple.td`` look like this:: [(in_language "c"), (out_language "executable"), (output_suffix "out"), - (cmd_line "gcc $INFILE -o $OUTFILE"), - (sink) + (command "gcc"), + (sink), + + // -o is what is used by default, out_file_option here is included for + // instructive purposes. + (out_file_option "-o") ]>; // Language map - def LanguageMap : LanguageMap<[LangToSuffixes<"c", ["c"]>]>; + def LanguageMap : LanguageMap<[(lang_to_suffixes "c", "c")]>; // Compilation graph - def CompilationGraph : CompilationGraph<[Edge<"root", "gcc">]>; + def CompilationGraph : CompilationGraph<[(edge "root", "gcc")]>; -As you can see, this file consists of three parts: tool descriptions, -language map, and the compilation graph definition. +As you can see, this file consists of three parts: tool descriptions, language +map, and the compilation graph definition. -At the heart of LLVMC is the idea of a compilation graph: vertices in -this graph are tools, and edges represent a transformation path -between two tools (for example, assembly source produced by the -compiler can be transformed into executable code by an assembler). The -compilation graph is basically a list of edges; a special node named -``root`` is used to mark graph entry points. +At the heart of LLVMC is the idea of a compilation graph: vertices in this graph +are tools, and edges represent a transformation path between two tools (for +example, assembly source produced by the compiler can be transformed into +executable code by an assembler). The compilation graph is basically a list of +edges; a special node named ``root`` is used to mark graph entry points. -Tool descriptions are represented as property lists: most properties -in the example above should be self-explanatory; the ``sink`` property -means that all options lacking an explicit description should be -forwarded to this tool. +Tool descriptions are represented as property lists: most properties in the +example above should be self-explanatory; the ``sink`` property means that all +options lacking an explicit description should be forwarded to this tool. -The ``LanguageMap`` associates a language name with a list of suffixes -and is used for deciding which toolchain corresponds to a given input -file. +The ``LanguageMap`` associates a language name with a list of suffixes and is +used for deciding which toolchain corresponds to a given input file. -To learn more about LLVMC customization, refer to the reference -manual and plugin source code in the ``plugins`` directory. +To learn more about writing your own drivers with LLVMC, refer to the reference +manual and examples in the ``examples`` directory. Of a particular interest is +the ``Skeleton`` example, which can serve as a template for your LLVMC-based +drivers. .. raw:: html diff --git a/tools/llvmc/examples/Skeleton/README b/tools/llvmc/examples/Skeleton/README index 61ff6fb..282ee15 100644 --- a/tools/llvmc/examples/Skeleton/README +++ b/tools/llvmc/examples/Skeleton/README @@ -1,6 +1,6 @@ This is a template that can be used to create your own LLVMC-based drivers. Just copy the `Skeleton` directory to the location of your preference and edit -`Skeleton/Makefile` and `Skeleton/AutoGenerated.inc`. +`Skeleton/Makefile` and `Skeleton/AutoGenerated.td`. The build system assumes that your project is based on LLVM. diff --git a/tools/llvmc/src/Base.td.in b/tools/llvmc/src/Base.td.in index 50533f1..527913c 100644 --- a/tools/llvmc/src/Base.td.in +++ b/tools/llvmc/src/Base.td.in @@ -191,7 +191,7 @@ class llvm_gcc_based output .ll (and (switch_on "emit-llvm", "S"), (not (switch_on "opt"))), [(forward "S"), (output_suffix "ll")], - // Ususally just output .bc + // Usually just output .bc (not (switch_on "fsyntax-only")), [(append_cmd "-c"), (append_cmd "-emit-llvm")], diff --git a/tools/lto/CMakeLists.txt b/tools/lto/CMakeLists.txt new file mode 100644 index 0000000..7e2c5f0 --- /dev/null +++ b/tools/lto/CMakeLists.txt @@ -0,0 +1,27 @@ +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + ipo scalaropts linker bitreader bitwriter mcdisassembler) + +add_definitions( -DLLVM_VERSION_INFO=\"${PACKAGE_VERSION}\" ) + +set(SOURCES + LTOCodeGenerator.cpp + lto.cpp + LTOModule.cpp + ) + +if( NOT WIN32 AND LLVM_ENABLE_PIC ) + set(bsl ${BUILD_SHARED_LIBS}) + set(BUILD_SHARED_LIBS ON) + add_llvm_library(LTO ${SOURCES}) + set_property(TARGET LTO PROPERTY OUTPUT_NAME "LTO") + set(BUILD_SHARED_LIBS ${bsl}) + set(LTO_STATIC_TARGET_NAME LTO_static) +else() + set(LTO_STATIC_TARGET_NAME LTO) +endif() + +if( NOT BUILD_SHARED_LIBS ) + add_llvm_library(${LTO_STATIC_TARGET_NAME} ${SOURCES}) + set_property(TARGET ${LTO_STATIC_TARGET_NAME} PROPERTY OUTPUT_NAME "LTO") +endif() diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index f72fdb0..d95f354 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -75,7 +75,6 @@ LTOCodeGenerator::LTOCodeGenerator() { InitializeAllTargets(); InitializeAllAsmPrinters(); - InitializeAllAsmParsers(); } LTOCodeGenerator::~LTOCodeGenerator() @@ -88,7 +87,17 @@ LTOCodeGenerator::~LTOCodeGenerator() bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) { - return _linker.LinkInModule(mod->getLLVVMModule(), &errMsg); + + if(mod->getLLVVMModule()->MaterializeAllPermanently(&errMsg)) + return true; + + bool ret = _linker.LinkInModule(mod->getLLVVMModule(), &errMsg); + + const std::vector &undefs = mod->getAsmUndefinedRefs(); + for (int i = 0, e = undefs.size(); i != e; ++i) + _asmUndefinedRefs[undefs[i]] = 1; + + return ret; } @@ -167,51 +176,63 @@ bool LTOCodeGenerator::writeMergedModules(const char *path, } -const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) +bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) { - // make unique temp .o file to put generated object file - sys::PathWithStatus uniqueObjPath("lto-llvm.o"); - if ( uniqueObjPath.createTemporaryFileOnDisk(false, &errMsg) ) { - uniqueObjPath.eraseFromDisk(); - return NULL; - } - sys::RemoveFileOnSignal(uniqueObjPath); - - // generate object file - bool genResult = false; - tool_output_file objFile(uniqueObjPath.c_str(), errMsg); - if (!errMsg.empty()) - return NULL; - genResult = this->generateObjectFile(objFile.os(), errMsg); - objFile.os().close(); - if (objFile.os().has_error()) { - objFile.os().clear_error(); - return NULL; - } - objFile.keep(); - if ( genResult ) { - uniqueObjPath.eraseFromDisk(); - return NULL; - } + // make unique temp .o file to put generated object file + sys::PathWithStatus uniqueObjPath("lto-llvm.o"); + if ( uniqueObjPath.createTemporaryFileOnDisk(false, &errMsg) ) { + uniqueObjPath.eraseFromDisk(); + return true; + } + sys::RemoveFileOnSignal(uniqueObjPath); + + // generate object file + bool genResult = false; + tool_output_file objFile(uniqueObjPath.c_str(), errMsg); + if (!errMsg.empty()) + return NULL; + genResult = this->generateObjectFile(objFile.os(), errMsg); + objFile.os().close(); + if (objFile.os().has_error()) { + objFile.os().clear_error(); + return true; + } + objFile.keep(); + if ( genResult ) { + uniqueObjPath.eraseFromDisk(); + return true; + } - const std::string& uniqueObjStr = uniqueObjPath.str(); - // remove old buffer if compile() called twice - delete _nativeObjectFile; + _nativeObjectPath = uniqueObjPath.str(); + *name = _nativeObjectPath.c_str(); + return false; +} - // read .o file into memory buffer - OwningPtr BuffPtr; - if (error_code ec = MemoryBuffer::getFile(uniqueObjStr.c_str(),BuffPtr)) - errMsg = ec.message(); - _nativeObjectFile = BuffPtr.take(); +const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) +{ + const char *name; + if (compile_to_file(&name, errMsg)) + return NULL; + + // remove old buffer if compile() called twice + delete _nativeObjectFile; + + // read .o file into memory buffer + OwningPtr BuffPtr; + if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) { + errMsg = ec.message(); + return NULL; + } + _nativeObjectFile = BuffPtr.take(); - // remove temp files - uniqueObjPath.eraseFromDisk(); + // remove temp files + sys::Path(_nativeObjectPath).eraseFromDisk(); - // return buffer, unless error - if ( _nativeObjectFile == NULL ) - return NULL; - *length = _nativeObjectFile->getBufferSize(); - return _nativeObjectFile->getBufferStart(); + // return buffer, unless error + if ( _nativeObjectFile == NULL ) + return NULL; + *length = _nativeObjectFile->getBufferSize(); + return _nativeObjectFile->getBufferStart(); } bool LTOCodeGenerator::determineTarget(std::string& errMsg) @@ -249,6 +270,34 @@ bool LTOCodeGenerator::determineTarget(std::string& errMsg) return false; } +void LTOCodeGenerator::applyRestriction(GlobalValue &GV, + std::vector &mustPreserveList, + SmallPtrSet &asmUsed, + Mangler &mangler) { + SmallString<64> Buffer; + mangler.getNameWithPrefix(Buffer, &GV, false); + + if (GV.isDeclaration()) + return; + if (_mustPreserveSymbols.count(Buffer)) + mustPreserveList.push_back(GV.getName().data()); + if (_asmUndefinedRefs.count(Buffer)) + asmUsed.insert(&GV); +} + +static void findUsedValues(GlobalVariable *LLVMUsed, + SmallPtrSet &UsedValues) { + if (LLVMUsed == 0) return; + + ConstantArray *Inits = dyn_cast(LLVMUsed->getInitializer()); + if (Inits == 0) return; + + for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) + if (GlobalValue *GV = + dyn_cast(Inits->getOperand(i)->stripPointerCasts())) + UsedValues.insert(GV); +} + void LTOCodeGenerator::applyScopeRestrictions() { if (_scopeRestrictionsDone) return; Module *mergedModule = _linker.getModule(); @@ -258,38 +307,47 @@ void LTOCodeGenerator::applyScopeRestrictions() { passes.add(createVerifierPass()); // mark which symbols can not be internalized - if (!_mustPreserveSymbols.empty()) { - MCContext Context(*_target->getMCAsmInfo(), NULL); - Mangler mangler(Context, *_target->getTargetData()); - std::vector mustPreserveList; - SmallString<64> Buffer; - for (Module::iterator f = mergedModule->begin(), - e = mergedModule->end(); f != e; ++f) { - Buffer.clear(); - mangler.getNameWithPrefix(Buffer, f, false); - if (!f->isDeclaration() && - _mustPreserveSymbols.count(Buffer)) - mustPreserveList.push_back(f->getName().data()); - } - for (Module::global_iterator v = mergedModule->global_begin(), - e = mergedModule->global_end(); v != e; ++v) { - Buffer.clear(); - mangler.getNameWithPrefix(Buffer, v, false); - if (!v->isDeclaration() && - _mustPreserveSymbols.count(Buffer)) - mustPreserveList.push_back(v->getName().data()); - } - for (Module::alias_iterator a = mergedModule->alias_begin(), - e = mergedModule->alias_end(); a != e; ++a) { - Buffer.clear(); - mangler.getNameWithPrefix(Buffer, a, false); - if (!a->isDeclaration() && - _mustPreserveSymbols.count(Buffer)) - mustPreserveList.push_back(a->getName().data()); - } - passes.add(createInternalizePass(mustPreserveList)); + MCContext Context(*_target->getMCAsmInfo(), NULL); + Mangler mangler(Context, *_target->getTargetData()); + std::vector mustPreserveList; + SmallPtrSet asmUsed; + + for (Module::iterator f = mergedModule->begin(), + e = mergedModule->end(); f != e; ++f) + applyRestriction(*f, mustPreserveList, asmUsed, mangler); + for (Module::global_iterator v = mergedModule->global_begin(), + e = mergedModule->global_end(); v != e; ++v) + applyRestriction(*v, mustPreserveList, asmUsed, mangler); + for (Module::alias_iterator a = mergedModule->alias_begin(), + e = mergedModule->alias_end(); a != e; ++a) + applyRestriction(*a, mustPreserveList, asmUsed, mangler); + + GlobalVariable *LLVMCompilerUsed = + mergedModule->getGlobalVariable("llvm.compiler.used"); + findUsedValues(LLVMCompilerUsed, asmUsed); + if (LLVMCompilerUsed) + LLVMCompilerUsed->eraseFromParent(); + + const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context); + std::vector asmUsed2; + for (SmallPtrSet::const_iterator i = asmUsed.begin(), + e = asmUsed.end(); i !=e; ++i) { + GlobalValue *GV = *i; + Constant *c = ConstantExpr::getBitCast(GV, i8PTy); + asmUsed2.push_back(c); } - + + llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size()); + LLVMCompilerUsed = + new llvm::GlobalVariable(*mergedModule, ATy, false, + llvm::GlobalValue::AppendingLinkage, + llvm::ConstantArray::get(ATy, asmUsed2), + "llvm.compiler.used"); + + LLVMCompilerUsed->setSection("llvm.metadata"); + + passes.add(createInternalizePass(mustPreserveList)); + // apply scope restrictions passes.run(*mergedModule); diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h index 0556520..f8fd357 100644 --- a/tools/lto/LTOCodeGenerator.h +++ b/tools/lto/LTOCodeGenerator.h @@ -19,6 +19,7 @@ #include "llvm/LLVMContext.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallPtrSet.h" #include @@ -40,12 +41,17 @@ struct LTOCodeGenerator { void addMustPreserveSymbol(const char* sym); bool writeMergedModules(const char* path, std::string& errMsg); + bool compile_to_file(const char** name, std::string& errMsg); const void* compile(size_t* length, std::string& errMsg); void setCodeGenDebugOptions(const char *opts); private: bool generateObjectFile(llvm::raw_ostream& out, std::string& errMsg); void applyScopeRestrictions(); + void applyRestriction(llvm::GlobalValue &GV, + std::vector &mustPreserveList, + llvm::SmallPtrSet &asmUsed, + llvm::Mangler &mangler); bool determineTarget(std::string& errMsg); typedef llvm::StringMap StringSet; @@ -57,9 +63,11 @@ private: bool _scopeRestrictionsDone; lto_codegen_model _codeModel; StringSet _mustPreserveSymbols; + StringSet _asmUndefinedRefs; llvm::MemoryBuffer* _nativeObjectFile; std::vector _codegenOptions; std::string _mCpu; + std::string _nativeObjectPath; }; #endif // LTO_CODE_GENERATOR_H diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index 1eac22c..8f2b1f4 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -26,11 +26,18 @@ #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/system_error.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/SubtargetFeature.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/TargetAsmParser.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetSelect.h" @@ -73,7 +80,7 @@ bool LTOModule::isTargetMatch(MemoryBuffer *buffer, const char *triplePrefix) { LTOModule::LTOModule(Module *m, TargetMachine *t) - : _module(m), _target(t), _symbolsParsed(false) + : _module(m), _target(t) { } @@ -84,32 +91,33 @@ LTOModule *LTOModule::makeLTOModule(const char *path, errMsg = ec.message(); return NULL; } - return makeLTOModule(buffer.get(), errMsg); + return makeLTOModule(buffer.take(), errMsg); } LTOModule *LTOModule::makeLTOModule(int fd, const char *path, - off_t size, + size_t size, + std::string &errMsg) { + return makeLTOModule(fd, path, size, size, 0, errMsg); +} + +LTOModule *LTOModule::makeLTOModule(int fd, const char *path, + size_t file_size, + size_t map_size, + off_t offset, std::string &errMsg) { OwningPtr buffer; - if (error_code ec = MemoryBuffer::getOpenFile(fd, path, buffer, size)) { + if (error_code ec = MemoryBuffer::getOpenFile(fd, path, buffer, file_size, + map_size, offset, false)) { errMsg = ec.message(); return NULL; } - return makeLTOModule(buffer.get(), errMsg); + return makeLTOModule(buffer.take(), 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. +/// makeBuffer - Create a MemoryBuffer from a memory range. 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)); + return MemoryBuffer::getMemBuffer(StringRef(startPtr, length), "", false); } @@ -118,17 +126,25 @@ LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length, OwningPtr buffer(makeBuffer(mem, length)); if (!buffer) return NULL; - return makeLTOModule(buffer.get(), errMsg); + return makeLTOModule(buffer.take(), errMsg); } LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, std::string &errMsg) { - InitializeAllTargets(); + static bool Initialized = false; + if (!Initialized) { + InitializeAllTargets(); + InitializeAllAsmParsers(); + Initialized = true; + } // parse bitcode buffer - OwningPtr m(ParseBitcodeFile(buffer, getGlobalContext(), &errMsg)); - if (!m) + OwningPtr m(getLazyBitcodeModule(buffer, getGlobalContext(), + &errMsg)); + if (!m) { + delete buffer; return NULL; + } std::string Triple = m->getTargetTriple(); if (Triple.empty()) @@ -139,12 +155,18 @@ LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, if (!march) return NULL; - // construct LTModule, hand over ownership of module and target + // construct LTOModule, 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); + LTOModule *Ret = new LTOModule(m.take(), target); + bool Err = Ret->ParseSymbols(); + if (Err) { + delete Ret; + return NULL; + } + return Ret; } @@ -159,16 +181,6 @@ void LTOModule::setTargetTriple(const char *triple) { 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. @@ -309,12 +321,6 @@ void LTOModule::addDefinedDataSymbol(GlobalValue *v, Mangler &mangler) { } } } - - // add external symbols referenced by this data. - for (unsigned count = 0, total = v->getNumOperands(); - count != total; ++count) { - findExternalRefs(v->getOperand(count), mangler); - } } @@ -324,10 +330,6 @@ void LTOModule::addDefinedSymbol(GlobalValue *def, Mangler &mangler, if (def->getName().startswith("llvm.")) return; - // ignore available_externally - if (def->hasAvailableExternallyLinkage()) - return; - // string is owned by _defines SmallString<64> Buffer; mangler.getNameWithPrefix(Buffer, def, false); @@ -383,7 +385,8 @@ void LTOModule::addDefinedSymbol(GlobalValue *def, Mangler &mangler, _symbols.push_back(info); } -void LTOModule::addAsmGlobalSymbol(const char *name) { +void LTOModule::addAsmGlobalSymbol(const char *name, + lto_symbol_attributes scope) { StringSet::value_type &entry = _defines.GetOrCreateValue(name); // only add new define if not already defined @@ -393,13 +396,32 @@ void LTOModule::addAsmGlobalSymbol(const char *name) { entry.setValue(1); const char *symbolName = entry.getKey().data(); uint32_t attr = LTO_SYMBOL_DEFINITION_REGULAR; - attr |= LTO_SYMBOL_SCOPE_DEFAULT; + attr |= scope; NameAndAttributes info; info.name = symbolName; info.attributes = (lto_symbol_attributes)attr; _symbols.push_back(info); } +void LTOModule::addAsmGlobalSymbolUndef(const char *name) { + StringMap::value_type &entry = + _undefines.GetOrCreateValue(name); + + _asm_undefines.push_back(entry.getKey().data()); + + // we already have the symbol + if (entry.getValue().name) + return; + + uint32_t attr = LTO_SYMBOL_DEFINITION_UNDEFINED;; + attr |= LTO_SYMBOL_SCOPE_DEFAULT; + NameAndAttributes info; + info.name = entry.getKey().data(); + info.attributes = (lto_symbol_attributes)attr; + + entry.setValue(info); +} + void LTOModule::addPotentialUndefinedSymbol(GlobalValue *decl, Mangler &mangler) { // ignore all llvm.* symbols @@ -432,41 +454,211 @@ void LTOModule::addPotentialUndefinedSymbol(GlobalValue *decl, } +namespace { + class RecordStreamer : public MCStreamer { + public: + enum State { NeverSeen, Global, Defined, DefinedGlobal, Used}; + + private: + StringMap Symbols; + + void markDefined(const MCSymbol &Symbol) { + State &S = Symbols[Symbol.getName()]; + switch (S) { + case DefinedGlobal: + case Global: + S = DefinedGlobal; + break; + case NeverSeen: + case Defined: + case Used: + S = Defined; + break; + } + } + void markGlobal(const MCSymbol &Symbol) { + State &S = Symbols[Symbol.getName()]; + switch (S) { + case DefinedGlobal: + case Defined: + S = DefinedGlobal; + break; + + case NeverSeen: + case Global: + case Used: + S = Global; + break; + } + } + void markUsed(const MCSymbol &Symbol) { + State &S = Symbols[Symbol.getName()]; + switch (S) { + case DefinedGlobal: + case Defined: + case Global: + break; + + case NeverSeen: + case Used: + S = Used; + break; + } + } + + // FIXME: mostly copied for the obj streamer. + void AddValueSymbols(const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Target: + // FIXME: What should we do in here? + break; + + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(Value); + AddValueSymbols(BE->getLHS()); + AddValueSymbols(BE->getRHS()); + break; + } + + case MCExpr::SymbolRef: + markUsed(cast(Value)->getSymbol()); + break; -// Find external symbols referenced by VALUE. This is a recursive function. -void LTOModule::findExternalRefs(Value *value, Mangler &mangler) { - if (GlobalValue *gv = dyn_cast(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; - } + case MCExpr::Unary: + AddValueSymbols(cast(Value)->getSubExpr()); + break; + } + } + + public: + typedef StringMap::const_iterator const_iterator; + + const_iterator begin() { + return Symbols.begin(); + } - // GlobalValue, even with InternalLinkage type, may have operands with - // ExternalLinkage type. Do not ignore these operands. - if (Constant *c = dyn_cast(value)) { - // Handle ConstantExpr, ConstantStruct, ConstantArry etc. - for (unsigned i = 0, e = c->getNumOperands(); i != e; ++i) - findExternalRefs(c->getOperand(i), mangler); + const_iterator end() { + return Symbols.end(); + } + + RecordStreamer(MCContext &Context) : MCStreamer(Context) {} + + virtual void ChangeSection(const MCSection *Section) {} + virtual void InitSections() {} + virtual void EmitLabel(MCSymbol *Symbol) { + Symbol->setSection(*getCurrentSection()); + markDefined(*Symbol); + } + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} + virtual void EmitThumbFunc(MCSymbol *Func) {} + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // FIXME: should we handle aliases? + markDefined(*Symbol); + } + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { + if (Attribute == MCSA_Global) + markGlobal(*Symbol); + } + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {} + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) {} + virtual void EmitCOFFSymbolStorageClass(int StorageClass) {} + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + unsigned Size , unsigned ByteAlignment) { + markDefined(*Symbol); + } + virtual void EmitCOFFSymbolType(int Type) {} + virtual void EndCOFFSymbolDef() {} + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + markDefined(*Symbol); + } + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {} + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) {} + virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {} + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) {} + virtual void EmitULEB128Value(const MCExpr *Value) {} + virtual void EmitSLEB128Value(const MCExpr *Value) {} + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, + unsigned ValueSize, + unsigned MaxBytesToEmit) {} + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) {} + virtual void EmitValueToOffset(const MCExpr *Offset, + unsigned char Value ) {} + virtual void EmitFileDirective(StringRef Filename) {} + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) {} + + virtual void EmitInstruction(const MCInst &Inst) { + // Scan for values. + for (unsigned i = Inst.getNumOperands(); i--; ) + if (Inst.getOperand(i).isExpr()) + AddValueSymbols(Inst.getOperand(i).getExpr()); + } + virtual void Finish() {} + }; +} + +bool LTOModule::addAsmGlobalSymbols(MCContext &Context) { + const std::string &inlineAsm = _module->getModuleInlineAsm(); + + OwningPtr Streamer(new RecordStreamer(Context)); + MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(inlineAsm); + SourceMgr SrcMgr; + SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); + OwningPtr Parser(createMCAsmParser(_target->getTarget(), SrcMgr, + Context, *Streamer, + *_target->getMCAsmInfo())); + OwningPtr + TAP(_target->getTarget().createAsmParser(*Parser.get(), *_target.get())); + Parser->setTargetParser(*TAP); + int Res = Parser->Run(false); + if (Res) + return true; + + for (RecordStreamer::const_iterator i = Streamer->begin(), + e = Streamer->end(); i != e; ++i) { + StringRef Key = i->first(); + RecordStreamer::State Value = i->second; + if (Value == RecordStreamer::DefinedGlobal) + addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_DEFAULT); + else if (Value == RecordStreamer::Defined) + addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_INTERNAL); + else if (Value == RecordStreamer::Global || + Value == RecordStreamer::Used) + addAsmGlobalSymbolUndef(Key.data()); } + return false; } -void LTOModule::lazyParseSymbols() { - if (_symbolsParsed) - return; +static bool isDeclaration(const GlobalValue &V) { + if (V.hasAvailableExternallyLinkage()) + return true; + if (V.isMaterializable()) + return false; + return V.isDeclaration(); +} - _symbolsParsed = true; +static bool isAliasToDeclaration(const GlobalAlias &V) { + return isDeclaration(*V.getAliasedGlobal()); +} +bool LTOModule::ParseSymbols() { // Use mangler to add GlobalPrefix to names to match linker names. MCContext Context(*_target->getMCAsmInfo(), NULL); Mangler mangler(Context, *_target->getTargetData()); // add functions for (Module::iterator f = _module->begin(); f != _module->end(); ++f) { - if (f->isDeclaration()) + if (isDeclaration(*f)) addPotentialUndefinedSymbol(f, mangler); else addDefinedFunctionSymbol(f, mangler); @@ -475,42 +667,20 @@ void LTOModule::lazyParseSymbols() { // add data for (Module::global_iterator v = _module->global_begin(), e = _module->global_end(); v != e; ++v) { - if (v->isDeclaration()) + if (isDeclaration(*v)) 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); - } + if (addAsmGlobalSymbols(Context)) + return true; // add aliases for (Module::alias_iterator i = _module->alias_begin(), e = _module->alias_end(); i != e; ++i) { - if (i->isDeclaration()) + if (isAliasToDeclaration(*i)) addPotentialUndefinedSymbol(i, mangler); else addDefinedDataSymbol(i, mangler); @@ -526,17 +696,16 @@ void LTOModule::lazyParseSymbols() { _symbols.push_back(info); } } + return false; } 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 @@ -544,7 +713,6 @@ lto_symbol_attributes LTOModule::getSymbolAttributes(uint32_t index) { } const char *LTOModule::getSymbolName(uint32_t index) { - lazyParseSymbols(); if (index < _symbols.size()) return _symbols[index].name; else diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h index 1794d81..0b64a90 100644 --- a/tools/lto/LTOModule.h +++ b/tools/lto/LTOModule.h @@ -52,7 +52,12 @@ struct LTOModule { static LTOModule* makeLTOModule(const char* path, std::string& errMsg); static LTOModule* makeLTOModule(int fd, const char *path, - off_t size, + size_t size, + std::string& errMsg); + static LTOModule* makeLTOModule(int fd, const char *path, + size_t file_size, + size_t map_size, + off_t offset, std::string& errMsg); static LTOModule* makeLTOModule(const void* mem, size_t length, std::string& errMsg); @@ -64,23 +69,27 @@ struct LTOModule { const char* getSymbolName(uint32_t index); llvm::Module * getLLVVMModule() { return _module.get(); } + const std::vector &getAsmUndefinedRefs() { + return _asm_undefines; + } private: LTOModule(llvm::Module* m, llvm::TargetMachine* t); - void lazyParseSymbols(); + bool ParseSymbols(); 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 *); + bool addAsmGlobalSymbols(llvm::MCContext &Context); + void addAsmGlobalSymbol(const char *, + lto_symbol_attributes scope); + void addAsmGlobalSymbolUndef(const char *); void addObjCClass(llvm::GlobalVariable* clgv); void addObjCCategory(llvm::GlobalVariable* clgv); void addObjCClassRef(llvm::GlobalVariable* clgv); @@ -103,11 +112,11 @@ private: llvm::OwningPtr _module; llvm::OwningPtr _target; - bool _symbolsParsed; std::vector _symbols; // _defines and _undefines only needed to disambiguate tentative definitions StringSet _defines; llvm::StringMap _undefines; + std::vector _asm_undefines; }; #endif // LTO_MODULE_H diff --git a/tools/lto/Makefile b/tools/lto/Makefile index 294c81b..46925e7 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -20,7 +20,8 @@ include $(LEVEL)/Makefile.config LINK_LIBS_IN_SHARED = 1 SHARED_LIBRARY = 1 -LINK_COMPONENTS := $(TARGETS_TO_BUILD) ipo scalaropts linker bitreader bitwriter +LINK_COMPONENTS := $(TARGETS_TO_BUILD) ipo scalaropts linker bitreader \ + bitwriter mcdisassembler include $(LEVEL)/Makefile.common diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index f48570c..dd658d1 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -95,12 +95,25 @@ lto_module_t lto_module_create(const char* path) // loads an object file from disk // returns NULL on error (check lto_get_error_message() for details) // -lto_module_t lto_module_create_from_fd(int fd, const char *path, off_t size) +lto_module_t lto_module_create_from_fd(int fd, const char *path, size_t size) { return LTOModule::makeLTOModule(fd, path, size, sLastErrorString); } // +// loads an object file from disk +// returns NULL on error (check lto_get_error_message() for details) +// +lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path, + size_t file_size, + size_t map_size, + off_t offset) +{ + return LTOModule::makeLTOModule(fd, path, file_size, map_size, + offset, sLastErrorString); +} + +// // loads an object file from memory // returns NULL on error (check lto_get_error_message() for details) // @@ -268,7 +281,7 @@ 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 +// On success 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. @@ -280,6 +293,12 @@ lto_codegen_compile(lto_code_gen_t cg, size_t* length) return cg->compile(length, sLastErrorString); } +extern bool +lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) +{ + return cg->compile_to_file(name, sLastErrorString); +} + // // Used to pass extra options to the code generator diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports index a374091..b900bfb 100644 --- a/tools/lto/lto.exports +++ b/tools/lto/lto.exports @@ -2,6 +2,7 @@ lto_get_error_message lto_get_version lto_module_create lto_module_create_from_fd +lto_module_create_from_fd_at_offset lto_module_create_from_memory lto_module_get_num_symbols lto_module_get_symbol_attribute @@ -25,3 +26,7 @@ lto_codegen_debug_options lto_codegen_set_assembler_args lto_codegen_set_assembler_path lto_codegen_set_cpu +lto_codegen_compile_to_file +LLVMCreateDisasm +LLVMDisasmDispose +LLVMDisasmInstruction diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp index c4c558d..f324259 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -49,25 +49,6 @@ static void Warning(const Twine &Msg) { /// -static int DumpHeader(MachOObject &Obj) { - // Read the header. - const macho::Header &Hdr = Obj.getHeader(); - outs() << "('cputype', " << Hdr.CPUType << ")\n"; - outs() << "('cpusubtype', " << Hdr.CPUSubtype << ")\n"; - outs() << "('filetype', " << Hdr.FileType << ")\n"; - outs() << "('num_load_commands', " << Hdr.NumLoadCommands << ")\n"; - outs() << "('load_commands_size', " << Hdr.SizeOfLoadCommands << ")\n"; - outs() << "('flag', " << Hdr.Flags << ")\n"; - - // Print extended header if 64-bit. - if (Obj.is64Bit()) { - const macho::Header64Ext &Hdr64 = Obj.getHeader64Ext(); - outs() << "('reserved', " << Hdr64.Reserved << ")\n"; - } - - return 0; -} - static void DumpSegmentCommandData(StringRef Name, uint64_t VMAddr, uint64_t VMSize, uint64_t FileOffset, uint64_t FileSize, @@ -376,8 +357,8 @@ int main(int argc, char **argv) { if (!InputObject) return Error("unable to load object: '" + ErrorStr + "'"); - if (int Res = DumpHeader(*InputObject)) - return Res; + // Print the header + InputObject->printHeader(outs()); // Print the load commands. int Res = 0; diff --git a/tools/opt/GraphPrinters.cpp b/tools/opt/GraphPrinters.cpp index 791caf5..30361f5 100644 --- a/tools/opt/GraphPrinters.cpp +++ b/tools/opt/GraphPrinters.cpp @@ -18,7 +18,7 @@ #include "llvm/Pass.h" #include "llvm/Value.h" #include "llvm/Analysis/CallGraph.h" -#include "llvm/Analysis/DominanceFrontier.h" +#include "llvm/Analysis/Dominators.h" #include "llvm/Support/ToolOutputFile.h" using namespace llvm; @@ -103,13 +103,11 @@ namespace { virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); - AU.addRequired(); } virtual bool runOnFunction(Function &F) { getAnalysis().dump(); - getAnalysis().dump(); return false; } }; diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index e55b4b3..25474c4 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -26,6 +26,7 @@ #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/PassNameParser.h" #include "llvm/Support/Signals.h" @@ -132,11 +133,11 @@ static cl::opt AnalyzeOnly("analyze", cl::desc("Only perform analysis, no optimization")); static cl::opt -PrintBreakpoints("print-breakpoints-for-testing", +PrintBreakpoints("print-breakpoints-for-testing", cl::desc("Print select breakpoints location for testing")); static cl::opt -DefaultDataLayout("default-data-layout", +DefaultDataLayout("default-data-layout", cl::desc("data layout string to use if not specified by module"), cl::value_desc("layout-string"), cl::init("")); @@ -327,7 +328,7 @@ struct BasicBlockPassPrinter : public BasicBlockPass { << "': Pass " << PassToPrint->getPassName() << ":\n"; // Get and print pass... - getAnalysisID(PassToPrint->getTypeInfo()).print(Out, + getAnalysisID(PassToPrint->getTypeInfo()).print(Out, BB.getParent()->getParent()); return false; } @@ -342,28 +343,43 @@ struct BasicBlockPassPrinter : public BasicBlockPass { char BasicBlockPassPrinter::ID = 0; -struct BreakpointPrinter : public FunctionPass { +struct BreakpointPrinter : public ModulePass { raw_ostream &Out; static char ID; BreakpointPrinter(raw_ostream &out) - : FunctionPass(ID), Out(out) { + : ModulePass(ID), Out(out) { } - virtual bool runOnFunction(Function &F) { - BasicBlock &EntryBB = F.getEntryBlock(); - BasicBlock::const_iterator BI = EntryBB.end(); - --BI; - do { - const Instruction *In = BI; - const DebugLoc DL = In->getDebugLoc(); - if (!DL.isUnknown()) { - DIScope S(DL.getScope(getGlobalContext())); - Out << S.getFilename() << " " << DL.getLine() << "\n"; - break; + void getContextName(DIDescriptor Context, std::string &N) { + if (Context.isNameSpace()) { + DINameSpace NS(Context); + if (!NS.getName().empty()) { + getContextName(NS.getContext(), N); + N = N + NS.getName().str() + "::"; + } + } else if (Context.isType()) { + DIType TY(Context); + if (!TY.getName().empty()) { + getContextName(TY.getContext(), N); + N = N + TY.getName().str() + "::"; + } + } + } + + virtual bool runOnModule(Module &M) { + StringSet<> Processed; + if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp")) + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { + std::string Name; + DISubprogram SP(NMD->getOperand(i)); + if (SP.Verify()) + getContextName(SP.getContext(), Name); + Name = Name + SP.getDisplayName().str(); + if (!Name.empty() && Processed.insert(Name)) { + Out << Name << "\n"; + } } - --BI; - } while (BI != EntryBB.begin()); return false; } @@ -463,7 +479,7 @@ int main(int argc, char **argv) { llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. LLVMContext &Context = getGlobalContext(); - + // Initialize passes PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeCore(Registry); @@ -475,7 +491,7 @@ int main(int argc, char **argv) { initializeInstCombine(Registry); initializeInstrumentation(Registry); initializeTarget(Registry); - + cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .bc modular optimizer and analysis printer\n"); @@ -533,12 +549,12 @@ int main(int argc, char **argv) { // Add an appropriate TargetLibraryInfo pass for the module's triple. TargetLibraryInfo *TLI = new TargetLibraryInfo(Triple(M->getTargetTriple())); - + // The -disable-simplify-libcalls flag actually disables all builtin optzns. if (DisableSimplifyLibCalls) TLI->disableAllFunctions(); Passes.add(TLI); - + // Add an appropriate TargetData instance for this module. TargetData *TD = 0; const std::string &ModuleDataLayout = M.get()->getDataLayout(); @@ -562,7 +578,7 @@ int main(int argc, char **argv) { if (!Out) { if (OutputFilename.empty()) OutputFilename = "-"; - + std::string ErrorInfo; Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, raw_fd_ostream::F_Binary)); @@ -685,6 +701,9 @@ int main(int argc, char **argv) { Passes.add(createBitcodeWriterPass(Out->os())); } + // Before executing passes, print the final values of the LLVM options. + cl::PrintOptionValues(); + // Now that we have all of the passes ready, run them. Passes.run(*M.get()); -- cgit v1.1