diff options
Diffstat (limited to 'tools')
68 files changed, 2162 insertions, 2681 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 8851a0b..e66648b 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -28,6 +28,7 @@ add_subdirectory(llc) add_subdirectory(llvm-ranlib) add_subdirectory(llvm-ar) add_subdirectory(llvm-nm) +add_subdirectory(llvm-size) add_subdirectory(llvm-ld) add_subdirectory(llvm-prof) @@ -39,13 +40,13 @@ add_subdirectory(llvm-diff) add_subdirectory(macho-dump) add_subdirectory(llvm-objdump) add_subdirectory(llvm-rtdyld) +add_subdirectory(llvm-dwarfdump) add_subdirectory(bugpoint) add_subdirectory(bugpoint-passes) add_subdirectory(llvm-bcanalyzer) add_subdirectory(llvm-stub) add_subdirectory(edis) -add_subdirectory(llvmc) if( NOT WIN32 ) add_subdirectory(lto) diff --git a/tools/Makefile b/tools/Makefile index 5960433..68ce314 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -25,8 +25,9 @@ PARALLEL_DIRS := opt llvm-as llvm-dis \ llvm-ld llvm-prof llvm-link \ lli llvm-extract llvm-mc \ bugpoint llvm-bcanalyzer llvm-stub \ - llvmc llvm-diff macho-dump llvm-objdump \ - llvm-rtdyld + llvm-diff macho-dump llvm-objdump \ + llvm-rtdyld llvm-dwarfdump llvm-cov \ + llvm-size # 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 aa3e290..677d178 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -127,7 +127,8 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { outs() << "Linking in input file: '" << Filenames[i] << "'\n"; std::string ErrorMessage; - if (Linker::LinkModules(Program, M.get(), &ErrorMessage)) { + if (Linker::LinkModules(Program, M.get(), Linker::DestroySource, + &ErrorMessage)) { errs() << ToolName << ": error linking in '" << Filenames[i] << "': " << ErrorMessage << '\n'; return true; diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index 9941add..73b65ca 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -175,7 +175,7 @@ static Constant *GetTorInit(std::vector<std::pair<Function*, int> > &TorList) { std::vector<Constant*> ArrayElts; Type *Int32Ty = Type::getInt32Ty(TorList[0].first->getContext()); - const StructType *STy = + StructType *STy = StructType::get(Int32Ty, TorList[0].first->getType(), NULL); for (unsigned i = 0, e = TorList.size(); i != e; ++i) { Constant *Elts[] = { diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index d645dfb..7ff16db 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -222,7 +222,7 @@ static Module *TestMergedProgram(const BugDriver &BD, Module *M1, Module *M2, M1 = CloneModule(M1); M2 = CloneModule(M2); } - if (Linker::LinkModules(M1, M2, &ErrorMsg)) { + if (Linker::LinkModules(M1, M2, Linker::DestroySource, &ErrorMsg)) { errs() << BD.getToolName() << ": Error linking modules together:" << ErrorMsg << '\n'; exit(1); @@ -384,7 +384,7 @@ static bool ExtractLoops(BugDriver &BD, outs() << "*** Loop extraction successful!\n"; - std::vector<std::pair<std::string, const FunctionType*> > MisCompFunctions; + std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions; for (Module::iterator I = ToOptimizeLoopExtracted->begin(), E = ToOptimizeLoopExtracted->end(); I != E; ++I) if (!I->isDeclaration()) @@ -396,7 +396,8 @@ static bool ExtractLoops(BugDriver &BD, // Replace the current program with the loop extracted version, and try to // extract another loop. std::string ErrorMsg; - if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted, &ErrorMsg)){ + if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted, + Linker::DestroySource, &ErrorMsg)){ errs() << BD.getToolName() << ": Error linking modules together:" << ErrorMsg << '\n'; exit(1); @@ -411,8 +412,6 @@ static bool ExtractLoops(BugDriver &BD, Function *NewF = ToNotOptimize->getFunction(MisCompFunctions[i].first); assert(NewF && "Function not found??"); - assert(NewF->getFunctionType() == MisCompFunctions[i].second && - "found wrong function type?"); MiscompiledFunctions.push_back(NewF); } @@ -569,7 +568,7 @@ static bool ExtractBlocks(BugDriver &BD, // together. delete ToExtract; - std::vector<std::pair<std::string, const FunctionType*> > MisCompFunctions; + std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions; for (Module::iterator I = Extracted->begin(), E = Extracted->end(); I != E; ++I) if (!I->isDeclaration()) @@ -577,7 +576,8 @@ static bool ExtractBlocks(BugDriver &BD, I->getFunctionType())); std::string ErrorMsg; - if (Linker::LinkModules(ProgClone, Extracted, &ErrorMsg)) { + if (Linker::LinkModules(ProgClone, Extracted, Linker::DestroySource, + &ErrorMsg)) { errs() << BD.getToolName() << ": Error linking modules together:" << ErrorMsg << '\n'; exit(1); @@ -593,8 +593,6 @@ 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 && - "Function has wrong type??"); MiscompiledFunctions.push_back(NewF); } @@ -834,8 +832,7 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, // GetElementPtr *funcName, ulong 0, ulong 0 std::vector<Constant*> GEPargs(2, Constant::getNullValue(Type::getInt32Ty(F->getContext()))); - Value *GEP = - ConstantExpr::getGetElementPtr(funcName, &GEPargs[0], 2); + Value *GEP = ConstantExpr::getGetElementPtr(funcName, GEPargs); std::vector<Value*> ResolverArgs; ResolverArgs.push_back(GEP); @@ -850,7 +847,7 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, NullPtr,F->getName()+".fpcache"); // Construct a new stub function that will re-route calls to F - const FunctionType *FuncTy = F->getFunctionType(); + FunctionType *FuncTy = F->getFunctionType(); Function *FuncWrapper = Function::Create(FuncTy, GlobalValue::InternalLinkage, F->getName() + "_wrapper", diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index e25414f..6a87521 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -17,16 +17,17 @@ #include "ToolRunner.h" #include "llvm/LinkAllPasses.h" #include "llvm/LLVMContext.h" +#include "llvm/PassManager.h" #include "llvm/Support/PassNameParser.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/PassManagerBuilder.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Valgrind.h" #include "llvm/LinkAllVMCore.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" //Enable this macro to debug bugpoint itself. //#define DEBUG_BUGPOINT 1 diff --git a/tools/edis/CMakeLists.txt b/tools/edis/CMakeLists.txt index 9406c2a..1e162f9 100644 --- a/tools/edis/CMakeLists.txt +++ b/tools/edis/CMakeLists.txt @@ -5,30 +5,17 @@ set(SOURCES EDMain.cpp ) -set(LLVM_LINK_COMPONENTS mcdisassembler) +set(EDIS_DEPENDS LLVMMCDisassembler LLVMMCParser) if( LLVM_TARGETS_TO_BUILD MATCHES X86 ) - list(APPEND LLVM_LINK_COMPONENTS x86asmprinter x86disassembler) + list(APPEND EDIS_DEPENDS LLVMX86AsmPrinter LLVMX86AsmParser LLVMX86Disassembler LLVMX86Desc) endif() if( LLVM_TARGETS_TO_BUILD MATCHES ARM ) - list(APPEND LLVM_LINK_COMPONENTS armasmprinter armdisassembler) + list(APPEND EDIS_DEPENDS LLVMARMAsmPrinter LLVMARMAsmParser LLVMARMDisassembler LLVMARMDesc) endif() -# TODO: Process EnhancedDisassembly.exports +add_llvm_library(EnhancedDisassembly ${SOURCES}) +set_property(TARGET EnhancedDisassembly PROPERTY + OUTPUT_NAME "EnhancedDisassembly") -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() +add_llvm_library_dependencies(EnhancedDisassembly + ${EDIS_DEPENDS}) diff --git a/tools/edis/EnhancedDisassembly.exports b/tools/edis/EnhancedDisassembly.exports deleted file mode 100644 index 7050f7f..0000000 --- a/tools/edis/EnhancedDisassembly.exports +++ /dev/null @@ -1,36 +0,0 @@ -EDGetDisassembler -EDGetRegisterName -EDRegisterIsStackPointer -EDRegisterIsProgramCounter -EDCreateInsts -EDReleaseInst -EDInstByteSize -EDGetInstString -EDInstIsBranch -EDInstIsMove -EDBranchTargetID -EDMoveSourceID -EDMoveTargetID -EDNumTokens -EDGetToken -EDGetTokenString -EDOperandIndexForToken -EDTokenIsWhitespace -EDTokenIsPunctuation -EDTokenIsOpcode -EDTokenIsLiteral -EDTokenIsRegister -EDTokenIsNegativeLiteral -EDLiteralTokenAbsoluteValue -EDRegisterTokenValue -EDNumOperands -EDGetOperand -EDOperandIsRegister -EDOperandIsImmediate -EDOperandIsMemory -EDRegisterOperandValue -EDImmediateOperandValue -EDEvaluateOperand -EDBlockCreateInsts -EDBlockEvaluateOperand -EDBlockVisitTokens diff --git a/tools/edis/Makefile b/tools/edis/Makefile index b5557fc..3fcb408 100644 --- a/tools/edis/Makefile +++ b/tools/edis/Makefile @@ -10,7 +10,6 @@ LEVEL = ../.. LIBRARYNAME = EnhancedDisassembly LINK_LIBS_IN_SHARED = 1 -SHARED_LIBRARY = 1 EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/EnhancedDisassembly.exports diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 9e43bef..6f547b3 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -17,6 +17,9 @@ #include "llvm-c/lto.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/system_error.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/Errno.h" #include "llvm/Support/Path.h" @@ -235,25 +238,43 @@ ld_plugin_status onload(ld_plugin_tv *tv) { static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, int *claimed) { lto_module_t M; - + const void *view; + OwningPtr<MemoryBuffer> buffer; 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; } - M = lto_module_create_from_memory(view, file->filesize); - } else if (file->offset) { + } else { + int64_t offset = 0; // 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 { - M = lto_module_create_from_fd(file->fd, file->name, file->filesize); + if (file->offset) { + offset = file->offset; + } + if (error_code ec = + MemoryBuffer::getOpenFile(file->fd, file->name, buffer, file->filesize, + -1, offset, false)) { + (*message)(LDPL_ERROR, ec.message().c_str()); + return LDPS_ERR; + } + view = buffer->getBufferStart(); } - if (!M) + + if (!lto_module_is_object_file_in_memory(view, file->filesize)) return LDPS_OK; + M = lto_module_create_from_memory(view, file->filesize); + if (!M) { + if (const char* msg = lto_get_error_message()) { + (*message)(LDPL_ERROR, + "LLVM gold plugin has failed to create LTO module: %s", + msg); + return LDPS_ERR; + } + return LDPS_OK; + } + *claimed = 1; Modules.resize(Modules.size() + 1); claimed_file &cf = Modules.back(); @@ -360,6 +381,8 @@ static ld_plugin_status all_symbols_read_hook(void) { bool anySymbolsPreserved = false; for (std::list<claimed_file>::iterator I = Modules.begin(), E = Modules.end(); I != E; ++I) { + if (I->syms.empty()) + continue; (*get_symbols)(I->handle, I->syms.size(), &I->syms[0]); for (unsigned i = 0, e = I->syms.size(); i != e; i++) { if (I->syms[i].resolution == LDPR_PREVAILING_DEF) { diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index b36e941..d29bd9b 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -32,10 +32,10 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/Host.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Target/TargetSelect.h" #include <memory> using namespace llvm; @@ -76,6 +76,37 @@ MAttrs("mattr", cl::desc("Target specific attributes (-mattr=help for details)"), cl::value_desc("a1,+a2,-a3,...")); +static cl::opt<Reloc::Model> +RelocModel("relocation-model", + cl::desc("Choose relocation model"), + cl::init(Reloc::Default), + cl::values( + clEnumValN(Reloc::Default, "default", + "Target default relocation model"), + clEnumValN(Reloc::Static, "static", + "Non-relocatable code"), + clEnumValN(Reloc::PIC_, "pic", + "Fully relocatable, position independent code"), + clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic", + "Relocatable external references, non-relocatable code"), + clEnumValEnd)); + +static cl::opt<llvm::CodeModel::Model> +CMModel("code-model", + cl::desc("Choose code model"), + cl::init(CodeModel::Default), + cl::values(clEnumValN(CodeModel::Default, "default", + "Target default code model"), + clEnumValN(CodeModel::Small, "small", + "Small code model"), + clEnumValN(CodeModel::Kernel, "kernel", + "Kernel code model"), + clEnumValN(CodeModel::Medium, "medium", + "Medium code model"), + clEnumValN(CodeModel::Large, "large", + "Large code model"), + clEnumValEnd)); + static cl::opt<bool> RelaxAll("mc-relax-all", cl::desc("When used with filetype=obj, " @@ -201,12 +232,13 @@ int main(int argc, char **argv) { // Initialize targets first, so that --version shows registered targets. InitializeAllTargets(); - InitializeAllMCAsmInfos(); - InitializeAllMCInstrInfos(); - InitializeAllMCSubtargetInfos(); + InitializeAllTargetMCs(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); + // Register the target printer for --version. + cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); + cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); // Load the module to be compiled... @@ -272,8 +304,9 @@ int main(int argc, char **argv) { } std::auto_ptr<TargetMachine> - target(TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, - FeaturesStr)); + target(TheTarget->createTargetMachine(TheTriple.getTriple(), + MCPU, FeaturesStr, + RelocModel, CMModel)); assert(target.get() && "Could not allocate target machine!"); TargetMachine &Target = *target.get(); diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 014925c..50c7a49 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -33,7 +33,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" -#include "llvm/Target/TargetSelect.h" +#include "llvm/Support/TargetSelect.h" #include <cerrno> #ifdef __CYGWIN__ @@ -108,6 +108,38 @@ namespace { NoLazyCompilation("disable-lazy-compilation", cl::desc("Disable JIT lazy compilation"), cl::init(false)); + + cl::opt<Reloc::Model> + RelocModel("relocation-model", + cl::desc("Choose relocation model"), + cl::init(Reloc::Default), + cl::values( + clEnumValN(Reloc::Default, "default", + "Target default relocation model"), + clEnumValN(Reloc::Static, "static", + "Non-relocatable code"), + clEnumValN(Reloc::PIC_, "pic", + "Fully relocatable, position independent code"), + clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic", + "Relocatable external references, non-relocatable code"), + clEnumValEnd)); + + cl::opt<llvm::CodeModel::Model> + CMModel("code-model", + cl::desc("Choose code model"), + cl::init(CodeModel::JITDefault), + cl::values(clEnumValN(CodeModel::JITDefault, "default", + "Target default JIT code model"), + clEnumValN(CodeModel::Small, "small", + "Small code model"), + clEnumValN(CodeModel::Kernel, "kernel", + "Kernel code model"), + clEnumValN(CodeModel::Medium, "medium", + "Medium code model"), + clEnumValN(CodeModel::Large, "large", + "Large code model"), + clEnumValEnd)); + } static ExecutionEngine *EE = 0; @@ -164,6 +196,8 @@ int main(int argc, char **argv, char * const *envp) { builder.setMArch(MArch); builder.setMCPU(MCPU); builder.setMAttrs(MAttrs); + builder.setRelocationModel(RelocModel); + builder.setCodeModel(CMModel); builder.setErrorStr(&ErrorMsg); builder.setEngineKind(ForceInterpreter ? EngineKind::Interpreter diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt index bc23a64..6016862 100644 --- a/tools/llvm-config/CMakeLists.txt +++ b/tools/llvm-config/CMakeLists.txt @@ -138,27 +138,3 @@ install(FILES ${LLVM_CONFIG} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION bin) - - -# Regeneration of library dependencies. - -# 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) -set(LLVMLibDeps_TMP ${CMAKE_CURRENT_BINARY_DIR}/LLVMLibDeps.cmake.tmp) - -add_custom_command(OUTPUT ${LLVMLibDeps_TMP} - COMMAND sed -e s'@\\.a@@g' -e s'@\\.so@@g' -e 's@libLLVM@LLVM@g' -e 's@: @ @' -e 's@\\\(.*\\\)@set\(MSVC_LIB_DEPS_\\1\)@' ${FINAL_LIBDEPS} > ${LLVMLibDeps_TMP} - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LLVMLibDeps_TMP} ${LLVMLibDeps} - DEPENDS ${FINAL_LIBDEPS} - COMMENT "Updating cmake library dependencies file ${LLVMLibDeps}" - ) - -if( LLVM_TARGETS_TO_BUILD STREQUAL LLVM_ALL_TARGETS ) - add_custom_target(llvmlibdeps.target ALL DEPENDS ${LLVMLibDeps_TMP}) - add_dependencies(llvmlibdeps.target llvm-config.target) - set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} llvmlibdeps.target) -endif() - -set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE) diff --git a/tools/llvm-cov/CMakeLists.txt b/tools/llvm-cov/CMakeLists.txt new file mode 100644 index 0000000..7184b9e --- /dev/null +++ b/tools/llvm-cov/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_LINK_COMPONENTS instrumentation ) + +add_llvm_tool(llvm-cov + llvm-cov.cpp + ) diff --git a/tools/llvmc/examples/mcc16/Makefile b/tools/llvm-cov/Makefile index 4409cff..bd9fa2a 100644 --- a/tools/llvmc/examples/mcc16/Makefile +++ b/tools/llvm-cov/Makefile @@ -1,15 +1,18 @@ -##===- llvmc/examples/mcc16/Makefile -----------------------*- Makefile -*-===## -# +##===- tools/llvm-cov/Makefile -----------------------------*- Makefile -*-===## +# # The LLVM Compiler Infrastructure # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. -# +# ##===----------------------------------------------------------------------===## -LEVEL = ../../../.. +LEVEL = ../.. + +TOOLNAME = llvm-cov +LINK_COMPONENTS := instrumentation -LLVMC_BASED_DRIVER = mcc16 -BUILT_SOURCES = PIC16.inc +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 include $(LEVEL)/Makefile.common diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp new file mode 100644 index 0000000..7b21c5b --- /dev/null +++ b/tools/llvm-cov/llvm-cov.cpp @@ -0,0 +1,78 @@ +//===- tools/llvm-cov/llvm-cov.cpp - LLVM coverage tool -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// llvm-cov is a command line tools to analyze and report coverage information. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/GCOV.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" +using namespace llvm; + +static cl::opt<bool> +DumpGCOV("dump", cl::init(false), cl::desc("dump gcov file")); + +static cl::opt<std::string> +InputGCNO("gcno", cl::desc("<input gcno file>"), cl::init("")); + +static cl::opt<std::string> +InputGCDA("gcda", cl::desc("<input gcda file>"), cl::init("")); + + +//===----------------------------------------------------------------------===// +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + cl::ParseCommandLineOptions(argc, argv, "llvm cov\n"); + + GCOVFile GF; + if (InputGCNO.empty()) + errs() << " " << argv[0] << ": No gcov input file!\n"; + + OwningPtr<MemoryBuffer> GCNO_Buff; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCNO, GCNO_Buff)) { + errs() << InputGCNO << ": " << ec.message() << "\n"; + return 1; + } + GCOVBuffer GCNO_GB(GCNO_Buff.take()); + if (!GF.read(GCNO_GB)) { + errs() << "Invalid .gcno File!\n"; + return 1; + } + + if (!InputGCDA.empty()) { + OwningPtr<MemoryBuffer> GCDA_Buff; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCDA, GCDA_Buff)) { + errs() << InputGCDA << ": " << ec.message() << "\n"; + return 1; + } + GCOVBuffer GCDA_GB(GCDA_Buff.take()); + if (!GF.read(GCDA_GB)) { + errs() << "Invalid .gcda File!\n"; + return 1; + } + } + + + if (DumpGCOV) + GF.dump(); + + FileInfo FI; + GF.collectLineCounts(FI); + return 0; +} diff --git a/tools/llvm-diff/DifferenceEngine.cpp b/tools/llvm-diff/DifferenceEngine.cpp index ba2cec2..b240d8c 100644 --- a/tools/llvm-diff/DifferenceEngine.cpp +++ b/tools/llvm-diff/DifferenceEngine.cpp @@ -195,12 +195,12 @@ class FunctionDifferenceEngine { DifferenceEngine::Context C(Engine, L, R); BasicBlock::iterator LI = L->begin(), LE = L->end(); - BasicBlock::iterator RI = R->begin(), RE = R->end(); + BasicBlock::iterator RI = R->begin(); llvm::SmallVector<std::pair<Instruction*,Instruction*>, 20> TentativePairs; do { - assert(LI != LE && RI != RE); + assert(LI != LE && RI != R->end()); Instruction *LeftI = &*LI, *RightI = &*RI; // If the instructions differ, start the more sophisticated diff diff --git a/tools/llvm-dwarfdump/CMakeLists.txt b/tools/llvm-dwarfdump/CMakeLists.txt new file mode 100644 index 0000000..05aad3f --- /dev/null +++ b/tools/llvm-dwarfdump/CMakeLists.txt @@ -0,0 +1,8 @@ +set(LLVM_LINK_COMPONENTS + DebugInfo + Object + ) + +add_llvm_tool(llvm-dwarfdump + llvm-dwarfdump.cpp + ) diff --git a/tools/llvmc/examples/Makefile b/tools/llvm-dwarfdump/Makefile index 8468e93..e61f27d 100644 --- a/tools/llvmc/examples/Makefile +++ b/tools/llvm-dwarfdump/Makefile @@ -1,4 +1,4 @@ -##===- tools/llvmc/examples/Makefile -----------------------*- Makefile -*-===## +##===- tools/llvm-dwarfdump/Makefile -----------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -6,9 +6,12 @@ # License. See LICENSE.TXT for details. # ##===----------------------------------------------------------------------===## +LEVEL = ../.. -LEVEL=../../.. +TOOLNAME = llvm-dwarfdump +LINK_COMPONENTS = DebugInfo Object -PARALLEL_DIRS := Hello Simple mcc16 Skeleton +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 include $(LEVEL)/Makefile.common diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp new file mode 100644 index 0000000..ca0493d --- /dev/null +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -0,0 +1,116 @@ +//===-- llvm-dwarfdump.cpp - Debug info dumping utility for llvm -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that works like "dwarfdump". +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" +#include <algorithm> +#include <cstring> +using namespace llvm; +using namespace object; + +static cl::list<std::string> +InputFilenames(cl::Positional, cl::desc("<input object files>"), + cl::ZeroOrMore); + +static cl::opt<unsigned long long> +Address("address", cl::init(-1ULL), + cl::desc("Print line information for a given address")); + +static void DumpInput(const StringRef &Filename) { + OwningPtr<MemoryBuffer> Buff; + + if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { + errs() << Filename << ": " << ec.message() << "\n"; + return; + } + + OwningPtr<ObjectFile> Obj(ObjectFile::createObjectFile(Buff.take())); + + StringRef DebugInfoSection; + StringRef DebugAbbrevSection; + StringRef DebugLineSection; + StringRef DebugArangesSection; + StringRef DebugStringSection; + + error_code ec; + for (section_iterator i = Obj->begin_sections(), + e = Obj->end_sections(); + i != e; i.increment(ec)) { + StringRef name; + i->getName(name); + StringRef data; + i->getContents(data); + + if (name.startswith("__DWARF,")) + name = name.substr(8); // Skip "__DWARF," prefix. + name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. + if (name == "debug_info") + DebugInfoSection = data; + else if (name == "debug_abbrev") + DebugAbbrevSection = data; + else if (name == "debug_line") + DebugLineSection = data; + else if (name == "debug_aranges") + DebugArangesSection = data; + else if (name == "debug_str") + DebugStringSection = data; + } + + OwningPtr<DIContext> dictx(DIContext::getDWARFContext(/*FIXME*/true, + DebugInfoSection, + DebugAbbrevSection, + DebugArangesSection, + DebugLineSection, + DebugStringSection)); + if (Address == -1ULL) { + outs() << Filename + << ":\tfile format " << Obj->getFileFormatName() << "\n\n"; + // Dump the complete DWARF structure. + dictx->dump(outs()); + } else { + // Print line info for the specified address. + DILineInfo dli = dictx->getLineInfoForAddress(Address); + outs() << (dli.getFileName() ? dli.getFileName() : "<unknown>") << ':' + << dli.getLine() << ':' << dli.getColumn() << '\n'; + } +} + +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + cl::ParseCommandLineOptions(argc, argv, "llvm dwarf dumper\n"); + + // Defaults to a.out if no filenames specified. + if (InputFilenames.size() == 0) + InputFilenames.push_back("a.out"); + + std::for_each(InputFilenames.begin(), InputFilenames.end(), DumpInput); + + return 0; +} diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index a6c229f..f6227ee 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -26,7 +26,9 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/Regex.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SetVector.h" #include <memory> using namespace llvm; @@ -45,16 +47,30 @@ Force("f", cl::desc("Enable binary output on terminals")); static cl::opt<bool> DeleteFn("delete", cl::desc("Delete specified Globals from Module")); -// ExtractFuncs - The functions to extract from the module... +// ExtractFuncs - The functions to extract from the module. static cl::list<std::string> ExtractFuncs("func", cl::desc("Specify function to extract"), cl::ZeroOrMore, cl::value_desc("function")); -// ExtractGlobals - The globals to extract from the module... +// ExtractRegExpFuncs - The functions, matched via regular expression, to +// extract from the module. +static cl::list<std::string> +ExtractRegExpFuncs("rfunc", cl::desc("Specify function(s) to extract using a " + "regular expression"), + cl::ZeroOrMore, cl::value_desc("rfunction")); + +// ExtractGlobals - The globals to extract from the module. static cl::list<std::string> ExtractGlobals("glob", cl::desc("Specify global to extract"), cl::ZeroOrMore, cl::value_desc("global")); +// ExtractRegExpGlobals - The globals, matched via regular expression, to +// extract from the module... +static cl::list<std::string> +ExtractRegExpGlobals("rglob", cl::desc("Specify global(s) to extract using a " + "regular expression"), + cl::ZeroOrMore, cl::value_desc("rglobal")); + static cl::opt<bool> OutputAssembly("S", cl::desc("Write output as LLVM assembly"), cl::Hidden); @@ -78,7 +94,8 @@ int main(int argc, char **argv) { return 1; } - std::vector<GlobalValue *> GVs; + // Use SetVector to avoid duplicates. + SetVector<GlobalValue *> GVs; // Figure out which globals we should extract. for (size_t i = 0, e = ExtractGlobals.size(); i != e; ++i) { @@ -88,7 +105,30 @@ int main(int argc, char **argv) { << ExtractGlobals[i] << "'!\n"; return 1; } - GVs.push_back(GV); + GVs.insert(GV); + } + + // Extract globals via regular expression matching. + for (size_t i = 0, e = ExtractRegExpGlobals.size(); i != e; ++i) { + std::string Error; + Regex RegEx(ExtractRegExpGlobals[i]); + if (!RegEx.isValid(Error)) { + errs() << argv[0] << ": '" << ExtractRegExpGlobals[i] << "' " + "invalid regex: " << Error; + } + bool match = false; + for (Module::global_iterator GV = M.get()->global_begin(), + E = M.get()->global_end(); GV != E; GV++) { + if (RegEx.match(GV->getName())) { + GVs.insert(&*GV); + match = true; + } + } + if (!match) { + errs() << argv[0] << ": program doesn't contain global named '" + << ExtractRegExpGlobals[i] << "'!\n"; + return 1; + } } // Figure out which functions we should extract. @@ -99,7 +139,30 @@ int main(int argc, char **argv) { << ExtractFuncs[i] << "'!\n"; return 1; } - GVs.push_back(GV); + GVs.insert(GV); + } + // Extract functions via regular expression matching. + for (size_t i = 0, e = ExtractRegExpFuncs.size(); i != e; ++i) { + std::string Error; + StringRef RegExStr = ExtractRegExpFuncs[i]; + Regex RegEx(RegExStr); + if (!RegEx.isValid(Error)) { + errs() << argv[0] << ": '" << ExtractRegExpFuncs[i] << "' " + "invalid regex: " << Error; + } + bool match = false; + for (Module::iterator F = M.get()->begin(), E = M.get()->end(); F != E; + F++) { + if (RegEx.match(F->getName())) { + GVs.insert(&*F); + match = true; + } + } + if (!match) { + errs() << argv[0] << ": program doesn't contain global named '" + << ExtractRegExpFuncs[i] << "'!\n"; + return 1; + } } // Materialize requisite global values. @@ -145,7 +208,9 @@ int main(int argc, char **argv) { PassManager Passes; Passes.add(new TargetData(M.get())); // Use correct TargetData - Passes.add(createGVExtractionPass(GVs, DeleteFn)); + std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end()); + + Passes.add(createGVExtractionPass(Gvs, DeleteFn)); if (!DeleteFn) Passes.add(createGlobalDCEPass()); // Delete unreachable globals Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info diff --git a/tools/llvm-ld/Optimize.cpp b/tools/llvm-ld/Optimize.cpp index ca6a477..7f3f900 100644 --- a/tools/llvm-ld/Optimize.cpp +++ b/tools/llvm-ld/Optimize.cpp @@ -12,14 +12,18 @@ //===----------------------------------------------------------------------===// #include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Analysis/Verifier.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/PassManagerBuilder.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/PassNameParser.h" #include "llvm/Support/PluginLoader.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Scalar.h" using namespace llvm; // Pass Name Options as generated by the PassNameParser diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index 3fb7ba4..95ad1ca 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -103,7 +103,8 @@ int main(int argc, char **argv) { if (Verbose) errs() << "Linking in '" << InputFilenames[i] << "'\n"; - if (Linker::LinkModules(Composite.get(), M.get(), &ErrorMessage)) { + if (Linker::LinkModules(Composite.get(), M.get(), Linker::DestroySource, + &ErrorMessage)) { errs() << argv[0] << ": link error in '" << InputFilenames[i] << "': " << ErrorMessage << "\n"; return 1; diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp index c389f6a..a9381b5 100644 --- a/tools/llvm-mc/Disassembler.cpp +++ b/tools/llvm-mc/Disassembler.cpp @@ -21,14 +21,15 @@ #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" -#include "llvm/Target/TargetRegistry.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryObject.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; typedef std::vector<std::pair<unsigned char, const char*> > ByteArrayTy; @@ -65,15 +66,26 @@ static bool PrintInsts(const MCDisassembler &DisAsm, for (Index = 0; Index < Bytes.size(); Index += Size) { MCInst Inst; - if (DisAsm.getInstruction(Inst, Size, memoryObject, Index, - /*REMOVE*/ nulls())) { - Printer.printInst(&Inst, Out); - Out << "\n"; - } else { + MCDisassembler::DecodeStatus S; + S = DisAsm.getInstruction(Inst, Size, memoryObject, Index, + /*REMOVE*/ nulls(), nulls()); + switch (S) { + case MCDisassembler::Fail: SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second), "invalid instruction encoding", "warning"); if (Size == 0) Size = 1; // skip illegible bytes + break; + + case MCDisassembler::SoftFail: + SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second), + "potentially undefined instruction encoding", "warning"); + // Fall through + + case MCDisassembler::Success: + Printer.printInst(&Inst, Out, ""); + Out << "\n"; + break; } } @@ -129,6 +141,8 @@ static bool ByteArrayFromString(ByteArrayTy &ByteArray, int Disassembler::disassemble(const Target &T, const std::string &Triple, + const std::string &Cpu, + const std::string &FeaturesStr, MemoryBuffer &Buffer, raw_ostream &Out) { // Set up disassembler. @@ -139,7 +153,13 @@ int Disassembler::disassemble(const Target &T, return -1; } - OwningPtr<const MCDisassembler> DisAsm(T.createMCDisassembler()); + OwningPtr<const MCSubtargetInfo> STI(T.createMCSubtargetInfo(Triple, Cpu, FeaturesStr)); + if (!STI) { + errs() << "error: no subtarget info for target " << Triple << "\n"; + return -1; + } + + OwningPtr<const MCDisassembler> DisAsm(T.createMCDisassembler(*STI)); if (!DisAsm) { errs() << "error: no disassembler for target " << Triple << "\n"; return -1; @@ -147,7 +167,7 @@ int Disassembler::disassemble(const Target &T, int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); OwningPtr<MCInstPrinter> IP(T.createMCInstPrinter(AsmPrinterVariant, - *AsmInfo)); + *AsmInfo, *STI)); if (!IP) { errs() << "error: no instruction printer for target " << Triple << '\n'; return -1; diff --git a/tools/llvm-mc/Disassembler.h b/tools/llvm-mc/Disassembler.h index 433e71b..e8cd92d 100644 --- a/tools/llvm-mc/Disassembler.h +++ b/tools/llvm-mc/Disassembler.h @@ -27,6 +27,8 @@ class Disassembler { public: static int disassemble(const Target &target, const std::string &tripleString, + const std::string &Cpu, + const std::string &FeaturesStr, MemoryBuffer &buffer, raw_ostream &Out); diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index 334bf32..5fb3fdf 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -14,23 +14,18 @@ #include "llvm/MC/MCParser/AsmLexer.h" #include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetAsmParser.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/Target/TargetAsmBackend.h" -#include "llvm/Target/TargetAsmParser.h" -#include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Target/TargetAsmInfo.h" // FIXME. -#include "llvm/Target/TargetLowering.h" // FIXME. -#include "llvm/Target/TargetLoweringObjectFile.h" // FIXME. -#include "llvm/Target/TargetMachine.h" // FIXME. -#include "llvm/Target/TargetSelect.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" @@ -42,6 +37,8 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/Host.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/system_error.h" #include "Disassembler.h" using namespace llvm; @@ -111,6 +108,43 @@ MCPU("mcpu", cl::value_desc("cpu-name"), cl::init("")); +static cl::list<std::string> +MAttrs("mattr", + cl::CommaSeparated, + cl::desc("Target specific attributes (-mattr=help for details)"), + cl::value_desc("a1,+a2,-a3,...")); + +static cl::opt<Reloc::Model> +RelocModel("relocation-model", + cl::desc("Choose relocation model"), + cl::init(Reloc::Default), + cl::values( + clEnumValN(Reloc::Default, "default", + "Target default relocation model"), + clEnumValN(Reloc::Static, "static", + "Non-relocatable code"), + clEnumValN(Reloc::PIC_, "pic", + "Fully relocatable, position independent code"), + clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic", + "Relocatable external references, non-relocatable code"), + clEnumValEnd)); + +static cl::opt<llvm::CodeModel::Model> +CMModel("code-model", + cl::desc("Choose code model"), + cl::init(CodeModel::Default), + cl::values(clEnumValN(CodeModel::Default, "default", + "Target default code model"), + clEnumValN(CodeModel::Small, "small", + "Small code model"), + clEnumValN(CodeModel::Kernel, "kernel", + "Kernel code model"), + clEnumValN(CodeModel::Medium, "medium", + "Medium code model"), + clEnumValN(CodeModel::Large, "large", + "Large code model"), + clEnumValEnd)); + static cl::opt<bool> NoInitialTextSection("n", cl::desc("Don't assume assembly file starts " "in the text section")); @@ -142,21 +176,42 @@ static const Target *GetTarget(const char *ProgName) { // Figure out the target triple. if (TripleName.empty()) TripleName = sys::getHostTriple(); + Triple TheTriple(Triple::normalize(TripleName)); + + const Target *TheTarget = 0; if (!ArchName.empty()) { - llvm::Triple TT(TripleName); - TT.setArchName(ArchName); - TripleName = TT.str(); - } + for (TargetRegistry::iterator it = TargetRegistry::begin(), + ie = TargetRegistry::end(); it != ie; ++it) { + if (ArchName == it->getName()) { + TheTarget = &*it; + break; + } + } - // Get the target specific parser. - std::string Error; - const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error); - if (TheTarget) - return TheTarget; + if (!TheTarget) { + errs() << ProgName << ": error: invalid target '" << ArchName << "'.\n"; + return 0; + } - errs() << ProgName << ": error: unable to get target for '" << TripleName - << "', see --version and --triple.\n"; - return 0; + // Adjust the triple to match (if known), otherwise stick with the + // module/host triple. + Triple::ArchType Type = Triple::getArchTypeForLLVMName(ArchName); + if (Type != Triple::UnknownArch) + TheTriple.setArch(Type); + } else { + // Get the target specific parser. + std::string Error; + TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error); + if (TheTarget == 0) { + errs() << ProgName << ": error: unable to get target for '" + << TheTriple.getTriple() + << "', see --version and --triple.\n"; + return 0; + } + } + + TripleName = TheTriple.getTriple(); + return TheTarget; } static tool_output_file *GetOutputStream() { @@ -309,28 +364,27 @@ static int AssembleInput(const char *ProgName) { llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName)); assert(MAI && "Unable to create target asm info!"); - // Package up features to be passed to target/subtarget - std::string FeaturesStr; + llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); + assert(MRI && "Unable to create target register info!"); - // 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<TargetMachine> TM(TheTarget->createTargetMachine(TripleName, - MCPU, - FeaturesStr)); - - if (!TM) { - errs() << ProgName << ": error: could not create target for triple '" - << TripleName << "'.\n"; - return 1; - } + // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and + // MCObjectFileInfo needs a MCContext reference in order to initialize itself. + OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); + MCContext Ctx(*MAI, *MRI, MOFI.get()); + MOFI->InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx); - const TargetAsmInfo *tai = new TargetAsmInfo(*TM); - MCContext Ctx(*MAI, tai); if (SaveTempLabels) Ctx.setAllowTemporaryLabels(false); + // Package up features to be passed to target/subtarget + std::string FeaturesStr; + if (MAttrs.size()) { + SubtargetFeatures Features; + for (unsigned i = 0; i != MAttrs.size(); ++i) + Features.AddFeature(MAttrs[i]); + FeaturesStr = Features.getString(); + } + OwningPtr<tool_output_file> Out(GetOutputStream()); if (!Out) return 1; @@ -338,10 +392,6 @@ static int AssembleInput(const char *ProgName) { formatted_raw_ostream FOS(Out->os()); OwningPtr<MCStreamer> Str; - const TargetLoweringObjectFile &TLOF = - TM->getTargetLowering()->getObjFileLowering(); - const_cast<TargetLoweringObjectFile&>(TLOF).Initialize(Ctx, *TM); - OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); OwningPtr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr)); @@ -349,35 +399,35 @@ 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(OutputAsmVariant, *MAI, *STI); MCCodeEmitter *CE = 0; - TargetAsmBackend *TAB = 0; + MCAsmBackend *MAB = 0; if (ShowEncoding) { - CE = TheTarget->createCodeEmitter(*MCII, *STI, Ctx); - TAB = TheTarget->createAsmBackend(TripleName); + CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx); + MAB = TheTarget->createMCAsmBackend(TripleName); } Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true, /*useLoc*/ true, - /*useCFI*/ true, IP, CE, TAB, + /*useCFI*/ true, IP, CE, MAB, ShowInst)); } else if (FileType == OFT_Null) { Str.reset(createNullStreamer(Ctx)); } else { assert(FileType == OFT_ObjectFile && "Invalid file type!"); - MCCodeEmitter *CE = TheTarget->createCodeEmitter(*MCII, *STI, Ctx); - TargetAsmBackend *TAB = TheTarget->createAsmBackend(TripleName); - Str.reset(TheTarget->createObjectStreamer(TripleName, Ctx, *TAB, - FOS, CE, RelaxAll, - NoExecStack)); + MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx); + MCAsmBackend *MAB = TheTarget->createMCAsmBackend(TripleName); + Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB, + FOS, CE, RelaxAll, + NoExecStack)); } if (EnableLogging) { Str.reset(createLoggingStreamer(Str.take(), errs())); } - OwningPtr<MCAsmParser> Parser(createMCAsmParser(*TheTarget, SrcMgr, Ctx, - *Str.get(), *MAI)); - OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(*STI, *Parser)); + OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, + *Str.get(), *MAI)); + OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser)); if (!TAP) { errs() << ProgName << ": error: this target does not support assembly parsing.\n"; @@ -415,7 +465,16 @@ static int DisassembleInput(const char *ProgName, bool Enhanced) { Res = Disassembler::disassembleEnhanced(TripleName, *Buffer.take(), Out->os()); } else { - Res = Disassembler::disassemble(*TheTarget, TripleName, + // Package up features to be passed to target/subtarget + std::string FeaturesStr; + if (MAttrs.size()) { + SubtargetFeatures Features; + for (unsigned i = 0; i != MAttrs.size(); ++i) + Features.AddFeature(MAttrs[i]); + FeaturesStr = Features.getString(); + } + + Res = Disassembler::disassemble(*TheTarget, TripleName, MCPU, FeaturesStr, *Buffer.take(), Out->os()); } @@ -434,12 +493,7 @@ int main(int argc, char **argv) { // Initialize targets and assembly printers/parsers. llvm::InitializeAllTargetInfos(); - // FIXME: We shouldn't need to initialize the Target(Machine)s. - llvm::InitializeAllTargets(); - llvm::InitializeAllMCAsmInfos(); - llvm::InitializeAllMCInstrInfos(); - llvm::InitializeAllMCSubtargetInfos(); - llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmParsers(); llvm::InitializeAllDisassemblers(); diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 014cb29..550ca4f 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -20,6 +20,7 @@ #include "llvm/Module.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Bitcode/Archive.h" +#include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -270,9 +271,9 @@ static void DumpSymbolNamesFromModule(Module *M) { static void DumpSymbolNamesFromObject(ObjectFile *obj) { error_code ec; - for (ObjectFile::symbol_iterator i = obj->begin_symbols(), - e = obj->end_symbols(); - i != e; i.increment(ec)) { + for (symbol_iterator i = obj->begin_symbols(), + e = obj->end_symbols(); + i != e; i.increment(ec)) { if (error(ec)) break; bool internal; if (error(i->isInternal(internal))) break; @@ -285,7 +286,7 @@ static void DumpSymbolNamesFromObject(ObjectFile *obj) { if (error(i->getSize(s.Size))) break; } if (PrintAddress) - if (error(i->getAddress(s.Address))) break; + if (error(i->getOffset(s.Address))) break; if (error(i->getNMTypeChar(s.TypeChar))) break; if (error(i->getName(s.Name))) break; SymbolList.push_back(s); @@ -318,18 +319,34 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; } else if (aPath.isArchive()) { - std::string ErrMsg; - Archive* archive = Archive::OpenAndLoad(sys::Path(Filename), Context, - &ErrorMessage); - if (!archive) - errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; - std::vector<Module *> Modules; - if (archive->getAllModules(Modules, &ErrorMessage)) { - errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n"; + OwningPtr<Binary> arch; + if (error_code ec = object::createBinary(aPath.str(), arch)) { + errs() << ToolName << ": " << Filename << ": " << ec.message() << ".\n"; return; } - MultipleFiles = true; - std::for_each (Modules.begin(), Modules.end(), DumpSymbolNamesFromModule); + if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) { + for (object::Archive::child_iterator i = a->begin_children(), + e = a->end_children(); i != e; ++i) { + OwningPtr<Binary> child; + if (error_code ec = i->getAsBinary(child)) { + // Try opening it as a bitcode file. + OwningPtr<MemoryBuffer> buff(i->getBuffer()); + Module *Result = 0; + if (buff) + Result = ParseBitcodeFile(buff.get(), Context, &ErrorMessage); + + if (Result) { + DumpSymbolNamesFromModule(Result); + delete Result; + } + continue; + } + if (object::ObjectFile *o = dyn_cast<ObjectFile>(child.get())) { + outs() << o->getFileName() << ":\n"; + DumpSymbolNamesFromObject(o); + } + } + } } else if (aPath.isObjectFile()) { OwningPtr<Binary> obj; if (error_code ec = object::createBinary(aPath.str(), obj)) { diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt index 4181b32..f3b2e1f 100644 --- a/tools/llvm-objdump/CMakeLists.txt +++ b/tools/llvm-objdump/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} + DebugInfo MC MCParser MCDisassembler @@ -8,4 +9,6 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-objdump llvm-objdump.cpp + MachODump.cpp + MCFunction.cpp ) diff --git a/tools/llvm-objdump/MCFunction.cpp b/tools/llvm-objdump/MCFunction.cpp new file mode 100644 index 0000000..5c67f1b --- /dev/null +++ b/tools/llvm-objdump/MCFunction.cpp @@ -0,0 +1,138 @@ +//===-- MCFunction.cpp ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the algorithm to break down a region of machine code +// into basic blocks and try to reconstruct a CFG from it. +// +//===----------------------------------------------------------------------===// + +#include "MCFunction.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrAnalysis.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" +#include <set> +using namespace llvm; + +MCFunction +MCFunction::createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm, + const MemoryObject &Region, uint64_t Start, + uint64_t End, const MCInstrAnalysis *Ana, + raw_ostream &DebugOut, + SmallVectorImpl<uint64_t> &Calls) { + std::vector<MCDecodedInst> Instructions; + std::set<uint64_t> Splits; + Splits.insert(Start); + uint64_t Size; + + MCFunction f(Name); + + { + DenseSet<uint64_t> VisitedInsts; + SmallVector<uint64_t, 16> WorkList; + WorkList.push_back(Start); + // Disassemble code and gather basic block split points. + while (!WorkList.empty()) { + uint64_t Index = WorkList.pop_back_val(); + if (VisitedInsts.find(Index) != VisitedInsts.end()) + continue; // Already visited this location. + + for (;Index < End; Index += Size) { + VisitedInsts.insert(Index); + + MCInst Inst; + if (DisAsm->getInstruction(Inst, Size, Region, Index, DebugOut, nulls())){ + Instructions.push_back(MCDecodedInst(Index, Size, Inst)); + if (Ana->isBranch(Inst)) { + uint64_t targ = Ana->evaluateBranch(Inst, Index, Size); + if (targ != -1ULL && targ == Index+Size) + continue; // Skip nop jumps. + + // If we could determine the branch target, make a note to start a + // new basic block there and add the target to the worklist. + if (targ != -1ULL) { + Splits.insert(targ); + WorkList.push_back(targ); + WorkList.push_back(Index+Size); + } + Splits.insert(Index+Size); + break; + } else if (Ana->isReturn(Inst)) { + // Return instruction. This basic block ends here. + Splits.insert(Index+Size); + break; + } else if (Ana->isCall(Inst)) { + uint64_t targ = Ana->evaluateBranch(Inst, Index, Size); + // Add the call to the call list if the destination is known. + if (targ != -1ULL && targ != Index+Size) + Calls.push_back(targ); + } + } else { + errs().write_hex(Index) << ": warning: invalid instruction encoding\n"; + if (Size == 0) + Size = 1; // skip illegible bytes + } + } + } + } + + // Make sure the instruction list is sorted. + std::sort(Instructions.begin(), Instructions.end()); + + // Create basic blocks. + unsigned ii = 0, ie = Instructions.size(); + for (std::set<uint64_t>::iterator spi = Splits.begin(), + spe = llvm::prior(Splits.end()); spi != spe; ++spi) { + MCBasicBlock BB; + uint64_t BlockEnd = *llvm::next(spi); + // Add instructions to the BB. + for (; ii != ie; ++ii) { + if (Instructions[ii].Address < *spi || + Instructions[ii].Address >= BlockEnd) + break; + BB.addInst(Instructions[ii]); + } + f.addBlock(*spi, BB); + } + + std::sort(f.Blocks.begin(), f.Blocks.end()); + + // Calculate successors of each block. + for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) { + MCBasicBlock &BB = const_cast<MCBasicBlock&>(i->second); + if (BB.getInsts().empty()) continue; + const MCDecodedInst &Inst = BB.getInsts().back(); + + if (Ana->isBranch(Inst.Inst)) { + uint64_t targ = Ana->evaluateBranch(Inst.Inst, Inst.Address, Inst.Size); + if (targ == -1ULL) { + // Indirect branch. Bail and add all blocks of the function as a + // successor. + for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) + BB.addSucc(i->first); + } else if (targ != Inst.Address+Inst.Size) + BB.addSucc(targ); + // Conditional branches can also fall through to the next block. + if (Ana->isConditionalBranch(Inst.Inst) && llvm::next(i) != e) + BB.addSucc(llvm::next(i)->first); + } else { + // No branch. Fall through to the next block. + if (!Ana->isReturn(Inst.Inst) && llvm::next(i) != e) + BB.addSucc(llvm::next(i)->first); + } + } + + return f; +} diff --git a/tools/llvm-objdump/MCFunction.h b/tools/llvm-objdump/MCFunction.h new file mode 100644 index 0000000..6d3a548 --- /dev/null +++ b/tools/llvm-objdump/MCFunction.h @@ -0,0 +1,100 @@ +//===-- MCFunction.h ------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the data structures to hold a CFG reconstructed from +// machine code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTDUMP_MCFUNCTION_H +#define LLVM_OBJECTDUMP_MCFUNCTION_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/MC/MCInst.h" +#include <map> + +namespace llvm { + +class MCDisassembler; +class MCInstrAnalysis; +class MemoryObject; +class raw_ostream; + +/// MCDecodedInst - Small container to hold an MCInst and associated info like +/// address and size. +struct MCDecodedInst { + uint64_t Address; + uint64_t Size; + MCInst Inst; + + MCDecodedInst() {} + MCDecodedInst(uint64_t Address, uint64_t Size, MCInst Inst) + : Address(Address), Size(Size), Inst(Inst) {} + + bool operator<(const MCDecodedInst &RHS) const { + return Address < RHS.Address; + } +}; + +/// MCBasicBlock - Consists of multiple MCDecodedInsts and a list of successing +/// MCBasicBlocks. +class MCBasicBlock { + std::vector<MCDecodedInst> Insts; + typedef DenseSet<uint64_t> SetTy; + SetTy Succs; +public: + ArrayRef<MCDecodedInst> getInsts() const { return Insts; } + + typedef SetTy::const_iterator succ_iterator; + succ_iterator succ_begin() const { return Succs.begin(); } + succ_iterator succ_end() const { return Succs.end(); } + + bool contains(uint64_t Addr) const { return Succs.count(Addr); } + + void addInst(const MCDecodedInst &Inst) { Insts.push_back(Inst); } + void addSucc(uint64_t Addr) { Succs.insert(Addr); } + + bool operator<(const MCBasicBlock &RHS) const { + return Insts.size() < RHS.Insts.size(); + } +}; + +/// MCFunction - Represents a named function in machine code, containing +/// multiple MCBasicBlocks. +class MCFunction { + const StringRef Name; + // Keep BBs sorted by address. + typedef std::vector<std::pair<uint64_t, MCBasicBlock> > MapTy; + MapTy Blocks; +public: + MCFunction(StringRef Name) : Name(Name) {} + + // Create an MCFunction from a region of binary machine code. + static MCFunction + createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm, + const MemoryObject &Region, uint64_t Start, uint64_t End, + const MCInstrAnalysis *Ana, raw_ostream &DebugOut, + SmallVectorImpl<uint64_t> &Calls); + + typedef MapTy::const_iterator iterator; + iterator begin() const { return Blocks.begin(); } + iterator end() const { return Blocks.end(); } + + StringRef getName() const { return Name; } + + MCBasicBlock &addBlock(uint64_t Address, const MCBasicBlock &BB) { + Blocks.push_back(std::make_pair(Address, BB)); + return Blocks.back().second; + } +}; + +} + +#endif diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp new file mode 100644 index 0000000..3f44b29 --- /dev/null +++ b/tools/llvm-objdump/MachODump.cpp @@ -0,0 +1,617 @@ +//===-- MachODump.cpp - Object file dumping utility for llvm --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MachO-specific dumper for llvm-objdump. +// +//===----------------------------------------------------------------------===// + +#include "llvm-objdump.h" +#include "MCFunction.h" +#include "llvm/Support/MachO.h" +#include "llvm/Object/MachOObject.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrAnalysis.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" +#include <algorithm> +#include <cstring> +using namespace llvm; +using namespace object; + +static cl::opt<bool> + CFG("cfg", cl::desc("Create a CFG for every symbol in the object file and" + "write it to a graphviz file (MachO-only)")); + +static cl::opt<bool> + UseDbg("g", cl::desc("Print line information from debug info if available")); + +static cl::opt<std::string> + DSYMFile("dsym", cl::desc("Use .dSYM file for debug info")); + +static const Target *GetTarget(const MachOObject *MachOObj) { + // Figure out the target triple. + llvm::Triple TT("unknown-unknown-unknown"); + switch (MachOObj->getHeader().CPUType) { + case llvm::MachO::CPUTypeI386: + TT.setArch(Triple::ArchType(Triple::x86)); + break; + case llvm::MachO::CPUTypeX86_64: + TT.setArch(Triple::ArchType(Triple::x86_64)); + break; + case llvm::MachO::CPUTypeARM: + TT.setArch(Triple::ArchType(Triple::arm)); + break; + case llvm::MachO::CPUTypePowerPC: + TT.setArch(Triple::ArchType(Triple::ppc)); + break; + case llvm::MachO::CPUTypePowerPC64: + TT.setArch(Triple::ArchType(Triple::ppc64)); + break; + } + + TripleName = TT.str(); + + // Get the target specific parser. + std::string Error; + const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error); + if (TheTarget) + return TheTarget; + + errs() << "llvm-objdump: error: unable to get target for '" << TripleName + << "', see --version and --triple.\n"; + return 0; +} + +struct Section { + char Name[16]; + uint64_t Address; + uint64_t Size; + uint32_t Offset; + uint32_t NumRelocs; + uint64_t RelocTableOffset; +}; + +struct Symbol { + uint64_t Value; + uint32_t StringIndex; + uint8_t SectionIndex; + bool operator<(const Symbol &RHS) const { return Value < RHS.Value; } +}; + +template <typename T> +static Section copySection(const T &Sect) { + Section S; + memcpy(S.Name, Sect->Name, 16); + S.Address = Sect->Address; + S.Size = Sect->Size; + S.Offset = Sect->Offset; + S.NumRelocs = Sect->NumRelocationTableEntries; + S.RelocTableOffset = Sect->RelocationTableOffset; + return S; +} + +template <typename T> +static Symbol copySymbol(const T &STE) { + Symbol S; + S.StringIndex = STE->StringIndex; + S.SectionIndex = STE->SectionIndex; + S.Value = STE->Value; + return S; +} + +// Print additional information about an address, if available. +static void DumpAddress(uint64_t Address, ArrayRef<Section> Sections, + MachOObject *MachOObj, raw_ostream &OS) { + for (unsigned i = 0; i != Sections.size(); ++i) { + uint64_t addr = Address-Sections[i].Address; + if (Sections[i].Address <= Address && + Sections[i].Address + Sections[i].Size > Address) { + StringRef bytes = MachOObj->getData(Sections[i].Offset, + Sections[i].Size); + // Print constant strings. + if (!strcmp(Sections[i].Name, "__cstring")) + OS << '"' << bytes.substr(addr, bytes.find('\0', addr)) << '"'; + // Print constant CFStrings. + if (!strcmp(Sections[i].Name, "__cfstring")) + OS << "@\"" << bytes.substr(addr, bytes.find('\0', addr)) << '"'; + } + } +} + +typedef std::map<uint64_t, MCFunction*> FunctionMapTy; +typedef SmallVector<MCFunction, 16> FunctionListTy; +static void createMCFunctionAndSaveCalls(StringRef Name, + const MCDisassembler *DisAsm, + MemoryObject &Object, uint64_t Start, + uint64_t End, + MCInstrAnalysis *InstrAnalysis, + uint64_t Address, + raw_ostream &DebugOut, + FunctionMapTy &FunctionMap, + FunctionListTy &Functions) { + SmallVector<uint64_t, 16> Calls; + MCFunction f = + MCFunction::createFunctionFromMC(Name, DisAsm, Object, Start, End, + InstrAnalysis, DebugOut, Calls); + Functions.push_back(f); + FunctionMap[Address] = &Functions.back(); + + // Add the gathered callees to the map. + for (unsigned i = 0, e = Calls.size(); i != e; ++i) + FunctionMap.insert(std::make_pair(Calls[i], (MCFunction*)0)); +} + +// Write a graphviz file for the CFG inside an MCFunction. +static void emitDOTFile(const char *FileName, const MCFunction &f, + MCInstPrinter *IP) { + // Start a new dot file. + std::string Error; + raw_fd_ostream Out(FileName, Error); + if (!Error.empty()) { + errs() << "llvm-objdump: warning: " << Error << '\n'; + return; + } + + Out << "digraph " << f.getName() << " {\n"; + Out << "graph [ rankdir = \"LR\" ];\n"; + for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) { + bool hasPreds = false; + // Only print blocks that have predecessors. + // FIXME: Slow. + for (MCFunction::iterator pi = f.begin(), pe = f.end(); pi != pe; + ++pi) + if (pi->second.contains(i->first)) { + hasPreds = true; + break; + } + + if (!hasPreds && i != f.begin()) + continue; + + Out << '"' << i->first << "\" [ label=\"<a>"; + // Print instructions. + for (unsigned ii = 0, ie = i->second.getInsts().size(); ii != ie; + ++ii) { + // Escape special chars and print the instruction in mnemonic form. + std::string Str; + raw_string_ostream OS(Str); + IP->printInst(&i->second.getInsts()[ii].Inst, OS, ""); + Out << DOT::EscapeString(OS.str()) << '|'; + } + Out << "<o>\" shape=\"record\" ];\n"; + + // Add edges. + for (MCBasicBlock::succ_iterator si = i->second.succ_begin(), + se = i->second.succ_end(); si != se; ++si) + Out << i->first << ":o -> " << *si <<":a\n"; + } + Out << "}\n"; +} + +static void getSectionsAndSymbols(const macho::Header &Header, + MachOObject *MachOObj, + InMemoryStruct<macho::SymtabLoadCommand> *SymtabLC, + std::vector<Section> &Sections, + std::vector<Symbol> &Symbols, + SmallVectorImpl<uint64_t> &FoundFns) { + // Make a list of all symbols in the object file. + for (unsigned i = 0; i != Header.NumLoadCommands; ++i) { + const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i); + if (LCI.Command.Type == macho::LCT_Segment) { + InMemoryStruct<macho::SegmentLoadCommand> SegmentLC; + MachOObj->ReadSegmentLoadCommand(LCI, SegmentLC); + + // Store the sections in this segment. + for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) { + InMemoryStruct<macho::Section> Sect; + MachOObj->ReadSection(LCI, SectNum, Sect); + Sections.push_back(copySection(Sect)); + + } + } else if (LCI.Command.Type == macho::LCT_Segment64) { + InMemoryStruct<macho::Segment64LoadCommand> Segment64LC; + MachOObj->ReadSegment64LoadCommand(LCI, Segment64LC); + + // Store the sections in this segment. + for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections; + ++SectNum) { + InMemoryStruct<macho::Section64> Sect64; + MachOObj->ReadSection64(LCI, SectNum, Sect64); + Sections.push_back(copySection(Sect64)); + } + } else if (LCI.Command.Type == macho::LCT_FunctionStarts) { + // We found a function starts segment, parse the addresses for later + // consumption. + InMemoryStruct<macho::LinkeditDataLoadCommand> LLC; + MachOObj->ReadLinkeditDataLoadCommand(LCI, LLC); + + MachOObj->ReadULEB128s(LLC->DataOffset, FoundFns); + } + } + // Store the symbols. + if (SymtabLC) { + for (unsigned i = 0; i != (*SymtabLC)->NumSymbolTableEntries; ++i) { + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> STE; + MachOObj->ReadSymbol64TableEntry((*SymtabLC)->SymbolTableOffset, i, + STE); + Symbols.push_back(copySymbol(STE)); + } else { + InMemoryStruct<macho::SymbolTableEntry> STE; + MachOObj->ReadSymbolTableEntry((*SymtabLC)->SymbolTableOffset, i, + STE); + Symbols.push_back(copySymbol(STE)); + } + } + } +} + +void llvm::DisassembleInputMachO(StringRef Filename) { + OwningPtr<MemoryBuffer> Buff; + + if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { + errs() << "llvm-objdump: " << Filename << ": " << ec.message() << "\n"; + return; + } + + OwningPtr<MachOObject> MachOObj(MachOObject::LoadFromBuffer(Buff.take())); + + const Target *TheTarget = GetTarget(MachOObj.get()); + if (!TheTarget) { + // GetTarget prints out stuff. + return; + } + OwningPtr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo()); + OwningPtr<MCInstrAnalysis> + InstrAnalysis(TheTarget->createMCInstrAnalysis(InstrInfo.get())); + + // Set up disassembler. + OwningPtr<const MCAsmInfo> AsmInfo(TheTarget->createMCAsmInfo(TripleName)); + OwningPtr<const MCSubtargetInfo> + STI(TheTarget->createMCSubtargetInfo(TripleName, "", "")); + OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); + int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); + OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( + AsmPrinterVariant, *AsmInfo, *STI)); + + if (!InstrAnalysis || !AsmInfo || !STI || !DisAsm || !IP) { + errs() << "error: couldn't initialize disassembler for target " + << TripleName << '\n'; + return; + } + + outs() << '\n' << Filename << ":\n\n"; + + const macho::Header &Header = MachOObj->getHeader(); + + const MachOObject::LoadCommandInfo *SymtabLCI = 0; + // First, find the symbol table segment. + for (unsigned i = 0; i != Header.NumLoadCommands; ++i) { + const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i); + if (LCI.Command.Type == macho::LCT_Symtab) { + SymtabLCI = &LCI; + break; + } + } + + // Read and register the symbol table data. + InMemoryStruct<macho::SymtabLoadCommand> SymtabLC; + MachOObj->ReadSymtabLoadCommand(*SymtabLCI, SymtabLC); + MachOObj->RegisterStringTable(*SymtabLC); + + std::vector<Section> Sections; + std::vector<Symbol> Symbols; + SmallVector<uint64_t, 8> FoundFns; + + getSectionsAndSymbols(Header, MachOObj.get(), &SymtabLC, Sections, Symbols, + FoundFns); + + // Make a copy of the unsorted symbol list. FIXME: duplication + std::vector<Symbol> UnsortedSymbols(Symbols); + // Sort the symbols by address, just in case they didn't come in that way. + array_pod_sort(Symbols.begin(), Symbols.end()); + +#ifndef NDEBUG + raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); +#else + raw_ostream &DebugOut = nulls(); +#endif + + StringRef DebugAbbrevSection, DebugInfoSection, DebugArangesSection, + DebugLineSection, DebugStrSection; + OwningPtr<DIContext> diContext; + OwningPtr<MachOObject> DSYMObj; + MachOObject *DbgInfoObj = MachOObj.get(); + // Try to find debug info and set up the DIContext for it. + if (UseDbg) { + ArrayRef<Section> DebugSections = Sections; + std::vector<Section> DSYMSections; + + // A separate DSym file path was specified, parse it as a macho file, + // get the sections and supply it to the section name parsing machinery. + if (!DSYMFile.empty()) { + OwningPtr<MemoryBuffer> Buf; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile.c_str(), Buf)) { + errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n'; + return; + } + DSYMObj.reset(MachOObject::LoadFromBuffer(Buf.take())); + const macho::Header &Header = DSYMObj->getHeader(); + + std::vector<Symbol> Symbols; + SmallVector<uint64_t, 8> FoundFns; + getSectionsAndSymbols(Header, DSYMObj.get(), 0, DSYMSections, Symbols, + FoundFns); + DebugSections = DSYMSections; + DbgInfoObj = DSYMObj.get(); + } + + // Find the named debug info sections. + for (unsigned SectIdx = 0; SectIdx != DebugSections.size(); SectIdx++) { + if (!strcmp(DebugSections[SectIdx].Name, "__debug_abbrev")) + DebugAbbrevSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_info")) + DebugInfoSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_aranges")) + DebugArangesSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_line")) + DebugLineSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_str")) + DebugStrSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + } + + // Setup the DIContext. + diContext.reset(DIContext::getDWARFContext(DbgInfoObj->isLittleEndian(), + DebugInfoSection, + DebugAbbrevSection, + DebugArangesSection, + DebugLineSection, + DebugStrSection)); + } + + FunctionMapTy FunctionMap; + FunctionListTy Functions; + + for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) { + if (strcmp(Sections[SectIdx].Name, "__text")) + continue; // Skip non-text sections + + // Insert the functions from the function starts segment into our map. + uint64_t VMAddr = Sections[SectIdx].Address - Sections[SectIdx].Offset; + for (unsigned i = 0, e = FoundFns.size(); i != e; ++i) + FunctionMap.insert(std::make_pair(FoundFns[i]+VMAddr, (MCFunction*)0)); + + StringRef Bytes = MachOObj->getData(Sections[SectIdx].Offset, + Sections[SectIdx].Size); + StringRefMemoryObject memoryObject(Bytes); + bool symbolTableWorked = false; + + // Parse relocations. + std::vector<std::pair<uint64_t, uint32_t> > Relocs; + for (unsigned j = 0; j != Sections[SectIdx].NumRelocs; ++j) { + InMemoryStruct<macho::RelocationEntry> RE; + MachOObj->ReadRelocationEntry(Sections[SectIdx].RelocTableOffset, j, RE); + Relocs.push_back(std::make_pair(RE->Word0, RE->Word1 & 0xffffff)); + } + array_pod_sort(Relocs.begin(), Relocs.end()); + + // Disassemble symbol by symbol. + for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) { + // Make sure the symbol is defined in this section. + if ((unsigned)Symbols[SymIdx].SectionIndex - 1 != SectIdx) + continue; + + // Start at the address of the symbol relative to the section's address. + uint64_t Start = Symbols[SymIdx].Value - Sections[SectIdx].Address; + // Stop disassembling either at the beginning of the next symbol or at + // the end of the section. + uint64_t End = (SymIdx+1 == Symbols.size() || + Symbols[SymIdx].SectionIndex != Symbols[SymIdx+1].SectionIndex) ? + Sections[SectIdx].Size : + Symbols[SymIdx+1].Value - Sections[SectIdx].Address; + uint64_t Size; + + if (Start >= End) + continue; + + symbolTableWorked = true; + + if (!CFG) { + // Normal disassembly, print addresses, bytes and mnemonic form. + outs() << MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex) + << ":\n"; + DILineInfo lastLine; + for (uint64_t Index = Start; Index < End; Index += Size) { + MCInst Inst; + + if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, + DebugOut, nulls())) { + outs() << format("%8llx:\t", Sections[SectIdx].Address + Index); + DumpBytes(StringRef(Bytes.data() + Index, Size)); + IP->printInst(&Inst, outs(), ""); + + // Print debug info. + if (diContext) { + DILineInfo dli = + diContext->getLineInfoForAddress(Sections[SectIdx].Address + + Index); + // Print valid line info if it changed. + if (dli != lastLine && dli.getLine() != 0) + outs() << "\t## " << dli.getFileName() << ':' + << dli.getLine() << ':' << dli.getColumn(); + lastLine = dli; + } + outs() << "\n"; + } else { + errs() << "llvm-objdump: warning: invalid instruction encoding\n"; + if (Size == 0) + Size = 1; // skip illegible bytes + } + } + } else { + // Create CFG and use it for disassembly. + createMCFunctionAndSaveCalls( + MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex), + DisAsm.get(), memoryObject, Start, End, InstrAnalysis.get(), + Start, DebugOut, FunctionMap, Functions); + } + } + + if (CFG) { + if (!symbolTableWorked) { + // Reading the symbol table didn't work, create a big __TEXT symbol. + createMCFunctionAndSaveCalls("__TEXT", DisAsm.get(), memoryObject, + 0, Sections[SectIdx].Size, + InstrAnalysis.get(), + Sections[SectIdx].Offset, DebugOut, + FunctionMap, Functions); + } + for (std::map<uint64_t, MCFunction*>::iterator mi = FunctionMap.begin(), + me = FunctionMap.end(); mi != me; ++mi) + if (mi->second == 0) { + // Create functions for the remaining callees we have gathered, + // but we didn't find a name for them. + SmallVector<uint64_t, 16> Calls; + MCFunction f = + MCFunction::createFunctionFromMC("unknown", DisAsm.get(), + memoryObject, mi->first, + Sections[SectIdx].Size, + InstrAnalysis.get(), DebugOut, + Calls); + Functions.push_back(f); + mi->second = &Functions.back(); + for (unsigned i = 0, e = Calls.size(); i != e; ++i) { + std::pair<uint64_t, MCFunction*> p(Calls[i], (MCFunction*)0); + if (FunctionMap.insert(p).second) + mi = FunctionMap.begin(); + } + } + + DenseSet<uint64_t> PrintedBlocks; + for (unsigned ffi = 0, ffe = Functions.size(); ffi != ffe; ++ffi) { + MCFunction &f = Functions[ffi]; + for (MCFunction::iterator fi = f.begin(), fe = f.end(); fi != fe; ++fi){ + if (!PrintedBlocks.insert(fi->first).second) + continue; // We already printed this block. + + // We assume a block has predecessors when it's the first block after + // a symbol. + bool hasPreds = FunctionMap.find(fi->first) != FunctionMap.end(); + + // See if this block has predecessors. + // FIXME: Slow. + for (MCFunction::iterator pi = f.begin(), pe = f.end(); pi != pe; + ++pi) + if (pi->second.contains(fi->first)) { + hasPreds = true; + break; + } + + // No predecessors, this is a data block. Print as .byte directives. + if (!hasPreds) { + uint64_t End = llvm::next(fi) == fe ? Sections[SectIdx].Size : + llvm::next(fi)->first; + outs() << "# " << End-fi->first << " bytes of data:\n"; + for (unsigned pos = fi->first; pos != End; ++pos) { + outs() << format("%8x:\t", Sections[SectIdx].Address + pos); + DumpBytes(StringRef(Bytes.data() + pos, 1)); + outs() << format("\t.byte 0x%02x\n", (uint8_t)Bytes[pos]); + } + continue; + } + + if (fi->second.contains(fi->first)) // Print a header for simple loops + outs() << "# Loop begin:\n"; + + DILineInfo lastLine; + // Walk over the instructions and print them. + for (unsigned ii = 0, ie = fi->second.getInsts().size(); ii != ie; + ++ii) { + const MCDecodedInst &Inst = fi->second.getInsts()[ii]; + + // If there's a symbol at this address, print its name. + if (FunctionMap.find(Sections[SectIdx].Address + Inst.Address) != + FunctionMap.end()) + outs() << FunctionMap[Sections[SectIdx].Address + Inst.Address]-> + getName() << ":\n"; + + outs() << format("%8llx:\t", Sections[SectIdx].Address + + Inst.Address); + DumpBytes(StringRef(Bytes.data() + Inst.Address, Inst.Size)); + + if (fi->second.contains(fi->first)) // Indent simple loops. + outs() << '\t'; + + IP->printInst(&Inst.Inst, outs(), ""); + + // Look for relocations inside this instructions, if there is one + // print its target and additional information if available. + for (unsigned j = 0; j != Relocs.size(); ++j) + if (Relocs[j].first >= Sections[SectIdx].Address + Inst.Address && + Relocs[j].first < Sections[SectIdx].Address + Inst.Address + + Inst.Size) { + outs() << "\t# " + << MachOObj->getStringAtIndex( + UnsortedSymbols[Relocs[j].second].StringIndex) + << ' '; + DumpAddress(UnsortedSymbols[Relocs[j].second].Value, Sections, + MachOObj.get(), outs()); + } + + // If this instructions contains an address, see if we can evaluate + // it and print additional information. + uint64_t targ = InstrAnalysis->evaluateBranch(Inst.Inst, + Inst.Address, + Inst.Size); + if (targ != -1ULL) + DumpAddress(targ, Sections, MachOObj.get(), outs()); + + // Print debug info. + if (diContext) { + DILineInfo dli = + diContext->getLineInfoForAddress(Sections[SectIdx].Address + + Inst.Address); + // Print valid line info if it changed. + if (dli != lastLine && dli.getLine() != 0) + outs() << "\t## " << dli.getFileName() << ':' + << dli.getLine() << ':' << dli.getColumn(); + lastLine = dli; + } + + outs() << '\n'; + } + } + + emitDOTFile((f.getName().str() + ".dot").c_str(), f, IP.get()); + } + } + } +} diff --git a/tools/llvm-objdump/Makefile b/tools/llvm-objdump/Makefile index 4d7cd34..703bf6c 100644 --- a/tools/llvm-objdump/Makefile +++ b/tools/llvm-objdump/Makefile @@ -9,7 +9,8 @@ LEVEL = ../.. TOOLNAME = llvm-objdump -LINK_COMPONENTS = $(TARGETS_TO_BUILD) MC MCParser MCDisassembler Object +LINK_COMPONENTS = $(TARGETS_TO_BUILD) DebugInfo MC MCParser MCDisassembler \ + Object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 4079e4a..4ae13be 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -13,6 +13,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm-objdump.h" +#include "MCFunction.h" +#include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Triple.h" @@ -21,9 +24,13 @@ #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" +#include "llvm/Support/GraphWriter.h" #include "llvm/Support/Host.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" @@ -31,44 +38,59 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Target/TargetSelect.h" #include <algorithm> #include <cstring> using namespace llvm; using namespace object; -namespace { - cl::list<std::string> - InputFilenames(cl::Positional, cl::desc("<input object files>"), - cl::ZeroOrMore); +static cl::list<std::string> +InputFilenames(cl::Positional, cl::desc("<input object files>"),cl::ZeroOrMore); - cl::opt<bool> - Disassemble("disassemble", - cl::desc("Display assembler mnemonics for the machine instructions")); - cl::alias - Disassembled("d", cl::desc("Alias for --disassemble"), - cl::aliasopt(Disassemble)); +static cl::opt<bool> +Disassemble("disassemble", + cl::desc("Display assembler mnemonics for the machine instructions")); +static cl::alias +Disassembled("d", cl::desc("Alias for --disassemble"), + cl::aliasopt(Disassemble)); - cl::opt<std::string> - TripleName("triple", cl::desc("Target triple to disassemble for, " +static cl::opt<bool> +Relocations("r", cl::desc("Display the relocation entries in the file")); + +static cl::opt<bool> +MachO("macho", cl::desc("Use MachO specific object file parser")); +static cl::alias +MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachO)); + +cl::opt<std::string> +llvm::TripleName("triple", cl::desc("Target triple to disassemble for, " + "see -version for available targets")); + +cl::opt<std::string> +llvm::ArchName("arch", cl::desc("Target arch to disassemble for, " "see -version for available targets")); - cl::opt<std::string> - ArchName("arch", cl::desc("Target arch to disassemble for, " - "see -version for available targets")); +static cl::opt<bool> +SectionHeaders("section-headers", cl::desc("Display summaries of the headers " + "for each section.")); +static cl::alias +SectionHeadersShort("headers", cl::desc("Alias for --section-headers"), + cl::aliasopt(SectionHeaders)); +static cl::alias +SectionHeadersShorter("h", cl::desc("Alias for --section-headers"), + cl::aliasopt(SectionHeaders)); - StringRef ToolName; +static StringRef ToolName; - bool error(error_code ec) { - if (!ec) return false; +static bool error(error_code ec) { + if (!ec) return false; - outs() << ToolName << ": error reading file: " << ec.message() << ".\n"; - outs().flush(); - return true; - } + outs() << ToolName << ": error reading file: " << ec.message() << ".\n"; + outs().flush(); + return true; } static const Target *GetTarget(const ObjectFile *Obj = NULL) { @@ -96,27 +118,8 @@ static const Target *GetTarget(const ObjectFile *Obj = NULL) { return 0; } -namespace { -class StringRefMemoryObject : public MemoryObject { -private: - StringRef Bytes; -public: - StringRefMemoryObject(StringRef bytes) : Bytes(bytes) {} - - uint64_t getBase() const { return 0; } - uint64_t getExtent() const { return Bytes.size(); } - - int readByte(uint64_t Addr, uint8_t *Byte) const { - if (Addr > getExtent()) - return -1; - *Byte = Bytes[Addr]; - return 0; - } -}; -} - -static void DumpBytes(StringRef bytes) { - static char hex_rep[] = "0123456789abcdef"; +void llvm::DumpBytes(StringRef bytes) { + static const char hex_rep[] = "0123456789abcdef"; // FIXME: The real way to do this is to figure out the longest instruction // and align to that size before printing. I'll fix this when I get // around to outputting relocations. @@ -141,44 +144,45 @@ static void DumpBytes(StringRef bytes) { outs() << output; } -static void DisassembleInput(const StringRef &Filename) { - OwningPtr<MemoryBuffer> Buff; - - if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { - errs() << ToolName << ": " << Filename << ": " << ec.message() << "\n"; - return; - } - - OwningPtr<ObjectFile> Obj(ObjectFile::createObjectFile(Buff.take())); +static bool RelocAddressLess(RelocationRef a, RelocationRef b) { + uint64_t a_addr, b_addr; + if (error(a.getAddress(a_addr))) return false; + if (error(b.getAddress(b_addr))) return false; + return a_addr < b_addr; +} - const Target *TheTarget = GetTarget(Obj.get()); +static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { + const Target *TheTarget = GetTarget(Obj); if (!TheTarget) { // GetTarget prints out stuff. return; } outs() << '\n'; - outs() << Filename + outs() << Obj->getFileName() << ":\tfile format " << Obj->getFileFormatName() << "\n\n"; error_code ec; - for (ObjectFile::section_iterator i = Obj->begin_sections(), - e = Obj->end_sections(); - i != e; i.increment(ec)) { + for (section_iterator i = Obj->begin_sections(), + e = Obj->end_sections(); + i != e; i.increment(ec)) { if (error(ec)) break; bool text; if (error(i->isText(text))) break; if (!text) continue; + uint64_t SectionAddr; + if (error(i->getAddress(SectionAddr))) break; + // Make a list of all the symbols in this section. std::vector<std::pair<uint64_t, StringRef> > Symbols; - for (ObjectFile::symbol_iterator si = Obj->begin_symbols(), - se = Obj->end_symbols(); - si != se; si.increment(ec)) { + for (symbol_iterator si = Obj->begin_symbols(), + se = Obj->end_symbols(); + si != se; si.increment(ec)) { bool contains; if (!error(i->containsSymbol(*si, contains)) && contains) { uint64_t Address; - if (error(si->getAddress(Address))) break; + if (error(si->getOffset(Address))) break; StringRef Name; if (error(si->getName(Name))) break; Symbols.push_back(std::make_pair(Address, Name)); @@ -188,6 +192,20 @@ static void DisassembleInput(const StringRef &Filename) { // Sort the symbols by address, just in case they didn't come in that way. array_pod_sort(Symbols.begin(), Symbols.end()); + // Make a list of all the relocations for this section. + std::vector<RelocationRef> Rels; + if (InlineRelocs) { + for (relocation_iterator ri = i->begin_relocations(), + re = i->end_relocations(); + ri != re; ri.increment(ec)) { + if (error(ec)) break; + Rels.push_back(*ri); + } + } + + // Sort relocations by address. + std::sort(Rels.begin(), Rels.end(), RelocAddressLess); + StringRef name; if (error(i->getName(name))) break; outs() << "Disassembly of section " << name << ':'; @@ -205,7 +223,16 @@ static void DisassembleInput(const StringRef &Filename) { return; } - OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler()); + OwningPtr<const MCSubtargetInfo> STI( + TheTarget->createMCSubtargetInfo(TripleName, "", "")); + + if (!STI) { + errs() << "error: no subtarget info for target " << TripleName << "\n"; + return; + } + + OwningPtr<const MCDisassembler> DisAsm( + TheTarget->createMCDisassembler(*STI)); if (!DisAsm) { errs() << "error: no disassembler for target " << TripleName << "\n"; return; @@ -213,9 +240,10 @@ static void DisassembleInput(const StringRef &Filename) { int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( - AsmPrinterVariant, *AsmInfo)); + AsmPrinterVariant, *AsmInfo, *STI)); if (!IP) { - errs() << "error: no instruction printer for target " << TripleName << '\n'; + errs() << "error: no instruction printer for target " << TripleName + << '\n'; return; } @@ -227,14 +255,24 @@ static void DisassembleInput(const StringRef &Filename) { uint64_t SectSize; if (error(i->getSize(SectSize))) break; + std::vector<RelocationRef>::const_iterator rel_cur = Rels.begin(); + std::vector<RelocationRef>::const_iterator rel_end = Rels.end(); // Disassemble symbol by symbol. for (unsigned si = 0, se = Symbols.size(); si != se; ++si) { uint64_t Start = Symbols[si].first; - uint64_t End = si == se-1 ? SectSize : Symbols[si + 1].first - 1; - outs() << '\n' << Symbols[si].second << ":\n"; + uint64_t End; + // The end is either the size of the section or the beginning of the next + // symbol. + if (si == se - 1) + End = SectSize; + // Make sure this symbol takes up space. + else if (Symbols[si + 1].first != Start) + End = Symbols[si + 1].first - 1; + else + // This symbol has the same address as the next symbol. Skip it. + continue; - for (Index = Start; Index < End; Index += Size) { - MCInst Inst; + outs() << '\n' << Symbols[si].second << ":\n"; #ifndef NDEBUG raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); @@ -242,23 +280,152 @@ static void DisassembleInput(const StringRef &Filename) { raw_ostream &DebugOut = nulls(); #endif - if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, DebugOut)) { - uint64_t addr; - if (error(i->getAddress(addr))) break; - outs() << format("%8x:\t", addr + Index); + for (Index = Start; Index < End; Index += Size) { + MCInst Inst; + + if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, + DebugOut, nulls())) { + outs() << format("%8x:\t", SectionAddr + Index); DumpBytes(StringRef(Bytes.data() + Index, Size)); - IP->printInst(&Inst, outs()); + IP->printInst(&Inst, outs(), ""); outs() << "\n"; } else { errs() << ToolName << ": warning: invalid instruction encoding\n"; if (Size == 0) Size = 1; // skip illegible bytes } + + // Print relocation for instruction. + while (rel_cur != rel_end) { + uint64_t addr; + SmallString<16> name; + SmallString<32> val; + if (error(rel_cur->getAddress(addr))) goto skip_print_rel; + // Stop when rel_cur's address is past the current instruction. + if (addr > Index + Size) break; + if (error(rel_cur->getTypeName(name))) goto skip_print_rel; + if (error(rel_cur->getValueString(val))) goto skip_print_rel; + + outs() << format("\t\t\t%8x: ", SectionAddr + addr) << name << "\t" + << val << "\n"; + + skip_print_rel: + ++rel_cur; + } } } } } +static void PrintRelocations(const ObjectFile *o) { + error_code ec; + for (section_iterator si = o->begin_sections(), se = o->end_sections(); + si != se; si.increment(ec)){ + if (error(ec)) return; + if (si->begin_relocations() == si->end_relocations()) + continue; + StringRef secname; + if (error(si->getName(secname))) continue; + outs() << "RELOCATION RECORDS FOR [" << secname << "]:\n"; + for (relocation_iterator ri = si->begin_relocations(), + re = si->end_relocations(); + ri != re; ri.increment(ec)) { + if (error(ec)) return; + + uint64_t address; + SmallString<32> relocname; + SmallString<32> valuestr; + if (error(ri->getTypeName(relocname))) continue; + if (error(ri->getAddress(address))) continue; + if (error(ri->getValueString(valuestr))) continue; + outs() << address << " " << relocname << " " << valuestr << "\n"; + } + outs() << "\n"; + } +} + +static void PrintSectionHeaders(const ObjectFile *o) { + outs() << "Sections:\n" + "Idx Name Size Address Type\n"; + error_code ec; + unsigned i = 0; + for (section_iterator si = o->begin_sections(), se = o->end_sections(); + si != se; si.increment(ec)) { + if (error(ec)) return; + StringRef Name; + if (error(si->getName(Name))) return; + uint64_t Address; + if (error(si->getAddress(Address))) return; + uint64_t Size; + if (error(si->getSize(Size))) return; + bool Text, Data, BSS; + if (error(si->isText(Text))) return; + if (error(si->isData(Data))) return; + if (error(si->isBSS(BSS))) return; + std::string Type = (std::string(Text ? "TEXT " : "") + + (Data ? "DATA " : "") + (BSS ? "BSS" : "")); + outs() << format("%3d %-13s %09"PRIx64" %017"PRIx64" %s\n", i, Name.str().c_str(), Size, + Address, Type.c_str()); + ++i; + } +} + +static void DumpObject(const ObjectFile *o) { + if (Disassemble) + DisassembleObject(o, Relocations); + if (Relocations && !Disassemble) + PrintRelocations(o); + if (SectionHeaders) + PrintSectionHeaders(o); +} + +/// @brief Dump each object file in \a a; +static void DumpArchive(const Archive *a) { + for (Archive::child_iterator i = a->begin_children(), + e = a->end_children(); i != e; ++i) { + OwningPtr<Binary> child; + if (error_code ec = i->getAsBinary(child)) { + errs() << ToolName << ": '" << a->getFileName() << "': " << ec.message() + << ".\n"; + continue; + } + if (ObjectFile *o = dyn_cast<ObjectFile>(child.get())) + DumpObject(o); + else + errs() << ToolName << ": '" << a->getFileName() << "': " + << "Unrecognized file type.\n"; + } +} + +/// @brief Open file and figure out how to dump it. +static void DumpInput(StringRef file) { + // If file isn't stdin, check that it exists. + if (file != "-" && !sys::fs::exists(file)) { + errs() << ToolName << ": '" << file << "': " << "No such file\n"; + return; + } + + if (MachO && Disassemble) { + DisassembleInputMachO(file); + return; + } + + // Attempt to open the binary. + OwningPtr<Binary> binary; + if (error_code ec = createBinary(file, binary)) { + errs() << ToolName << ": '" << file << "': " << ec.message() << ".\n"; + return; + } + + if (Archive *a = dyn_cast<Archive>(binary.get())) { + DumpArchive(a); + } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) { + DumpObject(o); + } else { + errs() << ToolName << ": '" << file << "': " << "Unrecognized file type.\n"; + } +} + int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); @@ -267,10 +434,7 @@ int main(int argc, char **argv) { // Initialize targets and assembly printers/parsers. llvm::InitializeAllTargetInfos(); - // FIXME: We shouldn't need to initialize the Target(Machine)s. - llvm::InitializeAllTargets(); - llvm::InitializeAllMCAsmInfos(); - llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmParsers(); llvm::InitializeAllDisassemblers(); @@ -283,15 +447,13 @@ int main(int argc, char **argv) { if (InputFilenames.size() == 0) InputFilenames.push_back("a.out"); - // -d is the only flag that is currently implemented, so just print help if - // it is not set. - if (!Disassemble) { + if (!Disassemble && !Relocations && !SectionHeaders) { cl::PrintHelpMessage(); return 2; } std::for_each(InputFilenames.begin(), InputFilenames.end(), - DisassembleInput); + DumpInput); return 0; } diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h new file mode 100644 index 0000000..75f852a --- /dev/null +++ b/tools/llvm-objdump/llvm-objdump.h @@ -0,0 +1,46 @@ +//===-- llvm-objdump.h ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJDUMP_H +#define LLVM_OBJDUMP_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/MemoryObject.h" + +namespace llvm { + +extern cl::opt<std::string> TripleName; +extern cl::opt<std::string> ArchName; + +// Various helper functions. +void DumpBytes(StringRef bytes); +void DisassembleInputMachO(StringRef Filename); + +class StringRefMemoryObject : public MemoryObject { +private: + StringRef Bytes; +public: + StringRefMemoryObject(StringRef bytes) : Bytes(bytes) {} + + uint64_t getBase() const { return 0; } + uint64_t getExtent() const { return Bytes.size(); } + + int readByte(uint64_t Addr, uint8_t *Byte) const { + if (Addr >= getExtent()) + return -1; + *Byte = Bytes[Addr]; + return 0; + } +}; + +} + +#endif diff --git a/tools/llvm-shlib/Makefile b/tools/llvm-shlib/Makefile index 9e6faca..0695c00 100644 --- a/tools/llvm-shlib/Makefile +++ b/tools/llvm-shlib/Makefile @@ -30,10 +30,11 @@ endif include $(LEVEL)/Makefile.common # Include all archives in libLLVM.(so|dylib) except the ones that have -# their own dynamic libraries. +# their own dynamic libraries and TableGen. Archives := $(wildcard $(LibDir)/libLLVM*.a) SharedLibraries := $(wildcard $(LibDir)/libLLVM*$(SHLIBEXT)) -IncludeInLibLlvm := $(filter-out $(basename $(SharedLibraries)).a, $(Archives)) +ExcludeFromLibLlvm := $(basename $(SharedLibraries)).a %/libLLVMTableGen.a +IncludeInLibLlvm := $(filter-out $(ExcludeFromLibLlvm), $(Archives)) LLVMLibsOptions := $(IncludeInLibLlvm:$(LibDir)/lib%.a=-l%) LLVMLibsPaths := $(IncludeInLibLlvm) diff --git a/tools/llvm-size/CMakeLists.txt b/tools/llvm-size/CMakeLists.txt new file mode 100644 index 0000000..933cc75 --- /dev/null +++ b/tools/llvm-size/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_LINK_COMPONENTS object) + +add_llvm_tool(llvm-size + llvm-size.cpp + ) diff --git a/tools/llvmc/examples/Simple/Makefile b/tools/llvm-size/Makefile index c10387c..5d0e27e 100644 --- a/tools/llvmc/examples/Simple/Makefile +++ b/tools/llvm-size/Makefile @@ -1,4 +1,4 @@ -##===- llvmc/examples/Simple/Makefile ----------------------*- Makefile -*-===## +##===- tools/llvm-size/Makefile ----------------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -6,10 +6,12 @@ # License. See LICENSE.TXT for details. # ##===----------------------------------------------------------------------===## +LEVEL = ../.. -LEVEL = ../../../.. +TOOLNAME = llvm-size +LINK_COMPONENTS = object -LLVMC_BASED_DRIVER = Simple -BUILT_SOURCES = Simple.inc +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 include $(LEVEL)/Makefile.common diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp new file mode 100644 index 0000000..70e5cb9 --- /dev/null +++ b/tools/llvm-size/llvm-size.cpp @@ -0,0 +1,311 @@ +//===-- llvm-size.cpp - Print the size of each object section -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that works like traditional Unix "size", +// that is, it prints out the size of each section, and the total size of all +// sections. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/APInt.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" +#include <algorithm> +#include <string> +using namespace llvm; +using namespace object; + +enum OutputFormatTy {berkeley, sysv}; +static cl::opt<OutputFormatTy> + OutputFormat("format", + cl::desc("Specify output format"), + cl::values(clEnumVal(sysv, "System V format"), + clEnumVal(berkeley, "Berkeley format"), + clEnumValEnd), + cl::init(berkeley)); + +static cl::opt<OutputFormatTy> + OutputFormatShort(cl::desc("Specify output format"), + cl::values(clEnumValN(sysv, "A", "System V format"), + clEnumValN(berkeley, "B", "Berkeley format"), + clEnumValEnd), + cl::init(berkeley)); + +enum RadixTy {octal = 8, decimal = 10, hexadecimal = 16}; +static cl::opt<unsigned int> + Radix("-radix", + cl::desc("Print size in radix. Only 8, 10, and 16 are valid"), + cl::init(decimal)); + +static cl::opt<RadixTy> + RadixShort(cl::desc("Print size in radix:"), + cl::values(clEnumValN(octal, "o", "Print size in octal"), + clEnumValN(decimal, "d", "Print size in decimal"), + clEnumValN(hexadecimal, "x", "Print size in hexadecimal"), + clEnumValEnd), + cl::init(decimal)); + +static cl::list<std::string> + InputFilenames(cl::Positional, cl::desc("<input files>"), + cl::ZeroOrMore); + +static std::string ToolName; + +/// @brief If ec is not success, print the error and return true. +static bool error(error_code ec) { + if (!ec) return false; + + outs() << ToolName << ": error reading file: " << ec.message() << ".\n"; + outs().flush(); + return true; +} + +/// @brief Get the length of the string that represents @p num in Radix +/// including the leading 0x or 0 for hexadecimal and octal respectively. +static size_t getNumLengthAsString(uint64_t num) { + APInt conv(64, num); + SmallString<32> result; + conv.toString(result, Radix, false, true); + return result.size(); +} + +/// @brief Print the size of each section in @p o. +/// +/// The format used is determined by @c OutputFormat and @c Radix. +static void PrintObjectSectionSizes(ObjectFile *o) { + uint64_t total = 0; + std::string fmtbuf; + raw_string_ostream fmt(fmtbuf); + + const char *radix_fmt = 0; + switch (Radix) { + case octal: + radix_fmt = "llo"; + break; + case decimal: + radix_fmt = "llu"; + break; + case hexadecimal: + radix_fmt = "llx"; + break; + } + if (OutputFormat == sysv) { + // Run two passes over all sections. The first gets the lengths needed for + // formatting the output. The second actually does the output. + std::size_t max_name_len = strlen("section"); + std::size_t max_size_len = strlen("size"); + std::size_t max_addr_len = strlen("addr"); + error_code ec; + for (section_iterator i = o->begin_sections(), + e = o->end_sections(); i != e; + i.increment(ec)) { + if (error(ec)) + return; + uint64_t size = 0; + if (error(i->getSize(size))) + return; + total += size; + + StringRef name; + uint64_t addr = 0; + if (error(i->getName(name))) return; + if (error(i->getAddress(addr))) return; + max_name_len = std::max(max_name_len, name.size()); + max_size_len = std::max(max_size_len, getNumLengthAsString(size)); + max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr)); + } + + // Add extra padding. + max_name_len += 2; + max_size_len += 2; + max_addr_len += 2; + + // Setup header format. + fmt << "%-" << max_name_len << "s " + << "%" << max_size_len << "s " + << "%" << max_addr_len << "s\n"; + + // Print header + outs() << format(fmt.str().c_str(), + static_cast<const char*>("section"), + static_cast<const char*>("size"), + static_cast<const char*>("addr")); + fmtbuf.clear(); + + // Setup per section format. + fmt << "%-" << max_name_len << "s " + << "%#" << max_size_len << radix_fmt << " " + << "%#" << max_addr_len << radix_fmt << "\n"; + + // Print each section. + for (section_iterator i = o->begin_sections(), + e = o->end_sections(); i != e; + i.increment(ec)) { + if (error(ec)) + return; + + StringRef name; + uint64_t size = 0; + uint64_t addr = 0; + if (error(i->getName(name))) return; + if (error(i->getSize(size))) return; + if (error(i->getAddress(addr))) return; + std::string namestr = name; + + outs() << format(fmt.str().c_str(), + namestr.c_str(), + size, + addr); + } + + // Print total. + fmtbuf.clear(); + fmt << "%-" << max_name_len << "s " + << "%#" << max_size_len << radix_fmt << "\n"; + outs() << format(fmt.str().c_str(), + static_cast<const char*>("Total"), + total); + } else { + // The Berkeley format does not display individual section sizes. It + // displays the cumulative size for each section type. + uint64_t total_text = 0; + uint64_t total_data = 0; + uint64_t total_bss = 0; + + // Make one pass over the section table to calculate sizes. + error_code ec; + for (section_iterator i = o->begin_sections(), + e = o->end_sections(); i != e; + i.increment(ec)) { + if (error(ec)) + return; + + uint64_t size = 0; + bool isText = false; + bool isData = false; + bool isBSS = false; + if (error(i->getSize(size))) return; + if (error(i->isText(isText))) return; + if (error(i->isData(isData))) return; + if (error(i->isBSS(isBSS))) return; + if (isText) + total_text += size; + else if (isData) + total_data += size; + else if (isBSS) + total_bss += size; + } + + total = total_text + total_data + total_bss; + + // Print result. + fmt << "%#7" << radix_fmt << " " + << "%#7" << radix_fmt << " " + << "%#7" << radix_fmt << " "; + outs() << format(fmt.str().c_str(), + total_text, + total_data, + total_bss); + fmtbuf.clear(); + fmt << "%7" << (Radix == octal ? "llo" : "llu") << " " + << "%7llx "; + outs() << format(fmt.str().c_str(), + total, + total); + } +} + +/// @brief Print the section sizes for @p file. If @p file is an archive, print +/// the section sizes for each archive member. +static void PrintFileSectionSizes(StringRef file) { + // If file is not stdin, check that it exists. + if (file != "-") { + bool exists; + if (sys::fs::exists(file, exists) || !exists) { + errs() << ToolName << ": '" << file << "': " << "No such file\n"; + return; + } + } + + // Attempt to open the binary. + OwningPtr<Binary> binary; + if (error_code ec = createBinary(file, binary)) { + errs() << ToolName << ": " << file << ": " << ec.message() << ".\n"; + return; + } + + if (Archive *a = dyn_cast<Archive>(binary.get())) { + // This is an archive. Iterate over each member and display its sizes. + for (object::Archive::child_iterator i = a->begin_children(), + e = a->end_children(); i != e; ++i) { + OwningPtr<Binary> child; + if (error_code ec = i->getAsBinary(child)) { + errs() << ToolName << ": " << file << ": " << ec.message() << ".\n"; + continue; + } + if (ObjectFile *o = dyn_cast<ObjectFile>(child.get())) { + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << a->getFileName() + << "):\n"; + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) + outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; + } + } + } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) { + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) + outs() << o->getFileName() << "\n"; + } else { + errs() << ToolName << ": " << file << ": " << "Unrecognized file type.\n"; + } + // System V adds an extra newline at the end of each file. + if (OutputFormat == sysv) + outs() << "\n"; +} + +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n"); + + ToolName = argv[0]; + if (OutputFormatShort.getNumOccurrences()) + OutputFormat = OutputFormatShort; + if (RadixShort.getNumOccurrences()) + Radix = RadixShort; + + if (InputFilenames.size() == 0) + InputFilenames.push_back("a.out"); + + if (OutputFormat == berkeley) + outs() << " text data bss " + << (Radix == octal ? "oct" : "dec") + << " hex filename\n"; + + std::for_each(InputFilenames.begin(), InputFilenames.end(), + PrintFileSectionSizes); + + return 0; +} diff --git a/tools/llvmc/CMakeLists.txt b/tools/llvmc/CMakeLists.txt deleted file mode 100644 index 10ad5d8..0000000 --- a/tools/llvmc/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# add_subdirectory(src) - -# TODO: support plugins and user-configured builds. -# See ./doc/LLVMC-Reference.rst "Customizing LLVMC: the compilation graph" diff --git a/tools/llvmc/Makefile b/tools/llvmc/Makefile deleted file mode 100644 index 7c03e2a..0000000 --- a/tools/llvmc/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- tools/llvmc/Makefile --------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../.. - -DIRS = src - -ifeq ($(BUILD_EXAMPLES),1) - OPTIONAL_DIRS += examples -endif - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/doc/LLVMC-Reference.rst b/tools/llvmc/doc/LLVMC-Reference.rst deleted file mode 100644 index 041aedf..0000000 --- a/tools/llvmc/doc/LLVMC-Reference.rst +++ /dev/null @@ -1,747 +0,0 @@ -=================================== -Customizing LLVMC: Reference Manual -=================================== -.. - This file was automatically generated by rst2html. - Please do not edit directly! - The ReST source lives in the directory 'tools/llvmc/doc'. - -.. contents:: - -.. raw:: html - - <div class="doc_author"> - <p>Written by <a href="mailto:foldr@codedgers.com">Mikhail Glushenkov</a></p> - </div> - -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 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. - -.. _TableGen: http://llvm.org/docs/TableGenFundamentals.html - - -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, -you shouldn't be able to notice them:: - - $ # This works as expected: - $ llvmc -O3 -Wall hello.cpp - $ ./a.out - hello - -One nice feature of LLVMC is that one doesn't have to distinguish between -different compilers for different languages (think ``g++`` vs. ``gcc``) - the -right toolchain is chosen automatically based on input language names (which -are, in turn, determined from file extensions). If you want to force files -ending with ".c" to compile as C++, use the ``-x`` option, just like you would -do it with ``gcc``:: - - $ # hello.c is really a C++ file - $ llvmc -x c++ hello.c - $ ./a.out - hello - -On the other hand, when using LLVMC as a linker to combine several C++ -object files you should provide the ``--linker`` option since it's -impossible for LLVMC to choose the right linker in that case:: - - $ llvmc -c hello.cpp - $ llvmc hello.o - [A lot of link-time errors skipped] - $ llvmc --linker=c++ hello.o - $ ./a.out - hello - -By default, LLVMC uses ``llvm-gcc`` to compile the source code. It is also -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 TableGen code: - -* ``-o FILE`` - Output file name. - -* ``-x LANGUAGE`` - Specify the language of the following input files - until the next -x option. - -* ``-v`` - Enable verbose mode, i.e. print out all executed commands. - -* ``--save-temps`` - Write temporary files to the current directory and do not - delete them on exit. This option can also take an argument: the - ``--save-temps=obj`` switch will write files into the directory specified with - the ``-o`` option. The ``--save-temps=cwd`` and ``--save-temps`` switches are - both synonyms for the default behaviour. - -* ``--temp-dir DIRECTORY`` - Store temporary files in the given directory. This - directory is deleted on exit unless ``--save-temps`` is specified. If - ``--save-temps=obj`` is also specified, ``--temp-dir`` is given the - precedence. - -* ``--check-graph`` - Check the compilation for common errors like mismatched - 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. - -* ``--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. - -* ``--help``, ``--help-hidden``, ``--version`` - These options have - their standard meaning. - -Compiling LLVMC-based drivers -============================= - -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/examples - $ cp -r Skeleton MyDriver - $ cd MyDriver - $ ls - AutoGenerated.td Hooks.cpp Main.cpp Makefile - -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_BASED_DRIVER`` -variable in the ``Makefile``:: - - LLVMC_BASED_DRIVER=MyDriver - -It can also be a good idea to put your TableGen code into a file with a less -generic name:: - - $ touch MyDriver.td - $ vim AutoGenerated.td - [...] - include "MyDriver.td" - -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. - -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/ - $ 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 - - -Customizing LLVMC: the compilation graph -======================================== - -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. - -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">, - Edge<"root", "llvm_gcc_assembler">, - ... - - Edge<"llvm_gcc_c", "llc">, - Edge<"llvm_gcc_cpp", "llc">, - ... - - OptionalEdge<"llvm_gcc_c", "opt", (case (switch_on "opt"), - (inc_weight))>, - OptionalEdge<"llvm_gcc_cpp", "opt", (case (switch_on "opt"), - (inc_weight))>, - ... - - OptionalEdge<"llvm_gcc_assembler", "llvm_gcc_cpp_linker", - (case (input_languages_contain "c++"), (inc_weight), - (or (parameter_equals "linker", "g++"), - (parameter_equals "linker", "c++")), (inc_weight))>, - ... - - ]>; - -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 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. - -Describing options -================== - -Command-line options supported by the driver are defined by using an -``OptionList``:: - - def Options : OptionList<[ - (switch_option "E", (help "Help string")), - (alias_option "quiet", "q") - ... - ]>; - -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: - - - ``switch_option`` - a simple boolean switch without arguments, for example - ``-O2`` or ``-time``. At most one occurrence is allowed by default. - - - ``parameter_option`` - option that takes one argument, for example - ``-std=c99``. It is also allowed to use spaces instead of the equality - sign: ``-std c99``. At most one occurrence is allowed. - - - ``parameter_list_option`` - same as the above, but more than one option - 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 - specified as ``-o file``; however, ``-o=file`` will be parsed incorrectly - (``=file`` will be interpreted as option value). At most one occurrence is - allowed. - - - ``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 - option types, aliases are not allowed to have any properties besides the - aliased option name. - Usage example: ``(alias_option "preprocess", "E")`` - - - ``switch_list_option`` - like ``switch_option`` with the ``zero_or_more`` - property, but remembers how many times the switch was turned on. Useful - mostly for forwarding. Example: when ``-foo`` is a switch option (with the - ``zero_or_more`` property), the command ``driver -foo -foo`` is forwarded - as ``some-tool -foo``, but when ``-foo`` is a switch list, the same command - is forwarded as ``some-tool -foo -foo``. - - -* Possible option properties: - - - ``help`` - help string associated with this option. Used for ``--help`` - output. - - - ``required`` - this option must be specified exactly once (or, in case of - the list options without the ``multi_val`` property, at least - once). Incompatible with ``optional`` and ``one_or_more``. - - - ``optional`` - the option can be specified either zero times or exactly - once. The default for switch options. Useful only for list options in - conjunction with ``multi_val``. Incompatible with ``required``, - ``zero_or_more`` and ``one_or_more``. - - - ``one_or_more`` - the option must be specified at least once. Can be useful - to allow switch options be both obligatory and be specified multiple - times. For list options is useful only in conjunction with ``multi_val``; - for ordinary it is synonymous with ``required``. Incompatible with - ``required``, ``optional`` and ``zero_or_more``. - - - ``zero_or_more`` - the option can be specified zero or more times. Useful - to allow a single switch option to be specified more than - once. Incompatible with ``required``, ``optional`` and ``one_or_more``. - - - ``hidden`` - the description of this option will not appear in - the ``--help`` output (but will appear in the ``--help-hidden`` - output). - - - ``really_hidden`` - the option will not be mentioned in any help - output. - - - ``comma_separated`` - Indicates that any commas specified for an option's - value should be used to split the value up into multiple values for the - option. This property is valid only for list options. In conjunction with - ``forward_value`` can be used to implement option forwarding in style of - gcc's ``-Wa,``. - - - ``multi_val n`` - this option takes *n* arguments (can be useful in some - special cases). Usage example: ``(parameter_list_option "foo", (multi_val - 3))``; the command-line syntax is '-foo a b c'. Only list options can have - this attribute; you can, however, use the ``one_or_more``, ``optional`` - and ``required`` properties. - - - ``init`` - this option has a default value, either a string (if it is a - parameter), or a boolean (if it is a switch; as in C++, boolean constants - are called ``true`` and ``false``). List options can't have ``init`` - attribute. - Usage examples: ``(switch_option "foo", (init true))``; ``(prefix_option - "bar", (init "baz"))``. - -.. _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. - -Examples:: - - // Edge weight calculation - - // Increases edge weight by 5 if "-A" is provided on the - // command-line, and by 5 more if "-B" is also provided. - (case - (switch_on "A"), (inc_weight 5), - (switch_on "B"), (inc_weight 5)) - - - // Tool command line specification - - // Evaluates to "cmdline1" if the option "-A" is provided on the - // command line; to "cmdline2" if "-B" is provided; - // otherwise to "cmdline3". - - (case - (switch_on "A"), "cmdline1", - (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. - -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. - -* Possible tests are: - - - ``switch_on`` - Returns true if a given command-line switch is provided by - the user. Can be given multiple arguments, in that case ``(switch_on "foo", - "bar", "baz")`` is equivalent to ``(and (switch_on "foo"), (switch_on - "bar"), (switch_on "baz"))``. - Example: ``(switch_on "opt")``. - - - ``any_switch_on`` - Given a number of switch options, returns true if any of - the switches is turned on. - Example: ``(any_switch_on "foo", "bar", "baz")`` is equivalent to ``(or - (switch_on "foo"), (switch_on "bar"), (switch_on "baz"))``. - - - ``parameter_equals`` - Returns true if a command-line parameter (first - argument) equals a given value (second argument). - Example: ``(parameter_equals "W", "all")``. - - - ``element_in_list`` - Returns true if a command-line parameter list (first - argument) contains a given value (second argument). - Example: ``(element_in_list "l", "pthread")``. - - - ``input_languages_contain`` - Returns true if a given language - belongs to the current input language set. - Example: ``(input_languages_contain "c++")``. - - - ``in_language`` - Evaluates to true if the input file language is equal to - the argument. At the moment works only with ``command`` and ``actions`` (on - non-join nodes). - Example: ``(in_language "c++")``. - - - ``not_empty`` - Returns true if a given option (which should be either a - parameter or a parameter list) is set by the user. Like ``switch_on``, can - be also given multiple arguments. - Examples: ``(not_empty "o")``, ``(not_empty "o", "l")``. - - - ``any_not_empty`` - Returns true if ``not_empty`` returns true for any of - the provided options. - Example: ``(any_not_empty "foo", "bar", "baz")`` is equivalent to ``(or - (not_empty "foo"), (not_empty "bar"), (not_empty "baz"))``. - - - ``empty`` - The opposite of ``not_empty``. Equivalent to ``(not (not_empty - X))``. Can be given multiple arguments. - - - ``any_not_empty`` - Returns true if ``not_empty`` returns true for any of - the provided options. - Example: ``(any_empty "foo", "bar", "baz")`` is equivalent to ``(or - (not_empty "foo"), (not_empty "bar"), (not_empty "baz"))``. - - - ``single_input_file`` - Returns true if there was only one input file - provided on the command-line. Used without arguments: - ``(single_input_file)``. - - - ``multiple_input_files`` - Equivalent to ``(not (single_input_file))`` (the - case of zero input files is considered an error). - - - ``default`` - Always evaluates to true. Should always be the last - test in the ``case`` expression. - - - ``and`` - A standard logical combinator that returns true iff all of - its arguments return true. Used like this: ``(and (test1), (test2), - ... (testN))``. Nesting of ``and`` and ``or`` is allowed, but not - encouraged. - - - ``or`` - A logical combinator that returns true iff any of its arguments - return true. - Example: ``(or (test1), (test2), ... (testN))``. - - - ``not`` - Standard unary logical combinator that negates its - argument. - 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 -``llvmc/src/Base.td`` file):: - - def llvm_gcc_cpp : Tool<[ - (in_language "c++"), - (out_language "llvm-assembler"), - (output_suffix "bc"), - (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. - -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. Used for typechecking and - mapping file extensions to tools. - - - ``out_language`` - output language name. Multiple output languages are - allowed. Used for typechecking the compilation graph. - - - ``output_suffix`` - output file suffix. Can also be changed dynamically, see - documentation on `actions`__. - -__ actions_ - - - ``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. - - - ``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_ - - - ``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:: - - def llvm_gcc_linker : Tool<[ - (in_language "object-code"), - (out_language "executable"), - (output_suffix "out"), - (command "llvm-gcc"), - (join), - (actions (case (not_empty "L"), (forward "L"), - (not_empty "l"), (forward "l"), - (not_empty "dummy"), - [(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 "join" property used in the example means that this tool behaves like a -linker. - -The list of all possible actions follows. - -* Possible actions: - - - ``append_cmd`` - Append a string to the tool invocation command. - Example: ``(case (switch_on "pthread"), (append_cmd "-lpthread"))``. - - - ``error`` - Exit with error. - Example: ``(error "Mixing -c and -S is not allowed!")``. - - - ``warning`` - Print a warning. - Example: ``(warning "Specifying both -O1 and -O2 is meaningless!")``. - - - ``forward`` - Forward the option unchanged. - Example: ``(forward "Wall")``. - - - ``forward_as`` - Change the option's name, but forward the argument - unchanged. - Example: ``(forward_as "O0", "--disable-optimization")``. - - - ``forward_value`` - Forward only option's value. Cannot be used with switch - options (since they don't have values), but works fine with lists. - Example: ``(forward_value "Wa,")``. - - - ``forward_transformed_value`` - As above, but applies a hook to the - option's value before forwarding (see `below`__). When - ``forward_transformed_value`` is applied to a list - option, the hook must have signature - ``std::string hooks::HookName (const std::vector<std::string>&)``. - Example: ``(forward_transformed_value "m", "ConvertToMAttr")``. - - __ hooks_ - - - ``output_suffix`` - Modify the output suffix of this tool. - Example: ``(output_suffix "i")``. - - - ``stop_compilation`` - Stop compilation after this tool processes its - input. Used without arguments. - Example: ``(stop_compilation)``. - - -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:: - - def LanguageMap : LanguageMap< - [LangToSuffixes<"c++", ["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]>, - LangToSuffixes<"c", ["c"]>, - ... - ]>; - -For example, without those definitions the following command wouldn't work:: - - $ llvmc hello.cpp - llvmc: Unknown suffix: cpp - -The language map entries are needed only for the tools that are linked from the -root node. A tool can have multiple output languages. - -Option preprocessor -=================== - -It is sometimes useful to run error-checking code before processing the -compilation graph. For example, if optimization options "-O1" and "-O2" are -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 ``llvm/src/Base.td.in``):: - - - def Preprocess : OptionPreprocessor< - (case (not (any_switch_on "O0", "O1", "O2", "O3")), - (set_option "O2"), - (and (switch_on "O3"), (any_switch_on "O0", "O1", "O2")), - (unset_option "O0", "O1", "O2"), - (and (switch_on "O2"), (any_switch_on "O0", "O1")), - (unset_option "O0", "O1"), - (and (switch_on "O1"), (switch_on "O0")), - (unset_option "O0")) - >; - -Here, ``OptionPreprocessor`` is used to unset all spurious ``-O`` options so -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 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 -two-argument form: ``(set_option "parameter", VALUE)``. Here, ``VALUE`` can be -either a string, a string list, or a boolean constant. - -For convenience, ``set_option`` and ``unset_option`` also work with multiple -arguments. That is, instead of ``[(unset_option "A"), (unset_option "B")]`` you -can use ``(unset_option "A", "B")``. Obviously, ``(set_option "A", "B")`` is -only valid if both ``A`` and ``B`` are switches. - - -More advanced topics -==================== - -.. _hooks: - -Hooks and environment variables -------------------------------- - -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:: - - (command "$CALL(MyHook)/path/to/file -o $CALL(AnotherHook)") - -To pass arguments to hooks, use the following syntax:: - - (command "$CALL(MyHook, 'Arg1', 'Arg2', 'Arg # 3')/path/to/file -o1 -o2") - -It is also possible to use environment variables in the same manner:: - - (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`__):: - - (command - (case - (switch_on "E"), - "llvm-g++ -E -x c $INFILE -o $OUTFILE", - (default), - "llvm-g++ -c -x c $INFILE -o $OUTFILE -emit-llvm")) - -__ case_ - -Debugging ---------- - -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/ - -Conditioning on the executable name ------------------------------------ - -For now, the executable name (the value passed to the driver in ``argv[0]``) is -accessible only in the C++ code (i.e. hooks). Use the following code:: - - namespace llvmc { - extern const char* ProgramName; - } - - namespace hooks { - - std::string MyHook() { - //... - if (strcmp(ProgramName, "mydriver") == 0) { - //... - - } - - } // end namespace hooks - -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 ``llvmc`` program behaves when it needs to choose the correct linker options -(think ``g++`` vs. ``gcc``). - -.. raw:: html - - <hr /> - <address> - <a href="http://jigsaw.w3.org/css-validator/check/referer"> - <img src="http://jigsaw.w3.org/css-validator/images/vcss-blue" - alt="Valid CSS" /></a> - <a href="http://validator.w3.org/check?uri=referer"> - <img src="http://www.w3.org/Icons/valid-xhtml10-blue" - alt="Valid XHTML 1.0 Transitional"/></a> - - <a href="mailto:foldr@codedgers.com">Mikhail Glushenkov</a><br /> - <a href="http://llvm.org">LLVM Compiler Infrastructure</a><br /> - - Last modified: $Date: 2008-12-11 11:34:48 -0600 (Thu, 11 Dec 2008) $ - </address> diff --git a/tools/llvmc/doc/LLVMC-Tutorial.rst b/tools/llvmc/doc/LLVMC-Tutorial.rst deleted file mode 100644 index fc4c124..0000000 --- a/tools/llvmc/doc/LLVMC-Tutorial.rst +++ /dev/null @@ -1,127 +0,0 @@ -====================== -Tutorial - Using LLVMC -====================== -.. - This file was automatically generated by rst2html. - Please do not edit directly! - The ReST source lives in the directory 'tools/llvmc/doc'. - -.. contents:: - -.. raw:: html - - <div class="doc_author"> - <p>Written by <a href="mailto:foldr@codedgers.com">Mikhail Glushenkov</a></p> - </div> - -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 high-level TableGen code, from which a corresponding C++ source -file is automatically generated. This tutorial describes the basic usage and -configuration of 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:: - - $ 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. - - -Using LLVMC to generate toolchain drivers -========================================= - -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_OBJ_DIR/tools/examples/Simple - $ make - $ cat > hello.c - #include <stdio.h> - int main() { printf("Hello\n"); } - $ $LLVM_BIN_DIR/Simple -v hello.c - gcc hello.c -o hello.out - $ ./hello.out - Hello - -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" - - // Tool descriptions - def gcc : Tool< - [(in_language "c"), - (out_language "executable"), - (output_suffix "out"), - (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<[(lang_to_suffixes "c", "c")]>; - - // Compilation graph - 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. - -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. - -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 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 - - <hr /> - <address> - <a href="http://jigsaw.w3.org/css-validator/check/referer"> - <img src="http://jigsaw.w3.org/css-validator/images/vcss-blue" - alt="Valid CSS" /></a> - <a href="http://validator.w3.org/check?uri=referer"> - <img src="http://www.w3.org/Icons/valid-xhtml10-blue" - alt="Valid XHTML 1.0 Transitional"/></a> - - <a href="mailto:foldr@codedgers.com">Mikhail Glushenkov</a><br /> - <a href="http://llvm.org">LLVM Compiler Infrastructure</a><br /> - - Last modified: $Date: 2008-12-11 11:34:48 -0600 (Thu, 11 Dec 2008) $ - </address> diff --git a/tools/llvmc/doc/Makefile b/tools/llvmc/doc/Makefile deleted file mode 100644 index ef98767..0000000 --- a/tools/llvmc/doc/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -##===- tools/llvmc/doc/Makefile ----------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL=../../.. - -ifneq (,$(strip $(wildcard $(LEVEL)/Makefile.config))) -include $(LEVEL)/Makefile.config -else -CP=cp -RM=rm -endif - -DOC_DIR=../../../docs -RST2HTML=rst2html --stylesheet=llvm.css --link-stylesheet - -all : LLVMC-Reference.html LLVMC-Tutorial.html - $(CP) LLVMC-Reference.html $(DOC_DIR)/CompilerDriver.html - $(CP) LLVMC-Tutorial.html $(DOC_DIR)/CompilerDriverTutorial.html - -LLVMC-Tutorial.html : LLVMC-Tutorial.rst - $(RST2HTML) $< $@ - -LLVMC-Reference.html : LLVMC-Reference.rst - $(RST2HTML) $< $@ - -clean : - $(RM) LLVMC-Tutorial.html LLVMC-Reference.html diff --git a/tools/llvmc/doc/img/lines.gif b/tools/llvmc/doc/img/lines.gif Binary files differdeleted file mode 100644 index 88f491e..0000000 --- a/tools/llvmc/doc/img/lines.gif +++ /dev/null diff --git a/tools/llvmc/examples/Hello/Hello.cpp b/tools/llvmc/examples/Hello/Hello.cpp deleted file mode 100644 index 71f04fd..0000000 --- a/tools/llvmc/examples/Hello/Hello.cpp +++ /dev/null @@ -1,29 +0,0 @@ -//===- Hello.cpp - Example code from "Writing an LLVMC Plugin" ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Shows how to write llvmc-based drivers without using TableGen. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CompilerDriver/AutoGenerated.h" -#include "llvm/CompilerDriver/Main.inc" - -#include "llvm/Support/raw_ostream.h" - -namespace llvmc { -namespace autogenerated { - -int PreprocessOptions () { return 0; } - -int PopulateLanguageMap (LanguageMap&) { llvm::outs() << "Hello!\n"; return 0; } - -int PopulateCompilationGraph (CompilationGraph&) { return 0; } - -} -} diff --git a/tools/llvmc/examples/Hello/Makefile b/tools/llvmc/examples/Hello/Makefile deleted file mode 100644 index c281be6..0000000 --- a/tools/llvmc/examples/Hello/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- tools/llvmc/examples/Hello/Makefile -----------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. - -LLVMC_BASED_DRIVER = Hello - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/examples/Simple/Simple.cpp b/tools/llvmc/examples/Simple/Simple.cpp deleted file mode 100644 index 8ac7313..0000000 --- a/tools/llvmc/examples/Simple/Simple.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "llvm/CompilerDriver/Main.inc" -#include "Simple.inc" diff --git a/tools/llvmc/examples/Simple/Simple.td b/tools/llvmc/examples/Simple/Simple.td deleted file mode 100644 index b47483b..0000000 --- a/tools/llvmc/examples/Simple/Simple.td +++ /dev/null @@ -1,41 +0,0 @@ -//===- Simple.td - A simple LLVMC-based driver ----------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// A simple LLVMC-based gcc wrapper. -// -// To compile, use this command: -// -// $ cd $LLVM_OBJ_DIR/tools/llvmc -// $ make BUILD_EXAMPLES=1 -// -// Run as: -// -// $ $LLVM_OBJ_DIR/$(BuildMode)/bin/Simple -// -// For instructions on how to build your own LLVMC-based driver, see -// the 'examples/Skeleton' directory. -//===----------------------------------------------------------------------===// - -include "llvm/CompilerDriver/Common.td" - -def gcc : Tool< -[(in_language "c"), - (out_language "executable"), - (output_suffix "out"), - (command "gcc"), - (sink), - - // -o is what is used by default, out_file_option here is included for - // instructive purposes. - (out_file_option "-o") -]>; - -def LanguageMap : LanguageMap<[(lang_to_suffixes "c", "c")]>; - -def CompilationGraph : CompilationGraph<[(edge "root", "gcc")]>; diff --git a/tools/llvmc/examples/Skeleton/AutoGenerated.td b/tools/llvmc/examples/Skeleton/AutoGenerated.td deleted file mode 100644 index 97483ce..0000000 --- a/tools/llvmc/examples/Skeleton/AutoGenerated.td +++ /dev/null @@ -1,7 +0,0 @@ -//===- AutoGenerated.td ------------------------------------*- tablegen -*-===// -// -// Write the TableGen description of your llvmc-based driver here. -// -//===----------------------------------------------------------------------===// - -include "llvm/CompilerDriver/Common.td" diff --git a/tools/llvmc/examples/Skeleton/Hooks.cpp b/tools/llvmc/examples/Skeleton/Hooks.cpp deleted file mode 100644 index ddd38f6..0000000 --- a/tools/llvmc/examples/Skeleton/Hooks.cpp +++ /dev/null @@ -1,12 +0,0 @@ -//===--- Hooks.cpp - The LLVM Compiler Driver -------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open -// Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Hook definitions should go here. -// -//===----------------------------------------------------------------------===// diff --git a/tools/llvmc/examples/Skeleton/Main.cpp b/tools/llvmc/examples/Skeleton/Main.cpp deleted file mode 100644 index 24c7768..0000000 --- a/tools/llvmc/examples/Skeleton/Main.cpp +++ /dev/null @@ -1,15 +0,0 @@ -//===--- Main.cpp - The LLVM Compiler Driver -------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open -// Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Just include CompilerDriver/Main.inc and AutoGenerated.inc. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CompilerDriver/Main.inc" -#include "AutoGenerated.inc" diff --git a/tools/llvmc/examples/Skeleton/Makefile b/tools/llvmc/examples/Skeleton/Makefile deleted file mode 100644 index 41ca823..0000000 --- a/tools/llvmc/examples/Skeleton/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -##===- llvmc/examples/Skeleton/Makefile --------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -# Change this so that $(LEVEL)/Makefile.common refers to -# $LLVM_OBJ_DIR/Makefile.common or $YOUR_LLVM_BASED_PROJECT/Makefile.common. -export LEVEL = ../../../.. - -# Change this to the name of your LLVMC-based driver. -LLVMC_BASED_DRIVER = llvmc-skeleton - -# Change this to the name of .inc file built from your .td file. -BUILT_SOURCES = AutoGenerated.inc - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc/examples/Skeleton/README b/tools/llvmc/examples/Skeleton/README deleted file mode 100644 index 282ee15..0000000 --- a/tools/llvmc/examples/Skeleton/README +++ /dev/null @@ -1,6 +0,0 @@ - -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.td`. - -The build system assumes that your project is based on LLVM. diff --git a/tools/llvmc/examples/mcc16/Hooks.cpp b/tools/llvmc/examples/mcc16/Hooks.cpp deleted file mode 100644 index 95158ef..0000000 --- a/tools/llvmc/examples/mcc16/Hooks.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "llvm/Support/Path.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/raw_ostream.h" - -#include <string> - -namespace llvmc { - extern char *ProgramName; - - namespace autogenerated { - extern llvm::cl::opt<std::string> Parameter_p; - } -} - -using namespace llvm; -using namespace llvmc; - -// Returns the platform specific directory separator via #ifdefs. -// FIXME: This currently work on linux and windows only. It does not -// work on other unices. -static std::string GetDirSeparator() { -#if __linux__ || __APPLE__ - return "/"; -#else - return "\\"; -#endif -} - -namespace hooks { -// Get preprocessor define for the part. -// It is __partname format in lower case. -std::string -GetLowerCasePartDefine(void) { - std::string Partname; - if (autogenerated::Parameter_p.empty()) { - Partname = "16f1xxx"; - } else { - Partname = autogenerated::Parameter_p; - } - - std::string LowerCase; - for (unsigned i = 0; i < Partname.size(); i++) { - LowerCase.push_back(std::tolower(Partname[i])); - } - - return "__" + LowerCase; -} - -std::string -GetUpperCasePartDefine(void) { - std::string Partname; - if (autogenerated::Parameter_p.empty()) { - Partname = "16f1xxx"; - } else { - Partname = autogenerated::Parameter_p; - } - - std::string UpperCase; - for (unsigned i = 0; i < Partname.size(); i++) { - UpperCase.push_back(std::toupper(Partname[i])); - } - - return "__" + UpperCase; -} - -// Get the dir where c16 executables reside. -std::string GetBinDir() { - // Construct a Path object from the program name. - void *P = (void*) (intptr_t) GetBinDir; - sys::Path ProgramFullPath - = sys::Path::GetMainExecutable(llvmc::ProgramName, P); - - // Get the dir name for the program. It's last component should be 'bin'. - std::string BinDir = ProgramFullPath.getDirname(); - - // llvm::errs() << "BinDir: " << BinDir << '\n'; - return BinDir + GetDirSeparator(); -} - -// Get the Top-level Installation dir for c16. -std::string GetInstallDir() { - sys::Path BinDirPath = sys::Path(GetBinDir()); - - // Go one more level up to get the install dir. - std::string InstallDir = BinDirPath.getDirname(); - - return InstallDir + GetDirSeparator(); -} - -// Get the dir where the c16 header files reside. -std::string GetStdHeadersDir() { - return GetInstallDir() + "include"; -} - -// Get the dir where the assembler header files reside. -std::string GetStdAsmHeadersDir() { - return GetInstallDir() + "inc"; -} - -// Get the dir where the linker scripts reside. -std::string GetStdLinkerScriptsDir() { - return GetInstallDir() + "lkr"; -} - -// Get the dir where startup code, intrinsics and lib reside. -std::string GetStdLibsDir() { - return GetInstallDir() + "lib"; -} -} diff --git a/tools/llvmc/examples/mcc16/Main.cpp b/tools/llvmc/examples/mcc16/Main.cpp deleted file mode 100644 index 5d4992d..0000000 --- a/tools/llvmc/examples/mcc16/Main.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//===--- Main.cpp - The LLVM Compiler Driver -------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open -// Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Usually this file just includes CompilerDriver/Main.inc, but here we apply -// some trickery to make the built-in '-save-temps' option hidden and enable -// '--temp-dir' by default. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CompilerDriver/BuiltinOptions.h" -#include "llvm/CompilerDriver/Main.h" - -#include "llvm/Support/Path.h" -#include "llvm/Config/config.h" - -#include <iostream> - -#include "PIC16.inc" - -namespace { - -// Modify the PACKAGE_VERSION to use build number in top level configure file. -void PIC16VersionPrinter(void) { - std::cout << "MPLAB C16 1.0 " << PACKAGE_VERSION << "\n"; -} - -} - -int main(int argc, char** argv) { - - // HACK - SaveTemps.setHiddenFlag(llvm::cl::Hidden); - TempDirname.setHiddenFlag(llvm::cl::Hidden); - Languages.setHiddenFlag(llvm::cl::Hidden); - DryRun.setHiddenFlag(llvm::cl::Hidden); - - llvm::cl::SetVersionPrinter(PIC16VersionPrinter); - - // Ask for a standard temp dir, but just cache its basename., and delete it. - llvm::sys::Path tempDir; - tempDir = llvm::sys::Path::GetTemporaryDirectory(); - TempDirname = tempDir.getBasename(); - tempDir.eraseFromDisk(true); - - // We are creating a temp dir in current dir, with the cached name. - // But before that remove if one already exists with that name.. - tempDir = TempDirname; - tempDir.eraseFromDisk(true); - - return llvmc::Main(argc, argv); -} diff --git a/tools/llvmc/examples/mcc16/PIC16.td b/tools/llvmc/examples/mcc16/PIC16.td deleted file mode 100644 index 6f04196..0000000 --- a/tools/llvmc/examples/mcc16/PIC16.td +++ /dev/null @@ -1,234 +0,0 @@ -//===- PIC16.td - PIC16 toolchain driver -------------------*- tablegen -*-===// -// -// A basic driver for the PIC16 toolchain. -// -//===----------------------------------------------------------------------===// - -include "llvm/CompilerDriver/Common.td" - -// Options - -def OptionList : OptionList<[ - (switch_option "g", - (help "Enable Debugging")), - (switch_option "E", - (help "Stop after preprocessing, do not compile")), - (switch_option "S", - (help "Stop after compilation, do not assemble")), - (switch_option "bc", - (help "Stop after b-code generation, do not compile")), - (switch_option "c", - (help "Stop after assemble, do not link")), - (prefix_option "p", - (help "Specify part name")), - (prefix_list_option "I", - (help "Add a directory to include path")), - (prefix_list_option "L", - (help "Add a directory to library path")), - (prefix_list_option "K", - (help "Add a directory to linker script search path")), - (parameter_option "l", - (help "Specify a library to link")), - (parameter_option "k", - (help "Specify a linker script")), - (parameter_option "m", - (help "Generate linker map file with the given name")), - (prefix_list_option "D", - (help "Define a macro")), - (switch_option "X", - (help "Do not invoke mp2hex to create an output hex file.")), - (switch_option "O0", - (help "Do not optimize")), - (switch_option "O1", - (help "Optimization Level 1.")), - (switch_option "O2", - (help "Optimization Level 2.")), - (switch_option "O3", - (help "Optimization Level 3.")), - (switch_option "Od", - (help "Perform Debug-safe Optimizations only.")), - (switch_option "w", - (help "Disable all warnings.")), -// (switch_option "O1", -// (help "Optimization level 1")), -// (switch_option "O2", -// (help "Optimization level 2. (Default)")), -// (parameter_option "pre-RA-sched", -// (help "Example of an option that is passed to llc")), - (parameter_option "regalloc", - (help "Register allocator to use (possible values: simple, linearscan, pbqp, local; default=linearscan)")), - (prefix_list_option "Wa,", (comma_separated), - (help "Pass options to assembler (Run 'gpasm -help' for assembler options)")), - (prefix_list_option "Wl,", (comma_separated), - (help "Pass options to linker (Run 'mplink -help' for linker options)")) -// (prefix_list_option "Wllc,", -// (help "Pass options to llc")), -// (prefix_list_option "Wo,", -// (help "Pass options to llvm-ld")) -]>; - -// Tools -class clang_based<string language, string cmd, string ext_E> : Tool< -[(in_language language), - (out_language "llvm-bitcode"), - (output_suffix "bc"), - (command cmd), - (actions (case - (and (multiple_input_files), - (or (switch_on "S"), (switch_on "c"))), - (error "cannot specify -o with -c or -S with multiple files"), - (switch_on "E"), [(forward "E"), - (stop_compilation), (output_suffix ext_E)], - (and (switch_on "E"), (empty "o")), (no_out_file), - (switch_on "bc"),[(stop_compilation), (output_suffix "bc")], - (switch_on "g"), (append_cmd "-g"), - (switch_on "w"), (append_cmd "-w"), - (switch_on "O1"), (append_cmd ""), - (switch_on "O2"), (append_cmd ""), - (switch_on "O3"), (append_cmd ""), - (switch_on "Od"), (append_cmd ""), - (not_empty "D"), (forward "D"), - (not_empty "I"), (forward "I"), - (switch_on "O0"), (append_cmd "-O0"), - (default), (append_cmd "-O1"))) -// (sink) -]>; - -def clang_cc : clang_based<"c", "$CALL(GetBinDir)clang -cc1 -I $CALL(GetStdHeadersDir) -D $CALL(GetLowerCasePartDefine) -D $CALL(GetUpperCasePartDefine) -triple=pic16- -emit-llvm-bc ", "i">; - -//def clang_cc : Tool<[ -// (in_language "c"), -// (out_language "llvm-bitcode"), -// (output_suffix "bc"), -// (cmd_line "$CALL(GetBinDir)clang-cc -I $CALL(GetStdHeadersDir) -triple=pic16- -emit-llvm-bc "), -// (cmd_line kkkkk -// (actions (case -// (switch_on "g"), (append_cmd "g"), -// (not_empty "I"), (forward "I"))), -// (sink) -//]>; - - -// pre-link-and-lto step. -def llvm_ld : Tool<[ - (in_language "llvm-bitcode"), - (out_language "llvm-bitcode"), - (output_suffix "bc"), - (command "$CALL(GetBinDir)llvm-ld -L $CALL(GetStdLibsDir) -disable-licm-promotion -l std"), - (out_file_option "-b"), - (actions (case - (switch_on "O0"), (append_cmd "-disable-opt"), - (switch_on "O1"), (append_cmd "-disable-opt"), -// Whenever O3 is not specified on the command line, default i.e. disable-inlining will always be added. - (switch_on "O2"), (append_cmd ""), - (switch_on "O3"), (append_cmd ""), - (default), (append_cmd "-disable-inlining"))), - (join) -]>; - -// optimize single file -def llvm_ld_optimizer : Tool<[ - (in_language "llvm-bitcode"), - (out_language "llvm-bitcode"), - (output_suffix "bc"), -// FIXME: we are still not disabling licm-promotion. -// -disable-licm-promotion and building stdn library causes c16-71 to fail. - (command "$CALL(GetBinDir)llvm-ld "), - (out_file_option "-b"), - (actions (case - (switch_on "O0"), (append_cmd "-disable-opt"), - (switch_on "O1"), (append_cmd "-disable-opt"), -// Whenever O3 is not specified on the command line, default i.e. disable-inlining will always be added. - (switch_on "O2"), (append_cmd ""), - (switch_on "O3"), (append_cmd ""), - (default), (append_cmd "-disable-inlining"))) -]>; - -// optimizer step. -def pic16passes : Tool<[ - (in_language "llvm-bitcode"), - (out_language "llvm-bitcode"), - (output_suffix "obc"), - (command "$CALL(GetBinDir)opt -pic16cloner -pic16overlay -f"), - (actions (case - (switch_on "O0"), (append_cmd "-disable-opt"))) -]>; - -def llc : Tool<[ - (in_language "llvm-bitcode"), - (out_language "assembler"), - (output_suffix "s"), - (command "$CALL(GetBinDir)llc -march=pic16 -disable-jump-tables -pre-RA-sched=list-burr -f"), - (actions (case - (switch_on "S"), (stop_compilation), -// (not_empty "Wllc,"), (unpack_values "Wllc,"), -// (not_empty "pre-RA-sched"), (forward "pre-RA-sched"))) - (not_empty "regalloc"), (forward "regalloc"), - (empty "regalloc"), (append_cmd "-regalloc=linearscan"))) -]>; - -def gpasm : Tool<[ - (in_language "assembler"), - (out_language "object-code"), - (output_suffix "o"), - (command "$CALL(GetBinDir)gpasm -z -r decimal -I $CALL(GetStdAsmHeadersDir) -C -c -w 2"), - (actions (case - (switch_on "c"), (stop_compilation), - (switch_on "g"), (append_cmd "-g"), - (not_empty "p"), (forward "p"), - (empty "p"), (append_cmd "-p 16f1xxx"), - (not_empty "Wa,"), (forward_value "Wa,"))) -]>; - -def mplink : Tool<[ - (in_language "object-code"), - (out_language "executable"), - (output_suffix "cof"), - (command "$CALL(GetBinDir)mplink -e -k $CALL(GetStdLinkerScriptsDir) -l $CALL(GetStdLibsDir) intrinsics.lib stdn.lib"), - (actions (case - (not_empty "Wl,"), (forward_value "Wl,"), - (switch_on "X"), (append_cmd "-x"), - (not_empty "L"), (forward_as "L", "-l"), - (not_empty "K"), (forward_as "K", "-k"), - (not_empty "m"), (forward "m"), - (not_empty "p"), [(forward "p"), (append_cmd "-c")], - (empty "p"), (append_cmd "-p 16f1xxx -c"), -// (not_empty "l"), [(unpack_values "l"),(append_cmd ".lib")])), - (not_empty "k"), (forward "k"), - (not_empty "l"), (forward "l"))), - (join) -]>; - -// Language map - -def LanguageMap : LanguageMap<[ - (lang_to_suffixes "c", "c"), - (lang_to_suffixes "c-cpp-output", "i"), - (lang_to_suffixes "assembler", "s"), - (lang_to_suffixes "assembler-with-cpp", "S"), - (lang_to_suffixes "llvm-assembler", "ll"), - (lang_to_suffixes "llvm-bitcode", "bc"), - (lang_to_suffixes "object-code", "o"), - (lang_to_suffixes "executable", "cof") -]>; - -// Compilation graph - -def CompilationGraph : CompilationGraph<[ - (edge "root", "clang_cc"), - (edge "root", "llvm_ld"), - (optional_edge "root", "llvm_ld_optimizer", - (case (switch_on "S"), (inc_weight), - (switch_on "c"), (inc_weight))), - (edge "root", "gpasm"), - (edge "root", "mplink"), - (edge "clang_cc", "llvm_ld"), - (optional_edge "clang_cc", "llvm_ld_optimizer", - (case (switch_on "S"), (inc_weight), - (switch_on "c"), (inc_weight))), - (edge "llvm_ld", "pic16passes"), - (edge "llvm_ld_optimizer", "pic16passes"), - (edge "pic16passes", "llc"), - (edge "llc", "gpasm"), - (edge "gpasm", "mplink") -]>; diff --git a/tools/llvmc/examples/mcc16/README b/tools/llvmc/examples/mcc16/README deleted file mode 100644 index 6d2b73d..0000000 --- a/tools/llvmc/examples/mcc16/README +++ /dev/null @@ -1,75 +0,0 @@ -This is a basic compiler driver for the PIC16 toolchain that shows how to create -your own llvmc-based drivers. It is based on the examples/Skeleton template. - -The PIC16 toolchain looks like this: - -clang-cc (FE) -> llvm-ld (optimizer) -> llc (codegen) -> native-as -> native-ld - -Following features were requested by Sanjiv: - -From: Sanjiv Gupta <sanjiv.gupta <at> microchip.com> -Subject: Re: llvmc for PIC16 -Newsgroups: gmane.comp.compilers.llvm.devel -Date: 2009-06-05 06:51:14 GMT - -The salient features that we want to have in the driver are: -1. llvm-ld will be used as "The Optimizer". -2. If the user has specified to generate the final executable, then -llvm-ld should run on all the .bc files generated by clang and create a -single optimized .bc file for further tools. -3. -Wo <options> - pass optimizations to the llvm-ld -4. mcc16 -Wl <options> - pass options to native linker. -5. mcc16 -Wa <options> - pass options to native assembler. - -Here are some example command lines and sample command invocations as to -what should be done. - -$ mcc16 -S foo.c -// [clang-cc foo.c] -> foo.bc -// [llvm-ld foo.bc] -> foo.opt.bc -// [llc foo.opt.bc] -> foo.s - -$ mcc16 -S foo.c bar.c -// [clang-cc foo.c] -> foo.bc -// [llvm-ld foo.bc] -> foo.opt.bc -// [llc foo.opt.bc] -> foo.s -// [clang-cc bar.c] -> bar.bc -// [llvm-ld bar.bc] -> bar.opt.bc -// [llc bar.opt.bc] -> bar.s - -** Use of -g causes llvm-ld to run with -disable-opt -$ mcc16 -S -g foo.c -// [clang-cc foo.c] -> foo.bc -// [llvm-ld -disable-opt foo.bc] -> foo.opt.bc -// [llc foo.opt.bc] -> foo.s - -** -I is passed to clang-cc, -pre-RA-sched=list-burr to llc. -$ mcc16 -S -g -I ../include -pre-RA-sched=list-burr foo.c -// [clang-cc -I ../include foo.c] -> foo.bc -// [llvm-ld -disable-opt foo.bc] -> foo.opt.bc -// [llc -pre-RA-sched=list-burr foo.opt.bc] -> foo.s - -** -Wo passes options to llvm-ld -$ mcc16 -Wo=opt1,opt2 -S -I ../include -pre-RA-sched=list-burr foo.c -// [clang-cc -I ../include foo.c] -> foo.bc -// [llvm-ld -opt1 -opt2 foo.bc] -> foo.opt.bc -// [llc -pre-RA-sched=list-burr foo.opt.bc] -> foo.s - -** -Wa passes options to native as. -$ mcc16 -c foo.c -Wa=opt1 -// [clang-cc foo.c] -> foo.bc -// [llvm-ld foo.bc] -> foo.opt.bc -// [llc foo.opt.bc] -> foo.s -// [native-as -opt1 foo.s] -> foo.o - -$ mcc16 -Wo=opt1 -Wl=opt2 -Wa=opt3 foo.c bar.c -// [clang-cc foo.c] -> foo.bc -// [clang-cc bar.c] -> bar.bc -// [llvm-ld -opt1 foo.bc bar.bc] -> a.out.bc -// [llc a.out.bc] -> a.out.s -// [native-as -opt3 a.out.s] -> a.out.o -// [native-ld -opt2 a.out.o] -> a.out - -Is this achievable by a tablegen based driver ? - -- Sanjiv diff --git a/tools/llvmc/src/AutoGenerated.td b/tools/llvmc/src/AutoGenerated.td deleted file mode 100644 index 8507b1f..0000000 --- a/tools/llvmc/src/AutoGenerated.td +++ /dev/null @@ -1,17 +0,0 @@ -//===- AutoGenerated.td - LLVMC toolchain descriptions -----*- tablegen -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains compilation graph description used by llvmc. -// -//===----------------------------------------------------------------------===// - -include "llvm/CompilerDriver/Common.td" - -include "Base.td" -include "Clang.td" diff --git a/tools/llvmc/src/Base.td.in b/tools/llvmc/src/Base.td.in deleted file mode 100644 index 84e39e7..0000000 --- a/tools/llvmc/src/Base.td.in +++ /dev/null @@ -1,461 +0,0 @@ -//===- Base.td - LLVMC toolchain descriptions --------------*- tablegen -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains compilation graph description used by llvmc. -// -//===----------------------------------------------------------------------===// - -// Options - -def OptList : OptionList<[ - (switch_option "emit-llvm", - (help "Emit LLVM .ll files instead of native object files")), - (switch_option "E", - (help "Stop after the preprocessing stage, do not run the compiler")), - (switch_option "fsyntax-only", - (help "Stop after checking the input for syntax errors")), - (switch_option "opt", - (help "Enable opt")), - (switch_option "O0", - (help "Turn off optimization"), (zero_or_more)), - (switch_option "O1", - (help "Optimization level 1"), (zero_or_more)), - (switch_option "O2", - (help "Optimization level 2"), (zero_or_more)), - (switch_option "O3", - (help "Optimization level 3"), (zero_or_more)), - (switch_option "S", - (help "Stop after compilation, do not assemble")), - (switch_option "c", - (help "Compile and assemble, but do not link")), - (switch_option "m32", - (help "Generate code for a 32-bit environment"), (hidden)), - (switch_option "m64", - (help "Generate code for a 64-bit environment"), (hidden)), - (switch_option "fPIC", - (help "Relocation model: PIC"), (hidden)), - (switch_option "mdynamic-no-pic", - (help "Relocation model: dynamic-no-pic"), (hidden)), - (parameter_option "linker", - (help "Choose linker (possible values: gcc, g++)")), - (parameter_option "mtune", - (help "Target a specific CPU type"), (forward_not_split)), - (parameter_list_option "march", - (help "Generate code for the specified machine type")), - (parameter_option "mcpu", - (help "A deprecated synonym for -mtune"), (hidden), (forward_not_split)), - (parameter_option "mfpu", - (help "Specify type of floating point unit"), - (hidden), (forward_not_split)), - (parameter_option "mabi", - (help "Generate code for the specified ABI"), (hidden)), - (parameter_option "mfloat-abi", - (help "Specifies which floating-point ABI to use"), (hidden)), - (switch_option "mfix-and-continue", - (help "Needed by gdb to load .o files dynamically"), (hidden)), - (parameter_option "MF", - (help "Specify a file to write dependencies to"), (hidden)), - (parameter_list_option "MT", - (help "Change the name of the rule emitted by dependency generation"), - (hidden)), - (parameter_list_option "include", - (help "Include the named file prior to preprocessing")), - (parameter_list_option "iquote", - (help "Search dir only for files requested with #inlcude \"file\""), - (hidden)), - (prefix_list_option "I", - (help "Add a directory to include path")), - (prefix_list_option "D", - (help "Define a macro")), - (parameter_list_option "Xpreprocessor", (hidden), - (help "Pass options to preprocessor")), - (prefix_list_option "Wa,", (comma_separated), - (help "Pass options to assembler")), - (parameter_list_option "Xassembler", (hidden), - (help "Pass options to assembler")), - (prefix_list_option "Wllc,", (comma_separated), - (help "Pass options to llc")), - (prefix_list_option "Wl,", - (help "Pass options to linker")), - (parameter_list_option "Xlinker", (hidden), - (help "Pass options to linker")), - (prefix_list_option "Wo,", (comma_separated), - (help "Pass options to opt")), - (prefix_list_option "m", - (help "Enable or disable various extensions (-mmmx, -msse, etc.)"), - (hidden)) -]>; - -def LinkerOptList : OptionList<[ - (prefix_list_option "L", - (help "Add a directory to link path")), - (prefix_list_option "l", - (help "Search a library when linking")), - (parameter_option "filelist", (hidden), - (help "Link the files listed in file")), - (switch_option "nostartfiles", - (help "Do not use the standard system startup files when linking"), - (hidden)), - (switch_option "nodefaultlibs", - (help "Do not use the standard system libraries when linking"), (hidden)), - (switch_option "nostdlib", - (help - "Do not use the standard system startup files or libraries when linking"), - (hidden)), - (switch_option "pie", - (help "Produce a position independent executable"), (hidden)), - (switch_option "rdynamic", - (help "Add all symbols to the dynamic export table"), (hidden)), - (switch_option "s", - (help "Strip all symbols"), (hidden)), - (switch_option "static", - (help "Do not link against shared libraries"), (hidden)), - (switch_option "static-libgcc", - (help "Use static libgcc"), (hidden)), - (switch_option "shared", - (help "Create a DLL instead of the regular executable")), - (switch_option "shared-libgcc", - (help "Use shared libgcc"), (hidden)), - (parameter_option "T", - (help "Read linker script"), (hidden)), - (parameter_option "u", - (help "Start with undefined reference to SYMBOL"), (hidden)), - (switch_option "pthread", - (help "Enable threads")), - - // TODO: Add a conditional compilation mechanism to make Darwin-only options - // like '-arch' really Darwin-only. - (parameter_option "arch", - (help "Compile for the specified target architecture"), (hidden)), - (prefix_list_option "F", - (help "Add a directory to framework search path")), - (parameter_list_option "framework", - (help "Specifies a framework to link against")), - (parameter_list_option "weak_framework", - (help "Specifies a framework to weakly link against"), (hidden)), - (switch_option "dynamiclib", (hidden), - (help "Produce a dynamic library")), - (switch_option "prebind", (hidden), - (help "Prebind all undefined symbols")), - (switch_option "dead_strip", (hidden), - (help "Remove unreachable blocks of code")), - (switch_option "single_module", (hidden), - (help "Build the library so it contains only one module")), - (parameter_option "install_name", (hidden), - (help "File name the library will be installed in")), - (parameter_option "compatibility_version", (hidden), - (help "Compatibility version number")), - (parameter_option "current_version", (hidden), - (help "Current version number")) -]>; - -// Option preprocessor. - -def Preprocess : OptionPreprocessor< -(case (not (any_switch_on "O0", "O1", "O2", "O3")), - (set_option "O2"), - (and (switch_on "O3"), (any_switch_on "O0", "O1", "O2")), - (unset_option "O0", "O1", "O2"), - (and (switch_on "O2"), (any_switch_on "O0", "O1")), - (unset_option "O0", "O1"), - (switch_on "O1", "O0"), - (unset_option "O0")) ->; - -// Tools - -class llvm_gcc_based <string cmd, string in_lang, string E_ext, dag out_lang, - string out_ext> : Tool< -[(in_language in_lang), - out_lang, - (output_suffix out_ext), - (command cmd), - (actions - (case - (and (not_empty "o"), - (multiple_input_files), (or (switch_on "S"), (switch_on "c"))), - (error "cannot specify -o with -c or -S with multiple files"), - (switch_on "E"), - [(forward "E"), (stop_compilation), (output_suffix E_ext)], - (and (switch_on "E"), (empty "o")), (no_out_file), - - // ('-emit-llvm') && !('opt') -> stop compilation - (and (switch_on "emit-llvm"), (not (switch_on "opt"))), - (stop_compilation), - // ('-S' && '-emit-llvm') && !('opt') -> output .ll - (and (switch_on "emit-llvm", "S"), (not (switch_on "opt"))), - [(forward "S"), (output_suffix "ll")], - // Usually just output .bc - (not (switch_on "fsyntax-only")), - [(append_cmd "-c"), (append_cmd "-emit-llvm")], - - // -fsyntax-only - (switch_on "fsyntax-only"), [(forward "fsyntax-only"), - (no_out_file), (stop_compilation)], - - // Forwards - (not_empty "Xpreprocessor"), (forward "Xpreprocessor"), - (not_empty "include"), (forward "include"), - (not_empty "iquote"), (forward "iquote"), - (not_empty "save-temps"), (append_cmd "-save-temps"), - (not_empty "I"), (forward "I"), - (not_empty "F"), (forward "F"), - (not_empty "D"), (forward "D"), - (not_empty "arch"), (forward "arch"), - (not_empty "march"), (forward "march"), - (not_empty "mcpu"), (forward "mcpu"), - (not_empty "mtune"), (forward "mtune"), - (not_empty "mfpu"), (forward "mfpu"), - (not_empty "mabi"), (forward "mabi"), - (not_empty "mfloat-abi"), (forward "mfloat-abi"), - (not_empty "m"), (forward "m"), - (switch_on "mfix-and-continue"), (forward "mfix-and-continue"), - (switch_on "m32"), (forward "m32"), - (switch_on "m64"), (forward "m64"), - (switch_on "O0"), (forward "O0"), - (switch_on "O1"), (forward "O1"), - (switch_on "O2"), (forward "O2"), - (switch_on "O3"), (forward "O3"), - (switch_on "fPIC"), (forward "fPIC"), - (switch_on "mdynamic-no-pic"), (forward "mdynamic-no-pic"), - (not_empty "MF"), (forward "MF"), - (not_empty "MT"), (forward "MT"))), - (sink) -]>; - -class llvm_gcc_comp_based <string cmd, string in_lang, string E_ext> -: llvm_gcc_based<cmd, in_lang, E_ext, - (out_language "llvm-bitcode", "object-code"), "bc">; - -class llvm_gcc_pch_based <string cmd, string in_lang, string E_ext> -: llvm_gcc_based<cmd, in_lang, E_ext, - (out_language "precompiled-header"), "gch">; - -def llvm_gcc_c : llvm_gcc_comp_based - <"@LLVMGCCCOMMAND@ -x c", "c", "i">; -def llvm_gcc_cpp : llvm_gcc_comp_based - <"@LLVMGXXCOMMAND@ -x c++", "c++", "i">; -def llvm_gcc_m : llvm_gcc_comp_based - <"@LLVMGCCCOMMAND@ -x objective-c", "objective-c", "mi">; -def llvm_gcc_mxx : llvm_gcc_comp_based - <"@LLVMGCCCOMMAND@ -x objective-c++", "objective-c++", "mi">; - -def llvm_gcc_c_pch : llvm_gcc_pch_based - <"@LLVMGCCCOMMAND@ -x c-header", "c-header", "i">; -def llvm_gcc_cpp_pch : llvm_gcc_pch_based - <"@LLVMGXXCOMMAND@ -x c++-header", "c++-header", "i">; -def llvm_gcc_m_pch : llvm_gcc_pch_based - <"@LLVMGCCCOMMAND@ -x objective-c-header", "objective-c-header", "mi">; -def llvm_gcc_mxx_pch : llvm_gcc_pch_based - <"@LLVMGCCCOMMAND@ -x objective-c++-header", "objective-c++-header", "mi">; - -def opt : Tool< -[(in_language "llvm-bitcode"), - (out_language "llvm-bitcode"), - (output_suffix "opt.bc"), - (actions (case (switch_on "emit-llvm"), (stop_compilation), - (switch_on "emit-llvm", "S"), - [(append_cmd "-S"), (output_suffix "ll")], - (not_empty "Wo,"), (forward_value "Wo,"), - (switch_on "O1"), (forward "O1"), - (switch_on "O2"), (forward "O2"), - (switch_on "O3"), (forward "O3"))), - (command "opt -f") -]>; - -def llvm_as : Tool< -[(in_language "llvm-assembler"), - (out_language "llvm-bitcode"), - (output_suffix "bc"), - (command "llvm-as"), - (actions (case (and (switch_on "emit-llvm"), (not (switch_on "opt"))), - (stop_compilation))) -]>; - -def llvm_gcc_assembler : Tool< -[(in_language "assembler"), - (out_language "object-code"), - (output_suffix "o"), - (command "@LLVMGCCCOMMAND@ -c -x assembler"), - (actions (case - (switch_on "c"), (stop_compilation), - (not_empty "arch"), (forward "arch"), - (not_empty "Xassembler"), (forward "Xassembler"), - (not_empty "march"), (forward "march"), - (not_empty "mcpu"), (forward "mcpu"), - (not_empty "mtune"), (forward "mtune"), - (not_empty "mabi"), (forward "mabi"), - (not_empty "mfloat-abi"), (forward "mfloat-abi"), - (switch_on "m32"), (forward "m32"), - (switch_on "m64"), (forward "m64"), - (not_empty "Wa,"), (forward "Wa,"))) -]>; - -def llc : Tool< -[(in_language "llvm-bitcode", "llvm-assembler"), - (out_language "assembler"), - (output_suffix "s"), - (command "llc -disable-cfi"), - (actions (case - (switch_on "S"), (stop_compilation), - (switch_on "O0"), (forward "O0"), - (switch_on "O1"), (forward "O1"), - (switch_on "O2"), (forward "O2"), - (switch_on "O3"), (forward "O3"), - (switch_on "fPIC"), (append_cmd "-relocation-model=pic"), - (switch_on "mdynamic-no-pic"), - (append_cmd "-relocation-model=dynamic-no-pic"), - (not_empty "march"), (forward_transformed_value - "march", "ConvertMArchToMAttr"), - (not_empty "mcpu"), (forward_transformed_value "mcpu", "ConvertMCpu"), - (and (not_empty "mtune"), (empty "mcpu")), - (forward_as "mtune", "-mcpu"), - (not_empty "mfpu"), (forward_transformed_value "mfpu", "ConvertMFpu"), - (not_empty "m"), (forward_transformed_value "m", "ConvertToMAttr"), - (not_empty "Wllc,"), (forward_value "Wllc,"))) -]>; - -// Base class for linkers -class llvm_gcc_based_linker <string cmd, dag on_empty> : Tool< -[(in_language "object-code", "static-library", "dynamic-library"), - (out_language "executable"), - (output_suffix "out"), - (command cmd), - (works_on_empty (case (and (not_empty "filelist"), on_empty), true, - (default), false)), - (join), - (actions (case - (switch_on "pthread"), (append_cmd "-lpthread"), - (not_empty "L"), (forward "L"), - (not_empty "F"), (forward "F"), - (not_empty "arch"), (forward "arch"), - (not_empty "framework"), (forward "framework"), - (not_empty "weak_framework"), (forward "weak_framework"), - (not_empty "filelist"), (forward "filelist"), - (not_empty "march"), (forward "march"), - (not_empty "mcpu"), (forward "mcpu"), - (not_empty "mtune"), (forward "mtune"), - (not_empty "mabi"), (forward "mabi"), - (not_empty "mfloat-abi"), (forward "mfloat-abi"), - (switch_on "m32"), (forward "m32"), - (switch_on "m64"), (forward "m64"), - (not_empty "l"), (forward "l"), - (not_empty "Xlinker"), (forward "Xlinker"), - (not_empty "Wl,"), (forward "Wl,"), - (switch_on "nostartfiles"), (forward "nostartfiles"), - (switch_on "nodefaultlibs"), (forward "nodefaultlibs"), - (switch_on "nostdlib"), (forward "nostdlib"), - (switch_on "pie"), (forward "pie"), - (switch_on "rdynamic"), (forward "rdynamic"), - (switch_on "s"), (forward "s"), - (switch_on "static"), (forward "static"), - (switch_on "static-libgcc"), (forward "static-libgcc"), - (switch_on "shared"), (forward "shared"), - (switch_on "shared-libgcc"), (forward "shared-libgcc"), - (not_empty "T"), (forward "T"), - (not_empty "u"), (forward "u"), - (switch_on "dynamiclib"), (forward "dynamiclib"), - (switch_on "prebind"), (forward "prebind"), - (switch_on "dead_strip"), (forward "dead_strip"), - (switch_on "single_module"), (forward "single_module"), - (not_empty "compatibility_version"), - (forward "compatibility_version"), - (not_empty "current_version"), (forward "current_version"), - (not_empty "install_name"), (forward "install_name"))) -]>; - -// Default linker -def llvm_gcc_linker : llvm_gcc_based_linker<"@LLVMGCCCOMMAND@", - (not (or (parameter_equals "linker", "g++"), - (parameter_equals "linker", "c++")))>; -// Alternative linker for C++ -def llvm_gcc_cpp_linker : llvm_gcc_based_linker<"@LLVMGXXCOMMAND@", - (or (parameter_equals "linker", "g++"), - (parameter_equals "linker", "c++"))>; - -// Language map - -def LanguageMap : LanguageMap<[ - (lang_to_suffixes "precompiled-header", ["gch", "pch"]), - (lang_to_suffixes "c++", ["cc", "cp", "cxx", "cpp", "CPP", "c++", "C"]), - (lang_to_suffixes "c++-header", "hpp"), - (lang_to_suffixes "c", "c"), - (lang_to_suffixes "c-header", "h"), - (lang_to_suffixes "c-cpp-output", "i"), - (lang_to_suffixes "objective-c-cpp-output", "mi"), - (lang_to_suffixes "objective-c++", "mm"), - (lang_to_suffixes "objective-c++-header", "hmm"), - (lang_to_suffixes "objective-c", "m"), - (lang_to_suffixes "objective-c-header", "hm"), - (lang_to_suffixes "assembler", "s"), - (lang_to_suffixes "assembler-with-cpp", "S"), - (lang_to_suffixes "llvm-assembler", "ll"), - (lang_to_suffixes "llvm-bitcode", "bc"), - (lang_to_suffixes "object-code", ["o", "*empty*"]), - (lang_to_suffixes "static-library", ["a", "lib"]), - (lang_to_suffixes "dynamic-library", ["so", "dylib", "dll"]), - (lang_to_suffixes "executable", "out") -]>; - -// Compilation graph - -def CompilationGraph : CompilationGraph<[ - (edge "root", "llvm_gcc_c"), - (edge "root", "llvm_gcc_assembler"), - (edge "root", "llvm_gcc_cpp"), - (edge "root", "llvm_gcc_m"), - (edge "root", "llvm_gcc_mxx"), - (edge "root", "llc"), - - (edge "root", "llvm_gcc_c_pch"), - (edge "root", "llvm_gcc_cpp_pch"), - (edge "root", "llvm_gcc_m_pch"), - (edge "root", "llvm_gcc_mxx_pch"), - - (edge "llvm_gcc_c", "llc"), - (edge "llvm_gcc_cpp", "llc"), - (edge "llvm_gcc_m", "llc"), - (edge "llvm_gcc_mxx", "llc"), - (edge "llvm_as", "llc"), - - (optional_edge "root", "llvm_as", - (case (or (switch_on "emit-llvm"), - (switch_on "opt")), (inc_weight))), - (optional_edge "llvm_gcc_c", "opt", - (case (switch_on "opt"), (inc_weight))), - (optional_edge "llvm_gcc_cpp", "opt", - (case (switch_on "opt"), (inc_weight))), - (optional_edge "llvm_gcc_m", "opt", - (case (switch_on "opt"), (inc_weight))), - (optional_edge "llvm_gcc_mxx", "opt", - (case (switch_on "opt"), (inc_weight))), - (optional_edge "llvm_as", "opt", - (case (switch_on "opt"), (inc_weight))), - (edge "opt", "llc"), - - (edge "llc", "llvm_gcc_assembler"), - (edge "llvm_gcc_assembler", "llvm_gcc_linker"), - (optional_edge "llvm_gcc_assembler", "llvm_gcc_cpp_linker", - (case - (or (input_languages_contain "c++"), - (input_languages_contain "objective-c++")), - (inc_weight), - (or (parameter_equals "linker", "g++"), - (parameter_equals "linker", "c++")), (inc_weight))), - - - (edge "root", "llvm_gcc_linker"), - (optional_edge "root", "llvm_gcc_cpp_linker", - (case - (or (input_languages_contain "c++"), - (input_languages_contain "objective-c++")), - (inc_weight), - (or (parameter_equals "linker", "g++"), - (parameter_equals "linker", "c++")), (inc_weight))) -]>; diff --git a/tools/llvmc/src/Clang.td b/tools/llvmc/src/Clang.td deleted file mode 100644 index e2d32e8..0000000 --- a/tools/llvmc/src/Clang.td +++ /dev/null @@ -1,87 +0,0 @@ -//===- Clang.td - LLVMC toolchain descriptions -------------*- tablegen -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains compilation graph description used by llvmc. -// -//===----------------------------------------------------------------------===// - - -def Options : OptionList<[ -(switch_option "clang", (help "Use Clang instead of llvm-gcc")) -]>; - -class clang_based<string language, string cmd, string ext_E> : Tool< -[(in_language language), - (out_language "llvm-bitcode"), - (output_suffix "bc"), - (command cmd), - (actions (case (switch_on "E"), - [(forward "E"), (stop_compilation), (output_suffix ext_E)], - (and (switch_on "E"), (empty "o")), (no_out_file), - (switch_on "fsyntax-only"), (stop_compilation), - (switch_on "S", "emit-llvm"), - [(append_cmd "-emit-llvm"), - (stop_compilation), (output_suffix "ll")], - (not (switch_on "S", "emit-llvm")), - (append_cmd "-emit-llvm-bc"), - (switch_on "c", "emit-llvm"), - (stop_compilation), - (not_empty "include"), (forward "include"), - (not_empty "I"), (forward "I"))), - (sink) -]>; - -def clang_c : clang_based<"c", "clang -x c", "i">; -def clang_cpp : clang_based<"c++", "clang -x c++", "i">; -def clang_objective_c : clang_based<"objective-c", - "clang -x objective-c", "mi">; -def clang_objective_cpp : clang_based<"objective-c++", - "clang -x objective-c++", "mi">; - -def as : Tool< -[(in_language "assembler"), - (out_language "object-code"), - (output_suffix "o"), - (command "as"), - (actions (case (not_empty "Wa,"), (forward_value "Wa,"), - (switch_on "c"), (stop_compilation))) -]>; - -// Default linker -def llvm_ld : Tool< -[(in_language "object-code"), - (out_language "executable"), - (output_suffix "out"), - (command "llvm-ld -native -disable-internalize"), - (actions (case - (switch_on "pthread"), (append_cmd "-lpthread"), - (not_empty "L"), (forward "L"), - (not_empty "l"), (forward "l"), - (not_empty "Wl,"), (forward_value "Wl,"))), - (join) -]>; - -// Compilation graph - -def ClangCompilationGraph : CompilationGraph<[ - (optional_edge "root", "clang_c", - (case (switch_on "clang"), (inc_weight))), - (optional_edge "root", "clang_cpp", - (case (switch_on "clang"), (inc_weight))), - (optional_edge "root", "clang_objective_c", - (case (switch_on "clang"), (inc_weight))), - (optional_edge "root", "clang_objective_cpp", - (case (switch_on "clang"), (inc_weight))), - (edge "clang_c", "llc"), - (edge "clang_cpp", "llc"), - (edge "clang_objective_c", "llc"), - (edge "clang_objective_cpp", "llc"), - (optional_edge "llc", "as", (case (switch_on "clang"), (inc_weight))), - (edge "as", "llvm_ld") -]>; diff --git a/tools/llvmc/src/Hooks.cpp b/tools/llvmc/src/Hooks.cpp deleted file mode 100644 index ddad08a..0000000 --- a/tools/llvmc/src/Hooks.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include "llvm/ADT/StringMap.h" - -#include <string> -#include <vector> - -namespace hooks { - -/// NUM_KEYS - Calculate the size of a const char* array. -#define NUM_KEYS(Keys) sizeof(Keys) / sizeof(const char*) - -// See http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 -inline unsigned NextHighestPowerOf2 (unsigned i) { - --i; - i |= i >> 1; - i |= i >> 2; - i |= i >> 4; - i |= i >> 8; - i |= i >> 16; - ++i; - return i; -} - -typedef std::vector<std::string> StrVec; -typedef llvm::StringMap<const char*> ArgMap; - -/// AddPlusOrMinus - Convert 'no-foo' to '-foo' and 'foo' to '+foo'. -void AddPlusOrMinus (const std::string& Arg, std::string& out) { - if (Arg.find("no-") == 0 && Arg[3] != 0) { - out += '-'; - out += Arg.c_str() + 3; - } - else { - out += '+'; - out += Arg; - } -} - -// -march values that need to be special-cased. -const char* MArchKeysARM[] = { "armv4t", "armv5t", "armv5te", "armv6", - "armv6-m", "armv6t2", "armv7-a", "armv7-m" }; -const char* MArchValuesARM[] = { "v4t", "v5t", "v5te", "v6", "v6m", "v6t2", - "v7a", "v7m" }; -const unsigned MArchNumKeysARM = NUM_KEYS(MArchKeysARM); -const unsigned MArchMapSize = NextHighestPowerOf2(MArchNumKeysARM); - -// -march values that should be forwarded as -mcpu -const char* MArchMCpuKeysARM[] = { "iwmmxt", "ep9312" }; -const char* MArchMCpuValuesARM[] = { "iwmmxt", "ep9312"}; -const unsigned MArchMCpuNumKeysARM = NUM_KEYS(MArchMCpuKeysARM); - - -void FillInArgMap(ArgMap& Args, const char* Keys[], - const char* Values[], unsigned NumKeys) -{ - for (unsigned i = 0; i < NumKeys; ++i) { - // Explicit cast to StringRef here is necessary to pick up the right - // overload. - Args.GetOrCreateValue(llvm::StringRef(Keys[i]), Values[i]); - } -} - -/// ConvertMArchToMAttr - Convert -march from the gcc dialect to -/// something llc can understand. -std::string ConvertMArchToMAttr(const StrVec& Opts) { - static ArgMap MArchMap(MArchMapSize); - static ArgMap MArchMCpuMap(MArchMapSize); - static bool StaticDataInitialized = false; - - if (!StaticDataInitialized) { - FillInArgMap(MArchMap, MArchKeysARM, MArchValuesARM, MArchNumKeysARM); - FillInArgMap(MArchMCpuMap, MArchMCpuKeysARM, - MArchMCpuValuesARM, MArchMCpuNumKeysARM); - StaticDataInitialized = true; - } - - std::string mattr("-mattr="); - std::string mcpu("-mcpu="); - bool mattrTouched = false; - bool mcpuTouched = false; - - for (StrVec::const_iterator B = Opts.begin(), E = Opts.end(); B!=E; ++B) { - const std::string& Arg = *B; - - // Check if the argument should be forwarded to -mcpu instead of -mattr. - { - ArgMap::const_iterator I = MArchMCpuMap.find(Arg); - - if (I != MArchMCpuMap.end()) { - mcpuTouched = true; - mcpu += I->getValue(); - continue; - } - } - - if (mattrTouched) - mattr += ","; - - // Check if the argument is a special case. - { - ArgMap::const_iterator I = MArchMap.find(Arg); - - if (I != MArchMap.end()) { - mattrTouched = true; - mattr += '+'; - mattr += I->getValue(); - continue; - } - } - - AddPlusOrMinus(Arg, mattr); - } - - std::string out; - if (mattrTouched) - out += mattr; - if (mcpuTouched) - out += (mattrTouched ? " " : "") + mcpu; - - return out; -} - -// -mcpu values that need to be special-cased. -const char* MCpuKeysPPC[] = { "G3", "G4", "G5", "powerpc", "powerpc64"}; -const char* MCpuValuesPPC[] = { "g3", "g4", "g5", "ppc", "ppc64"}; -const unsigned MCpuNumKeysPPC = NUM_KEYS(MCpuKeysPPC); -const unsigned MCpuMapSize = NextHighestPowerOf2(MCpuNumKeysPPC); - -/// ConvertMCpu - Convert -mcpu value from the gcc to the llc dialect. -std::string ConvertMCpu(const char* Val) { - static ArgMap MCpuMap(MCpuMapSize); - static bool StaticDataInitialized = false; - - if (!StaticDataInitialized) { - FillInArgMap(MCpuMap, MCpuKeysPPC, MCpuValuesPPC, MCpuNumKeysPPC); - StaticDataInitialized = true; - } - - std::string ret = "-mcpu="; - ArgMap::const_iterator I = MCpuMap.find(Val); - if (I != MCpuMap.end()) { - return ret + I->getValue(); - } - return ret + Val; -} - -// -mfpu values that need to be special-cased. -const char* MFpuKeysARM[] = { "vfp", "vfpv3", - "vfpv3-fp16", "vfpv3-d16", "vfpv3-d16-fp16", - "neon", "neon-fp16" }; -const char* MFpuValuesARM[] = { "vfp2", "vfp3", - "+vfp3,+fp16", "+vfp3,+d16", "+vfp3,+d16,+fp16", - "+neon", "+neon,+neonfp" }; -const unsigned MFpuNumKeysARM = NUM_KEYS(MFpuKeysARM); -const unsigned MFpuMapSize = NextHighestPowerOf2(MFpuNumKeysARM); - -/// ConvertMFpu - Convert -mfpu value from the gcc to the llc dialect. -std::string ConvertMFpu(const char* Val) { - static ArgMap MFpuMap(MFpuMapSize); - static bool StaticDataInitialized = false; - - if (!StaticDataInitialized) { - FillInArgMap(MFpuMap, MFpuKeysARM, MFpuValuesARM, MFpuNumKeysARM); - StaticDataInitialized = true; - } - - std::string ret = "-mattr="; - ArgMap::const_iterator I = MFpuMap.find(Val); - if (I != MFpuMap.end()) { - return ret + I->getValue(); - } - return ret + '+' + Val; -} - -/// ConvertToMAttr - Convert '-mfoo' and '-mno-bar' to '-mattr=+foo,-bar'. -std::string ConvertToMAttr(const StrVec& Opts) { - std::string out("-mattr="); - bool firstIter = true; - - for (StrVec::const_iterator B = Opts.begin(), E = Opts.end(); B!=E; ++B) { - const std::string& Arg = *B; - - if (firstIter) - firstIter = false; - else - out += ","; - - AddPlusOrMinus(Arg, out); - } - - return out; -} - -} diff --git a/tools/llvmc/src/Main.cpp b/tools/llvmc/src/Main.cpp deleted file mode 100644 index 9f9c71a..0000000 --- a/tools/llvmc/src/Main.cpp +++ /dev/null @@ -1,16 +0,0 @@ -//===--- Main.cpp - The LLVM Compiler Driver -------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open -// Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Just include AutoGenerated.inc and CompilerDriver/Main.inc. -// -//===----------------------------------------------------------------------===// - -#include "AutoGenerated.inc" - -#include "llvm/CompilerDriver/Main.inc" diff --git a/tools/llvmc/src/Makefile b/tools/llvmc/src/Makefile deleted file mode 100644 index f3f3091..0000000 --- a/tools/llvmc/src/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- tools/llvmc/src/Makefile ----------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -LLVMC_BASED_DRIVER = llvmc -BUILT_SOURCES = AutoGenerated.inc - -include $(LEVEL)/Makefile.common diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index 14594cf..6c8dbad 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/Passes.h" +#include "llvm/Analysis/Verifier.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" @@ -31,19 +32,21 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Target/TargetSelect.h" +#include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/PassManagerBuilder.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/Host.h" #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/system_error.h" #include "llvm/Config/config.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" #include <cstdlib> #include <unistd.h> #include <fcntl.h> @@ -73,8 +76,7 @@ LTOCodeGenerator::LTOCodeGenerator() _nativeObjectFile(NULL) { InitializeAllTargets(); - InitializeAllMCAsmInfos(); - InitializeAllMCSubtargetInfos(); + InitializeAllTargetMCs(); InitializeAllAsmPrinters(); } @@ -191,7 +193,7 @@ bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) bool genResult = false; tool_output_file objFile(uniqueObjPath.c_str(), errMsg); if (!errMsg.empty()) - return NULL; + return true; genResult = this->generateObjectFile(objFile.os(), errMsg); objFile.os().close(); if (objFile.os().has_error()) { @@ -250,23 +252,25 @@ bool LTOCodeGenerator::determineTarget(std::string& errMsg) // The relocation model is actually a static member of TargetMachine // and needs to be set before the TargetMachine is instantiated. + Reloc::Model RelocModel = Reloc::Default; switch( _codeModel ) { case LTO_CODEGEN_PIC_MODEL_STATIC: - TargetMachine::setRelocationModel(Reloc::Static); + RelocModel = Reloc::Static; break; case LTO_CODEGEN_PIC_MODEL_DYNAMIC: - TargetMachine::setRelocationModel(Reloc::PIC_); + RelocModel = Reloc::PIC_; break; case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: - TargetMachine::setRelocationModel(Reloc::DynamicNoPIC); + RelocModel = Reloc::DynamicNoPIC; break; } - // construct LTModule, hand over ownership of module and target + // construct LTOModule, hand over ownership of module and target SubtargetFeatures Features; Features.getDefaultSubtargetFeatures(llvm::Triple(Triple)); std::string FeatureStr = Features.getString(); - _target = march->createTargetMachine(Triple, _mCpu, FeatureStr); + _target = march->createTargetMachine(Triple, _mCpu, FeatureStr, + RelocModel); } return false; } @@ -308,7 +312,7 @@ void LTOCodeGenerator::applyScopeRestrictions() { passes.add(createVerifierPass()); // mark which symbols can not be internalized - MCContext Context(*_target->getMCAsmInfo(), NULL); + MCContext Context(*_target->getMCAsmInfo(), *_target->getRegisterInfo(), NULL); Mangler mangler(Context, *_target->getTargetData()); std::vector<const char*> mustPreserveList; SmallPtrSet<GlobalValue*, 8> asmUsed; @@ -329,7 +333,7 @@ void LTOCodeGenerator::applyScopeRestrictions() { if (LLVMCompilerUsed) LLVMCompilerUsed->eraseFromParent(); - const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context); + llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context); std::vector<Constant*> asmUsed2; for (SmallPtrSet<GlobalValue*, 16>::const_iterator i = asmUsed.begin(), e = asmUsed.end(); i !=e; ++i) { diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index dc99b94..4ba8985 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -27,6 +27,8 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/system_error.h" #include "llvm/Target/Mangler.h" #include "llvm/MC/MCAsmInfo.h" @@ -38,10 +40,9 @@ #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/Target/TargetAsmParser.h" +#include "llvm/MC/MCTargetAsmParser.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Target/TargetSelect.h" +#include "llvm/Target/TargetRegisterInfo.h" using namespace llvm; @@ -135,8 +136,7 @@ LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, static bool Initialized = false; if (!Initialized) { InitializeAllTargets(); - InitializeAllMCAsmInfos(); - InitializeAllMCSubtargetInfos(); + InitializeAllTargetMCs(); InitializeAllAsmParsers(); Initialized = true; } @@ -165,7 +165,7 @@ LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, std::string CPU; TargetMachine *target = march->createTargetMachine(Triple, CPU, FeatureStr); LTOModule *Ret = new LTOModule(m.take(), target); - bool Err = Ret->ParseSymbols(); + bool Err = Ret->ParseSymbols(errMsg); if (Err) { delete Ret; return NULL; @@ -581,7 +581,8 @@ namespace { markDefined(*Symbol); } virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {} + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) {} virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) {} virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {} @@ -612,22 +613,30 @@ namespace { }; } -bool LTOModule::addAsmGlobalSymbols(MCContext &Context) { +bool LTOModule::addAsmGlobalSymbols(MCContext &Context, std::string &errMsg) { const std::string &inlineAsm = _module->getModuleInlineAsm(); + if (inlineAsm.empty()) + return false; OwningPtr<RecordStreamer> Streamer(new RecordStreamer(Context)); MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(inlineAsm); SourceMgr SrcMgr; SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); - OwningPtr<MCAsmParser> Parser(createMCAsmParser(_target->getTarget(), SrcMgr, + OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Context, *Streamer, *_target->getMCAsmInfo())); OwningPtr<MCSubtargetInfo> STI(_target->getTarget(). createMCSubtargetInfo(_target->getTargetTriple(), _target->getTargetCPU(), _target->getTargetFeatureString())); - OwningPtr<TargetAsmParser> - TAP(_target->getTarget().createAsmParser(*STI, *Parser.get())); + OwningPtr<MCTargetAsmParser> + TAP(_target->getTarget().createMCAsmParser(*STI, *Parser.get())); + if (!TAP) { + errMsg = "target " + std::string(_target->getTarget().getName()) + + " does not define AsmParser."; + return true; + } + Parser->setTargetParser(*TAP); int Res = Parser->Run(false); if (Res) @@ -660,9 +669,9 @@ static bool isAliasToDeclaration(const GlobalAlias &V) { return isDeclaration(*V.getAliasedGlobal()); } -bool LTOModule::ParseSymbols() { +bool LTOModule::ParseSymbols(std::string &errMsg) { // Use mangler to add GlobalPrefix to names to match linker names. - MCContext Context(*_target->getMCAsmInfo(), NULL); + MCContext Context(*_target->getMCAsmInfo(), *_target->getRegisterInfo(),NULL); Mangler mangler(Context, *_target->getTargetData()); // add functions @@ -683,7 +692,7 @@ bool LTOModule::ParseSymbols() { } // add asm globals - if (addAsmGlobalSymbols(Context)) + if (addAsmGlobalSymbols(Context, errMsg)) return true; // add aliases diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h index 0b64a90..ca08aea 100644 --- a/tools/lto/LTOModule.h +++ b/tools/lto/LTOModule.h @@ -76,7 +76,7 @@ struct LTOModule { private: LTOModule(llvm::Module* m, llvm::TargetMachine* t); - bool ParseSymbols(); + bool ParseSymbols(std::string &errMsg); void addDefinedSymbol(llvm::GlobalValue* def, llvm::Mangler& mangler, bool isFunction); @@ -86,7 +86,8 @@ private: llvm::Mangler &mangler); void addDefinedDataSymbol(llvm::GlobalValue* v, llvm::Mangler &mangler); - bool addAsmGlobalSymbols(llvm::MCContext &Context); + bool addAsmGlobalSymbols(llvm::MCContext &Context, + std::string &errMsg); void addAsmGlobalSymbol(const char *, lto_symbol_attributes scope); void addAsmGlobalSymbolUndef(const char *); diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp index f324259..2b22c3b 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -310,6 +310,29 @@ static int DumpDysymtabCommand(MachOObject &Obj, return Res; } +static int DumpLinkeditDataCommand(MachOObject &Obj, + const MachOObject::LoadCommandInfo &LCI) { + InMemoryStruct<macho::LinkeditDataLoadCommand> LLC; + Obj.ReadLinkeditDataLoadCommand(LCI, LLC); + if (!LLC) + return Error("unable to read segment load command"); + + outs() << " ('dataoff', " << LLC->DataOffset << ")\n" + << " ('datasize', " << LLC->DataSize << ")\n" + << " ('_addresses', [\n"; + + SmallVector<uint64_t, 8> Addresses; + Obj.ReadULEB128s(LLC->DataOffset, Addresses); + for (unsigned i = 0, e = Addresses.size(); i != e; ++i) + outs() << " # Address " << i << '\n' + << " ('address', " << format("0x%x", Addresses[i]) << "),\n"; + + outs() << " ])\n"; + + return 0; +} + + static int DumpLoadCommand(MachOObject &Obj, unsigned Index) { const MachOObject::LoadCommandInfo &LCI = Obj.getLoadCommandInfo(Index); int Res = 0; @@ -330,6 +353,11 @@ static int DumpLoadCommand(MachOObject &Obj, unsigned Index) { case macho::LCT_Dysymtab: Res = DumpDysymtabCommand(Obj, LCI); break; + case macho::LCT_CodeSignature: + case macho::LCT_SegmentSplitInfo: + case macho::LCT_FunctionStarts: + Res = DumpLinkeditDataCommand(Obj, LCI); + break; default: Warning("unknown load command: " + Twine(LCI.Command.Type)); break; diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index aa375c5..ffd2c21 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -35,11 +35,11 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/PassManagerBuilder.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/LinkAllPasses.h" #include "llvm/LinkAllVMCore.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" #include <memory> #include <algorithm> using namespace llvm; @@ -431,8 +431,6 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM, static void AddStandardCompilePasses(PassManagerBase &PM) { PM.add(createVerifierPass()); // Verify that input is correct - addPass(PM, createLowerSetJmpPass()); // Lower llvm.setjmp/.longjmp - // If the -strip-debug command line option was specified, do it. if (StripDebug) addPass(PM, createStripSymbolsPass(true)); |