diff --git a/.arcconfig b/.arcconfig index 06323119c1d6391d1c17dbd03307ee47dc95d584..e06dc389d6fc73346850a952b66520ab6a4fb490 100644 --- a/.arcconfig +++ b/.arcconfig @@ -1,4 +1,4 @@ { "project_id" : "llvm", - "conduit_uri" : "http://reviews.llvm.org/" + "conduit_uri" : "https://reviews.llvm.org/" } diff --git a/.clang-tidy b/.clang-tidy index 97fbe23333bde38c4205a5a31581154af7647eff..c3bffa2af84a69af18dc88b977e536915513e0cb 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,4 +1,4 @@ -Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,readability-identifier-naming' +Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming' CheckOptions: - key: readability-identifier-naming.ClassCase value: CamelCase diff --git a/.gitignore b/.gitignore index e3d191dcbcced9f0c97a5b6838b88eddabc0b47f..8144debabd0d28f7e805f5f982d649d228afbd26 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,8 @@ autoconf/autom4te.cache projects/* !projects/*.* !projects/Makefile +runtimes/* +!runtimes/*.* # Clang, which is tracked independently. tools/clang # LLDB, which is tracked independently. diff --git a/CMakeLists.txt b/CMakeLists.txt index 13164d3c054984c2f8837325a86fccda7ebf9c65..ac59748993a15af8203b986c63b2147294610357 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # See docs/CMake.html for instructions about how to build LLVM with CMake. -cmake_minimum_required(VERSION 2.8.12.2) +cmake_minimum_required(VERSION 3.4.3) if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "No build type selected, default to Debug") @@ -20,12 +20,6 @@ if (POLICY CMP0051) cmake_policy(SET CMP0051 OLD) endif() -if(CMAKE_VERSION VERSION_LESS 3.1.20141117) - set(cmake_3_2_USES_TERMINAL) -else() - set(cmake_3_2_USES_TERMINAL USES_TERMINAL) -endif() - if(NOT DEFINED LLVM_VERSION_MAJOR) set(LLVM_VERSION_MAJOR 3) endif() @@ -56,12 +50,27 @@ project(LLVM ${cmake_3_0_LANGUAGES} C CXX ASM) +if(APPLE) + if(NOT CMAKE_LIBTOOL) + find_program(CMAKE_LIBTOOL NAMES libtool) + endif() + if(CMAKE_LIBTOOL) + set(CMAKE_LIBTOOL ${CMAKE_LIBTOOL} CACHE PATH "libtool executable") + message(STATUS "Found libtool - ${CMAKE_LIBTOOL}") + get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) + foreach(lang ${languages}) + set(CMAKE_${lang}_CREATE_STATIC_LIBRARY + "${CMAKE_LIBTOOL} -static -o ") + endforeach() + endif() +endif() + # The following only works with the Ninja generator in CMake >= 3.0. set(LLVM_PARALLEL_COMPILE_JOBS "" CACHE STRING "Define the maximum number of concurrent compilation jobs.") if(LLVM_PARALLEL_COMPILE_JOBS) - if(CMAKE_VERSION VERSION_LESS 3.0 OR NOT CMAKE_MAKE_PROGRAM MATCHES "ninja") - message(WARNING "Job pooling is only available with Ninja generators and CMake 3.0 and later.") + if(NOT CMAKE_MAKE_PROGRAM MATCHES "ninja") + message(WARNING "Job pooling is only available with Ninja generators.") else() set_property(GLOBAL APPEND PROPERTY JOB_POOLS compile_job_pool=${LLVM_PARALLEL_COMPILE_JOBS}) set(CMAKE_JOB_POOL_COMPILE compile_job_pool) @@ -76,8 +85,8 @@ endif() set(LLVM_PARALLEL_LINK_JOBS "" CACHE STRING "Define the maximum number of concurrent link jobs.") if(LLVM_PARALLEL_LINK_JOBS) - if(CMAKE_VERSION VERSION_LESS 3.0 OR NOT CMAKE_MAKE_PROGRAM MATCHES "ninja") - message(WARNING "Job pooling is only available with Ninja generators and CMake 3.0 and later.") + if(NOT CMAKE_MAKE_PROGRAM MATCHES "ninja") + message(WARNING "Job pooling is only available with Ninja generators.") else() set_property(GLOBAL APPEND PROPERTY JOB_POOLS link_job_pool=${LLVM_PARALLEL_LINK_JOBS}) set(CMAKE_JOB_POOL_LINK link_job_pool) @@ -186,6 +195,9 @@ endif() set(LLVM_LIBDIR_SUFFIX "" CACHE STRING "Define suffix of library directory name (32/64)" ) +set(LLVM_TOOLS_INSTALL_DIR "bin" CACHE STRING "Path for binary subdirectory (defaults to 'bin')") +mark_as_advanced(LLVM_TOOLS_INSTALL_DIR) + # They are used as destination of target generators. set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) @@ -211,7 +223,6 @@ set(LLVM_ALL_TARGETS AMDGPU ARM BPF - CppBackend Hexagon Mips MSP430 @@ -235,11 +246,6 @@ set(LLVM_EXPERIMENTAL_TARGETS_TO_BUILD "" option(BUILD_SHARED_LIBS "Build all libraries as shared libraries instead of static" OFF) -option(LLVM_ENABLE_TIMESTAMPS "Enable embedding timestamp information in build" ON) -if(LLVM_ENABLE_TIMESTAMPS) - set(ENABLE_TIMESTAMPS 1) -endif() - option(LLVM_ENABLE_BACKTRACES "Enable embedding backtraces on crash." ON) if(LLVM_ENABLE_BACKTRACES) set(ENABLE_BACKTRACES 1) @@ -277,6 +283,13 @@ include(AddLLVMDefinitions) option(LLVM_ENABLE_PIC "Build Position-Independent Code" ON) option(LLVM_ENABLE_WARNINGS "Enable compiler warnings." ON) option(LLVM_ENABLE_MODULES "Compile with C++ modules enabled." OFF) +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + option(LLVM_ENABLE_MODULE_DEBUGGING "Compile with -gmodules." ON) + option(LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY "Compile with -fmodules-local-submodule-visibility." OFF) +else() + option(LLVM_ENABLE_MODULE_DEBUGGING "Compile with -gmodules." OFF) + option(LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY "Compile with -fmodules-local-submodule-visibility." ON) +endif() option(LLVM_ENABLE_CXX1Y "Compile with C++1y enabled." OFF) option(LLVM_ENABLE_LIBCXX "Use libc++ if available." OFF) option(LLVM_ENABLE_LIBCXXABI "Use libc++abi when using libc++." OFF) @@ -289,6 +302,8 @@ else() option(LLVM_ENABLE_ASSERTIONS "Enable assertions" ON) endif() +option(LLVM_ENABLE_EXPENSIVE_CHECKS "Enable expensive checks" OFF) + set(LLVM_ABI_BREAKING_CHECKS "WITH_ASSERTS" CACHE STRING "Enable abi-breaking checks. Can be WITH_ASSERTS, FORCE_ON or FORCE_OFF.") @@ -326,8 +341,26 @@ set(LLVM_USE_SANITIZER "" CACHE STRING option(LLVM_USE_SPLIT_DWARF "Use -gsplit-dwarf when compiling llvm." OFF) -option(WITH_POLLY "Build LLVM with Polly" ON) -option(LINK_POLLY_INTO_TOOLS "Static link Polly into tools" OFF) +option(LLVM_POLLY_LINK_INTO_TOOLS "Statically link Polly into tools (if available)" ON) +option(LLVM_POLLY_BUILD "Build LLVM with Polly" ON) + +if (EXISTS ${LLVM_MAIN_SRC_DIR}/tools/polly/CMakeLists.txt) + set(POLLY_IN_TREE TRUE) +else() + set(POLLY_IN_TREE FALSE) +endif() + +if (LLVM_POLLY_BUILD AND POLLY_IN_TREE) + set(WITH_POLLY ON) +else() + set(WITH_POLLY OFF) +endif() + +if (LLVM_POLLY_LINK_INTO_TOOLS AND WITH_POLLY) + set(LINK_POLLY_INTO_TOOLS ON) +else() + set(LINK_POLLY_INTO_TOOLS OFF) +endif() # Define an option controlling whether we should build for 32-bit on 64-bit # platforms, where supported. @@ -358,6 +391,8 @@ option(LLVM_BUILD_TOOLS "Build the LLVM tools. If OFF, just generate build targets." ON) option(LLVM_INCLUDE_UTILS "Generate build targets for the LLVM utils." ON) +option(LLVM_BUILD_UTILS + "Build LLVM utility binaries. If OFF, just generate build targets." ON) option(LLVM_BUILD_RUNTIME "Build the LLVM runtime libraries." ON) @@ -404,6 +439,21 @@ else() set(LLVM_ADD_NATIVE_VISUALIZERS_TO_SOLUTION FALSE CACHE INTERNAL "For Visual Studio 2013, manually copy natvis files to Documents\\Visual Studio 2013\\Visualizers" FORCE) endif() +if (LLVM_BUILD_INSTRUMENTED OR LLVM_BUILD_INSTRUMENTED_COVERAGE) + if(NOT LLVM_PROFILE_MERGE_POOL_SIZE) + # A pool size of 1-2 is probably sufficient on a SSD. 3-4 should be fine + # for spining disks. Anything higher may only help on slower mediums. + set(LLVM_PROFILE_MERGE_POOL_SIZE "4") + endif() + if(NOT LLVM_PROFILE_FILE_PATTERN) + if(NOT LLVM_PROFILE_DATA_DIR) + set(LLVM_PROFILE_FILE_PATTERN "%${LLVM_PROFILE_MERGE_POOL_SIZE}m.profraw") + else() + file(TO_NATIVE_PATH "${LLVM_PROFILE_DATA_DIR}/%${LLVM_PROFILE_MERGE_POOL_SIZE}m.profraw" LLVM_PROFILE_FILE_PATTERN) + endif() + endif() +endif() + # All options referred to from HandleLLVMOptions have to be specified # BEFORE this include, otherwise options will not be correctly set on # first cmake run @@ -652,6 +702,15 @@ add_subdirectory(lib/TableGen) add_subdirectory(utils/TableGen) +# Force target to be built as soon as possible. Clang modules builds depend +# header-wise on it as they ship all headers from the umbrella folders. Building +# an entire module might include header, which depends on intrinsics_gen. This +# should be right after LLVMSupport and LLVMTableGen otherwise we introduce a +# circular dependence. +if (LLVM_ENABLE_MODULES) + list(APPEND LLVM_COMMON_DEPENDS intrinsics_gen) +endif(LLVM_ENABLE_MODULES) + add_subdirectory(include/llvm) add_subdirectory(lib) @@ -687,16 +746,12 @@ endforeach() add_subdirectory(projects) -if(WITH_POLLY) - if(NOT EXISTS ${LLVM_MAIN_SRC_DIR}/tools/polly/CMakeLists.txt) - set(WITH_POLLY OFF) - endif() -endif(WITH_POLLY) - if( LLVM_INCLUDE_TOOLS ) add_subdirectory(tools) endif() +add_subdirectory(runtimes) + if( LLVM_INCLUDE_EXAMPLES ) add_subdirectory(examples) endif() @@ -707,7 +762,8 @@ if( LLVM_INCLUDE_TESTS ) llvm_ExternalProject_Add(test-suite ${LLVM_MAIN_SRC_DIR}/projects/test-suite USE_TOOLCHAIN EXCLUDE_FROM_ALL - NO_INSTALL) + NO_INSTALL + ALWAYS_CLEAN) endif() add_subdirectory(test) add_subdirectory(unittests) @@ -731,6 +787,7 @@ if( LLVM_INCLUDE_TESTS ) ARGS ${LLVM_LIT_EXTRA_ARGS} ) add_custom_target(test-depends DEPENDS ${LLVM_LIT_DEPENDS}) + set_target_properties(test-depends PROPERTIES FOLDER "Tests") endif() if (LLVM_INCLUDE_DOCS) diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT index 24a41bc891eabec4f6feac646730b5cf90286dc4..60969849656f0f2a6f5288be4c38f43965f33594 100644 --- a/CODE_OWNERS.TXT +++ b/CODE_OWNERS.TXT @@ -12,17 +12,10 @@ N: Joe Abbey E: jabbey@arxan.com D: LLVM Bitcode (lib/Bitcode/* include/llvm/Bitcode/*) -N: Owen Anderson -E: resistor@mac.com -D: SelectionDAG (lib/CodeGen/SelectionDAG/*) - -N: Rafael Avila de Espindola -E: rafael.espindola@gmail.com -D: Gold plugin (tools/gold/*) - N: Justin Bogner E: mail@justinbogner.com D: InstrProfiling and related parts of ProfileData +D: SelectionDAG (lib/CodeGen/SelectionDAG/*) N: Chandler Carruth E: chandlerc@gmail.com @@ -41,9 +34,9 @@ N: Greg Clayton E: gclayton@apple.com D: LLDB -N: Hans Wennborg -E: hans@chromium.org -D: Release management (x.y.0 releases) +N: Sanjoy Das +E: sanjoy@playingwithpointers.com +D: IndVar Simplify, Scalar Evolution N: Marshall Clow E: mclow.lists@gmail.com @@ -91,7 +84,11 @@ D: NVPTX Target (lib/Target/NVPTX/*) N: Lang Hames E: lhames@gmail.com -D: MCJIT, RuntimeDyld and JIT event listeners +D: MCJIT, RuntimeDyld and JIT event listeners, Orcish Warchief + +N: Teresa Johnson +E: tejohnson@google.com +D: Gold plugin (tools/gold/*) N: Galina Kistanova E: gkistanova@gmail.com @@ -155,7 +152,7 @@ E: mcrosier@codeaurora.org D: Fast-Isel N: Nadav Rotem -E: nrotem@apple.com +E: nadav.rotem@me.com D: X86 Backend, Loop Vectorizer N: Daniel Sanders @@ -189,7 +186,7 @@ D: MemorySanitizer (LLVM part) N: Andrew Trick E: atrick@apple.com -D: IndVar Simplify, Loop Strength Reduction, Instruction Scheduling +D: Loop Strength Reduction, Instruction Scheduling N: Ulrich Weigand E: uweigand@de.ibm.com @@ -199,6 +196,10 @@ N: Bill Wendling E: isanbard@gmail.com D: libLTO, IR Linker +N: Hans Wennborg +E: hans@chromium.org +D: Release management (x.y.0 releases) + N: Peter Zotov E: whitequark@whitequark.org D: OCaml bindings diff --git a/CREDITS.TXT b/CREDITS.TXT index da1fb010e35b8892a88249f8e2de6760b83ed68b..818e54d3899e25c4d0a3d6fb5ba8fcb63df5fec0 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -347,6 +347,10 @@ N: Richard Osborne E: richard@xmos.com D: XCore backend +N: Piotr Padlewski +E: piotr.padlewski@gmail.com +D: !invariant.group metadata and other intrinsics for devirtualization in clang + N: Devang Patel E: dpatel@apple.com D: LTO tool, PassManager rewrite, Loop Pass Manager, Loop Rotate @@ -392,7 +396,7 @@ D: Fixes and improvements to the ARM fast-isel pass D: Fixes and improvements to the AArch64 backend N: Nadav Rotem -E: nrotem@apple.com +E: nadav.rotem@me.com D: X86 code generation improvements, Loop Vectorizer. N: Roman Samoilov diff --git a/LICENSE.TXT b/LICENSE.TXT index 84090c07a54f2ce947807c78e1cd02d6606d44cf..8b1585d9dbf6c92fc93ca39a14f449fec63826dd 100644 --- a/LICENSE.TXT +++ b/LICENSE.TXT @@ -4,7 +4,7 @@ LLVM Release License University of Illinois/NCSA Open Source License -Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign. +Copyright (c) 2003-2016 University of Illinois at Urbana-Champaign. All rights reserved. Developed by: diff --git a/bindings/ocaml/analysis/analysis_ocaml.c b/bindings/ocaml/analysis/analysis_ocaml.c index 44e31970a4b7484de1b3e8eeaf28fcc3f55de828..8b8263d9f337a7838bcea7faf533da99114f97d6 100644 --- a/bindings/ocaml/analysis/analysis_ocaml.c +++ b/bindings/ocaml/analysis/analysis_ocaml.c @@ -16,6 +16,7 @@ \*===----------------------------------------------------------------------===*/ #include "llvm-c/Analysis.h" +#include "llvm-c/Core.h" #include "caml/alloc.h" #include "caml/mlvalues.h" #include "caml/memory.h" diff --git a/bindings/ocaml/bitreader/bitreader_ocaml.c b/bindings/ocaml/bitreader/bitreader_ocaml.c index f91b092d9176775774c79d6b5b479799969de6d5..6d957760cff730efcdb6de0a4117cc811152427c 100644 --- a/bindings/ocaml/bitreader/bitreader_ocaml.c +++ b/bindings/ocaml/bitreader/bitreader_ocaml.c @@ -13,6 +13,7 @@ \*===----------------------------------------------------------------------===*/ #include "llvm-c/BitReader.h" +#include "llvm-c/Core.h" #include "caml/alloc.h" #include "caml/fail.h" #include "caml/memory.h" @@ -25,7 +26,7 @@ CAMLprim LLVMModuleRef llvm_get_module(LLVMContextRef C, LLVMMemoryBufferRef Mem LLVMModuleRef M; if (LLVMGetBitcodeModuleInContext2(C, MemBuf, &M)) - llvm_raise(*caml_named_value("Llvm_bitreader.Error"), ""); + llvm_raise(*caml_named_value("Llvm_bitreader.Error"), LLVMCreateMessage("")); return M; } @@ -35,7 +36,7 @@ CAMLprim LLVMModuleRef llvm_parse_bitcode(LLVMContextRef C, LLVMMemoryBufferRef LLVMModuleRef M; if (LLVMParseBitcodeInContext2(C, MemBuf, &M)) - llvm_raise(*caml_named_value("Llvm_bitreader.Error"), ""); + llvm_raise(*caml_named_value("Llvm_bitreader.Error"), LLVMCreateMessage("")); return M; } diff --git a/bindings/ocaml/executionengine/executionengine_ocaml.c b/bindings/ocaml/executionengine/executionengine_ocaml.c index b7992508bf9424ad8faa1908d1857dbb7fed1ce8..a5e62aca8a4e102e9d0b185ef3a818da877c4e67 100644 --- a/bindings/ocaml/executionengine/executionengine_ocaml.c +++ b/bindings/ocaml/executionengine/executionengine_ocaml.c @@ -17,6 +17,7 @@ #include #include +#include "llvm-c/Core.h" #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Target.h" #include "caml/alloc.h" diff --git a/bindings/ocaml/linker/linker_ocaml.c b/bindings/ocaml/linker/linker_ocaml.c index 498a5f0c8453bcbbd41cff1358cc4d2a0e879a4d..08737bd5843c1c3fdeccc8265ed7408d673d9a64 100644 --- a/bindings/ocaml/linker/linker_ocaml.c +++ b/bindings/ocaml/linker/linker_ocaml.c @@ -15,6 +15,7 @@ |* *| \*===----------------------------------------------------------------------===*/ +#include "llvm-c/Core.h" #include "llvm-c/Linker.h" #include "caml/alloc.h" #include "caml/memory.h" @@ -26,7 +27,7 @@ void llvm_raise(value Prototype, char *Message); /* llmodule -> llmodule -> unit */ CAMLprim value llvm_link_modules(LLVMModuleRef Dst, LLVMModuleRef Src) { if (LLVMLinkModules2(Dst, Src)) - llvm_raise(*caml_named_value("Llvm_linker.Error"), "Linking failed"); + llvm_raise(*caml_named_value("Llvm_linker.Error"), LLVMCreateMessage("Linking failed")); return Val_unit; } diff --git a/bindings/ocaml/llvm/llvm.ml b/bindings/ocaml/llvm/llvm.ml index 259d57bc06800ed4a63f056e8fcc923693a42e3e..513fe0c96870a24155cc011e7a68c3e3dc2c9a1b 100644 --- a/bindings/ocaml/llvm/llvm.ml +++ b/bindings/ocaml/llvm/llvm.ml @@ -283,6 +283,14 @@ module ValueKind = struct | Instruction of Opcode.t end +module DiagnosticSeverity = struct + type t = + | Error + | Warning + | Remark + | Note +end + exception IoError of string let () = Callback.register_exception "Llvm.IoError" (IoError "") @@ -304,6 +312,20 @@ type ('a, 'b) llrev_pos = | At_start of 'a | After of 'b + +(*===-- Context error handling --------------------------------------------===*) +module Diagnostic = struct + type t + + external description : t -> string = "llvm_get_diagnostic_description" + external severity : t -> DiagnosticSeverity.t + = "llvm_get_diagnostic_severity" +end + +external set_diagnostic_handler + : llcontext -> (Diagnostic.t -> unit) option -> unit + = "llvm_set_diagnostic_handler" + (*===-- Contexts ----------------------------------------------------------===*) external create_context : unit -> llcontext = "llvm_create_context" external dispose_context : llcontext -> unit = "llvm_dispose_context" @@ -461,6 +483,8 @@ external mdstring : llcontext -> string -> llvalue = "llvm_mdstring" external mdnode : llcontext -> llvalue array -> llvalue = "llvm_mdnode" external mdnull : llcontext -> llvalue = "llvm_mdnull" external get_mdstring : llvalue -> string option = "llvm_get_mdstring" +external get_mdnode_operands : llvalue -> llvalue array + = "llvm_get_mdnode_operands" external get_named_metadata : llmodule -> string -> llvalue array = "llvm_get_namedmd" external add_named_metadata_operand : llmodule -> string -> llvalue -> unit diff --git a/bindings/ocaml/llvm/llvm.mli b/bindings/ocaml/llvm/llvm.mli index 541c35a2a229d24f0a34ff6497f77a0cc95a5612..0f973000f754c35f3c8931d8a7fab654d4913c4e 100644 --- a/bindings/ocaml/llvm/llvm.mli +++ b/bindings/ocaml/llvm/llvm.mli @@ -15,7 +15,7 @@ (** {6 Abstract types} - These abstract types correlate directly to the LLVM VMCore classes. *) + These abstract types correlate directly to the LLVMCore classes. *) (** The top-level container for all LLVM global data. See the [llvm::LLVMContext] class. *) @@ -352,6 +352,16 @@ module ValueKind : sig | Instruction of Opcode.t end +(** The kind of [Diagnostic], the result of [Diagnostic.severity d]. + See [llvm::DiagnosticSeverity]. *) +module DiagnosticSeverity : sig + type t = + | Error + | Warning + | Remark + | Note +end + (** {6 Iteration} *) @@ -398,6 +408,22 @@ val reset_fatal_error_handler : unit -> unit See the function [llvm::cl::ParseCommandLineOptions()]. *) val parse_command_line_options : ?overview:string -> string array -> unit +(** {6 Context error handling} *) + +module Diagnostic : sig + type t + + (** [description d] returns a textual description of [d]. *) + val description : t -> string + + (** [severity d] returns the severity of [d]. *) + val severity : t -> DiagnosticSeverity.t +end + +(** [set_diagnostic_handler c h] set the diagnostic handler of [c] to [h]. + See the method [llvm::LLVMContext::setDiagnosticHandler]. *) +val set_diagnostic_handler : llcontext -> (Diagnostic.t -> unit) option -> unit + (** {6 Contexts} *) (** [create_context ()] creates a context for storing the "global" state in @@ -408,7 +434,7 @@ val create_context : unit -> llcontext [llvm::LLVMContext::~LLVMContext]. *) val dispose_context : llcontext -> unit -(** See the function [llvm::getGlobalContext]. *) +(** See the function [LLVMGetGlobalContext]. *) val global_context : unit -> llcontext (** [mdkind_id context name] returns the MDKind ID that corresponds to the @@ -826,6 +852,10 @@ val mdnull : llcontext -> llvalue See the method [llvm::MDString::getString] *) val get_mdstring : llvalue -> string option +(** [get_mdnode_operands v] returns the operands in the MDNode. *) +(* See the method [llvm::MDNode::getOperand] *) +val get_mdnode_operands : llvalue -> llvalue array + (** [get_named_metadata m name] returns all the MDNodes belonging to the named metadata (if any). See the method [llvm::NamedMDNode::getOperand]. *) diff --git a/bindings/ocaml/llvm/llvm_ocaml.c b/bindings/ocaml/llvm/llvm_ocaml.c index b4c47e7475e670e5eef01c6ea9cf9b98857963a4..f968db8efd0357c4f97644bd23ae0ebb5fd9dafd 100644 --- a/bindings/ocaml/llvm/llvm_ocaml.c +++ b/bindings/ocaml/llvm/llvm_ocaml.c @@ -19,6 +19,7 @@ #include #include #include "llvm-c/Core.h" +#include "llvm-c/Support.h" #include "caml/alloc.h" #include "caml/custom.h" #include "caml/memory.h" @@ -114,6 +115,49 @@ static value alloc_variant(int tag, void *Value) { return alloc_variant(0, pfun(Kid)); \ } +/*===-- Context error handling --------------------------------------------===*/ + +void llvm_diagnostic_handler_trampoline(LLVMDiagnosticInfoRef DI, + void *DiagnosticContext) { + caml_callback(*((value *)DiagnosticContext), (value)DI); +} + +/* Diagnostic.t -> string */ +CAMLprim value llvm_get_diagnostic_description(value Diagnostic) { + return llvm_string_of_message( + LLVMGetDiagInfoDescription((LLVMDiagnosticInfoRef)Diagnostic)); +} + +/* Diagnostic.t -> DiagnosticSeverity.t */ +CAMLprim value llvm_get_diagnostic_severity(value Diagnostic) { + return Val_int(LLVMGetDiagInfoSeverity((LLVMDiagnosticInfoRef)Diagnostic)); +} + +static void llvm_remove_diagnostic_handler(LLVMContextRef C) { + if (LLVMContextGetDiagnosticHandler(C) == + llvm_diagnostic_handler_trampoline) { + value *Handler = (value *)LLVMContextGetDiagnosticContext(C); + remove_global_root(Handler); + free(Handler); + } +} + +/* llcontext -> (Diagnostic.t -> unit) option -> unit */ +CAMLprim value llvm_set_diagnostic_handler(LLVMContextRef C, value Handler) { + llvm_remove_diagnostic_handler(C); + if (Handler == Val_int(0)) { + LLVMContextSetDiagnosticHandler(C, NULL, NULL); + } else { + value *DiagnosticContext = malloc(sizeof(value)); + if (DiagnosticContext == NULL) + caml_raise_out_of_memory(); + caml_register_global_root(DiagnosticContext); + *DiagnosticContext = Field(Handler, 0); + LLVMContextSetDiagnosticHandler(C, llvm_diagnostic_handler_trampoline, + DiagnosticContext); + } + return Val_unit; +} /*===-- Contexts ----------------------------------------------------------===*/ @@ -124,6 +168,7 @@ CAMLprim LLVMContextRef llvm_create_context(value Unit) { /* llcontext -> unit */ CAMLprim value llvm_dispose_context(LLVMContextRef C) { + llvm_remove_diagnostic_handler(C); LLVMContextDispose(C); return Val_unit; } @@ -689,6 +734,17 @@ CAMLprim value llvm_get_mdstring(LLVMValueRef V) { CAMLreturn(Val_int(0)); } +CAMLprim value llvm_get_mdnode_operands(LLVMValueRef V) { + CAMLparam0(); + CAMLlocal1(Operands); + unsigned int n; + + n = LLVMGetMDNodeNumOperands(V); + Operands = alloc(n, 0); + LLVMGetMDNodeOperands(V, (LLVMValueRef *) Operands); + CAMLreturn(Operands); +} + /* llmodule -> string -> llvalue array */ CAMLprim value llvm_get_namedmd(LLVMModuleRef M, value Name) { diff --git a/bindings/ocaml/target/llvm_target.ml b/bindings/ocaml/target/llvm_target.ml index d4910ac56f3b6338412dec73236c620daff65537..9e6b706b29ea8c2a8891302bc7f86c83a49d6892 100644 --- a/bindings/ocaml/target/llvm_target.ml +++ b/bindings/ocaml/target/llvm_target.ml @@ -54,9 +54,6 @@ module DataLayout = struct external of_string : string -> t = "llvm_datalayout_of_string" external as_string : t -> string = "llvm_datalayout_as_string" - external add_to_pass_manager : [ t -> unit - = "llvm_datalayout_add_to_pass_manager" external byte_order : t -> Endian.t = "llvm_datalayout_byte_order" external pointer_size : t -> int = "llvm_datalayout_pointer_size" external intptr_type : Llvm.llcontext -> t -> Llvm.lltype @@ -124,6 +121,8 @@ module TargetMachine = struct = "llvm_targetmachine_cpu" external features : t -> string = "llvm_targetmachine_features" + external data_layout : t -> DataLayout.t + = "llvm_targetmachine_data_layout" external add_analysis_passes : [< Llvm.PassManager.any ] Llvm.PassManager.t -> t -> unit = "llvm_targetmachine_add_analysis_passes" external set_verbose_asm : bool -> t -> unit diff --git a/bindings/ocaml/target/llvm_target.mli b/bindings/ocaml/target/llvm_target.mli index e826d5c401593c4a2d5e45cdc02f458b7cf07139..c59308c34e5434078c466562c18aa68bda239d5c 100644 --- a/bindings/ocaml/target/llvm_target.mli +++ b/bindings/ocaml/target/llvm_target.mli @@ -67,12 +67,6 @@ module DataLayout : sig See the method [llvm::DataLayout::getStringRepresentation]. *) val as_string : t -> string - (** [add_to_pass_manager pm dl] adds the data layout [dl] to - the pass manager [pm]. - See the method [llvm::PassManagerBase::add]. *) - val add_to_pass_manager : [ - t -> unit - (** Returns the byte order of a target, either [Endian.Big] or [Endian.Little]. See the method [llvm::DataLayout::isLittleEndian]. *) @@ -200,6 +194,9 @@ module TargetMachine : sig [llvm::TargetMachine::getCPU]. *) val cpu : t -> string + (** Returns the data layout of this target machine. *) + val data_layout : t -> DataLayout.t + (** Returns the feature string used while creating this target machine. See [llvm::TargetMachine::getFeatureString]. *) val features : t -> string diff --git a/bindings/ocaml/target/target_ocaml.c b/bindings/ocaml/target/target_ocaml.c index acc45da990f55868eedfcd7dee7751ab8a348b97..b63bef6d3d5b1d56161fbfc211eb4607fc1e49f6 100644 --- a/bindings/ocaml/target/target_ocaml.c +++ b/bindings/ocaml/target/target_ocaml.c @@ -15,6 +15,7 @@ |* *| \*===----------------------------------------------------------------------===*/ +#include "llvm-c/Core.h" #include "llvm-c/Target.h" #include "llvm-c/TargetMachine.h" #include "caml/alloc.h" @@ -64,13 +65,6 @@ CAMLprim value llvm_datalayout_as_string(value TD) { return Copy; } -/* [ DataLayout.t -> unit */ -CAMLprim value llvm_datalayout_add_to_pass_manager(LLVMPassManagerRef PM, - value DL) { - LLVMAddTargetData(DataLayout_val(DL), PM); - return Val_unit; -} - /* DataLayout.t -> Endian.t */ CAMLprim value llvm_datalayout_byte_order(value DL) { return Val_int(LLVMByteOrder(DataLayout_val(DL))); @@ -302,6 +296,12 @@ CAMLprim value llvm_targetmachine_features(value Machine) { TargetMachine_val(Machine))); } +/* TargetMachine.t -> DataLayout.t */ +CAMLprim value llvm_targetmachine_data_layout(value Machine) { + return llvm_alloc_data_layout(LLVMCreateTargetDataLayout( + TargetMachine_val(Machine))); +} + /* bool -> TargetMachine.t -> unit */ CAMLprim value llvm_targetmachine_set_verbose_asm(value Verb, value Machine) { LLVMSetTargetMachineAsmVerbosity(TargetMachine_val(Machine), Bool_val(Verb)); diff --git a/bindings/ocaml/transforms/scalar_opts/llvm_scalar_opts.mli b/bindings/ocaml/transforms/scalar_opts/llvm_scalar_opts.mli index b4cefed76d5288607d4fecceb607d650acdcec88..48109dfdb6b7260fac64e1c7e0046b10a5be6acb 100644 --- a/bindings/ocaml/transforms/scalar_opts/llvm_scalar_opts.mli +++ b/bindings/ocaml/transforms/scalar_opts/llvm_scalar_opts.mli @@ -127,17 +127,17 @@ external add_sccp : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit = "llvm_add_sccp" -(** See the [llvm::createScalarReplAggregatesPass] function. *) +(** See the [llvm::createSROAPass] function. *) external add_scalar_repl_aggregation : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit = "llvm_add_scalar_repl_aggregates" -(** See the [llvm::createScalarReplAggregatesPassSSA] function. *) +(** See the [llvm::createSROAPass] function. *) external add_scalar_repl_aggregation_ssa : [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit = "llvm_add_scalar_repl_aggregates_ssa" -(** See the [llvm::createScalarReplAggregatesWithThreshold] function. *) +(** See the [llvm::createSROAPass] function. *) external add_scalar_repl_aggregation_with_threshold : int -> [< Llvm.PassManager.any ] Llvm.PassManager.t -> unit = "llvm_add_scalar_repl_aggregates_with_threshold" diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index dd96b5c3091b4ff6854d5b2c55a572dae9d6b49b..b363a357c581782594dd978c9f5d2be06e960bcf 100755 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -67,6 +67,7 @@ check_include_file(sys/param.h HAVE_SYS_PARAM_H) check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H) check_include_file(sys/stat.h HAVE_SYS_STAT_H) check_include_file(sys/time.h HAVE_SYS_TIME_H) +check_include_file(sys/types.h HAVE_SYS_TYPES_H) check_include_file(sys/uio.h HAVE_SYS_UIO_H) check_include_file(termios.h HAVE_TERMIOS_H) check_include_file(unistd.h HAVE_UNISTD_H) @@ -109,7 +110,13 @@ if( NOT PURE_WINDOWS ) endif() if(HAVE_LIBPTHREAD) - set(PTHREAD_LIB pthread) + # We want to find pthreads library and at the moment we do want to + # have it reported as '-l' instead of '-pthread'. + # TODO: switch to -pthread once the rest of the build system can deal with it. + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + set(THREADS_HAVE_PTHREAD_ARG Off) + find_package(Threads REQUIRED) + set(PTHREAD_LIB ${CMAKE_THREAD_LIBS_INIT}) endif() # Don't look for these libraries on Windows. Also don't look for them if we're @@ -140,9 +147,15 @@ if( NOT PURE_WINDOWS AND NOT LLVM_USE_SANITIZER MATCHES "Memory.*") endif() endif() +check_library_exists(xar xar_open "" HAVE_LIBXAR) +if(HAVE_LIBXAR) + set(XAR_LIB xar) +endif() + # function checks check_symbol_exists(arc4random "stdlib.h" HAVE_DECL_ARC4RANDOM) check_symbol_exists(backtrace "execinfo.h" HAVE_BACKTRACE) +check_symbol_exists(_Unwind_Backtrace "unwind.h" HAVE_UNWIND_BACKTRACE) check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE) check_symbol_exists(getrusage sys/resource.h HAVE_GETRUSAGE) check_symbol_exists(setrlimit sys/resource.h HAVE_SETRLIMIT) @@ -155,6 +168,9 @@ if( HAVE_SETJMP_H ) check_symbol_exists(siglongjmp setjmp.h HAVE_SIGLONGJMP) check_symbol_exists(sigsetjmp setjmp.h HAVE_SIGSETJMP) endif() +if( HAVE_SIGNAL_H ) + check_symbol_exists(sigaltstack signal.h HAVE_SIGALTSTACK) +endif() if( HAVE_SYS_UIO_H ) check_symbol_exists(writev sys/uio.h HAVE_WRITEV) endif() @@ -400,12 +416,12 @@ else () set(LLVM_NATIVE_ASMPRINTER LLVMInitialize${LLVM_NATIVE_ARCH}AsmPrinter) # We don't have an ASM parser for all architectures yet. - if (EXISTS ${CMAKE_SOURCE_DIR}/lib/Target/${LLVM_NATIVE_ARCH}/AsmParser/CMakeLists.txt) + if (EXISTS ${PROJECT_SOURCE_DIR}/lib/Target/${LLVM_NATIVE_ARCH}/AsmParser/CMakeLists.txt) set(LLVM_NATIVE_ASMPARSER LLVMInitialize${LLVM_NATIVE_ARCH}AsmParser) endif () # We don't have an disassembler for all architectures yet. - if (EXISTS ${CMAKE_SOURCE_DIR}/lib/Target/${LLVM_NATIVE_ARCH}/Disassembler/CMakeLists.txt) + if (EXISTS ${PROJECT_SOURCE_DIR}/lib/Target/${LLVM_NATIVE_ARCH}/Disassembler/CMakeLists.txt) set(LLVM_NATIVE_DISASSEMBLER LLVMInitialize${LLVM_NATIVE_ARCH}Disassembler) endif () endif () @@ -516,7 +532,7 @@ else() if(GO_EXECUTABLE STREQUAL "GO_EXECUTABLE-NOTFOUND") message(STATUS "Go bindings disabled.") else() - execute_process(COMMAND ${GO_EXECUTABLE} run ${CMAKE_SOURCE_DIR}/bindings/go/conftest.go + execute_process(COMMAND ${GO_EXECUTABLE} run ${PROJECT_SOURCE_DIR}/bindings/go/conftest.go RESULT_VARIABLE GO_CONFTEST) if(GO_CONFTEST STREQUAL "0") set(LLVM_BINDINGS "${LLVM_BINDINGS} go") diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake index e4b0858f81dc0adf0307e2c70566c4adbf6ea274..26e439600140c685459e74f51250d8d55535c9e2 100644 --- a/cmake/modules/AddLLVM.cmake +++ b/cmake/modules/AddLLVM.cmake @@ -8,9 +8,9 @@ function(llvm_update_compile_flags name) set(update_src_props ON) endif() - # LLVM_REQUIRES_EH is an internal flag that individual - # targets can use to force EH - if((LLVM_REQUIRES_EH OR LLVM_ENABLE_EH) AND NOT CLANG_CL) + # LLVM_REQUIRES_EH is an internal flag that individual targets can use to + # force EH + if(LLVM_REQUIRES_EH OR LLVM_ENABLE_EH) if(NOT (LLVM_REQUIRES_RTTI OR LLVM_ENABLE_RTTI)) message(AUTHOR_WARNING "Exception handling requires RTTI. Enabling RTTI for ${name}") set(LLVM_REQUIRES_RTTI ON) @@ -328,11 +328,13 @@ endfunction(set_windows_version_resource_properties) # May specify header files for IDE generators. # SONAME # Should set SONAME link flags and create symlinks +# PLUGIN_TOOL +# The tool (i.e. cmake target) that this plugin will link against # ) function(llvm_add_library name) cmake_parse_arguments(ARG "MODULE;SHARED;STATIC;OBJECT;DISABLE_LLVM_LINK_LLVM_DYLIB;SONAME" - "OUTPUT_NAME" + "OUTPUT_NAME;PLUGIN_TOOL" "ADDITIONAL_HEADERS;DEPENDS;LINK_COMPONENTS;LINK_LIBS;OBJLIBS" ${ARGN}) list(APPEND LLVM_COMMON_DEPENDS ${ARG_DEPENDS}) @@ -350,11 +352,15 @@ function(llvm_add_library name) if(ARG_SHARED OR ARG_STATIC) message(WARNING "MODULE with SHARED|STATIC doesn't make sense.") endif() - if(NOT LLVM_ENABLE_PLUGINS) + # Plugins that link against a tool are allowed even when plugins in general are not + if(NOT LLVM_ENABLE_PLUGINS AND NOT (ARG_PLUGIN_TOOL AND LLVM_EXPORT_SYMBOLS_FOR_PLUGINS)) message(STATUS "${name} ignored -- Loadable modules not supported on this platform.") return() endif() else() + if(ARG_PLUGIN_TOOL) + message(WARNING "PLUGIN_TOOL without MODULE doesn't make sense.") + endif() if(BUILD_SHARED_LIBS AND NOT ARG_STATIC) set(ARG_SHARED TRUE) endif() @@ -468,7 +474,10 @@ function(llvm_add_library name) endif() endif() - if (DEFINED LLVM_LINK_COMPONENTS OR DEFINED ARG_LINK_COMPONENTS) + if(ARG_MODULE AND LLVM_EXPORT_SYMBOLS_FOR_PLUGINS AND ARG_PLUGIN_TOOL AND (WIN32 OR CYGWIN)) + # On DLL platforms symbols are imported from the tool by linking against it. + set(llvm_libs ${ARG_PLUGIN_TOOL}) + elseif (DEFINED LLVM_LINK_COMPONENTS OR DEFINED ARG_LINK_COMPONENTS) if (LLVM_LINK_LLVM_DYLIB AND NOT ARG_DISABLE_LLVM_LINK_LLVM_DYLIB) set(llvm_libs LLVM) else() @@ -487,27 +496,18 @@ function(llvm_add_library name) get_property(lib_deps GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_${name}) endif() - if(CMAKE_VERSION VERSION_LESS 2.8.12) - # Link libs w/o keywords, assuming PUBLIC. - target_link_libraries(${name} - ${ARG_LINK_LIBS} - ${lib_deps} - ${llvm_libs} - ) - elseif(ARG_STATIC) - target_link_libraries(${name} INTERFACE - ${ARG_LINK_LIBS} - ${lib_deps} - ${llvm_libs} - ) + if(ARG_STATIC) + set(libtype INTERFACE) else() # We can use PRIVATE since SO knows its dependent libs. - target_link_libraries(${name} PRIVATE + set(libtype PRIVATE) + endif() + + target_link_libraries(${name} ${libtype} ${ARG_LINK_LIBS} ${lib_deps} ${llvm_libs} ) - endif() if(LLVM_COMMON_DEPENDS) add_dependencies(${name} ${LLVM_COMMON_DEPENDS}) @@ -670,10 +670,78 @@ macro(add_llvm_executable name) if(NOT ARG_IGNORE_EXTERNALIZE_DEBUGINFO) llvm_externalize_debuginfo(${name}) endif() + if (PTHREAD_LIB) + # libpthreads overrides some standard library symbols, so main + # executable must be linked with it in order to provide consistent + # API for all shared libaries loaded by this executable. + target_link_libraries(${name} ${PTHREAD_LIB}) + endif() endmacro(add_llvm_executable name) function(export_executable_symbols target) - if (NOT MSVC) # MSVC's linker doesn't support exporting all symbols. + if (LLVM_EXPORTED_SYMBOL_FILE) + # The symbol file should contain the symbols we want the executable to + # export + set_target_properties(${target} PROPERTIES ENABLE_EXPORTS 1) + elseif (LLVM_EXPORT_SYMBOLS_FOR_PLUGINS) + # Extract the symbols to export from the static libraries that the + # executable links against. + set_target_properties(${target} PROPERTIES ENABLE_EXPORTS 1) + set(exported_symbol_file ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${target}.symbols) + # We need to consider not just the direct link dependencies, but also the + # transitive link dependencies. Do this by starting with the set of direct + # dependencies, then the dependencies of those dependencies, and so on. + get_target_property(new_libs ${target} LINK_LIBRARIES) + set(link_libs ${new_libs}) + while(NOT "${new_libs}" STREQUAL "") + foreach(lib ${new_libs}) + if(TARGET ${lib}) + get_target_property(lib_type ${lib} TYPE) + if("${lib_type}" STREQUAL "STATIC_LIBRARY") + list(APPEND static_libs ${lib}) + else() + list(APPEND other_libs ${lib}) + endif() + get_target_property(transitive_libs ${lib} INTERFACE_LINK_LIBRARIES) + foreach(transitive_lib ${transitive_libs}) + list(FIND link_libs ${transitive_lib} idx) + if(TARGET ${transitive_lib} AND idx EQUAL -1) + list(APPEND newer_libs ${transitive_lib}) + list(APPEND link_libs ${transitive_lib}) + endif() + endforeach(transitive_lib) + endif() + endforeach(lib) + set(new_libs ${newer_libs}) + set(newer_libs "") + endwhile() + if (MSVC) + set(mangling microsoft) + else() + set(mangling itanium) + endif() + add_custom_command(OUTPUT ${exported_symbol_file} + COMMAND ${PYTHON_EXECUTABLE} ${LLVM_MAIN_SRC_DIR}/utils/extract_symbols.py --mangling=${mangling} ${static_libs} -o ${exported_symbol_file} + WORKING_DIRECTORY ${LLVM_LIBRARY_OUTPUT_INTDIR} + DEPENDS ${LLVM_MAIN_SRC_DIR}/utils/extract_symbols.py ${static_libs} + VERBATIM + COMMENT "Generating export list for ${target}") + add_llvm_symbol_exports( ${target} ${exported_symbol_file} ) + # If something links against this executable then we want a + # transitive link against only the libraries whose symbols + # we aren't exporting. + set_target_properties(${target} PROPERTIES INTERFACE_LINK_LIBRARIES "${other_libs}") + # The default import library suffix that cmake uses for cygwin/mingw is + # ".dll.a", but for clang.exe that causes a collision with libclang.dll, + # where the import libraries of both get named libclang.dll.a. Use a suffix + # of ".exe.a" to avoid this. + if(CYGWIN OR MINGW) + set_target_properties(${target} PROPERTIES IMPORT_SUFFIX ".exe.a") + endif() + elseif(NOT (WIN32 OR CYGWIN)) + # On Windows auto-exporting everything doesn't work because of the limit on + # the size of the exported symbol table, but on other platforms we can do + # it without any trouble. set_target_properties(${target} PROPERTIES ENABLE_EXPORTS 1) if (APPLE) set_property(TARGET ${target} APPEND_STRING PROPERTY @@ -702,7 +770,7 @@ macro(add_llvm_tool name) if( LLVM_BUILD_TOOLS ) install(TARGETS ${name} EXPORT LLVMExports - RUNTIME DESTINATION bin + RUNTIME DESTINATION ${LLVM_TOOLS_INSTALL_DIR} COMPONENT ${name}) if (NOT CMAKE_CONFIGURATION_TYPES) @@ -732,11 +800,16 @@ macro(add_llvm_example name) set_target_properties(${name} PROPERTIES FOLDER "Examples") endmacro(add_llvm_example name) - +# This is a macro that is used to create targets for executables that are needed +# for development, but that are not intended to be installed by default. macro(add_llvm_utility name) + if ( NOT LLVM_BUILD_UTILS ) + set(EXCLUDE_FROM_ALL ON) + endif() + add_llvm_executable(${name} DISABLE_LLVM_LINK_LLVM_DYLIB ${ARGN}) set_target_properties(${name} PROPERTIES FOLDER "Utils") - if( LLVM_INSTALL_UTILS ) + if( LLVM_INSTALL_UTILS AND LLVM_BUILD_UTILS ) install (TARGETS ${name} RUNTIME DESTINATION bin COMPONENT ${name}) @@ -767,8 +840,8 @@ function(canonicalize_tool_name name output) endfunction(canonicalize_tool_name) # Custom add_subdirectory wrapper -# Takes in a project name (i.e. LLVM), the the subdirectory name, and an -# and an optional path if it differs from the name. +# Takes in a project name (i.e. LLVM), the subdirectory name, and an optional +# path if it differs from the name. macro(add_llvm_subdirectory project type name) set(add_llvm_external_dir "${ARGN}") if("${add_llvm_external_dir}" STREQUAL "") @@ -893,7 +966,10 @@ function(add_unittest test_suite test_name) add_llvm_executable(${test_name} IGNORE_EXTERNALIZE_DEBUGINFO ${ARGN}) set(outdir ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}) set_output_directory(${test_name} BINARY_DIR ${outdir} LIBRARY_DIR ${outdir}) - target_link_libraries(${test_name} gtest_main gtest) + # libpthreads overrides some standard library symbols, so main + # executable must be linked with it in order to provide consistent + # API for all shared libaries loaded by this executable. + target_link_libraries(${test_name} gtest_main gtest ${PTHREAD_LIB}) add_dependencies(${test_suite} ${test_name}) get_target_property(test_suite_folder ${test_suite} FOLDER) @@ -983,6 +1059,8 @@ function(configure_lit_site_cfg input output) set(HOST_CXX "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}") set(HOST_LDFLAGS "${CMAKE_EXE_LINKER_FLAGS}") + set(LIT_SITE_CFG_IN_HEADER "## Autogenerated from ${input}\n## Do not edit!") + configure_file(${input} ${output} @ONLY) endfunction() @@ -1008,7 +1086,7 @@ function(add_lit_target target comment) add_custom_target(${target} COMMAND ${LIT_COMMAND} ${ARG_UNPARSED_ARGUMENTS} COMMENT "${comment}" - ${cmake_3_2_USES_TERMINAL} + USES_TERMINAL ) else() add_custom_target(${target} @@ -1048,21 +1126,27 @@ endfunction() function(add_lit_testsuites project directory) if (NOT CMAKE_CONFIGURATION_TYPES) cmake_parse_arguments(ARG "" "" "PARAMS;DEPENDS;ARGS" ${ARGN}) - file(GLOB_RECURSE litCfg ${directory}/lit*.cfg) - set(lit_suites) - foreach(f ${litCfg}) - get_filename_component(dir ${f} DIRECTORY) - set(lit_suites ${lit_suites} ${dir}) - endforeach() - list(REMOVE_DUPLICATES lit_suites) - foreach(dir ${lit_suites}) - string(REPLACE ${directory} "" name_slash ${dir}) + + # Search recursively for test directories by assuming anything not + # in a directory called Inputs contains tests. + file(GLOB_RECURSE to_process LIST_DIRECTORIES true ${directory}/*) + foreach(lit_suite ${to_process}) + if(NOT IS_DIRECTORY ${lit_suite}) + continue() + endif() + string(FIND ${lit_suite} Inputs is_inputs) + if (NOT is_inputs EQUAL -1) + continue() + endif() + + # Create a check- target for the directory. + string(REPLACE ${directory} "" name_slash ${lit_suite}) if (name_slash) string(REPLACE "/" "-" name_slash ${name_slash}) string(REPLACE "\\" "-" name_dashes ${name_slash}) string(TOLOWER "${project}${name_dashes}" name_var) - add_lit_target("check-${name_var}" "Running lit suite ${dir}" - ${dir} + add_lit_target("check-${name_var}" "Running lit suite ${lit_suite}" + ${lit_suite} PARAMS ${ARG_PARAMS} DEPENDS ${ARG_DEPENDS} ARGS ${ARG_ARGS} @@ -1126,7 +1210,7 @@ function(llvm_install_symlink name dest) set(full_dest ${dest}${CMAKE_EXECUTABLE_SUFFIX}) install(SCRIPT ${INSTALL_SYMLINK} - CODE "install_symlink(${full_name} ${full_dest} bin)" + CODE "install_symlink(${full_name} ${full_dest} ${LLVM_TOOLS_INSTALL_DIR})" COMPONENT ${component}) if (NOT CMAKE_CONFIGURATION_TYPES AND NOT ARG_ALWAYS_GENERATE) @@ -1185,6 +1269,10 @@ function(llvm_externalize_debuginfo name) return() endif() + if(NOT LLVM_EXTERNALIZE_DEBUGINFO_SKIP_STRIP) + set(strip_command COMMAND xcrun strip -Sxl $) + endif() + if(APPLE) if(CMAKE_CXX_FLAGS MATCHES "-flto" OR CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE} MATCHES "-flto") @@ -1195,7 +1283,8 @@ function(llvm_externalize_debuginfo name) endif() add_custom_command(TARGET ${name} POST_BUILD COMMAND xcrun dsymutil $ - COMMAND xcrun strip -Sxl $) + ${strip_command} + ) else() message(FATAL_ERROR "LLVM_EXTERNALIZE_DEBUGINFO isn't implemented for non-darwin platforms!") endif() diff --git a/cmake/modules/AddOCaml.cmake b/cmake/modules/AddOCaml.cmake index 8b33332d07bcd5d046987c18da3abd52c2085282..e3dd1d840772cfe2052c926371a202e64f384691 100644 --- a/cmake/modules/AddOCaml.cmake +++ b/cmake/modules/AddOCaml.cmake @@ -73,7 +73,13 @@ function(add_ocaml_library name) get_property(system_libs TARGET LLVMSupport PROPERTY LLVM_SYSTEM_LIBS) foreach(system_lib ${system_libs}) - list(APPEND ocaml_flags "-l${system_lib}" ) + if (system_lib MATCHES "^-") + # If it's an option, pass it without changes. + list(APPEND ocaml_flags "${system_lib}" ) + else() + # Otherwise assume it's a library name we need to link with. + list(APPEND ocaml_flags "-l${system_lib}" ) + endif() endforeach() string(REPLACE ";" " " ARG_CFLAGS "${ARG_CFLAGS}") diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt index 7ebd2a265e07f28f73df2e1b2bcf3cf0f88fafe6..826dd366359db932574b21056309b7a9f62971c2 100644 --- a/cmake/modules/CMakeLists.txt +++ b/cmake/modules/CMakeLists.txt @@ -29,6 +29,7 @@ set(LLVM_CONFIG_LIBRARY_DIRS "${LLVM_LIBRARY_DIR}" ) set(LLVM_CONFIG_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +set(LLVM_CONFIG_BINARY_DIR "${LLVM_BINARY_DIR}") set(LLVM_CONFIG_TOOLS_BINARY_DIR "${LLVM_TOOLS_BINARY_DIR}") set(LLVM_CONFIG_EXPORTS_FILE "${llvm_cmake_builddir}/LLVMExports.cmake") configure_file( @@ -60,6 +61,7 @@ endforeach(p) set(LLVM_CONFIG_INCLUDE_DIRS "\${LLVM_INSTALL_PREFIX}/include") set(LLVM_CONFIG_LIBRARY_DIRS "\${LLVM_INSTALL_PREFIX}/lib\${LLVM_LIBDIR_SUFFIX}") set(LLVM_CONFIG_CMAKE_DIR "\${LLVM_INSTALL_PREFIX}/${LLVM_INSTALL_PACKAGE_DIR}") +set(LLVM_CONFIG_BINARY_DIR "\${LLVM_INSTALL_PREFIX}") set(LLVM_CONFIG_TOOLS_BINARY_DIR "\${LLVM_INSTALL_PREFIX}/bin") set(LLVM_CONFIG_EXPORTS_FILE "\${LLVM_CMAKE_DIR}/LLVMExports.cmake") configure_file( diff --git a/cmake/modules/CheckAtomic.cmake b/cmake/modules/CheckAtomic.cmake index 551de6ade84c0766d09540b188dacd8ee021666c..dcf021b8fddafa0e8afffa06795a9db72ee3ce91 100644 --- a/cmake/modules/CheckAtomic.cmake +++ b/cmake/modules/CheckAtomic.cmake @@ -18,6 +18,22 @@ int main() { set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) endfunction(check_working_cxx_atomics) +function(check_working_cxx_atomics64 varname) + set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}") + CHECK_CXX_SOURCE_COMPILES(" +#include +#include +std::atomic x (0); +int main() { + uint64_t i = x.load(std::memory_order_relaxed); + return 0; +} +" ${varname}) + set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) +endfunction(check_working_cxx_atomics64) + + # This isn't necessary on MSVC, so avoid command-line switch annoyance # by only running on GCC-like hosts. if (LLVM_COMPILER_IS_GCC_COMPATIBLE) @@ -38,6 +54,27 @@ if (LLVM_COMPILER_IS_GCC_COMPATIBLE) endif() endif() +# Check for 64 bit atomic operations. +if(MSVC) + set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True) +else() + check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB) +endif() + +# If not, check if the library exists, and atomics work with it. +if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) + check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64) + if(HAVE_CXX_LIBATOMICS64) + list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") + check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB) + if (NOT HAVE_CXX_ATOMICS64_WITH_LIB) + message(FATAL_ERROR "Host compiler must support std::atomic!") + endif() + else() + message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.") + endif() +endif() + ## TODO: This define is only used for the legacy atomic operations in ## llvm's Atomic.h, which should be replaced. Other code simply ## assumes C++11 works. diff --git a/cmake/modules/CrossCompile.cmake b/cmake/modules/CrossCompile.cmake index c136dfaa612e0e535182313df3a7566fe4f43d31..9c598a6a07b0f29dd7f6a36c23b0fa5e78575642 100644 --- a/cmake/modules/CrossCompile.cmake +++ b/cmake/modules/CrossCompile.cmake @@ -1,4 +1,4 @@ -function(llvm_create_cross_target_internal target_name toochain buildtype) +function(llvm_create_cross_target_internal target_name toolchain buildtype) if(NOT DEFINED LLVM_${target_name}_BUILD) set(LLVM_${target_name}_BUILD "${CMAKE_BINARY_DIR}/${target_name}") diff --git a/cmake/modules/GenerateVersionFromCVS.cmake b/cmake/modules/GenerateVersionFromCVS.cmake new file mode 100644 index 0000000000000000000000000000000000000000..6b1c719834667d4c7f1338d947d1e8c03e76ae38 --- /dev/null +++ b/cmake/modules/GenerateVersionFromCVS.cmake @@ -0,0 +1,39 @@ +# CMake project that writes Subversion revision information to a header. +# +# Input variables: +# SRC - Source directory +# HEADER_FILE - The header file to write +# +# The output header will contain macros FIRST_REPOSITORY and FIRST_REVISION, +# and SECOND_REPOSITORY and SECOND_REVISION if requested, where "FIRST" and +# "SECOND" are substituted with the names specified in the input variables. + + + +# Chop off cmake/modules/GetSVN.cmake +get_filename_component(LLVM_DIR "${CMAKE_SCRIPT_MODE_FILE}" PATH) +get_filename_component(LLVM_DIR "${LLVM_DIR}" PATH) +get_filename_component(LLVM_DIR "${LLVM_DIR}" PATH) + +set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + "${LLVM_DIR}/cmake/modules") +include(VersionFromVCS) + +# Handle strange terminals +set(ENV{TERM} "dumb") + +function(append_info name path) + add_version_info_from_vcs(REVISION ${path}) + string(STRIP "${REVISION}" REVISION) + file(APPEND "${HEADER_FILE}.txt" + "#define ${name} \"${REVISION}\"\n") +endfunction() + +append_info(${NAME} "${SOURCE_DIR}") + +# Copy the file only if it has changed. +execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${HEADER_FILE}.txt" "${HEADER_FILE}") +file(REMOVE "${HEADER_FILE}.txt") + diff --git a/cmake/modules/HandleLLVMOptions.cmake b/cmake/modules/HandleLLVMOptions.cmake index 7036e742873df57f05f4c42f236b932c37036797..22b4408b1ac0f32a5e0a8c343e9c32964f35d2e0 100644 --- a/cmake/modules/HandleLLVMOptions.cmake +++ b/cmake/modules/HandleLLVMOptions.cmake @@ -44,6 +44,11 @@ if( LLVM_ENABLE_ASSERTIONS ) endif() endif() +if(LLVM_ENABLE_EXPENSIVE_CHECKS) + add_definitions(-DEXPENSIVE_CHECKS) + add_definitions(-D_GLIBCXX_DEBUG) +endif() + string(TOUPPER "${LLVM_ABI_BREAKING_CHECKS}" uppercase_LLVM_ABI_BREAKING_CHECKS) if( uppercase_LLVM_ABI_BREAKING_CHECKS STREQUAL "WITH_ASSERTS" ) @@ -161,7 +166,8 @@ if( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32 ) # TODO: support other platforms and toolchains. if( LLVM_BUILD_32_BITS ) message(STATUS "Building 32 bits executables and libraries.") - add_llvm_definitions( -m32 ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -m32") @@ -221,14 +227,12 @@ if( MSVC ) include(ChooseMSVCCRT) - if( NOT (${CMAKE_VERSION} VERSION_LESS 2.8.11) ) - # set stack reserved size to ~10MB - # CMake previously automatically set this value for MSVC builds, but the - # behavior was changed in CMake 2.8.11 (Issue 12437) to use the MSVC default - # value (1 MB) which is not enough for us in tasks such as parsing recursive - # C++ templates in Clang. - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10000000") - endif() + # set stack reserved size to ~10MB + # CMake previously automatically set this value for MSVC builds, but the + # behavior was changed in CMake 2.8.11 (Issue 12437) to use the MSVC default + # value (1 MB) which is not enough for us in tasks such as parsing recursive + # C++ templates in Clang. + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10000000") if( MSVC11 ) add_llvm_definitions(-D_VARIADIC_MAX=10) @@ -245,6 +249,12 @@ if( MSVC ) -D_SCL_SECURE_NO_WARNINGS ) + # Tell MSVC to use the Unicode version of the Win32 APIs instead of ANSI. + add_llvm_definitions( + -DUNICODE + -D_UNICODE + ) + set(msvc_warning_flags # Disabled warnings. -wd4141 # Suppress ''modifier' : used more than once' (because of __forceinline combined with inline) @@ -347,17 +357,15 @@ if( MSVC ) # "Enforce type conversion rules". append("/Zc:rvalueCast" CMAKE_CXX_FLAGS) - if (NOT LLVM_ENABLE_TIMESTAMPS AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") # clang-cl and cl by default produce non-deterministic binaries because # link.exe /incremental requires a timestamp in the .obj file. clang-cl - # has the flag /Brepro to force deterministic binaries, so pass that when - # LLVM_ENABLE_TIMESTAMPS is turned off. + # has the flag /Brepro to force deterministic binaries. We want to pass that + # whenever you're building with clang unless you're passing /incremental. # This checks CMAKE_CXX_COMPILER_ID in addition to check_cxx_compiler_flag() # because cl.exe does not emit an error on flags it doesn't understand, # letting check_cxx_compiler_flag() claim it understands all flags. check_cxx_compiler_flag("/Brepro" SUPPORTS_BREPRO) - append_if(SUPPORTS_BREPRO "/Brepro" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) - if (SUPPORTS_BREPRO) # Check if /INCREMENTAL is passed to the linker and complain that it # won't work with /Brepro. @@ -365,14 +373,13 @@ if( MSVC ) string(TOUPPER "${CMAKE_MODULE_LINKER_FLAGS}" upper_module_flags) string(TOUPPER "${CMAKE_SHARED_LINKER_FLAGS}" upper_shared_flags) - string(FIND "${upper_exe_flags}" "/INCREMENTAL" exe_index) - string(FIND "${upper_module_flags}" "/INCREMENTAL" module_index) - string(FIND "${upper_shared_flags}" "/INCREMENTAL" shared_index) + string(FIND "${upper_exe_flags} ${upper_module_flags} ${upper_shared_flags}" + "/INCREMENTAL" linker_flag_idx) - if (${exe_index} GREATER -1 OR - ${module_index} GREATER -1 OR - ${shared_index} GREATER -1) - message(FATAL_ERROR "LLVM_ENABLE_TIMESTAMPS not compatible with /INCREMENTAL linking") + if (${linker_flag_idx} GREATER -1) + message(WARNING "/Brepro not compatible with /INCREMENTAL linking - builds will be non-deterministic") + else() + append("/Brepro" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) endif() endif() endif() @@ -438,9 +445,7 @@ elseif( LLVM_COMPILER_IS_GCC_COMPATIBLE ) endif() endif (LLVM_ENABLE_WARNINGS) append_if(LLVM_ENABLE_WERROR "-Werror" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) - if (NOT LLVM_ENABLE_TIMESTAMPS) - add_flag_if_supported("-Werror=date-time" WERROR_DATE_TIME) - endif () + add_flag_if_supported("-Werror=date-time" WERROR_DATE_TIME) if (LLVM_ENABLE_CXX1Y) check_cxx_compiler_flag("-std=c++1y" CXX_SUPPORTS_CXX1Y) append_if(CXX_SUPPORTS_CXX1Y "-std=c++1y" CMAKE_CXX_FLAGS) @@ -460,7 +465,21 @@ elseif( LLVM_COMPILER_IS_GCC_COMPATIBLE ) endif() if (LLVM_ENABLE_MODULES) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fmodules") + set(module_flags "-fmodules -fmodules-cache-path=module.cache") + if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # On Darwin -fmodules does not imply -fcxx-modules. + set(module_flags "${module_flags} -fcxx-modules") + endif() + if (LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY) + set(module_flags "${module_flags} -Xclang -fmodules-local-submodule-visibility") + endif() + if (LLVM_ENABLE_MODULE_DEBUGGING AND + ((uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG") OR + (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELWITHDEBINFO"))) + set(module_flags "${module_flags} -gmodules") + endif() + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${module_flags}") + # Check that we can build code with modules enabled, and that repeatedly # including still manages to respect NDEBUG properly. CHECK_CXX_SOURCE_COMPILES("#undef NDEBUG @@ -471,8 +490,7 @@ elseif( LLVM_COMPILER_IS_GCC_COMPATIBLE ) CXX_SUPPORTS_MODULES) set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) if (CXX_SUPPORTS_MODULES) - append_if(CXX_SUPPORTS_MODULES "-fmodules" CMAKE_C_FLAGS) - append_if(CXX_SUPPORTS_MODULES "-fmodules -fcxx-modules" CMAKE_CXX_FLAGS) + append("${module_flags}" CMAKE_CXX_FLAGS) else() message(FATAL_ERROR "LLVM_ENABLE_MODULES is not supported by this compiler") endif() @@ -560,7 +578,7 @@ add_llvm_definitions( -D__STDC_LIMIT_MACROS ) # clang doesn't print colored diagnostics when invoked from Ninja if (UNIX AND - CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND + CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_GENERATOR STREQUAL "Ninja") append("-fcolor-diagnostics" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) endif() @@ -582,15 +600,6 @@ if(NOT CYGWIN AND NOT WIN32) endif() endif() -if(CYGWIN OR MINGW) - # Prune --out-implib from executables. It doesn't make sense even - # with --export-all-symbols. - string(REGEX REPLACE "-Wl,--out-implib,[^ ]+ " " " - CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}") - string(REGEX REPLACE "-Wl,--out-implib,[^ ]+ " " " - CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE}") -endif() - if(MSVC) # Remove flags here, for exceptions and RTTI. # Each target property or source property should be responsible to control @@ -609,7 +618,15 @@ endif() option(LLVM_BUILD_INSTRUMENTED "Build LLVM and tools with PGO instrumentation (experimental)" Off) mark_as_advanced(LLVM_BUILD_INSTRUMENTED) -append_if(LLVM_BUILD_INSTRUMENTED "-fprofile-instr-generate" +append_if(LLVM_BUILD_INSTRUMENTED "-fprofile-instr-generate='${LLVM_PROFILE_FILE_PATTERN}'" + CMAKE_CXX_FLAGS + CMAKE_C_FLAGS + CMAKE_EXE_LINKER_FLAGS + CMAKE_SHARED_LINKER_FLAGS) + +option(LLVM_BUILD_INSTRUMENTED_COVERAGE "Build LLVM and tools with Code Coverage instrumentation (experimental)" Off) +mark_as_advanced(LLVM_BUILD_INSTRUMENTED_COVERAGE) +append_if(LLVM_BUILD_INSTRUMENTED_COVERAGE "-fprofile-instr-generate='${LLVM_PROFILE_FILE_PATTERN}' -fcoverage-mapping" CMAKE_CXX_FLAGS CMAKE_C_FLAGS CMAKE_EXE_LINKER_FLAGS @@ -628,6 +645,19 @@ elseif(LLVM_ENABLE_LTO) CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) endif() +# This option makes utils/extract_symbols.py be used to determine the list of +# symbols to export from LLVM tools. This is necessary when using MSVC if you +# want to allow plugins, though note that the plugin has to explicitly link +# against (exactly one) tool so we can't unilaterally turn on +# LLVM_ENABLE_PLUGINS when it's enabled. +option(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS "Export symbols from LLVM tools so that plugins can import them" OFF) +if(BUILD_SHARED_LIBS AND LLVM_EXPORT_SYMBOLS_FOR_PLUGINS) + message(FATAL_ERROR "BUILD_SHARED_LIBS not compatible with LLVM_EXPORT_SYMBOLS_FOR_PLUGINS") +endif() +if(LLVM_LINK_LLVM_DYLIB AND LLVM_EXPORT_SYMBOLS_FOR_PLUGINS) + message(FATAL_ERROR "LLVM_LINK_LLVM_DYLIB not compatible with LLVM_EXPORT_SYMBOLS_FOR_PLUGINS") +endif() + # Plugin support # FIXME: Make this configurable. if(WIN32 OR CYGWIN) diff --git a/cmake/modules/LLVMConfig.cmake.in b/cmake/modules/LLVMConfig.cmake.in index 6855c442254328b8fc11587bcff76aa13d06fa73..492a43d9ebc17bda9a02a2622142efc3e35a121e 100644 --- a/cmake/modules/LLVMConfig.cmake.in +++ b/cmake/modules/LLVMConfig.cmake.in @@ -7,6 +7,8 @@ set(LLVM_VERSION_MINOR @LLVM_VERSION_MINOR@) set(LLVM_VERSION_PATCH @LLVM_VERSION_PATCH@) set(LLVM_PACKAGE_VERSION @PACKAGE_VERSION@) +set(LLVM_BUILD_TYPE @CMAKE_BUILD_TYPE@) + set(LLVM_COMMON_DEPENDS @LLVM_COMMON_DEPENDS@) set(LLVM_AVAILABLE_LIBS @LLVM_AVAILABLE_LIBS@) @@ -39,7 +41,10 @@ set(LLVM_NATIVE_ARCH @LLVM_NATIVE_ARCH@) set(LLVM_ENABLE_PIC @LLVM_ENABLE_PIC@) +set(LLVM_BUILD_32_BITS @LLVM_BUILD_32_BITS@) + set(LLVM_ENABLE_PLUGINS @LLVM_ENABLE_PLUGINS@) +set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS @LLVM_EXPORT_SYMBOLS_FOR_PLUGINS@) set(LLVM_PLUGIN_EXT @LLVM_PLUGIN_EXT@) set(LLVM_ON_UNIX @LLVM_ON_UNIX@) @@ -49,11 +54,15 @@ set(LLVM_LIBDIR_SUFFIX @LLVM_LIBDIR_SUFFIX@) set(LLVM_INCLUDE_DIRS "@LLVM_CONFIG_INCLUDE_DIRS@") set(LLVM_LIBRARY_DIRS "@LLVM_CONFIG_LIBRARY_DIRS@") +set(LLVM_LIBRARY_DIR "@LLVM_CONFIG_LIBRARY_DIRS@") set(LLVM_DEFINITIONS "@LLVM_DEFINITIONS@") set(LLVM_CMAKE_DIR "@LLVM_CONFIG_CMAKE_DIR@") +set(LLVM_BINARY_DIR "@LLVM_CONFIG_BINARY_DIR@") set(LLVM_TOOLS_BINARY_DIR "@LLVM_CONFIG_TOOLS_BINARY_DIR@") +set(LLVM_TOOLS_INSTALL_DIR "@LLVM_TOOLS_INSTALL_DIR@") if(NOT TARGET LLVMSupport) + set(LLVM_EXPORTED_TARGETS "@LLVM_EXPORTS@") include("@LLVM_CONFIG_EXPORTS_FILE@") endif() diff --git a/cmake/modules/LLVMExternalProjectUtils.cmake b/cmake/modules/LLVMExternalProjectUtils.cmake index c2d9f530c200e9ebe0fd0233e1da639fbf0a6bc2..3e7355d4d6b2ca832c3d8f7b33a70e2869e08761 100644 --- a/cmake/modules/LLVMExternalProjectUtils.cmake +++ b/cmake/modules/LLVMExternalProjectUtils.cmake @@ -2,12 +2,12 @@ include(ExternalProject) # llvm_ExternalProject_BuildCmd(out_var target) # Utility function for constructing command lines for external project targets -function(llvm_ExternalProject_BuildCmd out_var target) +function(llvm_ExternalProject_BuildCmd out_var target bin_dir) if (CMAKE_GENERATOR MATCHES "Make") # Use special command for Makefiles to support parallelism. - set(${out_var} "$(MAKE)" "${target}" PARENT_SCOPE) + set(${out_var} "$(MAKE)" "-C" "${BINARY_DIR}" "${target}" PARENT_SCOPE) else() - set(${out_var} ${CMAKE_COMMAND} --build . --target ${target} + set(${out_var} ${CMAKE_COMMAND} --build ${bin_dir} --target ${target} --config $ PARENT_SCOPE) endif() endfunction() @@ -19,6 +19,8 @@ endfunction() # Exclude this project from the all target # NO_INSTALL # Don't generate install targets for this project +# ALWAYS_CLEAN +# Always clean the sub-project before building # CMAKE_ARGS arguments... # Optional cmake arguments to pass when configuring the project # TOOLCHAIN_TOOLS targets... @@ -27,11 +29,15 @@ endfunction() # Targets that this project depends on # EXTRA_TARGETS targets... # Extra targets in the subproject to generate targets for +# PASSTHROUGH_PREFIXES prefix... +# Extra variable prefixes (name is always included) to pass down # ) function(llvm_ExternalProject_Add name source_dir) - cmake_parse_arguments(ARG "USE_TOOLCHAIN;EXCLUDE_FROM_ALL;NO_INSTALL" + cmake_parse_arguments(ARG + "USE_TOOLCHAIN;EXCLUDE_FROM_ALL;NO_INSTALL;ALWAYS_CLEAN" "SOURCE_DIR" - "CMAKE_ARGS;TOOLCHAIN_TOOLS;RUNTIME_LIBRARIES;DEPENDS;EXTRA_TARGETS" ${ARGN}) + "CMAKE_ARGS;TOOLCHAIN_TOOLS;RUNTIME_LIBRARIES;DEPENDS;EXTRA_TARGETS;PASSTHROUGH_PREFIXES" + ${ARGN}) canonicalize_tool_name(${name} nameCanon) if(NOT ARG_TOOLCHAIN_TOOLS) set(ARG_TOOLCHAIN_TOOLS clang lld) @@ -52,6 +58,10 @@ function(llvm_ExternalProject_Add name source_dir) endif() endforeach() + if(ARG_ALWAYS_CLEAN) + set(always_clean clean) + endif() + list(FIND TOOLCHAIN_TOOLS clang FOUND_CLANG) if(FOUND_CLANG GREATER -1) set(CLANG_IN_TOOLCHAIN On) @@ -61,23 +71,6 @@ function(llvm_ExternalProject_Add name source_dir) list(APPEND TOOLCHAIN_BINS ${RUNTIME_LIBRARIES}) endif() - if(CMAKE_VERSION VERSION_GREATER 3.1.0) - set(cmake_3_1_EXCLUDE_FROM_ALL EXCLUDE_FROM_ALL 1) - endif() - - if(CMAKE_VERSION VERSION_GREATER 3.3.20150708) - set(cmake_3_4_USES_TERMINAL_OPTIONS - USES_TERMINAL_CONFIGURE 1 - USES_TERMINAL_BUILD 1 - USES_TERMINAL_INSTALL 1 - ) - set(cmake_3_4_USES_TERMINAL USES_TERMINAL 1) - endif() - - if(CMAKE_VERSION VERSION_GREATER 3.1.20141116) - set(cmake_3_2_USES_TERMINAL USES_TERMINAL) - endif() - set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/${name}-stamps/) set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${name}-bins/) @@ -85,18 +78,21 @@ function(llvm_ExternalProject_Add name source_dir) COMMAND ${CMAKE_COMMAND} -E remove_directory ${BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E remove_directory ${STAMP_DIR} COMMENT "Clobbering ${name} build and stamp directories" - ${cmake_3_2_USES_TERMINAL} + USES_TERMINAL ) - # Find all variables that start with COMPILER_RT and populate a variable with - # them. + # Find all variables that start with a prefix and propagate them through get_cmake_property(variableNames VARIABLES) - foreach(variableName ${variableNames}) - if(variableName MATCHES "^${nameCanon}") - string(REPLACE ";" "\;" value "${${variableName}}") - list(APPEND PASSTHROUGH_VARIABLES - -D${variableName}=${value}) - endif() + + list(APPEND ARG_PASSTHROUGH_PREFIXES ${nameCanon}) + foreach(prefix ${ARG_PASSTHROUGH_PREFIXES}) + foreach(variableName ${variableNames}) + if(variableName MATCHES "^${prefix}") + string(REPLACE ";" "\;" value "${${variableName}}") + list(APPEND PASSTHROUGH_VARIABLES + -D${variableName}=${value}) + endif() + endforeach() endforeach() if(ARG_USE_TOOLCHAIN) @@ -120,7 +116,7 @@ function(llvm_ExternalProject_Add name source_dir) DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp) if(ARG_EXCLUDE_FROM_ALL) - set(exclude ${cmake_3_1_EXCLUDE_FROM_ALL}) + set(exclude EXCLUDE_FROM_ALL 1) endif() ExternalProject_Add(${name} @@ -134,33 +130,35 @@ function(llvm_ExternalProject_Add name source_dir) CMAKE_ARGS ${${nameCanon}_CMAKE_ARGS} ${compiler_args} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} + -DLLVM_BINARY_DIR=${PROJECT_BINARY_DIR} + -DLLVM_CONFIG_PATH=$ + -DLLVM_ENABLE_WERROR=${LLVM_ENABLE_WERROR} + -DPACKAGE_VERSION=${PACKAGE_VERSION} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} ${ARG_CMAKE_ARGS} ${PASSTHROUGH_VARIABLES} INSTALL_COMMAND "" STEP_TARGETS configure build - ${cmake_3_4_USES_TERMINAL_OPTIONS} + BUILD_ALWAYS 1 + USES_TERMINAL_CONFIGURE 1 + USES_TERMINAL_BUILD 1 + USES_TERMINAL_INSTALL 1 ) - if(ARG_USE_TOOLCHAIN) - ExternalProject_Add_Step(${name} force-rebuild - COMMENT "Forcing rebuild becaues tools have changed" - DEPENDERS configure - DEPENDS ${TOOLCHAIN_BINS} - ${cmake_3_4_USES_TERMINAL} ) - endif() - if(ARG_USE_TOOLCHAIN) set(force_deps DEPENDS ${TOOLCHAIN_BINS}) endif() - llvm_ExternalProject_BuildCmd(run_clean clean) + llvm_ExternalProject_BuildCmd(run_clean clean ${BINARY_DIR}) ExternalProject_Add_Step(${name} clean COMMAND ${run_clean} COMMENT "Cleaning ${name}..." DEPENDEES configure ${force_deps} WORKING_DIRECTORY ${BINARY_DIR} - ${cmake_3_4_USES_TERMINAL} + EXCLUDE_FROM_MAIN 1 + USES_TERMINAL 1 ) ExternalProject_Add_StepTargets(${name} clean) @@ -179,17 +177,17 @@ function(llvm_ExternalProject_Add name source_dir) COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=${name} -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" - ${cmake_3_2_USES_TERMINAL}) + USES_TERMINAL) endif() # Add top-level targets foreach(target ${ARG_EXTRA_TARGETS}) - llvm_ExternalProject_BuildCmd(build_runtime_cmd ${target}) + llvm_ExternalProject_BuildCmd(build_runtime_cmd ${target} ${BINARY_DIR}) add_custom_target(${target} COMMAND ${build_runtime_cmd} DEPENDS ${name}-configure WORKING_DIRECTORY ${BINARY_DIR} VERBATIM - ${cmake_3_2_USES_TERMINAL}) + USES_TERMINAL) endforeach() endfunction() diff --git a/cmake/modules/TableGen.cmake b/cmake/modules/TableGen.cmake index fca7d1bda4b36105d3f500d9a6678c70cd49ec62..c88ee3fc196b5c3c9b5f0c0775d09540bf572f71 100644 --- a/cmake/modules/TableGen.cmake +++ b/cmake/modules/TableGen.cmake @@ -141,7 +141,7 @@ macro(add_tablegen target project) if (${project} STREQUAL LLVM AND NOT LLVM_INSTALL_TOOLCHAIN_ONLY) install(TARGETS ${target} EXPORT LLVMExports - RUNTIME DESTINATION bin) + RUNTIME DESTINATION ${LLVM_TOOLS_INSTALL_DIR}) endif() set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS ${target}) endmacro() diff --git a/cmake/modules/VersionFromVCS.cmake b/cmake/modules/VersionFromVCS.cmake index 6be4daa3166b500e81c42a631f7c8ccb7176e2cc..8d56b66fa4781afd0dfbbdfb1bfdbf5688983fc1 100644 --- a/cmake/modules/VersionFromVCS.cmake +++ b/cmake/modules/VersionFromVCS.cmake @@ -1,17 +1,22 @@ # Adds version control information to the variable VERS. For # determining the Version Control System used (if any) it inspects the -# existence of certain subdirectories under CMAKE_CURRENT_SOURCE_DIR. +# existence of certain subdirectories under SOURCE_DIR (if provided as an +# extra argument, otherwise uses CMAKE_CURRENT_SOURCE_DIR). function(add_version_info_from_vcs VERS) + SET(SOURCE_DIR ${ARGV1}) + if("${SOURCE_DIR}" STREQUAL "") + SET(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + endif() string(REPLACE "svn" "" result "${${VERS}}") - if( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn" ) + if( EXISTS "${SOURCE_DIR}/.svn" ) set(result "${result}svn") # FindSubversion does not work with symlinks. See PR 8437 - if( NOT IS_SYMLINK "${CMAKE_CURRENT_SOURCE_DIR}" ) + if( NOT IS_SYMLINK "${SOURCE_DIR}" ) find_package(Subversion) endif() if( Subversion_FOUND ) - subversion_wc_info( ${CMAKE_CURRENT_SOURCE_DIR} Project ) + subversion_wc_info( ${SOURCE_DIR} Project ) if( Project_WC_REVISION ) set(SVN_REVISION ${Project_WC_REVISION} PARENT_SCOPE) set(result "${result}-r${Project_WC_REVISION}") @@ -20,16 +25,16 @@ function(add_version_info_from_vcs VERS) set(LLVM_REPOSITORY ${Project_WC_URL} PARENT_SCOPE) endif() endif() - elseif( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git ) + elseif( EXISTS ${SOURCE_DIR}/.git ) set(result "${result}git") # Try to get a ref-id - if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git/svn ) + if( EXISTS ${SOURCE_DIR}/.git/svn ) find_program(git_executable NAMES git git.exe git.cmd) if( git_executable ) set(is_git_svn_rev_exact false) execute_process(COMMAND ${git_executable} svn info - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + WORKING_DIRECTORY ${SOURCE_DIR} TIMEOUT 5 RESULT_VARIABLE git_result OUTPUT_VARIABLE git_output) @@ -46,7 +51,7 @@ function(add_version_info_from_vcs VERS) # Determine if the HEAD points directly at a subversion revision. execute_process(COMMAND ${git_executable} svn find-rev HEAD - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + WORKING_DIRECTORY ${SOURCE_DIR} TIMEOUT 5 RESULT_VARIABLE git_result OUTPUT_VARIABLE git_output) @@ -61,10 +66,11 @@ function(add_version_info_from_vcs VERS) endif() execute_process(COMMAND ${git_executable} rev-parse --short HEAD - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + WORKING_DIRECTORY ${SOURCE_DIR} TIMEOUT 5 RESULT_VARIABLE git_result OUTPUT_VARIABLE git_output) + if( git_result EQUAL 0 AND NOT is_git_svn_rev_exact ) string(STRIP "${git_output}" git_ref_id) set(GIT_COMMIT ${git_ref_id} PARENT_SCOPE) diff --git a/docs/AMDGPUUsage.rst b/docs/AMDGPUUsage.rst index 5abbdec8ef09ef6582240cce948f6e1d1be956e5..34a9b6011d40c3a7e33dd15f55376673d625a4e1 100644 --- a/docs/AMDGPUUsage.rst +++ b/docs/AMDGPUUsage.rst @@ -9,6 +9,29 @@ The AMDGPU back-end provides ISA code generation for AMD GPUs, starting with the R600 family up until the current Volcanic Islands (GCN Gen 3). +Conventions +=========== + +Address Spaces +-------------- + +The AMDGPU back-end uses the following address space mapping: + + ============= ============================================ + Address Space Memory Space + ============= ============================================ + 0 Private + 1 Global + 2 Constant + 3 Local + 4 Generic (Flat) + 5 Region + ============= ============================================ + +The terminology in the table, aside from the region memory space, is from the +OpenCL standard. + + Assembler ========= @@ -65,14 +88,14 @@ wait for. .. code-block:: nasm - // Wait for all counters to be 0 + ; Wait for all counters to be 0 s_waitcnt 0 - // Equivalent to s_waitcnt 0. Counter names can also be delimited by - // '&' or ','. + ; Equivalent to s_waitcnt 0. Counter names can also be delimited by + ; '&' or ','. s_waitcnt vmcnt(0) expcnt(0) lgkcmt(0) - // Wait for vmcnt counter to be 1. + ; Wait for vmcnt counter to be 1. s_waitcnt vmcnt(1) VOP1, VOP2, VOP3, VOPC Instructions diff --git a/docs/AliasAnalysis.rst b/docs/AliasAnalysis.rst index e055b4e1afbc3ebb6e99630c0c93dfbeaaaa02f6..097f7bf75cbcd39b32d213c2a3dc8f2ec1e3fa4a 100644 --- a/docs/AliasAnalysis.rst +++ b/docs/AliasAnalysis.rst @@ -31,8 +31,7 @@ well together. This document contains information necessary to successfully implement this interface, use it, and to test both sides. It also explains some of the finer -points about what exactly results mean. If you feel that something is unclear -or should be added, please `let me know `_. +points about what exactly results mean. ``AliasAnalysis`` Class Overview ================================ diff --git a/docs/Atomics.rst b/docs/Atomics.rst index 79ab74792dd476fd83fdfc83044d29b57d88d6ee..4961348d0c97d7915f13c3afa51511a97e1283c3 100644 --- a/docs/Atomics.rst +++ b/docs/Atomics.rst @@ -8,17 +8,13 @@ LLVM Atomic Instructions and Concurrency Guide Introduction ============ -Historically, LLVM has not had very strong support for concurrency; some minimal -intrinsics were provided, and ``volatile`` was used in some cases to achieve -rough semantics in the presence of concurrency. However, this is changing; -there are now new instructions which are well-defined in the presence of threads -and asynchronous signals, and the model for existing instructions has been -clarified in the IR. +LLVM supports instructions which are well-defined in the presence of threads and +asynchronous signals. The atomic instructions are designed specifically to provide readable IR and optimized code generation for the following: -* The new C++11 ```` header. (`C++11 draft available here +* The C++11 ```` header. (`C++11 draft available here `_.) (`C11 draft available here `_.) @@ -371,7 +367,7 @@ Predicates for optimizer writers to query: that they return true for any operation which is volatile or at least Monotonic. -* ``isAtLeastAcquire()``/``isAtLeastRelease()``: These are predicates on +* ``isStrongerThan`` / ``isAtLeastOrStrongerThan``: These are predicates on orderings. They can be useful for passes that are aware of atomics, for example to do DSE across a single atomic access, but not across a release-acquire pair (see MemoryDependencyAnalysis for an example of this) @@ -402,7 +398,7 @@ operations: MemoryDependencyAnalysis (which is also used by other passes like GVN). * Folding a load: Any atomic load from a constant global can be constant-folded, - because it cannot be observed. Similar reasoning allows scalarrepl with + because it cannot be observed. Similar reasoning allows sroa with atomic loads and stores. Atomics and Codegen @@ -417,19 +413,28 @@ The MachineMemOperand for all atomic operations is currently marked as volatile; this is not correct in the IR sense of volatile, but CodeGen handles anything marked volatile very conservatively. This should get fixed at some point. -Common architectures have some way of representing at least a pointer-sized -lock-free ``cmpxchg``; such an operation can be used to implement all the other -atomic operations which can be represented in IR up to that size. Backends are -expected to implement all those operations, but not operations which cannot be -implemented in a lock-free manner. It is expected that backends will give an -error when given an operation which cannot be implemented. (The LLVM code -generator is not very helpful here at the moment, but hopefully that will -change.) +One very important property of the atomic operations is that if your backend +supports any inline lock-free atomic operations of a given size, you should +support *ALL* operations of that size in a lock-free manner. + +When the target implements atomic ``cmpxchg`` or LL/SC instructions (as most do) +this is trivial: all the other operations can be implemented on top of those +primitives. However, on many older CPUs (e.g. ARMv5, SparcV8, Intel 80386) there +are atomic load and store instructions, but no ``cmpxchg`` or LL/SC. As it is +invalid to implement ``atomic load`` using the native instruction, but +``cmpxchg`` using a library call to a function that uses a mutex, ``atomic +load`` must *also* expand to a library call on such architectures, so that it +can remain atomic with regards to a simultaneous ``cmpxchg``, by using the same +mutex. + +AtomicExpandPass can help with that: it will expand all atomic operations to the +proper ``__atomic_*`` libcalls for any size above the maximum set by +``setMaxAtomicSizeInBitsSupported`` (which defaults to 0). On x86, all atomic loads generate a ``MOV``. SequentiallyConsistent stores generate an ``XCHG``, other stores generate a ``MOV``. SequentiallyConsistent fences generate an ``MFENCE``, other fences do not cause any code to be -generated. cmpxchg uses the ``LOCK CMPXCHG`` instruction. ``atomicrmw xchg`` +generated. ``cmpxchg`` uses the ``LOCK CMPXCHG`` instruction. ``atomicrmw xchg`` uses ``XCHG``, ``atomicrmw add`` and ``atomicrmw sub`` use ``XADD``, and all other ``atomicrmw`` operations generate a loop with ``LOCK CMPXCHG``. Depending on the users of the result, some ``atomicrmw`` operations can be translated into @@ -450,10 +455,151 @@ atomic constructs. Here are some lowerings it can do: ``emitStoreConditional()`` * large loads/stores -> ll-sc/cmpxchg by overriding ``shouldExpandAtomicStoreInIR()``/``shouldExpandAtomicLoadInIR()`` -* strong atomic accesses -> monotonic accesses + fences - by using ``setInsertFencesForAtomic()`` and overriding ``emitLeadingFence()`` - and ``emitTrailingFence()`` +* strong atomic accesses -> monotonic accesses + fences by overriding + ``shouldInsertFencesForAtomic()``, ``emitLeadingFence()``, and + ``emitTrailingFence()`` * atomic rmw -> loop with cmpxchg or load-linked/store-conditional by overriding ``expandAtomicRMWInIR()`` +* expansion to __atomic_* libcalls for unsupported sizes. For an example of all of these, look at the ARM backend. + +Libcalls: __atomic_* +==================== + +There are two kinds of atomic library calls that are generated by LLVM. Please +note that both sets of library functions somewhat confusingly share the names of +builtin functions defined by clang. Despite this, the library functions are +not directly related to the builtins: it is *not* the case that ``__atomic_*`` +builtins lower to ``__atomic_*`` library calls and ``__sync_*`` builtins lower +to ``__sync_*`` library calls. + +The first set of library functions are named ``__atomic_*``. This set has been +"standardized" by GCC, and is described below. (See also `GCC's documentation +`_) + +LLVM's AtomicExpandPass will translate atomic operations on data sizes above +``MaxAtomicSizeInBitsSupported`` into calls to these functions. + +There are four generic functions, which can be called with data of any size or +alignment:: + + void __atomic_load(size_t size, void *ptr, void *ret, int ordering) + void __atomic_store(size_t size, void *ptr, void *val, int ordering) + void __atomic_exchange(size_t size, void *ptr, void *val, void *ret, int ordering) + bool __atomic_compare_exchange(size_t size, void *ptr, void *expected, void *desired, int success_order, int failure_order) + +There are also size-specialized versions of the above functions, which can only +be used with *naturally-aligned* pointers of the appropriate size. In the +signatures below, "N" is one of 1, 2, 4, 8, and 16, and "iN" is the appropriate +integer type of that size; if no such integer type exists, the specialization +cannot be used:: + + iN __atomic_load_N(iN *ptr, iN val, int ordering) + void __atomic_store_N(iN *ptr, iN val, int ordering) + iN __atomic_exchange_N(iN *ptr, iN val, int ordering) + bool __atomic_compare_exchange_N(iN *ptr, iN *expected, iN desired, int success_order, int failure_order) + +Finally there are some read-modify-write functions, which are only available in +the size-specific variants (any other sizes use a ``__atomic_compare_exchange`` +loop):: + + iN __atomic_fetch_add_N(iN *ptr, iN val, int ordering) + iN __atomic_fetch_sub_N(iN *ptr, iN val, int ordering) + iN __atomic_fetch_and_N(iN *ptr, iN val, int ordering) + iN __atomic_fetch_or_N(iN *ptr, iN val, int ordering) + iN __atomic_fetch_xor_N(iN *ptr, iN val, int ordering) + iN __atomic_fetch_nand_N(iN *ptr, iN val, int ordering) + +This set of library functions have some interesting implementation requirements +to take note of: + +- They support all sizes and alignments -- including those which cannot be + implemented natively on any existing hardware. Therefore, they will certainly + use mutexes in for some sizes/alignments. + +- As a consequence, they cannot be shipped in a statically linked + compiler-support library, as they have state which must be shared amongst all + DSOs loaded in the program. They must be provided in a shared library used by + all objects. + +- The set of atomic sizes supported lock-free must be a superset of the sizes + any compiler can emit. That is: if a new compiler introduces support for + inline-lock-free atomics of size N, the ``__atomic_*`` functions must also have a + lock-free implementation for size N. This is a requirement so that code + produced by an old compiler (which will have called the ``__atomic_*`` function) + interoperates with code produced by the new compiler (which will use native + the atomic instruction). + +Note that it's possible to write an entirely target-independent implementation +of these library functions by using the compiler atomic builtins themselves to +implement the operations on naturally-aligned pointers of supported sizes, and a +generic mutex implementation otherwise. + +Libcalls: __sync_* +================== + +Some targets or OS/target combinations can support lock-free atomics, but for +various reasons, it is not practical to emit the instructions inline. + +There's two typical examples of this. + +Some CPUs support multiple instruction sets which can be swiched back and forth +on function-call boundaries. For example, MIPS supports the MIPS16 ISA, which +has a smaller instruction encoding than the usual MIPS32 ISA. ARM, similarly, +has the Thumb ISA. In MIPS16 and earlier versions of Thumb, the atomic +instructions are not encodable. However, those instructions are available via a +function call to a function with the longer encoding. + +Additionally, a few OS/target pairs provide kernel-supported lock-free +atomics. ARM/Linux is an example of this: the kernel `provides +`_ a +function which on older CPUs contains a "magically-restartable" atomic sequence +(which looks atomic so long as there's only one CPU), and contains actual atomic +instructions on newer multicore models. This sort of functionality can typically +be provided on any architecture, if all CPUs which are missing atomic +compare-and-swap support are uniprocessor (no SMP). This is almost always the +case. The only common architecture without that property is SPARC -- SPARCV8 SMP +systems were common, yet it doesn't support any sort of compare-and-swap +operation. + +In either of these cases, the Target in LLVM can claim support for atomics of an +appropriate size, and then implement some subset of the operations via libcalls +to a ``__sync_*`` function. Such functions *must* not use locks in their +implementation, because unlike the ``__atomic_*`` routines used by +AtomicExpandPass, these may be mixed-and-matched with native instructions by the +target lowering. + +Further, these routines do not need to be shared, as they are stateless. So, +there is no issue with having multiple copies included in one binary. Thus, +typically these routines are implemented by the statically-linked compiler +runtime support library. + +LLVM will emit a call to an appropriate ``__sync_*`` routine if the target +ISelLowering code has set the corresponding ``ATOMIC_CMPXCHG``, ``ATOMIC_SWAP``, +or ``ATOMIC_LOAD_*`` operation to "Expand", and if it has opted-into the +availability of those library functions via a call to ``initSyncLibcalls()``. + +The full set of functions that may be called by LLVM is (for ``N`` being 1, 2, +4, 8, or 16):: + + iN __sync_val_compare_and_swap_N(iN *ptr, iN expected, iN desired) + iN __sync_lock_test_and_set_N(iN *ptr, iN val) + iN __sync_fetch_and_add_N(iN *ptr, iN val) + iN __sync_fetch_and_sub_N(iN *ptr, iN val) + iN __sync_fetch_and_and_N(iN *ptr, iN val) + iN __sync_fetch_and_or_N(iN *ptr, iN val) + iN __sync_fetch_and_xor_N(iN *ptr, iN val) + iN __sync_fetch_and_nand_N(iN *ptr, iN val) + iN __sync_fetch_and_max_N(iN *ptr, iN val) + iN __sync_fetch_and_umax_N(iN *ptr, iN val) + iN __sync_fetch_and_min_N(iN *ptr, iN val) + iN __sync_fetch_and_umin_N(iN *ptr, iN val) + +This list doesn't include any function for atomic load or store; all known +architectures support atomic loads and stores directly (possibly by emitting a +fence on either side of a normal load or store.) + +There's also, somewhat separately, the possibility to lower ``ATOMIC_FENCE`` to +``__sync_synchronize()``. This may happen or not happen independent of all the +above, controlled purely by ``setOperationAction(ISD::ATOMIC_FENCE, ...)``. diff --git a/docs/BitCodeFormat.rst b/docs/BitCodeFormat.rst index f6a560df8df57ff750461c62d6ee9c29c41b6715..ffa21763252756689c8b6d540ccfb0a0d2e1c4f1 100644 --- a/docs/BitCodeFormat.rst +++ b/docs/BitCodeFormat.rst @@ -690,6 +690,7 @@ global variable. The operand fields are: .. _linkage type: * *linkage*: An encoding of the linkage type for this variable: + * ``external``: code 0 * ``weak``: code 1 * ``appending``: code 2 @@ -714,20 +715,30 @@ global variable. The operand fields are: .. _visibility: * *visibility*: If present, an encoding of the visibility of this variable: + * ``default``: code 0 * ``hidden``: code 1 * ``protected``: code 2 +.. _bcthreadlocal: + * *threadlocal*: If present, an encoding of the thread local storage mode of the variable: + * ``not thread local``: code 0 * ``thread local; default TLS model``: code 1 * ``localdynamic``: code 2 * ``initialexec``: code 3 * ``localexec``: code 4 -* *unnamed_addr*: If present and non-zero, indicates that the variable has - ``unnamed_addr`` +.. _bcunnamedaddr: + +* *unnamed_addr*: If present, an encoding of the ``unnamed_addr`` attribute of this + variable: + + * not ``unnamed_addr``: code 0 + * ``unnamed_addr``: code 1 + * ``local_unnamed_addr``: code 2 .. _bcdllstorageclass: @@ -737,6 +748,8 @@ global variable. The operand fields are: * ``dllimport``: code 1 * ``dllexport``: code 2 +* *comdat*: An encoding of the COMDAT of this function + .. _FUNCTION: MODULE_CODE_FUNCTION Record @@ -757,6 +770,7 @@ function. The operand fields are: * ``anyregcc``: code 13 * ``preserve_mostcc``: code 14 * ``preserve_allcc``: code 15 + * ``swiftcc`` : code 16 * ``cxx_fast_tlscc``: code 17 * ``x86_stdcallcc``: code 64 * ``x86_fastcallcc``: code 65 @@ -783,8 +797,8 @@ function. The operand fields are: * *gc*: If present and nonzero, the 1-based garbage collector index in the table of `MODULE_CODE_GCNAME`_ entries. -* *unnamed_addr*: If present and non-zero, indicates that the function has - ``unnamed_addr`` +* *unnamed_addr*: If present, an encoding of the + :ref:`unnamed_addr` attribute of this function * *prologuedata*: If non-zero, the value index of the prologue data for this function, plus 1. @@ -803,7 +817,7 @@ function. The operand fields are: MODULE_CODE_ALIAS Record ^^^^^^^^^^^^^^^^^^^^^^^^ -``[ALIAS, alias type, aliasee val#, linkage, visibility, dllstorageclass]`` +``[ALIAS, alias type, aliasee val#, linkage, visibility, dllstorageclass, threadlocal, unnamed_addr]`` The ``ALIAS`` record (code 9) marks the definition of an alias. The operand fields are @@ -819,6 +833,12 @@ fields are * *dllstorageclass*: If present, an encoding of the :ref:`dllstorageclass` of the alias +* *threadlocal*: If present, an encoding of the + :ref:`thread local property` of the alias + +* *unnamed_addr*: If present, an encoding of the + :ref:`unnamed_addr` attribute of this alias + MODULE_CODE_PURGEVALS Record ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/BitSets.rst b/docs/BitSets.rst deleted file mode 100644 index b35493486b14cf8b2eb18b4f0a0c004d5dde6288..0000000000000000000000000000000000000000 --- a/docs/BitSets.rst +++ /dev/null @@ -1,221 +0,0 @@ -======= -Bitsets -======= - -This is a mechanism that allows IR modules to co-operatively build pointer -sets corresponding to addresses within a given set of globals. One example -of a use case for this is to allow a C++ program to efficiently verify (at -each call site) that a vtable pointer is in the set of valid vtable pointers -for the type of the class or its derived classes. - -To use the mechanism, a client creates a global metadata node named -``llvm.bitsets``. Each element is a metadata node with three elements: - -1. a metadata object representing an identifier for the bitset -2. either a global variable or a function -3. a byte offset into the global (generally zero for functions) - -Each bitset must exclusively contain either global variables or functions. - -.. admonition:: Limitation - - The current implementation only supports functions as members of bitsets on - the x86-32 and x86-64 architectures. - -An intrinsic, :ref:`llvm.bitset.test `, is used to test -whether a given pointer is a member of a bitset. - -Representing Type Information using Bitsets -=========================================== - -This section describes how Clang represents C++ type information associated with -virtual tables using bitsets. - -Consider the following inheritance hierarchy: - -.. code-block:: c++ - - struct A { - virtual void f(); - }; - - struct B : A { - virtual void f(); - virtual void g(); - }; - - struct C { - virtual void h(); - }; - - struct D : A, C { - virtual void f(); - virtual void h(); - }; - -The virtual table objects for A, B, C and D look like this (under the Itanium ABI): - -.. csv-table:: Virtual Table Layout for A, B, C, D - :header: Class, 0, 1, 2, 3, 4, 5, 6 - - A, A::offset-to-top, &A::rtti, &A::f - B, B::offset-to-top, &B::rtti, &B::f, &B::g - C, C::offset-to-top, &C::rtti, &C::h - D, D::offset-to-top, &D::rtti, &D::f, &D::h, D::offset-to-top, &D::rtti, thunk for &D::h - -When an object of type A is constructed, the address of ``&A::f`` in A's -virtual table object is stored in the object's vtable pointer. In ABI parlance -this address is known as an `address point`_. Similarly, when an object of type -B is constructed, the address of ``&B::f`` is stored in the vtable pointer. In -this way, the vtable in B's virtual table object is compatible with A's vtable. - -D is a little more complicated, due to the use of multiple inheritance. Its -virtual table object contains two vtables, one compatible with A's vtable and -the other compatible with C's vtable. Objects of type D contain two virtual -pointers, one belonging to the A subobject and containing the address of -the vtable compatible with A's vtable, and the other belonging to the C -subobject and containing the address of the vtable compatible with C's vtable. - -The full set of compatibility information for the above class hierarchy is -shown below. The following table shows the name of a class, the offset of an -address point within that class's vtable and the name of one of the classes -with which that address point is compatible. - -.. csv-table:: Bitsets for A, B, C, D - :header: VTable for, Offset, Compatible Class - - A, 16, A - B, 16, A - , , B - C, 16, C - D, 16, A - , , D - , 48, C - -The next step is to encode this compatibility information into the IR. The way -this is done is to create bitsets named after each of the compatible classes, -into which we add each of the compatible address points in each vtable. -For example, these bitset entries encode the compatibility information for -the above hierarchy: - -:: - - !0 = !{!"_ZTS1A", [3 x i8*]* @_ZTV1A, i64 16} - !1 = !{!"_ZTS1A", [4 x i8*]* @_ZTV1B, i64 16} - !2 = !{!"_ZTS1B", [4 x i8*]* @_ZTV1B, i64 16} - !3 = !{!"_ZTS1C", [3 x i8*]* @_ZTV1C, i64 16} - !4 = !{!"_ZTS1A", [7 x i8*]* @_ZTV1D, i64 16} - !5 = !{!"_ZTS1D", [7 x i8*]* @_ZTV1D, i64 16} - !6 = !{!"_ZTS1C", [7 x i8*]* @_ZTV1D, i64 48} - -With these bitsets, we can now use the ``llvm.bitset.test`` intrinsic to test -whether a given pointer is compatible with a bitset. Working backwards, -if ``llvm.bitset.test`` returns true for a particular pointer, we can also -statically determine the identities of the virtual functions that a particular -virtual call may call. For example, if a program assumes a pointer to be in the -``!"_ZST1A"`` bitset, we know that the address can be only be one of ``_ZTV1A+16``, -``_ZTV1B+16`` or ``_ZTV1D+16`` (i.e. the address points of the vtables of A, -B and D respectively). If we then load an address from that pointer, we know -that the address can only be one of ``&A::f``, ``&B::f`` or ``&D::f``. - -.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general - -Testing Bitset Addresses -======================== - -If a program tests an address using ``llvm.bitset.test``, this will cause -a link-time optimization pass, ``LowerBitSets``, to replace calls to this -intrinsic with efficient code to perform bitset tests. At a high level, -the pass will lay out referenced globals in a consecutive memory region in -the object file, construct bit vectors that map onto that memory region, -and generate code at each of the ``llvm.bitset.test`` call sites to test -pointers against those bit vectors. Because of the layout manipulation, the -globals' definitions must be available at LTO time. For more information, -see the `control flow integrity design document`_. - -A bit set containing functions is transformed into a jump table, which is a -block of code consisting of one branch instruction for each of the functions -in the bit set that branches to the target function. The pass will redirect -any taken function addresses to the corresponding jump table entry. In the -object file's symbol table, the jump table entries take the identities of -the original functions, so that addresses taken outside the module will pass -any verification done inside the module. - -Jump tables may call external functions, so their definitions need not -be available at LTO time. Note that if an externally defined function is a -member of a bitset, there is no guarantee that its identity within the module -will be the same as its identity outside of the module, as the former will -be the jump table entry if a jump table is necessary. - -The `GlobalLayoutBuilder`_ class is responsible for laying out the globals -efficiently to minimize the sizes of the underlying bitsets. - -.. _control flow integrity design document: http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html - -:Example: - -:: - - target datalayout = "e-p:32:32" - - @a = internal global i32 0 - @b = internal global i32 0 - @c = internal global i32 0 - @d = internal global [2 x i32] [i32 0, i32 0] - - define void @e() { - ret void - } - - define void @f() { - ret void - } - - declare void @g() - - !llvm.bitsets = !{!0, !1, !2, !3, !4, !5, !6} - - !0 = !{!"bitset1", i32* @a, i32 0} - !1 = !{!"bitset1", i32* @b, i32 0} - !2 = !{!"bitset2", i32* @b, i32 0} - !3 = !{!"bitset2", i32* @c, i32 0} - !4 = !{!"bitset2", i32* @d, i32 4} - !5 = !{!"bitset3", void ()* @e, i32 0} - !6 = !{!"bitset3", void ()* @g, i32 0} - - declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone - - define i1 @foo(i32* %p) { - %pi8 = bitcast i32* %p to i8* - %x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset1") - ret i1 %x - } - - define i1 @bar(i32* %p) { - %pi8 = bitcast i32* %p to i8* - %x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset2") - ret i1 %x - } - - define i1 @baz(void ()* %p) { - %pi8 = bitcast void ()* %p to i8* - %x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset3") - ret i1 %x - } - - define void @main() { - %a1 = call i1 @foo(i32* @a) ; returns 1 - %b1 = call i1 @foo(i32* @b) ; returns 1 - %c1 = call i1 @foo(i32* @c) ; returns 0 - %a2 = call i1 @bar(i32* @a) ; returns 0 - %b2 = call i1 @bar(i32* @b) ; returns 1 - %c2 = call i1 @bar(i32* @c) ; returns 1 - %d02 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 0)) ; returns 0 - %d12 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 1)) ; returns 1 - %e = call i1 @baz(void ()* @e) ; returns 1 - %f = call i1 @baz(void ()* @f) ; returns 0 - %g = call i1 @baz(void ()* @g) ; returns 1 - ret void - } - -.. _GlobalLayoutBuilder: http://llvm.org/klaus/llvm/blob/master/include/llvm/Transforms/IPO/LowerBitSets.h diff --git a/docs/CMake.rst b/docs/CMake.rst index 8b441a4b6b7cd70f1fa1d5352414ff72ce5710dc..5d57bc98596b36e945e6dc1eaab406ce04103aa6 100644 --- a/docs/CMake.rst +++ b/docs/CMake.rst @@ -22,6 +22,10 @@ and then go back to the `Quick start`_ section once you know what you are doing. `Options and variables`_ section is a reference for customizing your build. If you already have experience with CMake, this is the recommended starting point. +This page is geared towards users of the LLVM CMake build. If you're looking for +information about modifying the LLVM CMake build system you may want to see the +:doc:`CMakePrimer` page. It has a basic overview of the CMake language. + .. _Quick start: Quick start @@ -30,10 +34,7 @@ Quick start We use here the command-line, non-interactive CMake interface. #. `Download `_ and install - CMake. Version 2.8.8 is the minimum required, but if you're using the Ninja - backend, CMake v3.2 or newer is required to `get interactive output - `_ - when running :doc:`Lit `. + CMake. Version 3.4.3 is the minimum required. #. Open a shell. Your development tools must be reachable from this shell through the PATH environment variable. @@ -263,6 +264,9 @@ LLVM-specific variables link against LLVM libraries and make use of C++ exceptions in your own code that need to propagate through LLVM code. Defaults to OFF. +**LLVM_ENABLE_EXPENSIVE_CHECKS**:BOOL + Enable additional time/memory expensive checking. Defaults to OFF. + **LLVM_ENABLE_PIC**:BOOL Add the ``-fPIC`` flag to the compiler command-line, if the compiler supports this flag. Some systems, like Windows, do not need this flag. Defaults to ON. @@ -332,6 +336,14 @@ LLVM-specific variables will not be used. If the variable for an external project does not point to a valid path, then that project will not be built. +**LLVM_EXTERNAL_PROJECTS**:STRING + Semicolon-separated list of additional external projects to build as part of + llvm. For each project LLVM_EXTERNAL__SOURCE_DIR have to be specified + with the path for the source code of the project. Example: + ``-DLLVM_EXTERNAL_PROJECTS="Foo;Bar" + -DLLVM_EXTERNAL_FOO_SOURCE_DIR=/src/foo + -DLLVM_EXTERNAL_BAR_SOURCE_DIR=/src/bar``. + **LLVM_USE_OPROFILE**:BOOL Enable building OProfile JIT support. Defaults to OFF. @@ -554,7 +566,7 @@ and uses them to build a simple application ``simple-tool``. .. code-block:: cmake - cmake_minimum_required(VERSION 2.8.8) + cmake_minimum_required(VERSION 3.4.3) project(SimpleProject) find_package(LLVM REQUIRED CONFIG) diff --git a/docs/CMakePrimer.rst b/docs/CMakePrimer.rst new file mode 100644 index 0000000000000000000000000000000000000000..034779022142a8442a14175f7d3f9d8fb907846e --- /dev/null +++ b/docs/CMakePrimer.rst @@ -0,0 +1,465 @@ +============ +CMake Primer +============ + +.. contents:: + :local: + +.. warning:: + Disclaimer: This documentation is written by LLVM project contributors `not` + anyone affiliated with the CMake project. This document may contain + inaccurate terminology, phrasing, or technical details. It is provided with + the best intentions. + + +Introduction +============ + +The LLVM project and many of the core projects built on LLVM build using CMake. +This document aims to provide a brief overview of CMake for developers modifying +LLVM projects or building their own projects on top of LLVM. + +The official CMake language references is available in the cmake-language +manpage and `cmake-language online documentation +`_. + +10,000 ft View +============== + +CMake is a tool that reads script files in its own language that describe how a +software project builds. As CMake evaluates the scripts it constructs an +internal representation of the software project. Once the scripts have been +fully processed, if there are no errors, CMake will generate build files to +actually build the project. CMake supports generating build files for a variety +of command line build tools as well as for popular IDEs. + +When a user runs CMake it performs a variety of checks similar to how autoconf +worked historically. During the checks and the evaluation of the build +description scripts CMake caches values into the CMakeCache. This is useful +because it allows the build system to skip long-running checks during +incremental development. CMake caching also has some drawbacks, but that will be +discussed later. + +Scripting Overview +================== + +CMake's scripting language has a very simple grammar. Every language construct +is a command that matches the pattern _name_(_args_). Commands come in three +primary types: language-defined (commands implemented in C++ in CMake), defined +functions, and defined macros. The CMake distribution also contains a suite of +CMake modules that contain definitions for useful functionality. + +The example below is the full CMake build for building a C++ "Hello World" +program. The example uses only CMake language-defined functions. + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.2) + project(HelloWorld) + add_executable(HelloWorld HelloWorld.cpp) + +The CMake language provides control flow constructs in the form of foreach loops +and if blocks. To make the example above more complicated you could add an if +block to define "APPLE" when targeting Apple platforms: + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.2) + project(HelloWorld) + add_executable(HelloWorld HelloWorld.cpp) + if(APPLE) + target_compile_definitions(HelloWorld PUBLIC APPLE) + endif() + +Variables, Types, and Scope +=========================== + +Dereferencing +------------- + +In CMake variables are "stringly" typed. All variables are represented as +strings throughout evaluation. Wrapping a variable in ``${}`` dereferences it +and results in a literal substitution of the name for the value. CMake refers to +this as "variable evaluation" in their documentation. Dereferences are performed +*before* the command being called receives the arguments. This means +dereferencing a list results in multiple separate arguments being passed to the +command. + +Variable dereferences can be nested and be used to model complex data. For +example: + +.. code-block:: cmake + + set(var_name var1) + set(${var_name} foo) # same as "set(var1 foo)" + set(${${var_name}}_var bar) # same as "set(foo_var bar)" + +Dereferencing an unset variable results in an empty expansion. It is a common +pattern in CMake to conditionally set variables knowing that it will be used in +code paths that the variable isn't set. There are examples of this throughout +the LLVM CMake build system. + +An example of variable empty expansion is: + +.. code-block:: cmake + + if(APPLE) + set(extra_sources Apple.cpp) + endif() + add_executable(HelloWorld HelloWorld.cpp ${extra_sources}) + +In this example the ``extra_sources`` variable is only defined if you're +targeting an Apple platform. For all other targets the ``extra_sources`` will be +evaluated as empty before add_executable is given its arguments. + +One big "Gotcha" with variable dereferencing is that ``if`` commands implicitly +dereference values. This has some unexpected results. For example: + +.. code-block:: cmake + + if("${SOME_VAR}" STREQUAL "MSVC") + +In this code sample MSVC will be implicitly dereferenced, which will result in +the if command comparing the value of the dereferenced variables ``SOME_VAR`` +and ``MSVC``. A common workaround to this solution is to prepend strings being +compared with an ``x``. + +.. code-block:: cmake + + if("x${SOME_VAR}" STREQUAL "xMSVC") + +This works because while ``MSVC`` is a defined variable, ``xMSVC`` is not. This +pattern is uncommon, but it does occur in LLVM's CMake scripts. + +.. note:: + + Once the LLVM project upgrades its minimum CMake version to 3.1 or later we + can prevent this behavior by setting CMP0054 to new. For more information on + CMake policies please see the cmake-policies manpage or the `cmake-policies + online documentation + `_. + +Lists +----- + +In CMake lists are semi-colon delimited strings, and it is strongly advised that +you avoid using semi-colons in lists; it doesn't go smoothly. A few examples of +defining lists: + +.. code-block:: cmake + + # Creates a list with members a, b, c, and d + set(my_list a b c d) + set(my_list "a;b;c;d") + + # Creates a string "a b c d" + set(my_string "a b c d") + +Lists of Lists +-------------- + +One of the more complicated patterns in CMake is lists of lists. Because a list +cannot contain an element with a semi-colon to construct a list of lists you +make a list of variable names that refer to other lists. For example: + +.. code-block:: cmake + + set(list_of_lists a b c) + set(a 1 2 3) + set(b 4 5 6) + set(c 7 8 9) + +With this layout you can iterate through the list of lists printing each value +with the following code: + +.. code-block:: cmake + + foreach(list_name IN LISTS list_of_lists) + foreach(value IN LISTS ${list_name}) + message(${value}) + endforeach() + endforeach() + +You'll notice that the inner foreach loop's list is doubly dereferenced. This is +because the first dereference turns ``list_name`` into the name of the sub-list +(a, b, or c in the example), then the second dereference is to get the value of +the list. + +This pattern is used throughout CMake, the most common example is the compiler +flags options, which CMake refers to using the following variable expansions: +CMAKE_${LANGUAGE}_FLAGS and CMAKE_${LANGUAGE}_FLAGS_${CMAKE_BUILD_TYPE}. + +Other Types +----------- + +Variables that are cached or specified on the command line can have types +associated with them. The variable's type is used by CMake's UI tool to display +the right input field. The variable's type generally doesn't impact evaluation. +One of the few examples is PATH variables, which CMake does have some special +handling for. You can read more about the special handling in `CMake's set +documentation +`_. + +Scope +----- + +CMake inherently has a directory-based scoping. Setting a variable in a +CMakeLists file, will set the variable for that file, and all subdirectories. +Variables set in a CMake module that is included in a CMakeLists file will be +set in the scope they are included from, and all subdirectories. + +When a variable that is already set is set again in a subdirectory it overrides +the value in that scope and any deeper subdirectories. + +The CMake set command provides two scope-related options. PARENT_SCOPE sets a +variable into the parent scope, and not the current scope. The CACHE option sets +the variable in the CMakeCache, which results in it being set in all scopes. The +CACHE option will not set a variable that already exists in the CACHE unless the +FORCE option is specified. + +In addition to directory-based scope, CMake functions also have their own scope. +This means variables set inside functions do not bleed into the parent scope. +This is not true of macros, and it is for this reason LLVM prefers functions +over macros whenever reasonable. + +.. note:: + Unlike C-based languages, CMake's loop and control flow blocks do not have + their own scopes. + +Control Flow +============ + +CMake features the same basic control flow constructs you would expect in any +scripting language, but there are a few quarks because, as with everything in +CMake, control flow constructs are commands. + +If, ElseIf, Else +---------------- + +.. note:: + For the full documentation on the CMake if command go + `here `_. That resource is + far more complete. + +In general CMake if blocks work the way you'd expect: + +.. code-block:: cmake + + if() + .. do stuff + elseif() + .. do other stuff + else() + .. do other other stuff + endif() + +The single most important thing to know about CMake's if blocks coming from a C +background is that they do not have their own scope. Variables set inside +conditional blocks persist after the ``endif()``. + +Loops +----- + +The most common form of the CMake ``foreach`` block is: + +.. code-block:: cmake + + foreach(var ...) + .. do stuff + endforeach() + +The variable argument portion of the ``foreach`` block can contain dereferenced +lists, values to iterate, or a mix of both: + +.. code-block:: cmake + + foreach(var foo bar baz) + message(${var}) + endforeach() + # prints: + # foo + # bar + # baz + + set(my_list 1 2 3) + foreach(var ${my_list}) + message(${var}) + endforeach() + # prints: + # 1 + # 2 + # 3 + + foreach(var ${my_list} out_of_bounds) + message(${var}) + endforeach() + # prints: + # 1 + # 2 + # 3 + # out_of_bounds + +There is also a more modern CMake foreach syntax. The code below is equivalent +to the code above: + +.. code-block:: cmake + + foreach(var IN ITEMS foo bar baz) + message(${var}) + endforeach() + # prints: + # foo + # bar + # baz + + set(my_list 1 2 3) + foreach(var IN LISTS my_list) + message(${var}) + endforeach() + # prints: + # 1 + # 2 + # 3 + + foreach(var IN LISTS my_list ITEMS out_of_bounds) + message(${var}) + endforeach() + # prints: + # 1 + # 2 + # 3 + # out_of_bounds + +Similar to the conditional statements, these generally behave how you would +expect, and they do not have their own scope. + +CMake also supports ``while`` loops, although they are not widely used in LLVM. + +Modules, Functions and Macros +============================= + +Modules +------- + +Modules are CMake's vehicle for enabling code reuse. CMake modules are just +CMake script files. They can contain code to execute on include as well as +definitions for commands. + +In CMake macros and functions are universally referred to as commands, and they +are the primary method of defining code that can be called multiple times. + +In LLVM we have several CMake modules that are included as part of our +distribution for developers who don't build our project from source. Those +modules are the fundamental pieces needed to build LLVM-based projects with +CMake. We also rely on modules as a way of organizing the build system's +functionality for maintainability and re-use within LLVM projects. + +Argument Handling +----------------- + +When defining a CMake command handling arguments is very useful. The examples +in this section will all use the CMake ``function`` block, but this all applies +to the ``macro`` block as well. + +CMake commands can have named arguments, but all commands are implicitly +variable argument. If the command has named arguments they are required and must +be specified at every call site. Below is a trivial example of providing a +wrapper function for CMake's built in function ``add_dependencies``. + +.. code-block:: cmake + + function(add_deps target) + add_dependencies(${target} ${ARGV}) + endfunction() + +This example defines a new macro named ``add_deps`` which takes a required first +argument, and just calls another function passing through the first argument and +all trailing arguments. When variable arguments are present CMake defines them +in a list named ``ARGV``, and the count of the arguments is defined in ``ARGN``. + +CMake provides a module ``CMakeParseArguments`` which provides an implementation +of advanced argument parsing. We use this all over LLVM, and it is recommended +for any function that has complex argument-based behaviors or optional +arguments. CMake's official documentation for the module is in the +``cmake-modules`` manpage, and is also available at the +`cmake-modules online documentation +`_. + +.. note:: + As of CMake 3.5 the cmake_parse_arguments command has become a native command + and the CMakeParseArguments module is empty and only left around for + compatibility. + +Functions Vs Macros +------------------- + +Functions and Macros look very similar in how they are used, but there is one +fundamental difference between the two. Functions have their own scope, and +macros don't. This means variables set in macros will bleed out into the calling +scope. That makes macros suitable for defining very small bits of functionality +only. + +The other difference between CMake functions and macros is how arguments are +passed. Arguments to macros are not set as variables, instead dereferences to +the parameters are resolved across the macro before executing it. This can +result in some unexpected behavior if using unreferenced variables. For example: + +.. code-block:: cmake + + macro(print_list my_list) + foreach(var IN LISTS my_list) + message("${var}") + endforeach() + endmacro() + + set(my_list a b c d) + set(my_list_of_numbers 1 2 3 4) + print_list(my_list_of_numbers) + # prints: + # a + # b + # c + # d + +Generally speaking this issue is uncommon because it requires using +non-dereferenced variables with names that overlap in the parent scope, but it +is important to be aware of because it can lead to subtle bugs. + +LLVM Project Wrappers +===================== + +LLVM projects provide lots of wrappers around critical CMake built-in commands. +We use these wrappers to provide consistent behaviors across LLVM components +and to reduce code duplication. + +We generally (but not always) follow the convention that commands prefaced with +``llvm_`` are intended to be used only as building blocks for other commands. +Wrapper commands that are intended for direct use are generally named following +with the project in the middle of the command name (i.e. ``add_llvm_executable`` +is the wrapper for ``add_executable``). The LLVM ``add_*`` wrapper functions are +all defined in ``AddLLVM.cmake`` which is installed as part of the LLVM +distribution. It can be included and used by any LLVM sub-project that requires +LLVM. + +.. note:: + + Not all LLVM projects require LLVM for all use cases. For example compiler-rt + can be built without LLVM, and the compiler-rt sanitizer libraries are used + with GCC. + +Useful Built-in Commands +======================== + +CMake has a bunch of useful built-in commands. This document isn't going to +go into details about them because The CMake project has excellent +documentation. To highlight a few useful functions see: + +* `add_custom_command `_ +* `add_custom_target `_ +* `file `_ +* `list `_ +* `math `_ +* `string `_ + +The full documentation for CMake commands is in the ``cmake-commands`` manpage +and available on `CMake's website `_ diff --git a/docs/CodeGenerator.rst b/docs/CodeGenerator.rst index 347a372d80ef9b9ffc3f95cda1f42ff10cdee2c9..6a54343dfba629a91c39131d6c7d7168831aef63 100644 --- a/docs/CodeGenerator.rst +++ b/docs/CodeGenerator.rst @@ -386,32 +386,27 @@ functions make it easy to build arbitrary machine instructions. Usage of the .. code-block:: c++ // Create a 'DestReg = mov 42' (rendered in X86 assembly as 'mov DestReg, 42') - // instruction. The '1' specifies how many operands will be added. - MachineInstr *MI = BuildMI(X86::MOV32ri, 1, DestReg).addImm(42); - - // Create the same instr, but insert it at the end of a basic block. + // instruction and insert it at the end of the given MachineBasicBlock. + const TargetInstrInfo &TII = ... MachineBasicBlock &MBB = ... - BuildMI(MBB, X86::MOV32ri, 1, DestReg).addImm(42); + DebugLoc DL; + MachineInstr *MI = BuildMI(MBB, DL, TII.get(X86::MOV32ri), DestReg).addImm(42); // Create the same instr, but insert it before a specified iterator point. MachineBasicBlock::iterator MBBI = ... - BuildMI(MBB, MBBI, X86::MOV32ri, 1, DestReg).addImm(42); + BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32ri), DestReg).addImm(42); // Create a 'cmp Reg, 0' instruction, no destination reg. - MI = BuildMI(X86::CMP32ri, 2).addReg(Reg).addImm(0); + MI = BuildMI(MBB, DL, TII.get(X86::CMP32ri8)).addReg(Reg).addImm(42); // Create an 'sahf' instruction which takes no operands and stores nothing. - MI = BuildMI(X86::SAHF, 0); + MI = BuildMI(MBB, DL, TII.get(X86::SAHF)); // Create a self looping branch instruction. - BuildMI(MBB, X86::JNE, 1).addMBB(&MBB); + BuildMI(MBB, DL, TII.get(X86::JNE)).addMBB(&MBB); -The key thing to remember with the ``BuildMI`` functions is that you have to -specify the number of operands that the machine instruction will take. This -allows for efficient memory allocation. You also need to specify if operands -default to be uses of values, not definitions. If you need to add a definition -operand (other than the optional destination register), you must explicitly mark -it as such: +If you need to add a definition operand (other than the optional destination +register), you must explicitly mark it as such: .. code-block:: c++ @@ -1771,13 +1766,11 @@ table that summarizes what features are supported by each target. Target Feature Matrix --------------------- -Note that this table does not include the C backend or Cpp backends, since they -do not use the target independent code generator infrastructure. It also -doesn't list features that are not supported fully by any target yet. It -considers a feature to be supported if at least one subtarget supports it. A -feature being supported means that it is useful and works for most cases, it -does not indicate that there are zero known bugs in the implementation. Here is -the key: +Note that this table does not list features that are not supported fully by any +target yet. It considers a feature to be supported if at least one subtarget +supports it. A feature being supported means that it is useful and works for +most cases, it does not indicate that there are zero known bugs in the +implementation. Here is the key: :raw-html:`` :raw-html:`` @@ -2197,9 +2190,9 @@ prefix byte on an instruction causes the instruction's memory access to go to the specified segment. LLVM address space 0 is the default address space, which includes the stack, and any unqualified memory accesses in a program. Address spaces 1-255 are currently reserved for user-defined code. The GS-segment is -represented by address space 256, while the FS-segment is represented by address -space 257. Other x86 segments have yet to be allocated address space -numbers. +represented by address space 256, the FS-segment is represented by address space +257, and the SS-segment is represented by address space 258. Other x86 segments +have yet to be allocated address space numbers. While these address spaces may seem similar to TLS via the ``thread_local`` keyword, and often use the same underlying hardware, there are some fundamental @@ -2645,3 +2638,59 @@ of a program is limited to 4K instructions: this ensures fast termination and a limited number of kernel function calls. Prior to running an eBPF program, a verifier performs static analysis to prevent loops in the code and to ensure valid register usage and operand types. + +The AMDGPU backend +------------------ + +The AMDGPU code generator lives in the lib/Target/AMDGPU directory, and is an +open source native AMD GCN ISA code generator. + +Target triples supported +^^^^^^^^^^^^^^^^^^^^^^^^ + +The following are the known target triples that are supported by the AMDGPU +backend. + +* **amdgcn--** --- AMD GCN GPUs (AMDGPU.7.0.0+) +* **amdgcn--amdhsa** --- AMD GCN GPUs (AMDGPU.7.0.0+) with HSA support +* **r600--** --- AMD GPUs HD2XXX-HD6XXX + +Relocations +^^^^^^^^^^^ + +Supported relocatable fields are: + +* **word32** --- This specifies a 32-bit field occupying 4 bytes with arbitrary + byte alignment. These values use the same byte order as other word values in + the AMD GPU architecture +* **word64** --- This specifies a 64-bit field occupying 8 bytes with arbitrary + byte alignment. These values use the same byte order as other word values in + the AMD GPU architecture + +Following notations are used for specifying relocation calculations: + +* **A** --- Represents the addend used to compute the value of the relocatable + field +* **G** --- Represents the offset into the global offset table at which the + relocation entry’s symbol will reside during execution. +* **GOT** --- Represents the address of the global offset table. +* **P** --- Represents the place (section offset or address) of the storage unit + being relocated (computed using ``r_offset``) +* **S** --- Represents the value of the symbol whose index resides in the + relocation entry + +AMDGPU Backend generates *Elf64_Rela* relocation records with the following +supported relocation types: + + ===================== ===== ========== ==================== + Relocation type Value Field Calculation + ===================== ===== ========== ==================== + ``R_AMDGPU_NONE`` 0 ``none`` ``none`` + ``R_AMDGPU_ABS32_LO`` 1 ``word32`` (S + A) & 0xFFFFFFFF + ``R_AMDGPU_ABS32_HI`` 2 ``word32`` (S + A) >> 32 + ``R_AMDGPU_ABS64`` 3 ``word64`` S + A + ``R_AMDGPU_REL32`` 4 ``word32`` S + A - P + ``R_AMDGPU_REL64`` 5 ``word64`` S + A - P + ``R_AMDGPU_ABS32`` 6 ``word32`` S + A + ``R_AMDGPU_GOTPCREL`` 7 ``word32`` G + GOT + A - P + ===================== ===== ========== ==================== diff --git a/docs/CodeOfConduct.rst b/docs/CodeOfConduct.rst new file mode 100644 index 0000000000000000000000000000000000000000..aa366f3514e5ecff12400a6cb41263e5a053feb0 --- /dev/null +++ b/docs/CodeOfConduct.rst @@ -0,0 +1,112 @@ +============================== +LLVM Community Code of Conduct +============================== + +.. note:: + + This document is currently a **DRAFT** document while it is being discussed + by the community. + +The LLVM community has always worked to be a welcoming and respectful +community, and we want to ensure that doesn't change as we grow and evolve. To +that end, we have a few ground rules that we ask people to adhere to: + +* `be friendly and patient`_, +* `be welcoming`_, +* `be considerate`_, +* `be respectful`_, +* `be careful in the words that you choose and be kind to others`_, and +* `when we disagree, try to understand why`_. + +This isn't an exhaustive list of things that you can't do. Rather, take it in +the spirit in which it's intended - a guide to make it easier to communicate +and participate in the community. + +This code of conduct applies to all spaces managed by the LLVM project or The +LLVM Foundation. This includes IRC channels, mailing lists, bug trackers, LLVM +events such as the developer meetings and socials, and any other forums created +by the project that the community uses for communication. It applies to all of +your communication and conduct in these spaces, including emails, chats, things +you say, slides, videos, posters, signs, or even t-shirts you display in these +spaces. In addition, violations of this code outside these spaces may, in rare +cases, affect a person's ability to participate within them, when the conduct +amounts to an egregious violation of this code. + +If you believe someone is violating the code of conduct, we ask that you report +it by emailing conduct@llvm.org. For more details please see our +:doc:`Reporting Guide `. + +.. _be friendly and patient: + +* **Be friendly and patient.** + +.. _be welcoming: + +* **Be welcoming.** We strive to be a community that welcomes and supports + people of all backgrounds and identities. This includes, but is not limited + to members of any race, ethnicity, culture, national origin, colour, + immigration status, social and economic class, educational level, sex, sexual + orientation, gender identity and expression, age, size, family status, + political belief, religion or lack thereof, and mental and physical ability. + +.. _be considerate: + +* **Be considerate.** Your work will be used by other people, and you in turn + will depend on the work of others. Any decision you take will affect users + and colleagues, and you should take those consequences into account. Remember + that we're a world-wide community, so you might not be communicating in + someone else's primary language. + +.. _be respectful: + +* **Be respectful.** Not all of us will agree all the time, but disagreement is + no excuse for poor behavior and poor manners. We might all experience some + frustration now and then, but we cannot allow that frustration to turn into + a personal attack. It's important to remember that a community where people + feel uncomfortable or threatened is not a productive one. Members of the LLVM + community should be respectful when dealing with other members as well as + with people outside the LLVM community. + +.. _be careful in the words that you choose and be kind to others: + +* **Be careful in the words that you choose and be kind to others.** Do not + insult or put down other participants. Harassment and other exclusionary + behavior aren't acceptable. This includes, but is not limited to: + + * Violent threats or language directed against another person. + * Discriminatory jokes and language. + * Posting sexually explicit or violent material. + * Posting (or threatening to post) other people's personally identifying + information ("doxing"). + * Personal insults, especially those using racist or sexist terms. + * Unwelcome sexual attention. + * Advocating for, or encouraging, any of the above behavior. + + In general, if someone asks you to stop, then stop. Persisting in such + behavior after being asked to stop is considered harassment. + +.. _when we disagree, try to understand why: + +* **When we disagree, try to understand why.** Disagreements, both social and + technical, happen all the time and LLVM is no exception. It is important that + we resolve disagreements and differing views constructively. Remember that + we're different. The strength of LLVM comes from its varied community, people + from a wide range of backgrounds. Different people have different + perspectives on issues. Being unable to understand why someone holds + a viewpoint doesn't mean that they're wrong. Don't forget that it is human to + err and blaming each other doesn't get us anywhere. Instead, focus on helping + to resolve issues and learning from mistakes. + +Questions? +========== + +If you have questions, please feel free to contact the LLVM Foundation Code of +Conduct Advisory Committee by emailing conduct@llvm.org. + + +(This text is based on the `Django Project`_ Code of Conduct, which is in turn +based on wording from the `Speak Up! project`_.) + +.. _Django Project: https://www.djangoproject.com/conduct/ +.. _Speak Up! project: http://speakup.io/coc.html + diff --git a/docs/CommandGuide/FileCheck.rst b/docs/CommandGuide/FileCheck.rst index 8d88237f393b4481b446e8e5a68496125adbed66..a0ca1bfe52f92d93928af8143ae1f7462234663b 100644 --- a/docs/CommandGuide/FileCheck.rst +++ b/docs/CommandGuide/FileCheck.rst @@ -38,6 +38,11 @@ OPTIONS prefixes to match. Multiple prefixes are useful for tests which might change for different run options, but most lines remain the same. +.. option:: --check-prefixes prefix1,prefix2,... + + An alias of :option:`--check-prefix` that allows multiple prefixes to be + specified as a comma separated list. + .. option:: --input-file filename File to check (defaults to stdin). @@ -456,3 +461,22 @@ relative line number references, for example: // CHECK-NEXT: {{^ ;}} int a +Matching Newline Characters +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To match newline characters in regular expressions the character class +``[[:space:]]`` can be used. For example, the following pattern: + +.. code-block:: c++ + + // CHECK: DW_AT_location [DW_FORM_sec_offset] ([[DLOC:0x[0-9a-f]+]]){{[[:space:]].*}}"intd" + +matches output of the form (from llvm-dwarfdump): + +.. code-block:: llvm + + DW_AT_location [DW_FORM_sec_offset] (0x00000233) + DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000c9] = "intd") + +letting us set the :program:`FileCheck` variable ``DLOC`` to the desired value +``0x00000233``, extracted from the line immediately preceding "``intd``". diff --git a/docs/CommandGuide/lit.rst b/docs/CommandGuide/lit.rst index 0ec14bb2236eacb8c7b78165252238787514a75a..b2da58ec02c13b474014ee0d9dc416f2555bf58a 100644 --- a/docs/CommandGuide/lit.rst +++ b/docs/CommandGuide/lit.rst @@ -355,6 +355,35 @@ be used to define subdirectories of optional tests, or to change other configuration parameters --- for example, to change the test format, or the suffixes which identify test files. +PRE-DEFINED SUBSTITUTIONS +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:program:`lit` provides various patterns that can be used with the RUN command. +These are defined in TestRunner.py. + + ========== ============== + Macro Substitution + ========== ============== + %s source path (path to the file currently being run) + %S source dir (directory of the file currently being run) + %p same as %S + %{pathsep} path separator + %t temporary file name unique to the test + %T temporary directory unique to the test + %% % + %/s same as %s but replace all / with \\ + %/S same as %S but replace all / with \\ + %/p same as %p but replace all / with \\ + %/t same as %t but replace all / with \\ + %/T same as %T but replace all / with \\ + ========== ============== + +Further substitution patterns might be defined by each test module. +See the modules :ref:`local-configuration-files`. + +More information on the testing infrastucture can be found in the +:doc:`../TestingGuide`. + TEST RUN OUTPUT FORMAT ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/CommandGuide/llvm-cov.rst b/docs/CommandGuide/llvm-cov.rst index d0e78a9a1d11f714db47ce52582976d29e155b8b..cdb36e7b98fd2195bbe2aa3b91aabfd6cba0d13a 100644 --- a/docs/CommandGuide/llvm-cov.rst +++ b/docs/CommandGuide/llvm-cov.rst @@ -236,6 +236,18 @@ OPTIONS Show code coverage only for functions that match the given regular expression. +.. option:: -format= + + Use the specified output format. The supported formats are: "text", "html". + +.. option:: -output-dir=PATH + + Specify a directory to write coverage reports into. If the directory does not + exist, it is created. When used in function view mode (i.e when -name or + -name-regex are used to select specific functions), the report is written to + PATH/functions.EXTENSION. When used in file view mode, a report for each file + is written to PATH/REL_PATH_TO_FILE.EXTENSION. + .. option:: -line-coverage-gt= Show code coverage only for functions with line coverage greater than the diff --git a/docs/CommandGuide/llvm-profdata.rst b/docs/CommandGuide/llvm-profdata.rst index 7f647ef1c47f0ae68fe147c65d1753a6ed45d0c7..f5508b5b2b8f2c7d04f67d638b287b4f1b76c585 100644 --- a/docs/CommandGuide/llvm-profdata.rst +++ b/docs/CommandGuide/llvm-profdata.rst @@ -44,6 +44,9 @@ interpreted as relatively more important than a shorter run. Depending on the nature of the training runs it may be useful to adjust the weight given to each input file by using the ``-weighted-input`` option. +Profiles passed in via ``-weighted-input``, ``-input-files``, or via positional +arguments are processed once for each time they are seen. + OPTIONS ^^^^^^^ @@ -59,10 +62,17 @@ OPTIONS .. option:: -weighted-input=weight,filename - Specify an input file name along with a weight. The profile counts of the input - file will be scaled (multiplied) by the supplied ``weight``, where where ``weight`` - is a decimal integer >= 1. Input files specified without using this option are - assigned a default weight of 1. Examples are shown below. + Specify an input file name along with a weight. The profile counts of the + supplied ``filename`` will be scaled (multiplied) by the supplied + ``weight``, where where ``weight`` is a decimal integer >= 1. + Input files specified without using this option are assigned a default + weight of 1. Examples are shown below. + +.. option:: -input-files=path, -f=path + + Specify a file which contains a list of files to merge. The entries in this + file are newline-separated. Lines starting with '#' are skipped. Entries may + be of the form or ,. .. option:: -instr (default) @@ -90,7 +100,7 @@ OPTIONS Emit the profile using GCC's gcov format (Not yet supported). - .. option:: -sparse[=true|false] +.. option:: -sparse[=true|false] Do not emit function records with 0 execution count. Can only be used in conjunction with -instr. Defaults to false, since it can inhibit compiler diff --git a/docs/CompileCudaWithLLVM.rst b/docs/CompileCudaWithLLVM.rst index 8e7ed0de42f09ec28585ec7c194dca27f07b81d4..f57839cec961580705806dfe698649ea5f53221c 100644 --- a/docs/CompileCudaWithLLVM.rst +++ b/docs/CompileCudaWithLLVM.rst @@ -53,7 +53,7 @@ How to Compile CUDA C/C++ with LLVM =================================== We assume you have installed the CUDA driver and runtime. Consult the `NVIDIA -CUDA installation Guide +CUDA installation guide `_ if you have not. @@ -148,6 +148,46 @@ compilation, in host and device modes: Both clang and nvcc define ``__CUDACC__`` during CUDA compilation. You can detect NVCC specifically by looking for ``__NVCC__``. +Flags that control numerical code +================================= + +If you're using GPUs, you probably care about making numerical code run fast. +GPU hardware allows for more control over numerical operations than most CPUs, +but this results in more compiler options for you to juggle. + +Flags you may wish to tweak include: + +* ``-ffp-contract={on,off,fast}`` (defaults to ``fast`` on host and device when + compiling CUDA) Controls whether the compiler emits fused multiply-add + operations. + + * ``off``: never emit fma operations, and prevent ptxas from fusing multiply + and add instructions. + * ``on``: fuse multiplies and adds within a single statement, but never + across statements (C11 semantics). Prevent ptxas from fusing other + multiplies and adds. + * ``fast``: fuse multiplies and adds wherever profitable, even across + statements. Doesn't prevent ptxas from fusing additional multiplies and + adds. + + Fused multiply-add instructions can be much faster than the unfused + equivalents, but because the intermediate result in an fma is not rounded, + this flag can affect numerical code. + +* ``-fcuda-flush-denormals-to-zero`` (default: off) When this is enabled, + floating point operations may flush `denormal + `_ inputs and/or outputs to 0. + Operations on denormal numbers are often much slower than the same operations + on normal numbers. + +* ``-fcuda-approx-transcendentals`` (default: off) When this is enabled, the + compiler may emit calls to faster, approximate versions of transcendental + functions, instead of using the slower, fully IEEE-compliant versions. For + example, this flag allows clang to emit the ptx ``sin.approx.f32`` + instruction. + + This is implied by ``-ffast-math``. + Optimizations ============= @@ -167,10 +207,9 @@ customizable target-independent optimization pipeline. straight-line scalar optimizations `_. * **Inferring memory spaces**. `This optimization - `_ + `_ infers the memory space of an address so that the backend can emit faster - special loads and stores from it. Details can be found in the `design - document for memory space inference `_. + special loads and stores from it. * **Aggressive loop unrooling and function inlining**. Loop unrolling and function inlining need to be more aggressive for GPUs than for CPUs because @@ -201,6 +240,19 @@ customizable target-independent optimization pipeline. divides in our benchmarks have a divisor and dividend which fit in 32-bits at runtime. This optimization provides a fast path for this common case. +Publication +=========== + +| `gpucc: An Open-Source GPGPU Compiler `_ +| Jingyue Wu, Artem Belevich, Eli Bendersky, Mark Heffernan, Chris Leary, Jacques Pienaar, Bjarke Roune, Rob Springer, Xuetian Weng, Robert Hundt +| *Proceedings of the 2016 International Symposium on Code Generation and Optimization (CGO 2016)* +| `Slides for the CGO talk `_ + +Tutorial +======== + +`CGO 2016 gpucc tutorial `_ + Obtaining Help ============== diff --git a/docs/CompilerWriterInfo.rst b/docs/CompilerWriterInfo.rst index 9b4b4f8cce34bab609b72b619dbe058d1172ef9a..5ae47ea89fe2cb52ee504b24c3474eacecfb7234 100644 --- a/docs/CompilerWriterInfo.rst +++ b/docs/CompilerWriterInfo.rst @@ -90,21 +90,10 @@ SystemZ X86 --- -AMD - Official manuals and docs -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * `AMD processor manuals `_ -* `X86-64 ABI `_ - -Intel - Official manuals and docs -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * `Intel 64 and IA-32 manuals `_ * `Intel Itanium documentation `_ - -Other x86-specific information -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - +* `X86 and X86-64 SysV psABI `_ * `Calling conventions for different C++ compilers and operating systems `_ XCore @@ -127,6 +116,7 @@ ABI Linux ----- +* `Linux extensions to gabi `_ * `PowerPC 64-bit ELF ABI Supplement `_ * `Procedure Call Standard for the AArch64 Architecture `_ * `ELF for the ARM Architecture `_ diff --git a/docs/DeveloperPolicy.rst b/docs/DeveloperPolicy.rst index 17baf2d27b134b2f7e15e8b97ad747f2996ca185..23bdb2fcf17be4ec3cd98300472064001d12f1eb 100644 --- a/docs/DeveloperPolicy.rst +++ b/docs/DeveloperPolicy.rst @@ -186,7 +186,7 @@ problem, we have a notion of an 'owner' for a piece of the code. The sole responsibility of a code owner is to ensure that a commit to their area of the code is appropriately reviewed, either by themself or by someone else. The list of current code owners can be found in the file -`CODE_OWNERS.TXT `_ +`CODE_OWNERS.TXT `_ in the root of the LLVM source tree. Note that code ownership is completely different than reviewers: anyone can @@ -338,7 +338,7 @@ Obtaining Commit Access We grant commit access to contributors with a track record of submitting high quality patches. If you would like commit access, please send an email to -`Chris `_ with the following information: +`Chris `_ with the following information: #. The user name you want to commit with, e.g. "hacker". @@ -348,8 +348,10 @@ quality patches. If you would like commit access, please send an email to #. A "password hash" of the password you want to use, e.g. "``2ACR96qjUqsyM``". Note that you don't ever tell us what your password is; you just give it to us in an encrypted form. To get this, run "``htpasswd``" (a utility that - comes with apache) in crypt mode (often enabled with "``-d``"), or find a web - page that will do it for you. + comes with apache) in *crypt* mode (often enabled with "``-d``"), or find a web + page that will do it for you. Note that our system does not work with MD5 + hashes. These are significantly longer than a crypt hash - e.g. + "``$apr1$vea6bBV2$Z8IFx.AfeD8LhqlZFqJer0``", we only accept the shorter crypt hash. Once you've been granted commit access, you should be able to check out an LLVM tree with an SVN URL of "https://username@llvm.org/..." instead of the normal diff --git a/docs/GettingStarted.rst b/docs/GettingStarted.rst index 68333177fcbddba9fa70541f74bb0a0c65abb2f8..54240b92b6af83ddaf9c00fe48078db44ec2ed5a 100644 --- a/docs/GettingStarted.rst +++ b/docs/GettingStarted.rst @@ -83,9 +83,11 @@ Here's the short story for getting up and running quickly with LLVM: before trying to configure with cmake. cmake does not pickup newly added source directories in incremental builds. - The build uses `CMake `_. - Although the build is known to work with CMake >= 2.8.8, we recommend CMake - >= v3.2, especially if you're generating Ninja build files. + The build uses `CMake `_. LLVM requires CMake 3.4.3 to build. It + is generally recommended to use a recent CMake, especially if you're + generating Ninja build files. This is because the CMake project is constantly + improving the quality of the generators, and the Ninja generator gets a lot + of attention. * ``cd where you want to build llvm`` * ``mkdir build`` @@ -730,9 +732,9 @@ used by people developing LLVM. | | the configure script. The default list is defined | | | as ``LLVM_ALL_TARGETS``, and can be set to include | | | out-of-tree targets. The default value includes: | -| | ``AArch64, AMDGPU, ARM, BPF, CppBackend, Hexagon, | -| | Mips, MSP430, NVPTX, PowerPC, Sparc, SystemZ | -| | X86, XCore``. | +| | ``AArch64, AMDGPU, ARM, BPF, Hexagon, Mips, | +| | MSP430, NVPTX, PowerPC, Sparc, SystemZ, X86, | +| | XCore``. | +-------------------------+----------------------------------------------------+ | LLVM_ENABLE_DOXYGEN | Build doxygen-based documentation from the source | | | code This is disabled by default because it is | diff --git a/docs/GettingStartedVS.rst b/docs/GettingStartedVS.rst index 566a0f88c9c5791315347000cd8e45c2a8bc303b..57ed875ca4f8d3288e4c89c453e1cb9df1d78fad 100644 --- a/docs/GettingStartedVS.rst +++ b/docs/GettingStartedVS.rst @@ -45,10 +45,12 @@ approximately 3GB. Software -------- -You will need Visual Studio 2013 or higher. +You will need Visual Studio 2013 or higher, with the latest Update installed. You will also need the `CMake `_ build system since it -generates the project files you will use to build with. +generates the project files you will use to build with. CMake 2.8.12.2 is the +minimum required version for building with Visual Studio, though the latest +version of CMake is recommended. If you would like to run the LLVM tests you will need `Python `_. Version 2.7 and newer are known to work. You will diff --git a/docs/HowToCrossCompileLLVM.rst b/docs/HowToCrossCompileLLVM.rst index 1072517e4c2b6c3734e18df56d4dbda5c0441e81..e71c0b07a7a0e888cb5a9e217ebf86bc9f5ec0ba 100644 --- a/docs/HowToCrossCompileLLVM.rst +++ b/docs/HowToCrossCompileLLVM.rst @@ -39,6 +39,7 @@ For more information on how to configure CMake for LLVM/Clang, see :doc:`CMake`. The CMake options you need to add are: + * ``-DCMAKE_CROSSCOMPILING=True`` * ``-DCMAKE_INSTALL_PREFIX=`` * ``-DLLVM_TABLEGEN=/llvm-tblgen`` @@ -46,20 +47,40 @@ The CMake options you need to add are: * ``-DLLVM_DEFAULT_TARGET_TRIPLE=arm-linux-gnueabihf`` * ``-DLLVM_TARGET_ARCH=ARM`` * ``-DLLVM_TARGETS_TO_BUILD=ARM`` - * ``-DCMAKE_CXX_FLAGS='-target armv7a-linux-gnueabihf -mcpu=cortex-a9 -I/usr/arm-linux-gnueabihf/include/c++/4.7.2/arm-linux-gnueabihf/ -I/usr/arm-linux-gnueabihf/include/ -mfloat-abi=hard -ccc-gcc-name arm-linux-gnueabihf-gcc'`` + +If you're compiling with GCC, you can use architecture options for your target, +and the compiler driver will detect everything that it needs: + + * ``-DCMAKE_CXX_FLAGS='-march=armv7-a -mcpu=cortex-a9 -mfloat-abi=hard'`` + +However, if you're using Clang, the driver might not be up-to-date with your +specific Linux distribution, version or GCC layout, so you'll need to fudge. + +In addition to the ones above, you'll also need: + + * ``'-target arm-linux-gnueabihf'`` or whatever is the triple of your cross GCC. + * ``'--sysroot=/usr/arm-linux-gnueabihf'``, ``'--sysroot=/opt/gcc/arm-linux-gnueabihf'`` + or whatever is the location of your GCC's sysroot (where /lib, /bin etc are). + * Appropriate use of ``-I`` and ``-L``, depending on how the cross GCC is installed, + and where are the libraries and headers. The TableGen options are required to compile it with the host compiler, so you'll need to compile LLVM (or at least ``llvm-tblgen``) to your host -platform before you start. The CXX flags define the target, cpu (which +platform before you start. The CXX flags define the target, cpu (which in this case defaults to ``fpu=VFP3`` with NEON), and forcing the hard-float ABI. If you're -using Clang as a cross-compiler, you will *also* have to set ``-ccc-gcc-name``, +using Clang as a cross-compiler, you will *also* have to set ``--sysroot`` to make sure it picks the correct linker. +When using Clang, it's important that you choose the triple to be *identical* +to the GCC triple and the sysroot. This will make it easier for Clang to +find the correct tools and include headers. But that won't mean all headers and +libraries will be found. You'll still need to use ``-I`` and ``-L`` to locate +those extra ones, depending on your distribution. + Most of the time, what you want is to have a native compiler to the -platform itself, but not others. It might not even be feasible to -produce x86 binaries from ARM targets, so there's no point in compiling +platform itself, but not others. So there's rarely a point in compiling all back-ends. For that reason, you should also set the -``TARGETS_TO_BUILD`` to only build the ARM back-end. +``TARGETS_TO_BUILD`` to only build the back-end you're targeting to. You must set the ``CMAKE_INSTALL_PREFIX``, otherwise a ``ninja install`` will copy ARM binaries to your root filesystem, which is not what you @@ -83,14 +104,23 @@ running CMake: This is not a problem, since Clang/LLVM libraries are statically linked anyway, it shouldn't affect much. -#. The ARM libraries won't be installed in your system, and possibly - not easily installable anyway, so you'll have to build/download - them separately. But the CMake prepare step, which checks for +#. The ARM libraries won't be installed in your system. + But the CMake prepare step, which checks for dependencies, will check the *host* libraries, not the *target* - ones. + ones. Below there's a list of some dependencies, but your project could + have more, or this document could be outdated. You'll see the errors + while linking as an indication of that. + + Debian based distros have a way to add ``multiarch``, which adds + a new architecture and allows you to install packages for those + systems. See https://wiki.debian.org/Multiarch/HOWTO for more info. + + But not all distros will have that, and possibly not an easy way to + install them in any anyway, so you'll have to build/download + them separately. A quick way of getting the libraries is to download them from - a distribution repository, like Debian (http://packages.debian.org/wheezy/), + a distribution repository, like Debian (http://packages.debian.org/jessie/), and download the missing libraries. Note that the ``libXXX`` will have the shared objects (``.so``) and the ``libXXX-dev`` will give you the headers and the static (``.a``) library. Just in diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 01c255d2459364ac37e1d2aa3408d7db662720c9..f6dda59fda2554192be54f8865cb91d24de4e830 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -250,6 +250,11 @@ linkage: together. This is the LLVM, typesafe, equivalent of having the system linker append together "sections" with identical names when .o files are linked. + + Unfortunately this doesn't correspond to any feature in .o files, so it + can only be used for variables like ``llvm.global_ctors`` which llvm + interprets specially. + ``extern_weak`` The semantics of this linkage follow the ELF object file model: the symbol is weak until linked, if not linked, the symbol becomes null @@ -427,6 +432,10 @@ added in the future: - On X86-64 the callee preserves all general purpose registers, except for RDI and RAX. +"``swiftcc``" - This calling convention is used for Swift language. + - On X86-64 RCX and R8 are available for additional integer returns, and + XMM2 and XMM3 are available for additional FP/vector returns. + - On iOS platforms, we use AAPCS-VFP calling convention. "``cc ``" - Numbered convention Any calling convention may be specified by number, allowing target-specific calling conventions to be used. Target specific @@ -580,6 +589,9 @@ initializer. Note that a constant with significant address *can* be merged with a ``unnamed_addr`` constant, the result being a constant whose address is significant. +If the ``local_unnamed_addr`` attribute is given, the address is known to +not be significant within the module. + A global variable may be declared to reside in a target-specific numbered address space. For targets that support them, address spaces may affect how optimizations are performed and/or what target @@ -610,18 +622,20 @@ assume that the globals are densely packed in their section and try to iterate over them as an array, alignment padding would break this iteration. The maximum alignment is ``1 << 29``. -Globals can also have a :ref:`DLL storage class `. +Globals can also have a :ref:`DLL storage class ` and +an optional list of attached :ref:`metadata `, Variables and aliases can have a :ref:`Thread Local Storage Model `. Syntax:: - [@ =] [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal] - [unnamed_addr] [AddrSpace] [ExternallyInitialized] + @ = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal] + [(unnamed_addr|local_unnamed_addr)] [AddrSpace] + [ExternallyInitialized] [] [, section "name"] [, comdat [($name)]] - [, align ] + [, align ] (, !name !N)* For example, the following defines a global in a numbered address space with an initializer, section, and alignment: @@ -665,14 +679,14 @@ an optional list of attached :ref:`metadata `, an opening curly brace, a list of basic blocks, and a closing curly brace. LLVM function declarations consist of the "``declare``" keyword, an -optional :ref:`linkage type `, an optional :ref:`visibility -style `, an optional :ref:`DLL storage class `, -an optional :ref:`calling convention `, -an optional ``unnamed_addr`` attribute, a return type, an optional -:ref:`parameter attribute ` for the return type, a function -name, a possibly empty list of arguments, an optional alignment, an optional -:ref:`garbage collector name `, an optional :ref:`prefix `, -and an optional :ref:`prologue `. +optional :ref:`linkage type `, an optional :ref:`visibility style +`, an optional :ref:`DLL storage class `, an +optional :ref:`calling convention `, an optional ``unnamed_addr`` +or ``local_unnamed_addr`` attribute, a return type, an optional :ref:`parameter +attribute ` for the return type, a function name, a possibly +empty list of arguments, an optional alignment, an optional :ref:`garbage +collector name `, an optional :ref:`prefix `, and an optional +:ref:`prologue `. A function definition contains a list of basic blocks, forming the CFG (Control Flow Graph) for the function. Each basic block may optionally start with a label @@ -703,14 +717,17 @@ alignment. All alignments must be a power of 2. If the ``unnamed_addr`` attribute is given, the address is known to not be significant and two identical functions can be merged. +If the ``local_unnamed_addr`` attribute is given, the address is known to +not be significant within the module. + Syntax:: define [linkage] [visibility] [DLLStorageClass] [cconv] [ret attrs] @ ([argument list]) - [unnamed_addr] [fn Attrs] [section "name"] [comdat [($name)]] - [align N] [gc] [prefix Constant] [prologue Constant] - [personality Constant] (!name !N)* { ... } + [(unnamed_addr|local_unnamed_addr)] [fn Attrs] [section "name"] + [comdat [($name)]] [align N] [gc] [prefix Constant] + [prologue Constant] [personality Constant] (!name !N)* { ... } The argument list is a comma separated sequence of arguments where each argument is of the following form: @@ -737,7 +754,7 @@ Aliases may have an optional :ref:`linkage type `, an optional Syntax:: - @ = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal] [unnamed_addr] alias , * @ + @ = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal] [(unnamed_addr|local_unnamed_addr)] alias , * @ The linkage must be one of ``private``, ``internal``, ``linkonce``, ``weak``, ``linkonce_odr``, ``weak_odr``, ``external``. Note that some system linkers @@ -747,6 +764,9 @@ Aliases that are not ``unnamed_addr`` are guaranteed to have the same address as the aliasee expression. ``unnamed_addr`` ones are only guaranteed to point to the same content. +If the ``local_unnamed_addr`` attribute is given, the address is known to +not be significant within the module. + Since aliases are only a second name, some restrictions apply, of which some can only be checked when producing an object file: @@ -760,6 +780,25 @@ some can only be checked when producing an object file: * No global value in the expression can be a declaration, since that would require a relocation, which is not possible. +.. _langref_ifunc: + +IFuncs +------- + +IFuncs, like as aliases, don't create any new data or func. They are just a new +symbol that dynamic linker resolves at runtime by calling a resolver function. + +IFuncs have a name and a resolver that is a function called by dynamic linker +that returns address of another function associated with the name. + +IFunc may have an optional :ref:`linkage type ` and an optional +:ref:`visibility style `. + +Syntax:: + + @ = [Linkage] [Visibility] ifunc , * @ + + .. _langref_comdats: Comdats @@ -1009,7 +1048,8 @@ Currently, only the following parameter attributes are defined: ``nocapture`` This indicates that the callee does not make any copies of the pointer that outlive the callee itself. This is not a valid - attribute for return values. + attribute for return values. Addresses used in volatile operations + are considered to be captured. .. _nest: @@ -1020,12 +1060,13 @@ Currently, only the following parameter attributes are defined: ``returned`` This indicates that the function always returns the argument as its return - value. This is an optimization hint to the code generator when generating - the caller, allowing tail call optimization and omission of register saves - and restores in some cases; it is not checked or enforced when generating - the callee. The parameter and the function return type must be valid - operands for the :ref:`bitcast instruction `. This is not a - valid attribute for return values and can only be applied to one parameter. + value. This is a hint to the optimizer and code generator used when + generating the caller, allowing value propagation, tail call optimization, + and omission of register saves and restores in some cases; it is not + checked or enforced when generating the callee. The parameter and the + function return type must be valid operands for the + :ref:`bitcast instruction `. This is not a valid attribute for + return values and can only be applied to one parameter. ``nonnull`` This indicates that the parameter or return pointer is not null. This @@ -1058,6 +1099,30 @@ Currently, only the following parameter attributes are defined: ``dereferenceable()``). This attribute may only be applied to pointer typed parameters. +``swiftself`` + This indicates that the parameter is the self/context parameter. This is not + a valid attribute for return values and can only be applied to one + parameter. + +``swifterror`` + This attribute is motivated to model and optimize Swift error handling. It + can be applied to a parameter with pointer to pointer type or a + pointer-sized alloca. At the call site, the actual argument that corresponds + to a ``swifterror`` parameter has to come from a ``swifterror`` alloca. A + ``swifterror`` value (either the parameter or the alloca) can only be loaded + and stored from, or used as a ``swifterror`` argument. This is not a valid + attribute for return values and can only be applied to one parameter. + + These constraints allow the calling convention to optimize access to + ``swifterror`` variables by associating them with a specific register at + call boundaries rather than placing them in memory. Since this does change + the calling convention, a function which uses the ``swifterror`` attribute + on a parameter is not ABI-compatible with one which does not. + + These constraints also allow LLVM to assume that a ``swifterror`` argument + does not alias any other memory visible within a function and that a + ``swifterror`` alloca passed as an argument does not escape. + .. _gc: Garbage Collector Strategy Names @@ -1222,6 +1287,15 @@ example: epilogue, the backend should forcibly align the stack pointer. Specify the desired alignment, which must be a power of two, in parentheses. +``allocsize([, ])`` + This attribute indicates that the annotated function will always return at + least a given number of bytes (or null). Its arguments are zero-indexed + parameter numbers; if one argument is provided, then it's assumed that at + least ``CallSite.Args[EltSizeParam]`` bytes will be available at the + returned pointer. If two are provided, then it's assumed that + ``CallSite.Args[EltSizeParam] * CallSite.Args[NumEltsParam]`` bytes are + available. The referenced parameters must be integer types. No assumptions + are made about the contents of the returned block of memory. ``alwaysinline`` This attribute indicates that the inliner should attempt to inline this function into callers whenever possible, ignoring any active @@ -1245,7 +1319,7 @@ example: The ``convergent`` attribute may appear on functions or call/invoke instructions. When it appears on a function, it indicates that calls to this function should not be made control-dependent on additional values. - For example, the intrinsic ``llvm.cuda.syncthreads`` is ``convergent``, so + For example, the intrinsic ``llvm.nvvm.barrier0`` is ``convergent``, so calls to this intrinsic cannot be made control-dependent on additional values. @@ -1349,6 +1423,31 @@ example: passes make choices that keep the code size of this function low, and otherwise do optimizations specifically to reduce code size as long as they do not significantly impact runtime performance. +``"patchable-function"`` + This attribute tells the code generator that the code + generated for this function needs to follow certain conventions that + make it possible for a runtime function to patch over it later. + The exact effect of this attribute depends on its string value, + for which there currently is one legal possibility: + + * ``"prologue-short-redirect"`` - This style of patchable + function is intended to support patching a function prologue to + redirect control away from the function in a thread safe + manner. It guarantees that the first instruction of the + function will be large enough to accommodate a short jump + instruction, and will be sufficiently aligned to allow being + fully changed via an atomic compare-and-swap instruction. + While the first requirement can be satisfied by inserting large + enough NOP, LLVM can and will try to re-purpose an existing + instruction (i.e. one that would have to be emitted anyway) as + the patchable instruction larger than a short jump. + + ``"prologue-short-redirect"`` is currently only supported on + x86-64. + + This attribute by itself does not imply restrictions on + inter-procedural optimizations. All of the semantic effects the + patching may have to be separately conveyed via the linkage type. ``readnone`` On a function, this attribute indicates that the function computes its result (or decides to unwind an exception) based strictly on its arguments, @@ -1376,6 +1475,13 @@ example: On an argument, this attribute indicates that the function does not write through this pointer argument, even though it may write to the memory that the pointer points to. +``writeonly`` + On a function, this attribute indicates that the function may write to but + does not read from memory. + + On an argument, this attribute indicates that the function may write to but + does not read through this pointer argument (even though it may read from + the memory that the pointer points to). ``argmemonly`` This attribute indicates that the only memory accesses inside function are loads and stores from objects pointed to by its pointer-typed arguments, @@ -2115,6 +2221,26 @@ function's scope. uselistorder i32 (i32) @bar, { 1, 0 } uselistorder_bb @foo, %bb, { 5, 1, 3, 2, 0, 4 } +.. _source_filename: + +Source Filename +--------------- + +The *source filename* string is set to the original module identifier, +which will be the name of the compiled source file when compiling from +source through the clang front end, for example. It is then preserved through +the IR and bitcode. + +This is currently necessary to generate a consistent unique global +identifier for local functions used in profile data, which prepends the +source file name to the local function name. + +The syntax for the source file name is simply: + +.. code-block:: llvm + + source_filename = "/path/to/source.c" + .. _typesystem: Type System @@ -3482,8 +3608,14 @@ SystemZ: - ``K``: An immediate signed 16-bit integer. - ``L``: An immediate signed 20-bit integer. - ``M``: An immediate integer 0x7fffffff. -- ``Q``, ``R``, ``S``, ``T``: A memory address operand, treated the same as - ``m``, at the moment. +- ``Q``: A memory address operand with a base address and a 12-bit immediate + unsigned displacement. +- ``R``: A memory address operand with a base address, a 12-bit immediate + unsigned displacement, and an index register. +- ``S``: A memory address operand with a base address and a 20-bit immediate + signed displacement. +- ``T``: A memory address operand with a base address, a 20-bit immediate + signed displacement, and an index register. - ``r`` or ``d``: A 32, 64, or 128-bit integer register. - ``a``: A 32, 64, or 128-bit integer address register (excludes R0, which in an address context evaluates as zero). @@ -3821,7 +3953,7 @@ references to them from instructions). !0 = !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: true, flags: "-O2", runtimeVersion: 2, - splitDebugFilename: "abc.debug", emissionKind: 1, + splitDebugFilename: "abc.debug", emissionKind: FullDebug, enums: !2, retainedTypes: !3, subprograms: !4, globals: !5, imports: !6, macros: !7, dwoId: 0x0abcd) @@ -3907,21 +4039,28 @@ The following ``tag:`` values are valid: .. code-block:: llvm - DW_TAG_formal_parameter = 5 DW_TAG_member = 13 DW_TAG_pointer_type = 15 DW_TAG_reference_type = 16 DW_TAG_typedef = 22 + DW_TAG_inheritance = 28 DW_TAG_ptr_to_member_type = 31 DW_TAG_const_type = 38 + DW_TAG_friend = 42 DW_TAG_volatile_type = 53 DW_TAG_restrict_type = 55 +.. _DIDerivedTypeMember: + ``DW_TAG_member`` is used to define a member of a :ref:`composite type -` or :ref:`subprogram `. The type of the member -is the ``baseType:``. The ``offset:`` is the member's bit offset. -``DW_TAG_formal_parameter`` is used to define a member which is a formal -argument of a subprogram. +`. The type of the member is the ``baseType:``. The +``offset:`` is the member's bit offset. If the composite type has an ODR +``identifier:`` and does not set ``flags: DIFwdDecl``, then the member is +uniqued based only on its ``name:`` and ``scope:``. + +``DW_TAG_inheritance`` and ``DW_TAG_friend`` are used in the ``elements:`` +field of :ref:`composite types ` to describe parents and +friends. ``DW_TAG_typedef`` is used to provide a name for the ``baseType:``. @@ -3940,9 +4079,15 @@ DICompositeType structures and unions. ``elements:`` points to a tuple of the composed types. If the source language supports ODR, the ``identifier:`` field gives the unique -identifier used for type merging between modules. When specified, other types -can refer to composite types indirectly via a :ref:`metadata string -` that matches their identifier. +identifier used for type merging between modules. When specified, +:ref:`subprogram declarations ` and :ref:`member +derived types ` that reference the ODR-type in their +``scope:`` change uniquing rules. + +For a given ``identifier:``, there should only be a single composite type that +does not have ``flags: DIFlagFwdDecl`` set. LLVM tools that link modules +together will unique such definitions at parse time via the ``identifier:`` +field, even if the nodes are ``distinct``. .. code-block:: llvm @@ -3962,9 +4107,6 @@ The following ``tag:`` values are valid: DW_TAG_enumeration_type = 4 DW_TAG_structure_type = 19 DW_TAG_union_type = 23 - DW_TAG_subroutine_type = 21 - DW_TAG_inheritance = 28 - For ``DW_TAG_array_type``, the ``elements:`` should be :ref:`subrange descriptors `, each representing the range of subscripts at that @@ -3978,7 +4120,9 @@ value for the set. All enumeration type descriptors are collected in the For ``DW_TAG_structure_type``, ``DW_TAG_class_type``, and ``DW_TAG_union_type``, the ``elements:`` should be :ref:`derived types -` with ``tag: DW_TAG_member`` or ``tag: DW_TAG_inheritance``. +` with ``tag: DW_TAG_member``, ``tag: DW_TAG_inheritance``, or +``tag: DW_TAG_friend``; or :ref:`subprograms ` with +``isDefinition: false``. .. _DISubrange: @@ -4067,6 +4211,14 @@ metadata. The ``variables:`` field points at :ref:`variables ` that must be retained, even if their IR counterparts are optimized out of the IR. The ``type:`` field must point at an :ref:`DISubroutineType`. +.. _DISubprogramDeclaration: + +When ``isDefinition: false``, subprograms describe a declaration in the type +tree as opposed to a definition of a function. If the scope is a composite +type with an ODR ``identifier:`` and that does not set ``flags: DIFwdDecl``, +then the subprogram declaration is uniqued based only on its ``linkageName:`` +and ``scope:``. + .. code-block:: llvm define void @_Z3foov() !dbg !0 { @@ -4075,7 +4227,7 @@ the IR. The ``type:`` field must point at an :ref:`DISubroutineType`. !0 = distinct !DISubprogram(name: "foo", linkageName: "_Zfoov", scope: !1, file: !2, line: 7, type: !3, isLocal: true, - isDefinition: false, scopeLine: 8, + isDefinition: true, scopeLine: 8, containingType: !4, virtuality: DW_VIRTUALITY_pure_virtual, virtualIndex: 10, flags: DIFlagPrototyped, @@ -4194,7 +4346,7 @@ DIMacro ``DIMacro`` nodes represent definition or undefinition of a macro identifiers. The ``name:`` field is the macro identifier, followed by macro parameters when -definining a function-like macro, and the ``value`` field is the token-string +defining a function-like macro, and the ``value`` field is the token-string used to expand the macro identifier. .. code-block:: llvm @@ -4291,12 +4443,20 @@ instructions (loads, stores, memory-accessing calls, etc.) that carry ``noalias`` metadata can specifically be specified not to alias with some other collection of memory access instructions that carry ``alias.scope`` metadata. Each type of metadata specifies a list of scopes where each scope has an id and -a domain. When evaluating an aliasing query, if for some domain, the set +a domain. + +When evaluating an aliasing query, if for some domain, the set of scopes with that domain in one instruction's ``alias.scope`` list is a subset of (or equal to) the set of scopes for that domain in another instruction's ``noalias`` list, then the two memory accesses are assumed not to alias. +Because scopes in one domain don't affect scopes in other domains, separate +domains can be used to compose multiple independent noalias sets. This is +used for example during inlining. As the noalias function parameters are +turned into noalias scope metadata, a new domain is used every time the +function is inlined. + The metadata identifying each domain is itself a list containing one or two entries. The first entry is the name of the domain. Note that if the name is a string then it can be combined across functions and translation units. A @@ -4358,8 +4518,8 @@ it. ULP is defined as follows: distance between the two non-equal finite floating-point numbers nearest ``x``. Moreover, ``ulp(NaN)`` is ``NaN``. -The metadata node shall consist of a single positive floating point -number representing the maximum relative error, for example: +The metadata node shall consist of a single positive float type number +representing the maximum relative error, for example: .. code-block:: llvm @@ -4582,6 +4742,27 @@ which is the string ``llvm.loop.licm_versioning.disable``. For example: !0 = !{!"llvm.loop.licm_versioning.disable"} +'``llvm.loop.distribute.enable``' Metadata +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Loop distribution allows splitting a loop into multiple loops. Currently, +this is only performed if the entire loop cannot be vectorized due to unsafe +memory dependencies. The transformation will atempt to isolate the unsafe +dependencies into their own loop. + +This metadata can be used to selectively enable or disable distribution of the +loop. The first operand is the string ``llvm.loop.distribute.enable`` and the +second operand is a bit. If the bit operand value is 1 distribution is +enabled. A value of 0 disables distribution: + +.. code-block:: llvm + + !0 = !{!"llvm.loop.distribute.enable", i1 0} + !1 = !{!"llvm.loop.distribute.enable", i1 1} + +This metadata should be used in conjunction with ``llvm.loop`` loop +identification metadata. + '``llvm.mem``' ^^^^^^^^^^^^^^^ @@ -4595,7 +4776,8 @@ The ``llvm.mem.parallel_loop_access`` metadata refers to a loop identifier, or metadata containing a list of loop identifiers for nested loops. The metadata is attached to memory accessing instructions and denotes that no loop carried memory dependence exist between it and other instructions denoted -with the same loop identifier. +with the same loop identifier. The metadata on memory reads also implies that +if conversion (i.e. speculative execution within a loop iteration) is safe. Precisely, given two instructions ``m1`` and ``m2`` that both have the ``llvm.mem.parallel_loop_access`` metadata, with ``L1`` and ``L2`` being the @@ -4665,12 +4847,6 @@ the loop identifier metadata node directly: !1 = !{!1} ; an identifier for the inner loop !2 = !{!2} ; an identifier for the outer loop -'``llvm.bitsets``' -^^^^^^^^^^^^^^^^^^ - -The ``llvm.bitsets`` global metadata is used to implement -:doc:`bitsets `. - '``invariant.group``' Metadata ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -5307,7 +5483,7 @@ Syntax: :: - = invoke [cconv] [ret attrs] () [fn attrs] + = invoke [cconv] [ret attrs] | () [fn attrs] [operand bundles] to label unwind label Overview: @@ -5343,12 +5519,16 @@ This instruction requires several arguments: #. The optional :ref:`Parameter Attributes ` list for return values. Only '``zeroext``', '``signext``', and '``inreg``' attributes are valid here. -#. '``ptr to function ty``': shall be the signature of the pointer to - function value being invoked. In most cases, this is a direct - function invocation, but indirect ``invoke``'s are just as possible, - branching off an arbitrary pointer to function value. -#. '``function ptr val``': An LLVM value containing a pointer to a - function to be invoked. +#. '``ty``': the type of the call instruction itself which is also the + type of the return value. Functions that return no value are marked + ``void``. +#. '``fnty``': shall be the signature of the function being invoked. The + argument types must match the types implied by this signature. This + type can be omitted if the function is not varargs. +#. '``fnptrval``': An LLVM value containing a pointer to a function to + be invoked. In most cases, this is a direct function invocation, but + indirect ``invoke``'s are just as possible, calling an arbitrary pointer + to function value. #. '``function args``': argument list whose types match the function signature argument types and parameter attributes. All arguments must be of :ref:`first class ` type. If the function signature @@ -6807,7 +6987,7 @@ Syntax: :: = load [volatile] , * [, align ][, !nontemporal !][, !invariant.load !][, !invariant.group !][, !nonnull !][, !dereferenceable !][, !dereferenceable_or_null !][, !align !] - = load atomic [volatile] * [singlethread] , align [, !invariant.group !] + = load atomic [volatile] , * [singlethread] , align [, !invariant.group !] ! = !{ i32 1 } ! = !{i64 } ! = !{ i64 } @@ -6820,12 +7000,12 @@ The '``load``' instruction is used to read from memory. Arguments: """""""""" -The argument to the ``load`` instruction specifies the memory address -from which to load. The type specified must be a :ref:`first -class ` type. If the ``load`` is marked as ``volatile``, -then the optimizer is not allowed to modify the number or order of -execution of this ``load`` with other :ref:`volatile -operations `. +The argument to the ``load`` instruction specifies the memory address from which +to load. The type specified must be a :ref:`first class ` type of +known size (i.e. not containing an :ref:`opaque structural type `). If +the ``load`` is marked as ``volatile``, then the optimizer is not allowed to +modify the number or order of execution of this ``load`` with other +:ref:`volatile operations `. If the ``load`` is marked as ``atomic``, it takes an extra :ref:`ordering ` and optional ``singlethread`` argument. The ``release`` and @@ -6845,7 +7025,12 @@ alignment for the target. It is the responsibility of the code emitter to ensure that the alignment information is correct. Overestimating the alignment results in undefined behavior. Underestimating the alignment may produce less efficient code. An alignment of 1 is always safe. The -maximum possible alignment is ``1 << 29``. +maximum possible alignment is ``1 << 29``. An alignment value higher +than the size of the loaded type implies memory up to the alignment +value bytes can be safely loaded without trapping in the default +address space. Access of the high bytes can interfere with debugging +tools, so should not be accessed if the function has the +``sanitize_thread`` or ``sanitize_address`` attributes. The optional ``!nontemporal`` metadata must reference a single metadata name ```` corresponding to a metadata node with one @@ -6943,13 +7128,14 @@ The '``store``' instruction is used to write to memory. Arguments: """""""""" -There are two arguments to the ``store`` instruction: a value to store -and an address at which to store it. The type of the ```` -operand must be a pointer to the :ref:`first class ` type of -the ```` operand. If the ``store`` is marked as ``volatile``, -then the optimizer is not allowed to modify the number or order of -execution of this ``store`` with other :ref:`volatile -operations `. +There are two arguments to the ``store`` instruction: a value to store and an +address at which to store it. The type of the ```` operand must be a +pointer to the :ref:`first class ` type of the ```` +operand. If the ``store`` is marked as ``volatile``, then the optimizer is not +allowed to modify the number or order of execution of this ``store`` with other +:ref:`volatile operations `. Only values of :ref:`first class +` types of known size (i.e. not containing an :ref:`opaque +structural type `) can be stored. If the ``store`` is marked as ``atomic``, it takes an extra :ref:`ordering ` and optional ``singlethread`` argument. The ``acquire`` and @@ -6969,7 +7155,14 @@ alignment for the target. It is the responsibility of the code emitter to ensure that the alignment information is correct. Overestimating the alignment results in undefined behavior. Underestimating the alignment may produce less efficient code. An alignment of 1 is always -safe. The maximum possible alignment is ``1 << 29``. +safe. The maximum possible alignment is ``1 << 29``. An alignment +value higher than the size of the stored type implies memory up to the +alignment value bytes can be stored to without trapping in the default +address space. Storing to the higher bytes however may result in data +races if another thread can access the same address. Introducing a +data race is not allowed. Storing to the extra bytes is not allowed +even in situations where a data race is known to not exist if the +function has the ``sanitize_address`` attribute. The optional ``!nontemporal`` metadata must reference a single metadata name ```` corresponding to a metadata node with one ``i32`` entry of @@ -8017,7 +8210,7 @@ Arguments: The '``icmp``' instruction takes three operands. The first operand is the condition code indicating the kind of comparison to perform. It is -not a value, just a keyword. The possible condition code are: +not a value, just a keyword. The possible condition codes are: #. ``eq``: equal #. ``ne``: not equal @@ -8081,9 +8274,6 @@ Example: = icmp ule i16 -4, 5 ; yields: result=false = icmp sge i16 4, 5 ; yields: result=false -Note that the code generator does not yet support vector types with the -``icmp`` instruction. - .. _i_fcmp: '``fcmp``' Instruction @@ -8114,7 +8304,7 @@ Arguments: The '``fcmp``' instruction takes three operands. The first operand is the condition code indicating the kind of comparison to perform. It is -not a value, just a keyword. The possible condition code are: +not a value, just a keyword. The possible condition codes are: #. ``false``: no comparison, always returns false #. ``oeq``: ordered and equal @@ -8196,9 +8386,6 @@ Example: = fcmp olt float 4.0, 5.0 ; yields: result=true = fcmp ueq double 1.0, 2.0 ; yields: result=false -Note that the code generator does not yet support vector types with the -``fcmp`` instruction. - .. _i_phi: '``phi``' Instruction @@ -8310,7 +8497,7 @@ Syntax: :: - = [tail | musttail | notail ] call [fast-math flags] [cconv] [ret attrs] [*] () [fn attrs] + = [tail | musttail | notail ] call [fast-math flags] [cconv] [ret attrs] | () [fn attrs] [ operand bundles ] Overview: @@ -8383,13 +8570,11 @@ This instruction requires several arguments: #. '``ty``': the type of the call instruction itself which is also the type of the return value. Functions that return no value are marked ``void``. -#. '``fnty``': shall be the signature of the pointer to function value - being invoked. The argument types must match the types implied by - this signature. This type can be omitted if the function is not - varargs and if the function type does not return a pointer to a - function. +#. '``fnty``': shall be the signature of the function being called. The + argument types must match the types implied by this signature. This + type can be omitted if the function is not varargs. #. '``fnptrval``': An LLVM value containing a pointer to a function to - be invoked. In most cases, this is a direct function invocation, but + be called. In most cases, this is a direct function call, but indirect ``call``'s are just as possible, calling an arbitrary pointer to function value. #. '``function args``': argument list whose types match the function @@ -8398,8 +8583,8 @@ This instruction requires several arguments: indicates the function accepts a variable number of arguments, the extra arguments can be specified. #. The optional :ref:`function attributes ` list. Only - '``noreturn``', '``nounwind``', '``readonly``' and '``readnone``' - attributes are valid here. + '``noreturn``', '``nounwind``', '``readonly``' , '``readnone``', + and '``convergent``' attributes are valid here. #. The optional :ref:`operand bundles ` list. Semantics: @@ -9537,6 +9722,33 @@ pass will generate the appropriate data structures and replace the ``llvm.instrprof_value_profile`` intrinsic with the call to the profile runtime library with proper arguments. +'``llvm.thread.pointer``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare i8* @llvm.thread.pointer() + +Overview: +""""""""" + +The '``llvm.thread.pointer``' intrinsic returns the value of the thread +pointer. + +Semantics: +"""""""""" + +The '``llvm.thread.pointer``' intrinsic returns a pointer to the TLS area +for the current thread. The exact semantics of this value are target +specific: it may point to the start of TLS area, to the end, or somewhere +in the middle. Depending on the target, this intrinsic may read a register, +call a helper function, read from an alternate memory space, or perform +other operations necessary to locate the TLS area. Not all targets support +this intrinsic. + Standard C Library Intrinsics ----------------------------- @@ -10680,7 +10892,26 @@ then the result is the size in bits of the type of ``src`` if Arithmetic with Overflow Intrinsics ----------------------------------- -LLVM provides intrinsics for some arithmetic with overflow operations. +LLVM provides intrinsics for fast arithmetic overflow checking. + +Each of these intrinsics returns a two-element struct. The first +element of this struct contains the result of the corresponding +arithmetic operation modulo 2\ :sup:`n`\ , where n is the bit width of +the result. Therefore, for example, the first element of the struct +returned by ``llvm.sadd.with.overflow.i32`` is always the same as the +result of a 32-bit ``add`` instruction with the same operands, where +the ``add`` is *not* modified by an ``nsw`` or ``nuw`` flag. + +The second element of the result is an ``i1`` that is 1 if the +arithmetic operation overflowed and 0 otherwise. An operation +overflows if, for any values of its operands ``A`` and ``B`` and for +any ``N`` larger than the operands' width, ``ext(A op B) to iN`` is +not equal to ``(ext(A) to iN) op (ext(B) to iN)`` where ``ext`` is +``sext`` for signed overflow and ``zext`` for unsigned overflow, and +``op`` is the underlying arithmetic operation. + +The behavior of these intrinsics is well-defined for all argument +values. '``llvm.sadd.with.overflow.*``' Intrinsics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11344,12 +11575,12 @@ This is an overloaded intrinsic. The loaded data is a vector of any integer, flo :: - declare <16 x float> @llvm.masked.load.v16f32 (<16 x float>* , i32 , <16 x i1> , <16 x float> ) - declare <2 x double> @llvm.masked.load.v2f64 (<2 x double>* , i32 , <2 x i1> , <2 x double> ) + declare <16 x float> @llvm.masked.load.v16f32.p0v16f32 (<16 x float>* , i32 , <16 x i1> , <16 x float> ) + declare <2 x double> @llvm.masked.load.v2f64.p0v2f64 (<2 x double>* , i32 , <2 x i1> , <2 x double> ) ;; The data is a vector of pointers to double - declare <8 x double*> @llvm.masked.load.v8p0f64 (<8 x double*>* , i32 , <8 x i1> , <8 x double*> ) + declare <8 x double*> @llvm.masked.load.v8p0f64.p0v8p0f64 (<8 x double*>* , i32 , <8 x i1> , <8 x double*> ) ;; The data is a vector of function pointers - declare <8 x i32 ()*> @llvm.masked.load.v8p0f_i32f (<8 x i32 ()*>* , i32 , <8 x i1> , <8 x i32 ()*> ) + declare <8 x i32 ()*> @llvm.masked.load.v8p0f_i32f.p0v8p0f_i32f (<8 x i32 ()*>* , i32 , <8 x i1> , <8 x i32 ()*> ) Overview: """"""""" @@ -11372,7 +11603,7 @@ The result of this operation is equivalent to a regular vector load instruction :: - %res = call <16 x float> @llvm.masked.load.v16f32 (<16 x float>* %ptr, i32 4, <16 x i1>%mask, <16 x float> %passthru) + %res = call <16 x float> @llvm.masked.load.v16f32.p0v16f32 (<16 x float>* %ptr, i32 4, <16 x i1>%mask, <16 x float> %passthru) ;; The result of the two following instructions is identical aside from potential memory access exception %loadlal = load <16 x float>, <16 x float>* %ptr, align 4 @@ -11389,12 +11620,12 @@ This is an overloaded intrinsic. The data stored in memory is a vector of any in :: - declare void @llvm.masked.store.v8i32 (<8 x i32> , <8 x i32>* , i32 , <8 x i1> ) - declare void @llvm.masked.store.v16f32 (<16 x float> , <16 x float>* , i32 , <16 x i1> ) + declare void @llvm.masked.store.v8i32.p0v8i32 (<8 x i32> , <8 x i32>* , i32 , <8 x i1> ) + declare void @llvm.masked.store.v16f32.p0v16f32 (<16 x float> , <16 x float>* , i32 , <16 x i1> ) ;; The data is a vector of pointers to double - declare void @llvm.masked.store.v8p0f64 (<8 x double*> , <8 x double*>* , i32 , <8 x i1> ) + declare void @llvm.masked.store.v8p0f64.p0v8p0f64 (<8 x double*> , <8 x double*>* , i32 , <8 x i1> ) ;; The data is a vector of function pointers - declare void @llvm.masked.store.v4p0f_i32f (<4 x i32 ()*> , <4 x i32 ()*>* , i32 , <4 x i1> ) + declare void @llvm.masked.store.v4p0f_i32f.p0v4p0f_i32f (<4 x i32 ()*> , <4 x i32 ()*>* , i32 , <4 x i1> ) Overview: """"""""" @@ -11415,7 +11646,7 @@ The result of this operation is equivalent to a load-modify-store sequence. Howe :: - call void @llvm.masked.store.v16f32(<16 x float> %value, <16 x float>* %ptr, i32 4, <16 x i1> %mask) + call void @llvm.masked.store.v16f32.p0v16f32(<16 x float> %value, <16 x float>* %ptr, i32 4, <16 x i1> %mask) ;; The result of the following instructions is identical aside from potential data races and memory access exceptions %oldval = load <16 x float>, <16 x float>* %ptr, align 4 @@ -11899,43 +12130,40 @@ checked against the original guard by ``llvm.stackprotectorcheck``. If they are different, then ``llvm.stackprotectorcheck`` causes the program to abort by calling the ``__stack_chk_fail()`` function. -'``llvm.stackprotectorcheck``' Intrinsic -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +'``llvm.stackguard``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Syntax: """"""" :: - declare void @llvm.stackprotectorcheck(i8** ) + declare i8* @llvm.stackguard() Overview: """"""""" -The ``llvm.stackprotectorcheck`` intrinsic compares ``guard`` against an already -created stack protector and if they are not equal calls the -``__stack_chk_fail()`` function. +The ``llvm.stackguard`` intrinsic returns the system stack guard value. + +It should not be generated by frontends, since it is only for internal usage. +The reason why we create this intrinsic is that we still support IR form Stack +Protector in FastISel. Arguments: """""""""" -The ``llvm.stackprotectorcheck`` intrinsic requires one pointer argument, the -the variable ``@__stack_chk_guard``. +None. Semantics: """""""""" -This intrinsic is provided to perform the stack protector check by comparing -``guard`` with the stack slot created by ``llvm.stackprotector`` and if the -values do not match call the ``__stack_chk_fail()`` function. +On some platforms, the value returned by this intrinsic remains unchanged +between loads in the same thread. On other platforms, it returns the same +global variable value, if any, e.g. ``@__stack_chk_guard``. -The reason to provide this as an IR level intrinsic instead of implementing it -via other IR operations is that in order to perform this operation at the IR -level without an intrinsic, one would need to create additional basic blocks to -handle the success/failure cases. This makes it difficult to stop the stack -protector check from disrupting sibling tail calls in Codegen. With this -intrinsic, we are able to generate the stack protector basic blocks late in -codegen after the tail call decision has occurred. +Currently some platforms have IR-level customized stack guard loading (e.g. +X86 Linux) that is not handled by ``llvm.stackguard()``, while they should be +in the future. '``llvm.objectsize``' Intrinsic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12050,9 +12278,9 @@ sufficient overall improvement in code quality. For this reason, that the optimizer can otherwise deduce or facts that are of little use to the optimizer. -.. _bitset.test: +.. _type.test: -'``llvm.bitset.test``' Intrinsic +'``llvm.type.test``' Intrinsic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Syntax: @@ -12060,20 +12288,74 @@ Syntax: :: - declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone + declare i1 @llvm.type.test(i8* %ptr, metadata %type) nounwind readnone Arguments: """""""""" The first argument is a pointer to be tested. The second argument is a -metadata object representing an identifier for a :doc:`bitset `. +metadata object representing a :doc:`type identifier `. + +Overview: +""""""""" + +The ``llvm.type.test`` intrinsic tests whether the given pointer is associated +with the given type identifier. + +'``llvm.type.checked.load``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare {i8*, i1} @llvm.type.checked.load(i8* %ptr, i32 %offset, metadata %type) argmemonly nounwind readonly + + +Arguments: +"""""""""" + +The first argument is a pointer from which to load a function pointer. The +second argument is the byte offset from which to load the function pointer. The +third argument is a metadata object representing a :doc:`type identifier +`. Overview: """"""""" -The ``llvm.bitset.test`` intrinsic tests whether the given pointer is a -member of the given bitset. +The ``llvm.type.checked.load`` intrinsic safely loads a function pointer from a +virtual table pointer using type metadata. This intrinsic is used to implement +control flow integrity in conjunction with virtual call optimization. The +virtual call optimization pass will optimize away ``llvm.type.checked.load`` +intrinsics associated with devirtualized calls, thereby removing the type +check in cases where it is not needed to enforce the control flow integrity +constraint. + +If the given pointer is associated with a type metadata identifier, this +function returns true as the second element of its return value. (Note that +the function may also return true if the given pointer is not associated +with a type metadata identifier.) If the function's return value's second +element is true, the following rules apply to the first element: + +- If the given pointer is associated with the given type metadata identifier, + it is the function pointer loaded from the given byte offset from the given + pointer. + +- If the given pointer is not associated with the given type metadata + identifier, it is one of the following (the choice of which is unspecified): + + 1. The function pointer that would have been loaded from an arbitrarily chosen + (through an unspecified mechanism) pointer associated with the type + metadata. + + 2. If the function has a non-void return type, a pointer to a function that + returns an unspecified value without causing side effects. + +If the function's return value's second element is false, the value of the +first element is undefined. + '``llvm.donothing``' Intrinsic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12164,6 +12446,9 @@ The inliner composes the ``"deopt"`` continuations of the caller into the ``"deopt"`` continuations present in the inlinee, and also updates calls to this intrinsic to return directly from the frame of the function it inlined into. +All declarations of ``@llvm.experimental.deoptimize`` must share the +same calling convention. + .. _deoptimize_lowering: Lowering: @@ -12176,6 +12461,80 @@ ensure that this symbol is defined). The call arguments to arguments of the specified types, and not as varargs. +'``llvm.experimental.guard``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare void @llvm.experimental.guard(i1, ...) [ "deopt"(...) ] + +Overview: +""""""""" + +This intrinsic, together with :ref:`deoptimization operand bundles +`, allows frontends to express guards or checks on +optimistic assumptions made during compilation. The semantics of +``@llvm.experimental.guard`` is defined in terms of +``@llvm.experimental.deoptimize`` -- its body is defined to be +equivalent to: + +.. code-block:: llvm + + define void @llvm.experimental.guard(i1 %pred, ) { + %realPred = and i1 %pred, undef + br i1 %realPred, label %continue, label %leave [, !make.implicit !{}] + + leave: + call void @llvm.experimental.deoptimize() [ "deopt"() ] + ret void + + continue: + ret void + } + + +with the optional ``[, !make.implicit !{}]`` present if and only if it +is present on the call site. For more details on ``!make.implicit``, +see :doc:`FaultMaps`. + +In words, ``@llvm.experimental.guard`` executes the attached +``"deopt"`` continuation if (but **not** only if) its first argument +is ``false``. Since the optimizer is allowed to replace the ``undef`` +with an arbitrary value, it can optimize guard to fail "spuriously", +i.e. without the original condition being false (hence the "not only +if"); and this allows for "check widening" type optimizations. + +``@llvm.experimental.guard`` cannot be invoked. + + +'``llvm.load.relative``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +:: + + declare i8* @llvm.load.relative.iN(i8* %ptr, iN %offset) argmemonly nounwind readonly + +Overview: +""""""""" + +This intrinsic loads a 32-bit value from the address ``%ptr + %offset``, +adds ``%ptr`` to that value and returns it. The constant folder specifically +recognizes the form of this intrinsic and the constant initializers it may +load from; if a loaded constant initializer is known to have the form +``i32 trunc(x - %ptr)``, the intrinsic call is folded to ``x``. + +LLVM provides that the calculation of such a constant initializer will +not overflow at link time under the medium code model if ``x`` is an +``unnamed_addr`` function. However, it does not provide this guarantee for +a constant initializer folded into a function body. This intrinsic can be +used to avoid the possibility of overflows when loading from such a constant. + Stack Map Intrinsics -------------------- diff --git a/docs/LibFuzzer.rst b/docs/LibFuzzer.rst index 5c4cdcdf94e578141616289c887eba33fd7e49a3..92937c2d0b529d4b1654e36a71ea51a6cbb6b401 100644 --- a/docs/LibFuzzer.rst +++ b/docs/LibFuzzer.rst @@ -1,6 +1,6 @@ -======================================================== -LibFuzzer -- a library for coverage-guided fuzz testing. -======================================================== +======================================================= +libFuzzer – a library for coverage-guided fuzz testing. +======================================================= .. contents:: :local: :depth: 1 @@ -8,92 +8,355 @@ LibFuzzer -- a library for coverage-guided fuzz testing. Introduction ============ -libFuzzer -- library for in-process evolutionary fuzzing of other libraries. +LibFuzzer is a library for in-process, coverage-guided, evolutionary fuzzing +of other libraries. -The typical workflow looks like the following. -First, implement a fuzzing target function, like this:: +LibFuzzer is similar in concept to American Fuzzy Lop (AFL_), but it performs +all of its fuzzing inside a single process. This in-process fuzzing can be more +restrictive and fragile, but is potentially much faster as there is no overhead +for process start-up. + +The fuzzer is linked with the library under test, and feeds fuzzed inputs to the +library via a specific fuzzing entrypoint (aka "target function"); the fuzzer +then tracks which areas of the code are reached, and generates mutations on the +corpus of input data in order to maximize the code coverage. The code coverage +information for libFuzzer is provided by LLVM's SanitizerCoverage_ +instrumentation. + +Contact: libfuzzer(#)googlegroups.com + +Versions +======== + +LibFuzzer is under active development so a current (or at least very recent) +version of Clang is the only supported variant. + +(If `building Clang from trunk`_ is too time-consuming or difficult, then +the Clang binaries that the Chromium developers build are likely to be +fairly recent: + +.. code-block:: console + + mkdir TMP_CLANG + cd TMP_CLANG + git clone https://chromium.googlesource.com/chromium/src/tools/clang + cd .. + TMP_CLANG/clang/scripts/update.py + +This installs the Clang binary as +``./third_party/llvm-build/Release+Asserts/bin/clang``) + +The libFuzzer code resides in the LLVM repository, and requires a recent Clang +compiler to build (and is used to `fuzz various parts of LLVM itself`_). +However the fuzzer itself does not (and should not) depend on any part of LLVM +infrastructure and can be used for other projects without requiring the rest +of LLVM. + + + +Getting Started +=============== + +.. contents:: + :local: + :depth: 1 + +Building +-------- + +The first step for using libFuzzer on a library is to implement a fuzzing +target function that accepts a sequence of bytes, like this: + +.. code-block:: c++ // fuzz_target.cc extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { DoSomethingInterestingWithMyAPI(Data, Size); - return 0; + return 0; // Non-zero return values are reserved for future use. } -Next, build the Fuzzer library as a static archive. Note that libFuzzer contains the `main()` function:: +Next, build the libFuzzer library as a static archive, without any sanitizer +options. Note that the libFuzzer library contains the ``main()`` function: + +.. code-block:: console svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer + # Alternative: get libFuzzer from a dedicated git mirror: + # git clone https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer clang++ -c -g -O2 -std=c++11 Fuzzer/*.cpp -IFuzzer ar ruv libFuzzer.a Fuzzer*.o -Then build the target function and the library you are going to test. -You should use SanitizerCoverage_ and one of ASan, MSan, or UBSan. -Link it with `libFuzzer.a`:: +Then build the fuzzing target function and the library under test using +the SanitizerCoverage_ option, which instruments the code so that the fuzzer +can retrieve code coverage information (to guide the fuzzing). Linking with +the libFuzzer code then gives an fuzzer executable. + +You should also enable one or more of the *sanitizers*, which help to expose +latent bugs by making incorrect behavior generate errors at runtime: + + - AddressSanitizer_ (ASAN) detects memory access errors. Use `-fsanitize=address`. + - UndefinedBehaviorSanitizer_ (UBSAN) detects the use of various features of C/C++ that are explicitly + listed as resulting in undefined behavior. Use `-fsanitize=undefined -fno-sanitize-recover=undefined` + or any individual UBSAN check, e.g. `-fsanitize=signed-integer-overflow -fno-sanitize-recover=undefined`. + You may combine ASAN and UBSAN in one build. + - MemorySanitizer_ (MSAN) detects uninitialized reads: code whose behavior relies on memory + contents that have not been initialized to a specific value. Use `-fsanitize=memory`. + MSAN can not be combined with other sanirizers and should be used as a seprate build. + +Finally, link with ``libFuzzer.a``:: clang -fsanitize-coverage=edge -fsanitize=address your_lib.cc fuzz_target.cc libFuzzer.a -o my_fuzzer -Create a directory with the initial "seed" samlpes. -For some input types libFuzzer will work just fine w/o any seeds, -but for complex inputs this step is very important:: +Corpus +------ - mkdir CORPUS_DIR - cp /some/input/samples/* CORPUS_DIR +Coverage-guided fuzzers like libFuzzer rely on a corpus of sample inputs for the +code under test. This corpus should ideally be seeded with a varied collection +of valid and invalid inputs for the code under test; for example, for a graphics +library the initial corpus might hold a variety of different small PNG/JPG/GIF +files. The fuzzer generates random mutations based around the sample inputs in +the current corpus. If a mutation triggers execution of a previously-uncovered +path in the code under test, then that mutation is saved to the corpus for +future variations. + +LibFuzzer will work without any initial seeds, but will be less +efficient if the library under test accepts complex, +structured inputs. + +The corpus can also act as a sanity/regression check, to confirm that the +fuzzing entrypoint still works and that all of the sample inputs run through +the code under test without problems. -Finally, run the fuzzer on the `CORPUS_DIR`:: +If you have a large corpus (either generated by fuzzing or acquired by other means) +you may want to minimize it while still preserving the full coverage. One way to do that +is to use the `-merge=1` flag: - ./my_fuzzer CORPUS_DIR # -max_len=1000 -jobs=20 -more_lags=... +.. code-block:: console + mkdir NEW_CORPUS_DIR # Store minimized corpus here. + ./my_fuzzer -merge=1 NEW_CORPUS_DIR FULL_CORPUS_DIR -As new interesting test cases are discovered they will be added to the corpus. -If a bug is discovered by the sanitizer (ASan, etc) it will be reported as usual and the reproducer -will be written to disk. -Each Fuzzer process is single-threaded (unless the library starts its own -threads). You can run the libFuzzer on the same corpus in multiple processes -in parallel (use the flags `-jobs=N` and `-workers=N`). +You may use the same flag to add more interesting items to an existing corpus. +Only the inputs that trigger new coverage will be added to the first corpus. -libFuzzer is similar in concept to AFL_, -but uses in-process Fuzzing, which is more fragile and restrictive, but -potentially much faster as it has no overhead for process start-up. -It uses LLVM's SanitizerCoverage_ instrumentation to get in-process -coverage-feedback +.. code-block:: console -The code resides in the LLVM repository, requires the fresh Clang compiler to build -and is used to fuzz various parts of LLVM, -but the Fuzzer itself does not (and should not) depend on any -part of LLVM and can be used for other projects w/o requiring the rest of LLVM. + ./my_fuzzer -merge=1 CURRENT_CORPUS_DIR NEW_POTENTIALLY_INTERESTING_INPUTS_DIR -Usage -===== -To run fuzzing pass 0 or more directories. New samples will be written into `dir1`, other directories will be read once during startup.:: -./fuzzer [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ] +Running +------- -To run individual tests without fuzzing pass 1 or more files:: +To run the fuzzer, first create a Corpus_ directory that holds the +initial "seed" sample inputs: -./fuzzer [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...] +.. code-block:: console -The most important flags are:: + mkdir CORPUS_DIR + cp /some/input/samples/* CORPUS_DIR - seed 0 Random seed. If 0, seed is generated. - runs -1 Number of individual test runs (-1 for infinite runs). - max_len 0 Maximum length of the test input. If 0, libFuzzer tries to guess a good value based on the corpus and reports it. - timeout 1200 Timeout in seconds (if positive). If one unit runs more than this number of seconds the process will abort. - timeout_exitcode 77 Unless abort_on_timeout is set, use this exitcode on timeout. - max_total_time 0 If positive, indicates the maximal total time in seconds to run the fuzzer. - help 0 Print help. - merge 0 If 1, the 2-nd, 3-rd, etc corpora will be merged into the 1-st corpus. Only interesting units will be taken. - jobs 0 Number of jobs to run. If jobs >= 1 we spawn this number of jobs in separate worker processes with stdout/stderr redirected to fuzz-JOB.log. - workers 0 Number of simultaneous worker processes to run the jobs. If zero, "min(jobs,NumberOfCpuCores()/2)" is used. - use_traces 0 Experimental: use instruction traces - only_ascii 0 If 1, generate only ASCII (isprint+isspace) inputs. - artifact_prefix "" Write fuzzing artifacts (crash, timeout, or slow inputs) as $(artifact_prefix)file - exact_artifact_path "" Write the single artifact on failure (crash, timeout) as $(exact_artifact_path). This overrides -artifact_prefix and will not use checksum in the file name. Do not use the same path for several parallel processes. - print_final_stats 0 If 1, print statistics at exit. - close_fd_mask 0 If 1, close stdout at startup; if 2, close stderr; if 3, close both. +Then run the fuzzer on the corpus directory: + +.. code-block:: console + + ./my_fuzzer CORPUS_DIR # -max_len=1000 -jobs=20 ... + +As the fuzzer discovers new interesting test cases (i.e. test cases that +trigger coverage of new paths through the code under test), those test cases +will be added to the corpus directory. + +By default, the fuzzing process will continue indefinitely – at least until +a bug is found. Any crashes or sanitizer failures will be reported as usual, +stopping the fuzzing process, and the particular input that triggered the bug +will be written to disk (typically as ``crash-``, ``leak-``, +or ``timeout-``). + + +Parallel Fuzzing +---------------- + +Each libFuzzer process is single-threaded, unless the library under test starts +its own threads. However, it is possible to run multiple libFuzzer processes in +parallel with a shared corpus directory; this has the advantage that any new +inputs found by one fuzzer process will be available to the other fuzzer +processes (unless you disable this with the ``-reload=0`` option). + +This is primarily controlled by the ``-jobs=N`` option, which indicates that +that `N` fuzzing jobs should be run to completion (i.e. until a bug is found or +time/iteration limits are reached). These jobs will be run across a set of +worker processes, by default using half of the available CPU cores; the count of +worker processes can be overridden by the ``-workers=N`` option. For example, +running with ``-jobs=30`` on a 12-core machine would run 6 workers by default, +with each worker averaging 5 bugs by completion of the entire process. + + +Options +======= + +To run the fuzzer, pass zero or more corpus directories as command line +arguments. The fuzzer will read test inputs from each of these corpus +directories, and any new test inputs that are generated will be written +back to the first corpus directory: + +.. code-block:: console + + ./fuzzer [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ] + +If a list of files (rather than directories) are passed to the fuzzer program, +then it will re-run those files as test inputs but will not perform any fuzzing. +In this mode the fuzzer binary can be used as a regression test (e.g. on a +continuous integration system) to check the target function and saved inputs +still work. + +The most important command line options are: + +``-help`` + Print help message. +``-seed`` + Random seed. If 0 (the default), the seed is generated. +``-runs`` + Number of individual test runs, -1 (the default) to run indefinitely. +``-max_len`` + Maximum length of a test input. If 0 (the default), libFuzzer tries to guess + a good value based on the corpus (and reports it). +``-timeout`` + Timeout in seconds, default 1200. If an input takes longer than this timeout, + the process is treated as a failure case. +``-rss_limit_mb`` + Memory usage limit in Mb, default 2048. Use 0 to disable the limit. + If an input requires more than this amount of RSS memory to execute, + the process is treated as a failure case. + The limit is checked in a separate thread every second. + If running w/o ASAN/MSAN, you may use 'ulimit -v' instead. +``-timeout_exitcode`` + Exit code (default 77) to emit when terminating due to timeout, when + ``-abort_on_timeout`` is not set. +``-max_total_time`` + If positive, indicates the maximum total time in seconds to run the fuzzer. + If 0 (the default), run indefinitely. +``-merge`` + If set to 1, any corpus inputs from the 2nd, 3rd etc. corpus directories + that trigger new code coverage will be merged into the first corpus + directory. Defaults to 0. This flag can be used to minimize a corpus. +``-reload`` + If set to 1 (the default), the corpus directory is re-read periodically to + check for new inputs; this allows detection of new inputs that were discovered + by other fuzzing processes. +``-jobs`` + Number of fuzzing jobs to run to completion. Default value is 0, which runs a + single fuzzing process until completion. If the value is >= 1, then this + number of jobs performing fuzzing are run, in a collection of parallel + separate worker processes; each such worker process has its + ``stdout``/``stderr`` redirected to ``fuzz-.log``. +``-workers`` + Number of simultaneous worker processes to run the fuzzing jobs to completion + in. If 0 (the default), ``min(jobs, NumberOfCpuCores()/2)`` is used. +``-dict`` + Provide a dictionary of input keywords; see Dictionaries_. +``-use_counters`` + Use `coverage counters`_ to generate approximate counts of how often code + blocks are hit; defaults to 1. +``-use_traces`` + Use instruction traces (experimental, defaults to 0); see `Data-flow-guided fuzzing`_. +``-only_ascii`` + If 1, generate only ASCII (``isprint``+``isspace``) inputs. Defaults to 0. +``-artifact_prefix`` + Provide a prefix to use when saving fuzzing artifacts (crash, timeout, or + slow inputs) as ``$(artifact_prefix)file``. Defaults to empty. +``-exact_artifact_path`` + Ignored if empty (the default). If non-empty, write the single artifact on + failure (crash, timeout) as ``$(exact_artifact_path)``. This overrides + ``-artifact_prefix`` and will not use checksum in the file name. Do not use + the same path for several parallel processes. +``-print_final_stats`` + If 1, print statistics at exit. Defaults to 0. +``-detect-leaks`` + If 1 (default) and if LeakSanitizer is enabled + try to detect memory leaks during fuzzing (i.e. not only at shut down). +``-close_fd_mask`` + Indicate output streams to close at startup. Be careful, this will + remove diagnostic output from target code (e.g. messages on assert failure). + + - 0 (default): close neither ``stdout`` nor ``stderr`` + - 1 : close ``stdout`` + - 2 : close ``stderr`` + - 3 : close both ``stdout`` and ``stderr``. For the full list of flags run the fuzzer binary with ``-help=1``. -Usage examples -============== +Output +====== + +During operation the fuzzer prints information to ``stderr``, for example:: + + INFO: Seed: 3338750330 + Loaded 1024/1211 files from corpus/ + INFO: -max_len is not provided, using 64 + #0 READ units: 1211 exec/s: 0 + #1211 INITED cov: 2575 bits: 8855 indir: 5 units: 830 exec/s: 1211 + #1422 NEW cov: 2580 bits: 8860 indir: 5 units: 831 exec/s: 1422 L: 21 MS: 1 ShuffleBytes- + #1688 NEW cov: 2581 bits: 8865 indir: 5 units: 832 exec/s: 1688 L: 19 MS: 2 EraseByte-CrossOver- + #1734 NEW cov: 2583 bits: 8879 indir: 5 units: 833 exec/s: 1734 L: 27 MS: 3 ChangeBit-EraseByte-ShuffleBytes- + ... + +The early parts of the output include information about the fuzzer options and +configuration, including the current random seed (in the ``Seed:`` line; this +can be overridden with the ``-seed=N`` flag). + +Further output lines have the form of an event code and statistics. The +possible event codes are: + +``READ`` + The fuzzer has read in all of the provided input samples from the corpus + directories. +``INITED`` + The fuzzer has completed initialization, which includes running each of + the initial input samples through the code under test. +``NEW`` + The fuzzer has created a test input that covers new areas of the code + under test. This input will be saved to the primary corpus directory. +``pulse`` + The fuzzer has generated 2\ :sup:`n` inputs (generated periodically to reassure + the user that the fuzzer is still working). +``DONE`` + The fuzzer has completed operation because it has reached the specified + iteration limit (``-runs``) or time limit (``-max_total_time``). +``MIN`` + The fuzzer is minimizing the combination of input corpus directories into + a single unified corpus (due to the ``-merge`` command line option). +``RELOAD`` + The fuzzer is performing a periodic reload of inputs from the corpus + directory; this allows it to discover any inputs discovered by other + fuzzer processes (see `Parallel Fuzzing`_). + +Each output line also reports the following statistics (when non-zero): + +``cov:`` + Total number of code blocks or edges covered by the executing the current + corpus. +``bits:`` + Rough measure of the number of code blocks or edges covered, and how often; + only valid if the fuzzer is run with ``-use_counters=1``. +``indir:`` + Number of distinct function `caller-callee pairs`_ executed with the + current corpus; only valid if the code under test was built with + ``-fsanitize-coverage=indirect-calls``. +``units:`` + Number of entries in the current input corpus. +``exec/s:`` + Number of fuzzer iterations per second. + +For ``NEW`` events, the output line also includes information about the mutation +operation that produced the new input: + +``L:`` + Size of the new input in bytes. +``MS: `` + Count and list of the mutation operations used to generate the input. + + +Examples +======== .. contents:: :local: :depth: 1 @@ -101,9 +364,10 @@ Usage examples Toy example ----------- -A simple function that does something interesting if it receives the input "HI!":: +A simple function that does something interesting if it receives the input +"HI!":: - cat << EOF >> test_fuzzer.cc + cat << EOF > test_fuzzer.cc #include #include extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { @@ -123,8 +387,8 @@ You should get an error pretty quickly:: #0 READ units: 1 exec/s: 0 #1 INITED cov: 3 units: 1 exec/s: 0 - #2 NEW cov: 5 units: 2 exec/s: 0 L: 64 MS: 0 - #19237 NEW cov: 9 units: 3 exec/s: 0 L: 64 MS: 0 + #2 NEW cov: 5 units: 2 exec/s: 0 L: 64 MS: 0 + #19237 NEW cov: 9 units: 3 exec/s: 0 L: 64 MS: 0 #20595 NEW cov: 10 units: 4 exec/s: 0 L: 1 MS: 4 ChangeASCIIInt-ShuffleBytes-ChangeByte-CrossOver- #34574 NEW cov: 13 units: 5 exec/s: 0 L: 2 MS: 3 ShuffleBytes-CrossOver-ChangeBit- #34807 NEW cov: 15 units: 6 exec/s: 0 L: 3 MS: 1 CrossOver- @@ -140,9 +404,10 @@ Here we show how to use libFuzzer on something real, yet simple: pcre2_:: COV_FLAGS=" -fsanitize-coverage=edge,indirect-calls,8bit-counters" # Get PCRE2 - svn co svn://vcs.exim.org/pcre2/code/trunk pcre - # Build PCRE2 with AddressSanitizer and coverage. - (cd pcre; ./autogen.sh; CC="clang -fsanitize=address $COV_FLAGS" ./configure --prefix=`pwd`/../inst && make -j && make install) + wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre2-10.20.tar.gz + tar xf pcre2-10.20.tar.gz + # Build PCRE2 with AddressSanitizer and coverage; requires autotools. + (cd pcre2-10.20; ./autogen.sh; CC="clang -fsanitize=address $COV_FLAGS" ./configure --prefix=`pwd`/../inst && make -j && make install) # Build the fuzzing target function that does something interesting with PCRE2. cat << EOF > pcre_fuzzer.cc #include @@ -167,52 +432,64 @@ Here we show how to use libFuzzer on something real, yet simple: pcre2_:: clang++ -g -fsanitize=address -Wl,--whole-archive inst/lib/*.a -Wl,-no-whole-archive libFuzzer.a pcre_fuzzer.o -o pcre_fuzzer This will give you a binary of the fuzzer, called ``pcre_fuzzer``. -Now, create a directory that will hold the test corpus:: +Now, create a directory that will hold the test corpus: + +.. code-block:: console mkdir -p CORPUS For simple input languages like regular expressions this is all you need. -For more complicated inputs populate the directory with some input samples. -Now run the fuzzer with the corpus dir as the only parameter:: +For more complicated/structured inputs, the fuzzer works much more efficiently +if you can populate the corpus directory with a variety of valid and invalid +inputs for the code under test. +Now run the fuzzer with the corpus directory as the only parameter: - ./pcre_fuzzer ./CORPUS +.. code-block:: console -You will see output like this:: + ./pcre_fuzzer ./CORPUS - Seed: 1876794929 - #0 READ cov 0 bits 0 units 1 exec/s 0 - #1 pulse cov 3 bits 0 units 1 exec/s 0 - #1 INITED cov 3 bits 0 units 1 exec/s 0 - #2 pulse cov 208 bits 0 units 1 exec/s 0 - #2 NEW cov 208 bits 0 units 2 exec/s 0 L: 64 - #3 NEW cov 217 bits 0 units 3 exec/s 0 L: 63 - #4 pulse cov 217 bits 0 units 3 exec/s 0 +Initially, you will see Output_ like this:: -* The ``Seed:`` line shows you the current random seed (you can change it with ``-seed=N`` flag). -* The ``READ`` line shows you how many input files were read (since you passed an empty dir there were inputs, but one dummy input was synthesised). -* The ``INITED`` line shows you that how many inputs will be fuzzed. -* The ``NEW`` lines appear with the fuzzer finds a new interesting input, which is saved to the CORPUS dir. If multiple corpus dirs are given, the first one is used. -* The ``pulse`` lines appear periodically to show the current status. + INFO: Seed: 2938818941 + INFO: -max_len is not provided, using 64 + INFO: A corpus is not provided, starting from an empty corpus + #0 READ units: 1 exec/s: 0 + #1 INITED cov: 3 bits: 3 units: 1 exec/s: 0 + #2 NEW cov: 176 bits: 176 indir: 3 units: 2 exec/s: 0 L: 64 MS: 0 + #8 NEW cov: 176 bits: 179 indir: 3 units: 3 exec/s: 0 L: 63 MS: 2 ChangeByte-EraseByte- + ... + #14004 NEW cov: 1500 bits: 4536 indir: 5 units: 406 exec/s: 0 L: 54 MS: 3 ChangeBit-ChangeBit-CrossOver- Now, interrupt the fuzzer and run it again the same way. You will see:: - Seed: 1879995378 - #0 READ cov 0 bits 0 units 564 exec/s 0 - #1 pulse cov 502 bits 0 units 564 exec/s 0 + INFO: Seed: 3398349082 + INFO: -max_len is not provided, using 64 + #0 READ units: 405 exec/s: 0 + #405 INITED cov: 1499 bits: 4535 indir: 5 units: 286 exec/s: 0 + #587 NEW cov: 1499 bits: 4540 indir: 5 units: 287 exec/s: 0 L: 52 MS: 2 InsertByte-EraseByte- + #667 NEW cov: 1501 bits: 4542 indir: 5 units: 288 exec/s: 0 L: 39 MS: 2 ChangeBit-InsertByte- + #672 NEW cov: 1501 bits: 4543 indir: 5 units: 289 exec/s: 0 L: 15 MS: 2 ChangeASCIIInt-ChangeBit- + #739 NEW cov: 1501 bits: 4544 indir: 5 units: 290 exec/s: 0 L: 64 MS: 4 ShuffleBytes-ChangeASCIIInt-InsertByte-ChangeBit- ... - #512 pulse cov 2933 bits 0 units 564 exec/s 512 - #564 INITED cov 2991 bits 0 units 344 exec/s 564 - #1024 pulse cov 2991 bits 0 units 344 exec/s 1024 - #1455 NEW cov 2995 bits 0 units 345 exec/s 1455 L: 49 -This time you were running the fuzzer with a non-empty input corpus (564 items). -As the first step, the fuzzer minimized the set to produce 344 interesting items (the ``INITED`` line) +On the second execution the fuzzer has a non-empty input corpus (405 items). As +the first step, the fuzzer minimized this corpus (the ``INITED`` line) to +produce 286 interesting items, omitting inputs that do not hit any additional +code. + +(Aside: although the fuzzer only saves new inputs that hit additional code, this +does not mean that the corpus as a whole is kept minimized. For example, if +an input hitting A-B-C then an input that hits A-B-C-D are generated, +they will both be saved, even though the latter subsumes the former.) + -You may run ``N`` independent fuzzer jobs in parallel on ``M`` CPUs:: +You may run ``N`` independent fuzzer jobs in parallel on ``M`` CPUs: + +.. code-block:: console N=100; M=4; ./pcre_fuzzer ./CORPUS -jobs=$N -workers=$M -By default (``-reload=1``) the fuzzer processes will periodically scan the CORPUS directory +By default (``-reload=1``) the fuzzer processes will periodically scan the corpus directory and reload any new tests. This way the test inputs found by one process will be picked up by all others. @@ -222,15 +499,15 @@ Heartbleed ---------- Remember Heartbleed_? As it was recently `shown `_, -fuzzing with AddressSanitizer can find Heartbleed. Indeed, here are the step-by-step instructions -to find Heartbleed with LibFuzzer:: +fuzzing with AddressSanitizer_ can find Heartbleed. Indeed, here are the step-by-step instructions +to find Heartbleed with libFuzzer:: wget https://www.openssl.org/source/openssl-1.0.1f.tar.gz tar xf openssl-1.0.1f.tar.gz COV_FLAGS="-fsanitize-coverage=edge,indirect-calls" # -fsanitize-coverage=8bit-counters (cd openssl-1.0.1f/ && ./config && make -j 32 CC="clang -g -fsanitize=address $COV_FLAGS") - # Get and build LibFuzzer + # Get and build libFuzzer svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer clang -c -g -O2 -std=c++11 Fuzzer/*.cpp -IFuzzer # Get examples of key/pem files. @@ -284,7 +561,7 @@ Voila:: #2 0x580be3 in ssl3_read_bytes openssl-1.0.1f/ssl/s3_pkt.c:1092:4 Note: a `similar fuzzer `_ -is now a part of the boringssl source tree. +is now a part of the BoringSSL_ source tree. Advanced features ================= @@ -294,7 +571,6 @@ Advanced features Dictionaries ------------ -*EXPERIMENTAL*. LibFuzzer supports user-supplied dictionaries with input language keywords or other interesting byte sequences (e.g. multi-byte magic values). Use ``-dict=DICTIONARY_FILE``. For some input languages using a dictionary @@ -324,16 +600,51 @@ It will later use those recorded inputs during mutations. This mode can be combined with DataFlowSanitizer_ to achieve better sensitivity. +Fuzzer-friendly build mode +--------------------------- +Sometimes the code under test is not fuzzing-friendly. Examples: + + - The target code uses a PRNG seeded e.g. by system time and + thus two consequent invocations may potentially execute different code paths + even if the end result will be the same. This will cause a fuzzer to treat + two similar inputs as significantly different and it will blow up the test corpus. + E.g. libxml uses ``rand()`` inside its hash table. + - The target code uses checksums to protect from invalid inputs. + E.g. png checks CRC for every chunk. + +In many cases it makes sense to build a special fuzzing-friendly build +with certain fuzzing-unfriendly features disabled. We propose to use a common build macro +for all such cases for consistency: ``FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION``. + +.. code-block:: c++ + + void MyInitPRNG() { + #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + // In fuzzing mode the behavior of the code should be deterministic. + srand(0); + #else + srand(time(0)); + #endif + } + + + AFL compatibility ----------------- -LibFuzzer can be used in parallel with AFL_ on the same test corpus. +LibFuzzer can be used together with AFL_ on the same test corpus. Both fuzzers expect the test corpus to reside in a directory, one file per input. -You can run both fuzzers on the same corpus in parallel:: +You can run both fuzzers on the same corpus, one after another: + +.. code-block:: console - ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program -r @@ + ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@ ./llvm-fuzz testcase_dir findings_dir # Will write new tests to testcase_dir Periodically restart both fuzzers so that they can use each other's findings. +Currently, there is no simple way to run both fuzzing engines in parallel while sharing the same corpus dir. + +You may also use AFL on your target function ``LLVMFuzzerTestOneInput``: +see an example `here `__. How good is my fuzzer? ---------------------- @@ -341,14 +652,20 @@ How good is my fuzzer? Once you implement your target function ``LLVMFuzzerTestOneInput`` and fuzz it to death, you will want to know whether the function or the corpus can be improved further. One easy to use metric is, of course, code coverage. -You can get the coverage for your corpus like this:: +You can get the coverage for your corpus like this: + +.. code-block:: console + + ASAN_OPTIONS=coverage=1:html_cov_report=1 ./fuzzer CORPUS_DIR -runs=0 - ASAN_OPTIONS=coverage=1 ./fuzzer CORPUS_DIR -runs=0 +This will run all tests in the CORPUS_DIR but will not perform any fuzzing. +At the end of the process it will dump a single html file with coverage information. +See SanitizerCoverage_ for details. -This will run all the tests in the CORPUS_DIR but will not generate any new tests -and dump covered PCs to disk before exiting. -Then you can subtract the set of covered PCs from the set of all instrumented PCs in the binary, -see SanitizerCoverage_ for details. +You may also use other ways to visualize coverage, +e.g. using `Clang coverage `_, +but those will require +you to rebuild the code with different compiler flags. User-supplied mutators ---------------------- @@ -360,27 +677,59 @@ Startup initialization ---------------------- If the library being tested needs to be initialized, there are several options. -The simplest way is to have a statically initialized global object:: +The simplest way is to have a statically initialized global object inside +`LLVMFuzzerTestOneInput` (or in global scope if that works for you): - static bool Initialized = DoInitialization(); +.. code-block:: c++ + + extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + static bool Initialized = DoInitialization(); + ... Alternatively, you may define an optional init function and it will receive -the program arguments that you can read and modify:: +the program arguments that you can read and modify. Do this **only** if you +realy need to access ``argv``/``argc``. + +.. code-block:: c++ extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { ReadAndMaybeModify(argc, argv); return 0; } -Try to avoid initialization inside the target function itself as -it will skew the coverage data. Don't do this:: - extern "C" int LLVMFuzzerTestOneInput(...) { - static bool initialized = false; - if (!initialized) { - ... - } - } +Leaks +----- + +Binaries built with AddressSanitizer_ or LeakSanitizer_ will try to detect +memory leaks at the process shutdown. +For in-process fuzzing this is inconvenient +since the fuzzer needs to report a leak with a reproducer as soon as the leaky +mutation is found. However, running full leak detection after every mutation +is expensive. + +By default (``-detect_leaks=1``) libFuzzer will count the number of +``malloc`` and ``free`` calls when executing every mutation. +If the numbers don't match (which by itself doesn't mean there is a leak) +libFuzzer will invoke the more expensive LeakSanitizer_ +pass and if the actual leak is found, it will be reported with the reproducer +and the process will exit. + +If your target has massive leaks and the leak detection is disabled +you will eventually run out of RAM (see the ``-rss_limit_mb`` flag). + + +Developing libFuzzer +==================== + +Building libFuzzer as a part of LLVM project and running its test requires +fresh clang as the host compiler and special CMake configuration: + +.. code-block:: console + + cmake -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_USE_SANITIZER=Address -DLLVM_USE_SANITIZE_COVERAGE=YES -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON /path/to/llvm + ninja check-fuzzer + Fuzzing components of LLVM ========================== @@ -388,18 +737,19 @@ Fuzzing components of LLVM :local: :depth: 1 +To build any of the LLVM fuzz targets use the build instructions above. + clang-format-fuzzer ------------------- The inputs are random pieces of C++-like text. -Build (make sure to use fresh clang as the host compiler):: +.. code-block:: console - cmake -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_USE_SANITIZER=Address -DLLVM_USE_SANITIZE_COVERAGE=YES -DCMAKE_BUILD_TYPE=Release /path/to/llvm ninja clang-format-fuzzer mkdir CORPUS_DIR ./bin/clang-format-fuzzer CORPUS_DIR -Optionally build other kinds of binaries (asan+Debug, msan, ubsan, etc). +Optionally build other kinds of binaries (ASan+Debug, MSan, UBSan, etc). Tracking bug: https://llvm.org/bugs/show_bug.cgi?id=23052 @@ -429,25 +779,27 @@ finds an invalid instruction or runs out of data. Please note that the command line interface differs slightly from that of other fuzzers. The fuzzer arguments should follow ``--fuzzer-args`` and should have a single dash, while other arguments control the operation mode and target in a -similar manner to ``llvm-mc`` and should have two dashes. For example:: +similar manner to ``llvm-mc`` and should have two dashes. For example: + +.. code-block:: console llvm-mc-fuzzer --triple=aarch64-linux-gnu --disassemble --fuzzer-args -max_len=4 -jobs=10 Buildbot -------- -We have a buildbot that runs the above fuzzers for LLVM components -24/7/365 at http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fuzzer . +A buildbot continuously runs the above fuzzers for LLVM components, with results +shown at http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fuzzer . FAQ ========================= -Q. Why libFuzzer does not use any of the LLVM support? ------------------------------------------------------- +Q. Why doesn't libFuzzer use any of the LLVM support? +----------------------------------------------------- There are two reasons. -First, we want this library to be used outside of the LLVM w/o users having to +First, we want this library to be used outside of the LLVM without users having to build the rest of LLVM. This may sound unconvincing for many LLVM folks, but in practice the need for building the whole LLVM frightens many potential users -- and we want more users to use this code. @@ -459,7 +811,7 @@ coverage set of the process (since the fuzzer is in-process). In other words, by using more external dependencies we will slow down the fuzzer while the main reason for it to exist is extreme speed. -Q. What about Windows then? The Fuzzer contains code that does not build on Windows. +Q. What about Windows then? The fuzzer contains code that does not build on Windows. ------------------------------------------------------------------------------------ Volunteers are welcome. @@ -469,7 +821,7 @@ Q. When this Fuzzer is not a good solution for a problem? * If the test inputs are validated by the target library and the validator asserts/crashes on invalid inputs, in-process fuzzing is not applicable. -* Bugs in the target library may accumulate w/o being detected. E.g. a memory +* Bugs in the target library may accumulate without being detected. E.g. a memory corruption that goes undetected at first and then leads to a crash while testing another input. This is why it is highly recommended to run this in-process fuzzer with all sanitizers to detect most bugs on the spot. @@ -477,7 +829,7 @@ Q. When this Fuzzer is not a good solution for a problem? consumption and infinite loops in the target library (still possible). * The target library should not have significant global state that is not reset between the runs. -* Many interesting target libs are not designed in a way that supports +* Many interesting target libraries are not designed in a way that supports the in-process fuzzer interface (e.g. require a file path instead of a byte array). * If a single test run takes a considerable fraction of a second (or @@ -498,10 +850,7 @@ Trophies ======== * GLIBC: https://sourceware.org/glibc/wiki/FuzzingLibc -* MUSL LIBC: - - * http://git.musl-libc.org/cgit/musl/commit/?id=39dfd58417ef642307d90306e1c7e50aaec5a35c - * http://www.openwall.com/lists/oss-security/2015/03/30/3 +* MUSL LIBC: `[1] `__ `[2] `__ * `pugixml `_ @@ -518,23 +867,39 @@ Trophies * `Python `_ -* OpenSSL/BoringSSL: `[1] `_ `[2] `_ `[3] `_ `[4] `_ +* OpenSSL/BoringSSL: `[1] `_ `[2] `_ `[3] `_ `[4] `_ `[5] `_ `[6] `_ * `Libxml2 - `_ + `_ and `[HT206167] `_ (CVE-2015-5312, CVE-2015-7500, CVE-2015-7942) * `Linux Kernel's BPF verifier `_ +* Capstone: `[1] `__ `[2] `__ + +* file:`[1] `__ `[2] `__ `[3] `__ `[4] `__ + +* Radare2: `[1] `__ + +* gRPC: `[1] `__ `[2] `__ `[3] `__ `[4] `__ `[5] `__ `[6] `__ + +* WOFF2: `[1] `__ + * LLVM: `Clang `_, `Clang-format `_, `libc++ `_, `llvm-as `_, Disassembler: http://reviews.llvm.org/rL247405, http://reviews.llvm.org/rL247414, http://reviews.llvm.org/rL247416, http://reviews.llvm.org/rL247417, http://reviews.llvm.org/rL247420, http://reviews.llvm.org/rL247422. .. _pcre2: http://www.pcre.org/ - .. _AFL: http://lcamtuf.coredump.cx/afl/ - .. _SanitizerCoverage: http://clang.llvm.org/docs/SanitizerCoverage.html .. _SanitizerCoverageTraceDataFlow: http://clang.llvm.org/docs/SanitizerCoverage.html#tracing-data-flow .. _DataFlowSanitizer: http://clang.llvm.org/docs/DataFlowSanitizer.html - +.. _AddressSanitizer: http://clang.llvm.org/docs/AddressSanitizer.html +.. _LeakSanitizer: http://clang.llvm.org/docs/LeakSanitizer.html .. _Heartbleed: http://en.wikipedia.org/wiki/Heartbleed - .. _FuzzerInterface.h: https://github.com/llvm-mirror/llvm/blob/master/lib/Fuzzer/FuzzerInterface.h +.. _3.7.0: http://llvm.org/releases/3.7.0/docs/LibFuzzer.html +.. _building Clang from trunk: http://clang.llvm.org/get_started.html +.. _MemorySanitizer: http://clang.llvm.org/docs/MemorySanitizer.html +.. _UndefinedBehaviorSanitizer: http://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html +.. _`coverage counters`: http://clang.llvm.org/docs/SanitizerCoverage.html#coverage-counters +.. _`caller-callee pairs`: http://clang.llvm.org/docs/SanitizerCoverage.html#caller-callee-coverage +.. _BoringSSL: https://boringssl.googlesource.com/boringssl/ +.. _`fuzz various parts of LLVM itself`: `Fuzzing components of LLVM`_ diff --git a/docs/LinkTimeOptimization.rst b/docs/LinkTimeOptimization.rst index 55a7486874a31bfca211bc91e34381649a2fb4f4..9c1e5607596bbd5173a722e5ff9cc444a2c7a4da 100644 --- a/docs/LinkTimeOptimization.rst +++ b/docs/LinkTimeOptimization.rst @@ -87,9 +87,9 @@ To compile, run: .. code-block:: console - % clang -emit-llvm -c a.c -o a.o # <-- a.o is LLVM bitcode file + % clang -flto -c a.c -o a.o # <-- a.o is LLVM bitcode file % clang -c main.c -o main.o # <-- main.o is native object file - % clang a.o main.o -o main # <-- standard link command without modifications + % clang -flto a.o main.o -o main # <-- standard link command with -flto * In this example, the linker recognizes that ``foo2()`` is an externally visible symbol defined in LLVM bitcode file. The linker completes its usual diff --git a/docs/MergeFunctions.rst b/docs/MergeFunctions.rst index 377ea4d698d1d30569fb3598b461ee3150aafb7d..f808010f3acf6d032d3bcb0421ce51565d5d1d51 100644 --- a/docs/MergeFunctions.rst +++ b/docs/MergeFunctions.rst @@ -56,7 +56,7 @@ As a good start point, Kaleidoscope tutorial could be used: Especially it's important to understand chapter 3 of tutorial: -:doc:`tutorial/LangImpl3` +:doc:`tutorial/LangImpl03` Reader also should know how passes work in LLVM, they could use next article as a reference and start point here: diff --git a/docs/NVPTXUsage.rst b/docs/NVPTXUsage.rst index 71acb0c79fc17ce86cc0556d8d03456feaccbf53..8b8c40f1fd7e7fdda625bffcbe015db3a03b6371 100644 --- a/docs/NVPTXUsage.rst +++ b/docs/NVPTXUsage.rst @@ -39,7 +39,7 @@ declare a function as a kernel function. This metadata is attached to the .. code-block:: llvm - !0 = metadata !{, metadata !"kernel", i32 1} + !0 = !{, metadata !"kernel", i32 1} The first parameter is a reference to the kernel function. The following example shows a kernel function calling a device function in LLVM IR. The @@ -54,14 +54,14 @@ function ``@my_kernel`` is callable from host code, but ``@my_fmad`` is not. } define void @my_kernel(float* %ptr) { - %val = load float* %ptr + %val = load float, float* %ptr %ret = call float @my_fmad(float %val, float %val, float %val) store float %ret, float* %ptr ret void } !nvvm.annotations = !{!1} - !1 = metadata !{void (float*)* @my_kernel, metadata !"kernel", i32 1} + !1 = !{void (float*)* @my_kernel, !"kernel", i32 1} When compiled, the PTX kernel functions are callable by host-side code. @@ -361,7 +361,7 @@ With programmatic pass pipeline: .. code-block:: c++ - extern ModulePass *llvm::createNVVMReflectPass(const StringMap& Mapping); + extern FunctionPass *llvm::createNVVMReflectPass(const StringMap& Mapping); StringMap ReflectParams; ReflectParams["__CUDA_FTZ"] = 1; @@ -446,13 +446,13 @@ The Kernel %id = tail call i32 @llvm.nvvm.read.ptx.sreg.tid.x() readnone nounwind ; Compute pointers into A, B, and C - %ptrA = getelementptr float addrspace(1)* %A, i32 %id - %ptrB = getelementptr float addrspace(1)* %B, i32 %id - %ptrC = getelementptr float addrspace(1)* %C, i32 %id + %ptrA = getelementptr float, float addrspace(1)* %A, i32 %id + %ptrB = getelementptr float, float addrspace(1)* %B, i32 %id + %ptrC = getelementptr float, float addrspace(1)* %C, i32 %id ; Read A, B - %valA = load float addrspace(1)* %ptrA, align 4 - %valB = load float addrspace(1)* %ptrB, align 4 + %valA = load float, float addrspace(1)* %ptrA, align 4 + %valB = load float, float addrspace(1)* %ptrB, align 4 ; Compute C = A + B %valC = fadd float %valA, %valB @@ -464,9 +464,9 @@ The Kernel } !nvvm.annotations = !{!0} - !0 = metadata !{void (float addrspace(1)*, - float addrspace(1)*, - float addrspace(1)*)* @kernel, metadata !"kernel", i32 1} + !0 = !{void (float addrspace(1)*, + float addrspace(1)*, + float addrspace(1)*)* @kernel, !"kernel", i32 1} We can use the LLVM ``llc`` tool to directly run the NVPTX code generator: @@ -566,7 +566,7 @@ Intrinsic CUDA Equivalent ``i32 @llvm.nvvm.read.ptx.sreg.ctaid.{x,y,z}`` blockIdx.{x,y,z} ``i32 @llvm.nvvm.read.ptx.sreg.ntid.{x,y,z}`` blockDim.{x,y,z} ``i32 @llvm.nvvm.read.ptx.sreg.nctaid.{x,y,z}`` gridDim.{x,y,z} -``void @llvm.cuda.syncthreads()`` __syncthreads() +``void @llvm.nvvm.barrier0()`` __syncthreads() ================================================ ==================== @@ -608,16 +608,16 @@ as a PTX `kernel` function. These metadata nodes take the form: .. code-block:: text - metadata !{, metadata !"kernel", i32 1} + !{, metadata !"kernel", i32 1} For the previous example, we have: .. code-block:: llvm !nvvm.annotations = !{!0} - !0 = metadata !{void (float addrspace(1)*, - float addrspace(1)*, - float addrspace(1)*)* @kernel, metadata !"kernel", i32 1} + !0 = !{void (float addrspace(1)*, + float addrspace(1)*, + float addrspace(1)*)* @kernel, !"kernel", i32 1} Here, we have a single metadata declaration in ``nvvm.annotations``. This metadata annotates our ``@kernel`` function with the ``kernel`` attribute. @@ -830,13 +830,13 @@ Libdevice provides an ``__nv_powf`` function that we will use. %id = tail call i32 @llvm.nvvm.read.ptx.sreg.tid.x() readnone nounwind ; Compute pointers into A, B, and C - %ptrA = getelementptr float addrspace(1)* %A, i32 %id - %ptrB = getelementptr float addrspace(1)* %B, i32 %id - %ptrC = getelementptr float addrspace(1)* %C, i32 %id + %ptrA = getelementptr float, float addrspace(1)* %A, i32 %id + %ptrB = getelementptr float, float addrspace(1)* %B, i32 %id + %ptrC = getelementptr float, float addrspace(1)* %C, i32 %id ; Read A, B - %valA = load float addrspace(1)* %ptrA, align 4 - %valB = load float addrspace(1)* %ptrB, align 4 + %valA = load float, float addrspace(1)* %ptrA, align 4 + %valB = load float, float addrspace(1)* %ptrB, align 4 ; Compute C = pow(A, B) %valC = call float @__nv_powf(float %valA, float %valB) @@ -848,9 +848,9 @@ Libdevice provides an ``__nv_powf`` function that we will use. } !nvvm.annotations = !{!0} - !0 = metadata !{void (float addrspace(1)*, - float addrspace(1)*, - float addrspace(1)*)* @kernel, metadata !"kernel", i32 1} + !0 = !{void (float addrspace(1)*, + float addrspace(1)*, + float addrspace(1)*)* @kernel, !"kernel", i32 1} To compile this kernel, we perform the following steps: diff --git a/docs/Passes.rst b/docs/Passes.rst index cc0a853bc4deb6a8839a8e1925d35add00e65a0f..77461f3c52d9bc07cf4c74c7926f04b746bc594e 100644 --- a/docs/Passes.rst +++ b/docs/Passes.rst @@ -253,14 +253,6 @@ This pass decodes the debug info metadata in a module and prints in a For example, run this pass from ``opt`` along with the ``-analyze`` option, and it'll print to standard output. -``-no-aa``: No Alias Analysis (always returns 'may' alias) ----------------------------------------------------------- - -This is the default implementation of the Alias Analysis interface. It always -returns "I don't know" for alias queries. NoAA is unlike other alias analysis -implementations, in that it does not chain to a previous analysis. As such it -doesn't follow many of the rules that other alias analyses must. - ``-postdomfrontier``: Post-Dominance Frontier Construction ---------------------------------------------------------- @@ -955,7 +947,7 @@ that this should make CFG hacking much easier. To make later hacking easier, the entry block is split into two, such that all introduced ``alloca`` instructions (and nothing else) are in the entry block. -``-scalarrepl``: Scalar Replacement of Aggregates (DT) +``-sroa``: Scalar Replacement of Aggregates ------------------------------------------------------ The well-known scalar replacement of aggregates transformation. This transform @@ -964,12 +956,6 @@ individual ``alloca`` instructions for each member if possible. Then, if possible, it transforms the individual ``alloca`` instructions into nice clean scalar SSA form. -This combines a simple scalar replacement of aggregates algorithm with the -:ref:`mem2reg ` algorithm because they often interact, -especially for C++ programs. As such, iterating between ``scalarrepl``, then -:ref:`mem2reg ` until we run out of things to promote works -well. - .. _passes-sccp: ``-sccp``: Sparse Conditional Constant Propagation diff --git a/docs/ProgrammersManual.rst b/docs/ProgrammersManual.rst index 32145550fe2b4adf5655b089270c0ca9613e990e..030637048bfb21a2627d9ef8b92da547a0e68612 100644 --- a/docs/ProgrammersManual.rst +++ b/docs/ProgrammersManual.rst @@ -480,7 +480,7 @@ The ``function_ref`` class template ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``function_ref`` -(`doxygen `__) class +(`doxygen `__) class template represents a reference to a callable object, templated over the type of the callable. This is a good choice for passing a callback to a function, if you don't need to hold onto the callback after the function returns. In this @@ -2221,7 +2221,7 @@ sequence of instructions that form a ``BasicBlock``: CallInst* callTwo = Builder.CreateCall(...); Value* result = Builder.CreateMul(callOne, callTwo); - See :doc:`tutorial/LangImpl3` for a practical use of the ``IRBuilder``. + See :doc:`tutorial/LangImpl03` for a practical use of the ``IRBuilder``. .. _schanges_deleting: @@ -2419,11 +2419,6 @@ determine what context they belong to by looking at their own ``Type``. If you are adding new entities to LLVM IR, please try to maintain this interface design. -For clients that do *not* require the benefits of isolation, LLVM provides a -convenience API ``getGlobalContext()``. This returns a global, lazily -initialized ``LLVMContext`` that may be used in situations where isolation is -not a concern. - .. _jitthreading: Threads and the JIT diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index 982ade993b3eb448906e143b8f3062cb0d62b57f..54f2d530b1e7d80ae24ca21d480ea307393ad2be 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -38,6 +38,8 @@ Non-comprehensive list of changes in this release (other than GlobalValue). This is intended to be used in release builds by clients that are interested in saving CPU/memory as much as possible. +* There is no longer a "global context" available in LLVM, except for the C API. + * .. note about autoconf build having been removed. * .. note about C API functions LLVMParseBitcode, @@ -52,6 +54,26 @@ Non-comprehensive list of changes in this release * The C API function LLVMGetDataLayout is deprecated in favor of LLVMGetDataLayoutStr. +* The C API enum LLVMAttribute and associated API is deprecated in favor of + the new LLVMAttributeRef API. The deprecated functions are + LLVMAddFunctionAttr, LLVMAddTargetDependentFunctionAttr, + LLVMRemoveFunctionAttr, LLVMGetFunctionAttr, LLVMAddAttribute, + LLVMRemoveAttribute, LLVMGetAttribute, LLVMAddInstrAttribute, + LLVMRemoveInstrAttribute and LLVMSetInstrParamAlignment. + +* ``TargetFrameLowering::eliminateCallFramePseudoInstr`` now returns an + iterator to the next instruction instead of ``void``. Targets that previously + did ``MBB.erase(I); return;`` now probably want ``return MBB.erase(I);``. + +* ``SelectionDAGISel::Select`` now returns ``void``. Out of tree targets will + need to be updated to replace the argument node and remove any dead nodes in + cases where they currently return an ``SDNode *`` from this interface. + +* Introduction of ThinLTO: [FIXME: needs to be documented more extensively in + /docs/ ; ping Mehdi/Teresa before the release if not done] + +* Raised the minimum required CMake version to 3.4.3. + .. NOTE For small 1-3 sentence descriptions, just add an entry at the end of this list. If your description won't fit comfortably in one bullet @@ -71,6 +93,23 @@ Non-comprehensive list of changes in this release Makes programs 10x faster by doing Special New Thing. +Changes to the LLVM IR +---------------------- + +* New intrinsics ``llvm.masked.load``, ``llvm.masked.store``, + ``llvm.masked.gather`` and ``llvm.masked.scatter`` were introduced to the + LLVM IR to allow selective memory access for vector data types. + +Changes to LLVM's IPO model +--------------------------- + +LLVM no longer does inter-procedural analysis and optimization (except +inlining) on functions with comdat linkage. Doing IPO over such +functions is unsound because the implementation the linker chooses at +link-time may be differently optimized than the one what was visible +during optimization, and may have arbitrarily different observable +behavior. See `PR26774 `_ for more details. + Changes to the ARM Backend -------------------------- @@ -86,13 +125,20 @@ Changes to the MIPS Target Changes to the PowerPC Target ----------------------------- - During this release ... + Moved some optimizations from O3 to O2 (D18562) +* Enable sibling call optimization on ppc64 ELFv1/ELFv2 abi Changes to the X86 Target ------------------------------ +------------------------- - During this release ... +* LLVM now supports the Intel CPU codenamed Skylake Server with AVX-512 + extensions using ``-march=skylake-avx512``. The switch enables the + ISA extensions AVX-512{F, CD, VL, BW, DQ}. + +* LLVM now supports the Intel CPU codenamed Knights Landing with AVX-512 + extensions using ``-march=knl``. The switch enables the ISA extensions + AVX-512{F, CD, ER, PF}. Changes to the AMDGPU Target ----------------------------- diff --git a/docs/ReportingGuide.rst b/docs/ReportingGuide.rst new file mode 100644 index 0000000000000000000000000000000000000000..f7ecbb38d45e40001af862ea9b5a1a25ac7e74fd --- /dev/null +++ b/docs/ReportingGuide.rst @@ -0,0 +1,143 @@ +=============== +Reporting Guide +=============== + +.. note:: + + This document is currently a **DRAFT** document while it is being discussed + by the community. + +If you believe someone is violating the :doc:`code of conduct ` +you can always report it to the LLVM Foundation Code of Conduct Advisory +Committee by emailing conduct@llvm.org. **All reports will be kept +confidential.** This isn't a public list and only `members`_ of the advisory +committee will receive the report. + +If you believe anyone is in **physical danger**, please notify appropriate law +enforcement first. If you are unsure what law enforcement agency is +appropriate, please include this in your report and we will attempt to notify +them. + +If the violation occurs at an event such as a Developer Meeting and requires +immediate attention, you can also reach out to any of the event organizers or +staff. Event organizers and staff will be prepared to handle the incident and +able to help. If you cannot find one of the organizers, the venue staff can +locate one for you. We will also post detailed contact information for specific +events as part of each events' information. In person reports will still be +kept confidential exactly as above, but also feel free to (anonymously if +needed) email conduct@llvm.org. + +.. note:: + The LLVM community has long handled inappropriate behavior on its own, using + both private communication and public responses. Nothing in this document is + intended to discourage this self enforcement of community norms. Instead, + the mechanisms described here are intended to supplement any self + enforcement within the community. They provide avenues for handling severe + cases or cases where the reporting party does not wish to respond directly + for any reason. + +Filing a report +=============== + +Reports can be as formal or informal as needed for the situation at hand. If +possible, please include as much information as you can. If you feel +comfortable, please consider including: + +* Your contact info (so we can get in touch with you if we need to follow up). +* Names (real, nicknames, or pseudonyms) of any individuals involved. If there + were other witnesses besides you, please try to include them as well. +* When and where the incident occurred. Please be as specific as possible. +* Your account of what occurred. If there is a publicly available record (e.g. + a mailing list archive or a public IRC logger) please include a link. +* Any extra context you believe existed for the incident. +* If you believe this incident is ongoing. +* Any other information you believe we should have. + +What happens after you file a report? +===================================== + +You will receive an email from the advisory committee acknowledging receipt +within 24 hours (and we will aim to respond much quicker than that). + +The advisory committee will immediately meet to review the incident and try to +determine: + +* What happened and who was involved. +* Whether this event constitutes a code of conduct violation. +* Whether this is an ongoing situation, or if there is a threat to anyone's + physical safety. + +If this is determined to be an ongoing incident or a threat to physical safety, +the working groups' immediate priority will be to protect everyone involved. +This means we may delay an "official" response until we believe that the +situation has ended and that everyone is physically safe. + +The working group will try to contact other parties involved or witnessing the +event to gain clarity on what happened and understand any different +perspectives. + +Once the advisory committee has a complete account of the events they will make +a decision as to how to respond. Responses may include: + +* Nothing, if we determine no violation occurred or it has already been + appropriately resolved. +* Providing either moderation or mediation to ongoing interactions (where + appropriate, safe, and desired by both parties). +* A private reprimand from the working group to the individuals involved. +* An imposed vacation (i.e. asking someone to "take a week off" from a mailing + list or IRC). +* A public reprimand. +* A permanent or temporary ban from some or all LLVM spaces (mailing lists, + IRC, etc.) +* Involvement of relevant law enforcement if appropriate. + +If the situation is not resolved within one week, we'll respond within one week +to the original reporter with an update and explanation. + +Once we've determined our response, we will separately contact the original +reporter and other individuals to let them know what actions (if any) we'll be +taking. We will take into account feedback from the individuals involved on the +appropriateness of our response, but we don't guarantee we'll act on it. + +After any incident, the advisory committee will make a report on the situation +to the LLVM Foundation board. The board may choose to make a public statement +about the incident. If that's the case, the identities of anyone involved will +remain confidential unless instructed by those inviduals otherwise. + +Appealing +========= + +Only permanent resolutions (such as bans) or requests for public actions may be +appealed. To appeal a decision of the working group, contact the LLVM +Foundation board at board@llvm.org with your appeal and the board will review +the case. + +In general, it is **not** appropriate to appeal a particular decision on +a public mailing list. Doing so would involve disclosure of information which +whould be confidential. Disclosing this kind of information publicly may be +considered a separate and (potentially) more serious violation of the Code of +Conduct. This is not meant to limit discussion of the Code of Conduct, the +advisory board itself, or the appropriateness of responses in general, but +**please** refrain from mentioning specific facts about cases without the +explicit permission of all parties involved. + +.. _members: + +Members of the Code of Conduct Advisory Committee +================================================= + +The members serving on the advisory committee are listed here with contact +information in case you are more comfortable talking directly to a specific +member of the committee. + +.. note:: + + FIXME: When we form the initial advisory committee, the members names and private contact info need to be added here. + + + +(This text is based on the `Django Project`_ Code of Conduct, which is in turn +based on wording from the `Speak Up! project`_.) + +.. _Django Project: https://www.djangoproject.com/conduct/ +.. _Speak Up! project: http://speakup.io/coc.html diff --git a/docs/ScudoHardenedAllocator.rst b/docs/ScudoHardenedAllocator.rst new file mode 100644 index 0000000000000000000000000000000000000000..5bc390eadd5c4997f0eb8bfea3e2be1c5fc38bf5 --- /dev/null +++ b/docs/ScudoHardenedAllocator.rst @@ -0,0 +1,117 @@ +======================== +Scudo Hardened Allocator +======================== + +.. contents:: + :local: + :depth: 1 + +Introduction +============ +The Scudo Hardened Allocator is a user-mode allocator based on LLVM Sanitizer's +CombinedAllocator, which aims at providing additional mitigations against heap +based vulnerabilities, while maintaining good performance. + +The name "Scudo" has been retained from the initial implementation (Escudo +meaning Shield in Spanish and Portuguese). + +Design +====== +Chunk Header +------------ +Every chunk of heap memory will be preceded by a chunk header. This has two +purposes, the first one being to store various information about the chunk, +the second one being to detect potential heap overflows. In order to achieve +this, the header will be checksumed, involving the pointer to the chunk itself +and a global secret. Any corruption of the header will be detected when said +header is accessed, and the process terminated. + +The following information is stored in the header: + +- the 16-bit checksum; +- the user requested size for that chunk, which is necessary for reallocation + purposes; +- the state of the chunk (available, allocated or quarantined); +- the allocation type (malloc, new, new[] or memalign), to detect potential + mismatches in the allocation APIs used; +- whether or not the chunk is offseted (ie: if the chunk beginning is different + than the backend allocation beginning, which is most often the case with some + aligned allocations); +- the associated offset; +- a 16-bit salt. + +On x64, which is currently the only architecture supported, the header fits +within 16-bytes, which works nicely with the minimum alignment requirements. + +The checksum is computed as a CRC32 (requiring the SSE 4.2 instruction set) +of the global secret, the chunk pointer itself, and the 16 bytes of header with +the checksum field zeroed out. + +The header is atomically loaded and stored to prevent races (this requires +platform support such as the cmpxchg16b instruction). This is important as two +consecutive chunks could belong to different threads. We also want to avoid +any type of double fetches of information located in the header, and use local +copies of the header for this purpose. + +Delayed Freelist +----------------- +A delayed freelist allows us to not return a chunk directly to the backend, but +to keep it aside for a while. Once a criterion is met, the delayed freelist is +emptied, and the quarantined chunks are returned to the backend. This helps +mitigate use-after-free vulnerabilities by reducing the determinism of the +allocation and deallocation patterns. + +This feature is using the Sanitizer's Quarantine as its base, and the amount of +memory that it can hold is configurable by the user (see the Options section +below). + +Randomness +---------- +It is important for the allocator to not make use of fixed addresses. We use +the dynamic base option for the SizeClassAllocator, allowing us to benefit +from the randomness of mmap. + +Usage +===== + +Library +------- +The allocator static library can be built from the LLVM build tree thanks to +the "scudo" CMake rule. The associated tests can be exercised thanks to the +"check-scudo" CMake rule. + +Linking the static library to your project can require the use of the +"whole-archive" linker flag (or equivalent), depending on your linker. +Additional flags might also be necessary. + +Your linked binary should now make use of the Scudo allocation and deallocation +functions. + +Options +------- +Several aspects of the allocator can be configured through environment options, +following the usual ASan options syntax, through the variable SCUDO_OPTIONS. + +For example: SCUDO_OPTIONS="DeleteSizeMismatch=1:QuarantineSizeMb=16". + +The following options are available: + +- QuarantineSizeMb (integer, defaults to 64): the size (in Mb) of quarantine + used to delay the actual deallocation of chunks. Lower value may reduce + memory usage but decrease the effectiveness of the mitigation; a negative + value will fallback to a default of 64Mb; + +- ThreadLocalQuarantineSizeKb (integer, default to 1024): the size (in Kb) of + per-thread cache used to offload the global quarantine. Lower value may + reduce memory usage but might increase the contention on the global + quarantine. + +- DeallocationTypeMismatch (boolean, defaults to true): whether or not we report + errors on malloc/delete, new/free, new/delete[], etc; + +- DeleteSizeMismatch (boolean, defaults to true): whether or not we report + errors on mismatch between size of new and delete; + +- ZeroContents (boolean, defaults to false): whether or not we zero chunk + contents on allocation and deallocation. + diff --git a/docs/SourceLevelDebugging.rst b/docs/SourceLevelDebugging.rst index 300096b7ccf02184464cb4aa316e4acbaac66f7b..1815ee398e0c1666a6dcc7c4e98e10373184f15f 100644 --- a/docs/SourceLevelDebugging.rst +++ b/docs/SourceLevelDebugging.rst @@ -63,16 +63,18 @@ away during the compilation process. This meta information provides an LLVM user a relationship between generated code and the original program source code. -Currently, debug information is consumed by DwarfDebug to produce dwarf -information used by the gdb debugger. Other targets could use the same -information to produce stabs or other debug forms. +Currently, there are two backend consumers of debug info: DwarfDebug and +CodeViewDebug. DwarfDebug produces DWARF sutable for use with GDB, LLDB, and +other DWARF-based debuggers. :ref:`CodeViewDebug ` produces CodeView, +the Microsoft debug info format, which is usable with Microsoft debuggers such +as Visual Studio and WinDBG. LLVM's debug information format is mostly derived +from and inspired by DWARF, but it is feasible to translate into other target +debug info formats such as STABS. It would also be reasonable to use debug information to feed profiling tools for analysis of generated code, or, tools for reconstructing the original source from generated code. -TODO - expound a bit more. - .. _intro_debugopt: Debugging optimized code @@ -259,7 +261,7 @@ Compiled to LLVM, this function would be represented like this: !llvm.module.flags = !{!7, !8, !9} !llvm.ident = !{!10} - !0 = !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.7.0 (trunk 231150) (llvm/trunk 231154)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2) + !0 = !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.7.0 (trunk 231150) (llvm/trunk 231154)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2) !1 = !DIFile(filename: "/dev/stdin", directory: "/Users/dexonsmith/data/llvm/debug-info") !2 = !{} !3 = !{!4} @@ -407,7 +409,7 @@ a C/C++ front-end would generate the following descriptors: !0 = !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.7.0 (trunk 231150) (llvm/trunk 231154)", - isOptimized: false, runtimeVersion: 0, emissionKind: 1, + isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, subprograms: !2, globals: !3, imports: !2) @@ -679,7 +681,13 @@ New DWARF Constants | DW_APPLE_PROPERTY_strong | 0x400 | +--------------------------------------+-------+ | DW_APPLE_PROPERTY_unsafe_unretained | 0x800 | -+--------------------------------+-----+-------+ ++--------------------------------------+-------+ +| DW_APPLE_PROPERTY_nullability | 0x1000| ++--------------------------------------+-------+ +| DW_APPLE_PROPERTY_null_resettable | 0x2000| ++--------------------------------------+-------+ +| DW_APPLE_PROPERTY_class | 0x4000| ++--------------------------------------+-------+ Name Accelerator Tables ----------------------- @@ -1333,3 +1341,74 @@ names as follows: * "``.apple_namespaces``" -> "``__apple_namespac``" (16 character limit) * "``.apple_objc``" -> "``__apple_objc``" +.. _codeview: + +CodeView Debug Info Format +========================== + +LLVM supports emitting CodeView, the Microsoft debug info format, and this +section describes the design and implementation of that support. + +Format Background +----------------- + +CodeView as a format is clearly oriented around C++ debugging, and in C++, the +majority of debug information tends to be type information. Therefore, the +overriding design constraint of CodeView is the separation of type information +from other "symbol" information so that type information can be efficiently +merged across translation units. Both type information and symbol information is +generally stored as a sequence of records, where each record begins with a +16-bit record size and a 16-bit record kind. + +Type information is usually stored in the ``.debug$T`` section of the object +file. All other debug info, such as line info, string table, symbol info, and +inlinee info, is stored in one or more ``.debug$S`` sections. There may only be +one ``.debug$T`` section per object file, since all other debug info refers to +it. If a PDB (enabled by the ``/Zi`` MSVC option) was used during compilation, +the ``.debug$T`` section will contain only an ``LF_TYPESERVER2`` record pointing +to the PDB. When using PDBs, symbol information appears to remain in the object +file ``.debug$S`` sections. + +Type records are referred to by their index, which is the number of records in +the stream before a given record plus ``0x1000``. Many common basic types, such +as the basic integral types and unqualified pointers to them, are represented +using type indices less than ``0x1000``. Such basic types are built in to +CodeView consumers and do not require type records. + +Each type record may only contain type indices that are less than its own type +index. This ensures that the graph of type stream references is acyclic. While +the source-level type graph may contain cycles through pointer types (consider a +linked list struct), these cycles are removed from the type stream by always +referring to the forward declaration record of user-defined record types. Only +"symbol" records in the ``.debug$S`` streams may refer to complete, +non-forward-declaration type records. + +Working with CodeView +--------------------- + +These are instructions for some common tasks for developers working to improve +LLVM's CodeView support. Most of them revolve around using the CodeView dumper +embedded in ``llvm-readobj``. + +* Testing MSVC's output:: + + $ cl -c -Z7 foo.cpp # Use /Z7 to keep types in the object file + $ llvm-readobj -codeview foo.obj + +* Getting LLVM IR debug info out of Clang:: + + $ clang -g -gcodeview --target=x86_64-windows-msvc foo.cpp -S -emit-llvm + + Use this to generate LLVM IR for LLVM test cases. + +* Generate and dump CodeView from LLVM IR metadata:: + + $ llc foo.ll -filetype=obj -o foo.obj + $ llvm-readobj -codeview foo.obj > foo.txt + + Use this pattern in lit test cases and FileCheck the output of llvm-readobj + +Improving LLVM's CodeView support is a process of finding interesting type +records, constructing a C++ test case that makes MSVC emit those records, +dumping the records, understanding them, and then generating equivalent records +in LLVM's backend. diff --git a/docs/TableGen/LangRef.rst b/docs/TableGen/LangRef.rst index 27b2c8beaa69a47ad0a2b4c403d716ab2eed6f5a..58da6285c077eac82ef172448242da171921d143 100644 --- a/docs/TableGen/LangRef.rst +++ b/docs/TableGen/LangRef.rst @@ -154,7 +154,7 @@ programmer. .. productionlist:: Declaration: `Type` `TokIdentifier` ["=" `Value`] -It assigns the value to the identifer. +It assigns the value to the identifier. Types ----- diff --git a/docs/TestingGuide.rst b/docs/TestingGuide.rst index ced0fd34a6e7152e97f629e54f30885b2cca74f5..5dac58309e45ae201e2e360eb96c684b46fc0b90 100644 --- a/docs/TestingGuide.rst +++ b/docs/TestingGuide.rst @@ -25,6 +25,10 @@ In order to use the LLVM testing infrastructure, you will need all of the software required to build LLVM, as well as `Python `_ 2.7 or later. +If you intend to run the :ref:`test-suite `, you will also +need a development version of zlib (zlib1g-dev is known to work on several Linux +distributions). + LLVM testing infrastructure organization ======================================== @@ -383,6 +387,23 @@ depends on special features of sub-architectures, you must add the specific triple, test with the specific FileCheck and put it into the specific directory that will filter out all other architectures. +REQUIRES and REQUIRES-ANY directive +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests can be enabled only in specific situation - like having +debug build. Use ``REQUIRES`` directive to specify those requirements. + +.. code-block:: llvm + + ; This test will be only enabled in the build with asserts + ; REQUIRES: asserts + +You can separate requirements by a comma. +``REQUIRES`` means all listed requirements must be satisfied. +``REQUIRES-ANY`` means at least one must be satisfied. + +List of features that can be used in ``REQUIRES`` and ``REQUIRES-ANY`` can be +found in lit.cfg files. Substitutions ------------- @@ -535,6 +556,8 @@ the last RUN: line. This has two side effects: (b) it speeds things up for really big test cases by avoiding interpretation of the remainder of the file. +.. _test-suite-overview: + ``test-suite`` Overview ======================= diff --git a/docs/TypeMetadata.rst b/docs/TypeMetadata.rst new file mode 100644 index 0000000000000000000000000000000000000000..98d58b71a6d3b63bfa5a1113a14bbb1647482b51 --- /dev/null +++ b/docs/TypeMetadata.rst @@ -0,0 +1,226 @@ +============= +Type Metadata +============= + +Type metadata is a mechanism that allows IR modules to co-operatively build +pointer sets corresponding to addresses within a given set of globals. LLVM's +`control flow integrity`_ implementation uses this metadata to efficiently +check (at each call site) that a given address corresponds to either a +valid vtable or function pointer for a given class or function type, and its +whole-program devirtualization pass uses the metadata to identify potential +callees for a given virtual call. + +To use the mechanism, a client creates metadata nodes with two elements: + +1. a byte offset into the global (generally zero for functions) +2. a metadata object representing an identifier for the type + +These metadata nodes are associated with globals by using global object +metadata attachments with the ``!type`` metadata kind. + +Each type identifier must exclusively identify either global variables +or functions. + +.. admonition:: Limitation + + The current implementation only supports attaching metadata to functions on + the x86-32 and x86-64 architectures. + +An intrinsic, :ref:`llvm.type.test `, is used to test whether a +given pointer is associated with a type identifier. + +.. _control flow integrity: http://clang.llvm.org/docs/ControlFlowIntegrity.html + +Representing Type Information using Type Metadata +================================================= + +This section describes how Clang represents C++ type information associated with +virtual tables using type metadata. + +Consider the following inheritance hierarchy: + +.. code-block:: c++ + + struct A { + virtual void f(); + }; + + struct B : A { + virtual void f(); + virtual void g(); + }; + + struct C { + virtual void h(); + }; + + struct D : A, C { + virtual void f(); + virtual void h(); + }; + +The virtual table objects for A, B, C and D look like this (under the Itanium ABI): + +.. csv-table:: Virtual Table Layout for A, B, C, D + :header: Class, 0, 1, 2, 3, 4, 5, 6 + + A, A::offset-to-top, &A::rtti, &A::f + B, B::offset-to-top, &B::rtti, &B::f, &B::g + C, C::offset-to-top, &C::rtti, &C::h + D, D::offset-to-top, &D::rtti, &D::f, &D::h, D::offset-to-top, &D::rtti, thunk for &D::h + +When an object of type A is constructed, the address of ``&A::f`` in A's +virtual table object is stored in the object's vtable pointer. In ABI parlance +this address is known as an `address point`_. Similarly, when an object of type +B is constructed, the address of ``&B::f`` is stored in the vtable pointer. In +this way, the vtable in B's virtual table object is compatible with A's vtable. + +D is a little more complicated, due to the use of multiple inheritance. Its +virtual table object contains two vtables, one compatible with A's vtable and +the other compatible with C's vtable. Objects of type D contain two virtual +pointers, one belonging to the A subobject and containing the address of +the vtable compatible with A's vtable, and the other belonging to the C +subobject and containing the address of the vtable compatible with C's vtable. + +The full set of compatibility information for the above class hierarchy is +shown below. The following table shows the name of a class, the offset of an +address point within that class's vtable and the name of one of the classes +with which that address point is compatible. + +.. csv-table:: Type Offsets for A, B, C, D + :header: VTable for, Offset, Compatible Class + + A, 16, A + B, 16, A + , , B + C, 16, C + D, 16, A + , , D + , 48, C + +The next step is to encode this compatibility information into the IR. The way +this is done is to create type metadata named after each of the compatible +classes, with which we associate each of the compatible address points in +each vtable. For example, these type metadata entries encode the compatibility +information for the above hierarchy: + +:: + + @_ZTV1A = constant [...], !type !0 + @_ZTV1B = constant [...], !type !0, !type !1 + @_ZTV1C = constant [...], !type !2 + @_ZTV1D = constant [...], !type !0, !type !3, !type !4 + + !0 = !{i64 16, !"_ZTS1A"} + !1 = !{i64 16, !"_ZTS1B"} + !2 = !{i64 16, !"_ZTS1C"} + !3 = !{i64 16, !"_ZTS1D"} + !4 = !{i64 48, !"_ZTS1C"} + +With this type metadata, we can now use the ``llvm.type.test`` intrinsic to +test whether a given pointer is compatible with a type identifier. Working +backwards, if ``llvm.type.test`` returns true for a particular pointer, +we can also statically determine the identities of the virtual functions +that a particular virtual call may call. For example, if a program assumes +a pointer to be a member of ``!"_ZST1A"``, we know that the address can +be only be one of ``_ZTV1A+16``, ``_ZTV1B+16`` or ``_ZTV1D+16`` (i.e. the +address points of the vtables of A, B and D respectively). If we then load +an address from that pointer, we know that the address can only be one of +``&A::f``, ``&B::f`` or ``&D::f``. + +.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general + +Testing Addresses For Type Membership +===================================== + +If a program tests an address using ``llvm.type.test``, this will cause +a link-time optimization pass, ``LowerTypeTests``, to replace calls to this +intrinsic with efficient code to perform type member tests. At a high level, +the pass will lay out referenced globals in a consecutive memory region in +the object file, construct bit vectors that map onto that memory region, +and generate code at each of the ``llvm.type.test`` call sites to test +pointers against those bit vectors. Because of the layout manipulation, the +globals' definitions must be available at LTO time. For more information, +see the `control flow integrity design document`_. + +A type identifier that identifies functions is transformed into a jump table, +which is a block of code consisting of one branch instruction for each +of the functions associated with the type identifier that branches to the +target function. The pass will redirect any taken function addresses to the +corresponding jump table entry. In the object file's symbol table, the jump +table entries take the identities of the original functions, so that addresses +taken outside the module will pass any verification done inside the module. + +Jump tables may call external functions, so their definitions need not +be available at LTO time. Note that if an externally defined function is +associated with a type identifier, there is no guarantee that its identity +within the module will be the same as its identity outside of the module, +as the former will be the jump table entry if a jump table is necessary. + +The `GlobalLayoutBuilder`_ class is responsible for laying out the globals +efficiently to minimize the sizes of the underlying bitsets. + +.. _control flow integrity design document: http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html + +:Example: + +:: + + target datalayout = "e-p:32:32" + + @a = internal global i32 0, !type !0 + @b = internal global i32 0, !type !0, !type !1 + @c = internal global i32 0, !type !1 + @d = internal global [2 x i32] [i32 0, i32 0], !type !2 + + define void @e() !type !3 { + ret void + } + + define void @f() { + ret void + } + + declare void @g() !type !3 + + !0 = !{i32 0, !"typeid1"} + !1 = !{i32 0, !"typeid2"} + !2 = !{i32 4, !"typeid2"} + !3 = !{i32 0, !"typeid3"} + + declare i1 @llvm.type.test(i8* %ptr, metadata %typeid) nounwind readnone + + define i1 @foo(i32* %p) { + %pi8 = bitcast i32* %p to i8* + %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid1") + ret i1 %x + } + + define i1 @bar(i32* %p) { + %pi8 = bitcast i32* %p to i8* + %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid2") + ret i1 %x + } + + define i1 @baz(void ()* %p) { + %pi8 = bitcast void ()* %p to i8* + %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid3") + ret i1 %x + } + + define void @main() { + %a1 = call i1 @foo(i32* @a) ; returns 1 + %b1 = call i1 @foo(i32* @b) ; returns 1 + %c1 = call i1 @foo(i32* @c) ; returns 0 + %a2 = call i1 @bar(i32* @a) ; returns 0 + %b2 = call i1 @bar(i32* @b) ; returns 1 + %c2 = call i1 @bar(i32* @c) ; returns 1 + %d02 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 0)) ; returns 0 + %d12 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 1)) ; returns 1 + %e = call i1 @baz(void ()* @e) ; returns 1 + %f = call i1 @baz(void ()* @f) ; returns 0 + %g = call i1 @baz(void ()* @g) ; returns 1 + ret void + } + +.. _GlobalLayoutBuilder: http://llvm.org/klaus/llvm/blob/master/include/llvm/Transforms/IPO/LowerTypeTests.h diff --git a/docs/WritingAnLLVMBackend.rst b/docs/WritingAnLLVMBackend.rst index fdadbb04e94f73bf4e7c6e415101dbc8a7a87e5b..023f6ffc46029a1cb06cf1a9e4add95a7f745dde 100644 --- a/docs/WritingAnLLVMBackend.rst +++ b/docs/WritingAnLLVMBackend.rst @@ -135,14 +135,13 @@ First, you should create a subdirectory under ``lib/Target`` to hold all the files related to your target. If your target is called "Dummy", create the directory ``lib/Target/Dummy``. -In this new directory, create a ``Makefile``. It is easiest to copy a -``Makefile`` of another target and modify it. It should at least contain the -``LEVEL``, ``LIBRARYNAME`` and ``TARGET`` variables, and then include -``$(LEVEL)/Makefile.common``. The library can be named ``LLVMDummy`` (for -example, see the MIPS target). Alternatively, you can split the library into -``LLVMDummyCodeGen`` and ``LLVMDummyAsmPrinter``, the latter of which should be -implemented in a subdirectory below ``lib/Target/Dummy`` (for example, see the -PowerPC target). +In this new directory, create a ``CMakeLists.txt``. It is easiest to copy a +``CMakeLists.txt`` of another target and modify it. It should at least contain +the ``LLVM_TARGET_DEFINITIONS`` variable. The library can be named ``LLVMDummy`` +(for example, see the MIPS target). Alternatively, you can split the library +into ``LLVMDummyCodeGen`` and ``LLVMDummyAsmPrinter``, the latter of which +should be implemented in a subdirectory below ``lib/Target/Dummy`` (for example, +see the PowerPC target). Note that these two naming schemes are hardcoded into ``llvm-config``. Using any other naming scheme will confuse ``llvm-config`` and produce a lot of @@ -156,13 +155,12 @@ generator, you should do what all current machine backends do: create a subclass of ``LLVMTargetMachine``. (To create a target from scratch, create a subclass of ``TargetMachine``.) -To get LLVM to actually build and link your target, you need to add it to the -``TARGETS_TO_BUILD`` variable. To do this, you modify the configure script to -know about your target when parsing the ``--enable-targets`` option. Search -the configure script for ``TARGETS_TO_BUILD``, add your target to the lists -there (some creativity required), and then reconfigure. Alternatively, you can -change ``autoconf/configure.ac`` and regenerate configure by running -``./autoconf/AutoRegen.sh``. +To get LLVM to actually build and link your target, you need to run ``cmake`` +with ``-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=Dummy``. This will build your +target without needing to add it to the list of all the targets. + +Once your target is stable, you can add it to the ``LLVM_ALL_TARGETS`` variable +located in the main ``CMakeLists.txt``. Target Machine ============== diff --git a/docs/index.rst b/docs/index.rst index 2f253485dd0e457bcf71deecd2be0150b562ad6e..ef1d4ec64eb5509b29c611d3a95677e7a2535910 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -65,6 +65,7 @@ representation. :hidden: CMake + CMakePrimer AdvancedBuilds HowToBuildOnARM HowToCrossCompileLLVM @@ -86,7 +87,9 @@ representation. GetElementPtr Frontend/PerformanceTips MCJITDesignAndImplementation + CodeOfConduct CompileCudaWithLLVM + ReportingGuide :doc:`GettingStarted` Discusses how to get up and running quickly with the LLVM infrastructure. @@ -175,6 +178,7 @@ For developers of applications which use LLVM as a library. ProgrammersManual Extensions LibFuzzer + ScudoHardenedAllocator :doc:`LLVM Language Reference Manual ` Defines the LLVM intermediate representation and the assembly form of the @@ -219,6 +223,9 @@ For developers of applications which use LLVM as a library. :doc:`LibFuzzer` A library for writing in-process guided fuzzers. +:doc:`ScudoHardenedAllocator` + A library that implements a security-hardened `malloc()`. + Subsystem Documentation ======================= @@ -256,7 +263,7 @@ For API clients and LLVM developers. CoverageMappingFormat Statepoints MergeFunctions - BitSets + TypeMetadata FaultMaps MIRLangRef diff --git a/docs/tutorial/BuildingAJIT1.rst b/docs/tutorial/BuildingAJIT1.rst new file mode 100644 index 0000000000000000000000000000000000000000..f30b979579dcf794c3114f956adcd7869f396a71 --- /dev/null +++ b/docs/tutorial/BuildingAJIT1.rst @@ -0,0 +1,375 @@ +======================================================= +Building a JIT: Starting out with KaleidoscopeJIT +======================================================= + +.. contents:: + :local: + +Chapter 1 Introduction +====================== + +Welcome to Chapter 1 of the "Building an ORC-based JIT in LLVM" tutorial. This +tutorial runs through the implementation of a JIT compiler using LLVM's +On-Request-Compilation (ORC) APIs. It begins with a simplified version of the +KaleidoscopeJIT class used in the +`Implementing a language with LLVM `_ tutorials and then +introduces new features like optimization, lazy compilation and remote +execution. + +The goal of this tutorial is to introduce you to LLVM's ORC JIT APIs, show how +these APIs interact with other parts of LLVM, and to teach you how to recombine +them to build a custom JIT that is suited to your use-case. + +The structure of the tutorial is: + +- Chapter #1: Investigate the simple KaleidoscopeJIT class. This will + introduce some of the basic concepts of the ORC JIT APIs, including the + idea of an ORC *Layer*. + +- `Chapter #2 `_: Extend the basic KaleidoscopeJIT by adding + a new layer that will optimize IR and generated code. + +- `Chapter #3 `_: Further extend the JIT by adding a + Compile-On-Demand layer to lazily compile IR. + +- `Chapter #4 `_: Improve the laziness of our JIT by + replacing the Compile-On-Demand layer with a custom layer that uses the ORC + Compile Callbacks API directly to defer IR-generation until functions are + called. + +- `Chapter #5 `_: Add process isolation by JITing code into + a remote process with reduced privileges using the JIT Remote APIs. + +To provide input for our JIT we will use the Kaleidoscope REPL from +`Chapter 7 `_ of the "Implementing a language in LLVM tutorial", +with one minor modification: We will remove the FunctionPassManager from the +code for that chapter and replace it with optimization support in our JIT class +in Chapter #2. + +Finally, a word on API generations: ORC is the 3rd generation of LLVM JIT API. +It was preceded by MCJIT, and before that by the (now deleted) legacy JIT. +These tutorials don't assume any experience with these earlier APIs, but +readers acquainted with them will see many familiar elements. Where appropriate +we will make this connection with the earlier APIs explicit to help people who +are transitioning from them to ORC. + +JIT API Basics +============== + +The purpose of a JIT compiler is to compile code "on-the-fly" as it is needed, +rather than compiling whole programs to disk ahead of time as a traditional +compiler does. To support that aim our initial, bare-bones JIT API will be: + +1. Handle addModule(Module &M) -- Make the given IR module available for + execution. +2. JITSymbol findSymbol(const std::string &Name) -- Search for pointers to + symbols (functions or variables) that have been added to the JIT. +3. void removeModule(Handle H) -- Remove a module from the JIT, releasing any + memory that had been used for the compiled code. + +A basic use-case for this API, executing the 'main' function from a module, +will look like: + +.. code-block:: c++ + + std::unique_ptr M = buildModule(); + JIT J; + Handle H = J.addModule(*M); + int (*Main)(int, char*[]) = + (int(*)(int, char*[])J.findSymbol("main").getAddress(); + int Result = Main(); + J.removeModule(H); + +The APIs that we build in these tutorials will all be variations on this simple +theme. Behind the API we will refine the implementation of the JIT to add +support for optimization and lazy compilation. Eventually we will extend the +API itself to allow higher-level program representations (e.g. ASTs) to be +added to the JIT. + +KaleidoscopeJIT +=============== + +In the previous section we described our API, now we examine a simple +implementation of it: The KaleidoscopeJIT class [1]_ that was used in the +`Implementing a language with LLVM `_ tutorials. We will use +the REPL code from `Chapter 7 `_ of that tutorial to supply the +input for our JIT: Each time the user enters an expression the REPL will add a +new IR module containing the code for that expression to the JIT. If the +expression is a top-level expression like '1+1' or 'sin(x)', the REPL will also +use the findSymbol method of our JIT class find and execute the code for the +expression, and then use the removeModule method to remove the code again +(since there's no way to re-invoke an anonymous expression). In later chapters +of this tutorial we'll modify the REPL to enable new interactions with our JIT +class, but for now we will take this setup for granted and focus our attention on +the implementation of our JIT itself. + +Our KaleidoscopeJIT class is defined in the KaleidoscopeJIT.h header. After the +usual include guards and #includes [2]_, we get to the definition of our class: + +.. code-block:: c++ + + #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H + #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H + + #include "llvm/ExecutionEngine/ExecutionEngine.h" + #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" + #include "llvm/ExecutionEngine/Orc/CompileUtils.h" + #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" + #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" + #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" + #include "llvm/IR/Mangler.h" + #include "llvm/Support/DynamicLibrary.h" + + namespace llvm { + namespace orc { + + class KaleidoscopeJIT { + private: + + std::unique_ptr TM; + const DataLayout DL; + ObjectLinkingLayer<> ObjectLayer; + IRCompileLayer CompileLayer; + + public: + + typedef decltype(CompileLayer)::ModuleSetHandleT ModuleHandleT; + +Our class begins with four members: A TargetMachine, TM, which will be used +to build our LLVM compiler instance; A DataLayout, DL, which will be used for +symbol mangling (more on that later), and two ORC *layers*: an +ObjectLinkingLayer and a IRCompileLayer. We'll be talking more about layers in +the next chapter, but for now you can think of them as analogous to LLVM +Passes: they wrap up useful JIT utilities behind an easy to compose interface. +The first layer, ObjectLinkingLayer, is the foundation of our JIT: it takes +in-memory object files produced by a compiler and links them on the fly to make +them executable. This JIT-on-top-of-a-linker design was introduced in MCJIT, +however the linker was hidden inside the MCJIT class. In ORC we expose the +linker so that clients can access and configure it directly if they need to. In +this tutorial our ObjectLinkingLayer will just be used to support the next layer +in our stack: the IRCompileLayer, which will be responsible for taking LLVM IR, +compiling it, and passing the resulting in-memory object files down to the +object linking layer below. + +That's it for member variables, after that we have a single typedef: +ModuleHandle. This is the handle type that will be returned from our JIT's +addModule method, and can be passed to the removeModule method to remove a +module. The IRCompileLayer class already provides a convenient handle type +(IRCompileLayer::ModuleSetHandleT), so we just alias our ModuleHandle to this. + +.. code-block:: c++ + + KaleidoscopeJIT() + : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), + CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { + llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + } + + TargetMachine &getTargetMachine() { return *TM; } + +Next up we have our class constructor. We begin by initializing TM using the +EngineBuilder::selectTarget helper method, which constructs a TargetMachine for +the current process. Next we use our newly created TargetMachine to initialize +DL, our DataLayout. Then we initialize our IRCompileLayer. Our IRCompile layer +needs two things: (1) A reference to our object linking layer, and (2) a +compiler instance to use to perform the actual compilation from IR to object +files. We use the off-the-shelf SimpleCompiler instance for now. Finally, in +the body of the constructor, we call the DynamicLibrary::LoadLibraryPermanently +method with a nullptr argument. Normally the LoadLibraryPermanently method is +called with the path of a dynamic library to load, but when passed a null +pointer it will 'load' the host process itself, making its exported symbols +available for execution. + +.. code-block:: c++ + + ModuleHandle addModule(std::unique_ptr M) { + // Build our symbol resolver: + // Lambda 1: Look back into the JIT itself to find symbols that are part of + // the same "logical dylib". + // Lambda 2: Search for external symbols in the host process. + auto Resolver = createLambdaResolver( + [&](const std::string &Name) { + if (auto Sym = CompileLayer.findSymbol(Name, false)) + return Sym.toRuntimeDyldSymbol(); + return RuntimeDyld::SymbolInfo(nullptr); + }, + [](const std::string &S) { + if (auto SymAddr = + RTDyldMemoryManager::getSymbolAddressInProcess(Name)) + return RuntimeDyld::SymbolInfo(SymAddr, JITSymbolFlags::Exported); + return RuntimeDyld::SymbolInfo(nullptr); + }); + + // Build a singlton module set to hold our module. + std::vector> Ms; + Ms.push_back(std::move(M)); + + // Add the set to the JIT with the resolver we created above and a newly + // created SectionMemoryManager. + return CompileLayer.addModuleSet(std::move(Ms), + make_unique(), + std::move(Resolver)); + } + +Now we come to the first of our JIT API methods: addModule. This method is +responsible for adding IR to the JIT and making it available for execution. In +this initial implementation of our JIT we will make our modules "available for +execution" by adding them straight to the IRCompileLayer, which will +immediately compile them. In later chapters we will teach our JIT to be lazier +and instead add the Modules to a "pending" list to be compiled if and when they +are first executed. + +To add our module to the IRCompileLayer we need to supply two auxiliary objects +(as well as the module itself): a memory manager and a symbol resolver. The +memory manager will be responsible for managing the memory allocated to JIT'd +machine code, setting memory permissions, and registering exception handling +tables (if the JIT'd code uses exceptions). For our memory manager we will use +the SectionMemoryManager class: another off-the-shelf utility that provides all +the basic functionality we need. The second auxiliary class, the symbol +resolver, is more interesting for us. It exists to tell the JIT where to look +when it encounters an *external symbol* in the module we are adding. External +symbols are any symbol not defined within the module itself, including calls to +functions outside the JIT and calls to functions defined in other modules that +have already been added to the JIT. It may seem as though modules added to the +JIT should "know about one another" by default, but since we would still have to +supply a symbol resolver for references to code outside the JIT it turns out to +be easier to just re-use this one mechanism for all symbol resolution. This has +the added benefit that the user has full control over the symbol resolution +process. Should we search for definitions within the JIT first, then fall back +on external definitions? Or should we prefer external definitions where +available and only JIT code if we don't already have an available +implementation? By using a single symbol resolution scheme we are free to choose +whatever makes the most sense for any given use case. + +Building a symbol resolver is made especially easy by the *createLambdaResolver* +function. This function takes two lambdas [3]_ and returns a +RuntimeDyld::SymbolResolver instance. The first lambda is used as the +implementation of the resolver's findSymbolInLogicalDylib method, which searches +for symbol definitions that should be thought of as being part of the same +"logical" dynamic library as this Module. If you are familiar with static +linking: this means that findSymbolInLogicalDylib should expose symbols with +common linkage and hidden visibility. If all this sounds foreign you can ignore +the details and just remember that this is the first method that the linker will +use to try to find a symbol definition. If the findSymbolInLogicalDylib method +returns a null result then the linker will call the second symbol resolver +method, called findSymbol, which searches for symbols that should be thought of +as external to (but visibile from) the module and its logical dylib. In this +tutorial we will adopt the following simple scheme: All modules added to the JIT +will behave as if they were linked into a single, ever-growing logical dylib. To +implement this our first lambda (the one defining findSymbolInLogicalDylib) will +just search for JIT'd code by calling the CompileLayer's findSymbol method. If +we don't find a symbol in the JIT itself we'll fall back to our second lambda, +which implements findSymbol. This will use the +RTDyldMemoyrManager::getSymbolAddressInProcess method to search for the symbol +within the program itself. If we can't find a symbol definition via either of +these paths the JIT will refuse to accept our module, returning a "symbol not +found" error. + +Now that we've built our symbol resolver we're ready to add our module to the +JIT. We do this by calling the CompileLayer's addModuleSet method [4]_. Since +we only have a single Module and addModuleSet expects a collection, we will +create a vector of modules and add our module as the only member. Since we +have already typedef'd our ModuleHandle type to be the same as the +CompileLayer's handle type, we can return the handle from addModuleSet +directly from our addModule method. + +.. code-block:: c++ + + JITSymbol findSymbol(const std::string Name) { + std::string MangledName; + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + return CompileLayer.findSymbol(MangledNameStream.str(), true); + } + + void removeModule(ModuleHandle H) { + CompileLayer.removeModuleSet(H); + } + +Now that we can add code to our JIT, we need a way to find the symbols we've +added to it. To do that we call the findSymbol method on our IRCompileLayer, +but with a twist: We have to *mangle* the name of the symbol we're searching +for first. The reason for this is that the ORC JIT components use mangled +symbols internally the same way a static compiler and linker would, rather +than using plain IR symbol names. The kind of mangling will depend on the +DataLayout, which in turn depends on the target platform. To allow us to +remain portable and search based on the un-mangled name, we just re-produce +this mangling ourselves. + +We now come to the last method in our JIT API: removeModule. This method is +responsible for destructing the MemoryManager and SymbolResolver that were +added with a given module, freeing any resources they were using in the +process. In our Kaleidoscope demo we rely on this method to remove the module +representing the most recent top-level expression, preventing it from being +treated as a duplicate definition when the next top-level expression is +entered. It is generally good to free any module that you know you won't need +to call further, just to free up the resources dedicated to it. However, you +don't strictly need to do this: All resources will be cleaned up when your +JIT class is destructed, if the haven't been freed before then. + +This brings us to the end of Chapter 1 of Building a JIT. You now have a basic +but fully functioning JIT stack that you can use to take LLVM IR and make it +executable within the context of your JIT process. In the next chapter we'll +look at how to extend this JIT to produce better quality code, and in the +process take a deeper look at the ORC layer concept. + +`Next: Extending the KaleidoscopeJIT `_ + +Full Code Listing +================= + +Here is the complete code listing for our running example. To build this +example, use: + +.. code-block:: bash + + # Compile + clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orc native` -O3 -o toy + # Run + ./toy + +Here is the code: + +.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h + :language: c++ + +.. [1] Actually we use a cut-down version of KaleidoscopeJIT that makes a + simplifying assumption: symbols cannot be re-defined. This will make it + impossible to re-define symbols in the REPL, but will make our symbol + lookup logic simpler. Re-introducing support for symbol redefinition is + left as an exercise for the reader. (The KaleidoscopeJIT.h used in the + original tutorials will be a helpful reference). + +.. [2] +-----------------------+-----------------------------------------------+ + | File | Reason for inclusion | + +=======================+===============================================+ + | ExecutionEngine.h | Access to the EngineBuilder::selectTarget | + | | method. | + +-----------------------+-----------------------------------------------+ + | | Access to the | + | RTDyldMemoryManager.h | RTDyldMemoryManager::getSymbolAddressInProcess| + | | method. | + +-----------------------+-----------------------------------------------+ + | CompileUtils.h | Provides the SimpleCompiler class. | + +-----------------------+-----------------------------------------------+ + | IRCompileLayer.h | Provides the IRCompileLayer class. | + +-----------------------+-----------------------------------------------+ + | | Access the createLambdaResolver function, | + | LambdaResolver.h | which provides easy construction of symbol | + | | resolvers. | + +-----------------------+-----------------------------------------------+ + | ObjectLinkingLayer.h | Provides the ObjectLinkingLayer class. | + +-----------------------+-----------------------------------------------+ + | Mangler.h | Provides the Mangler class for platform | + | | specific name-mangling. | + +-----------------------+-----------------------------------------------+ + | DynamicLibrary.h | Provides the DynamicLibrary class, which | + | | makes symbols in the host process searchable. | + +-----------------------+-----------------------------------------------+ + +.. [3] Actually they don't have to be lambdas, any object with a call operator + will do, including plain old functions or std::functions. + +.. [4] ORC layers accept sets of Modules, rather than individual ones, so that + all Modules in the set could be co-located by the memory manager, though + this feature is not yet implemented. diff --git a/docs/tutorial/BuildingAJIT2.rst b/docs/tutorial/BuildingAJIT2.rst new file mode 100644 index 0000000000000000000000000000000000000000..8fa92317f54fedf57ee1d19617fb7e67286bf5bc --- /dev/null +++ b/docs/tutorial/BuildingAJIT2.rst @@ -0,0 +1,336 @@ +===================================================================== +Building a JIT: Adding Optimizations -- An introduction to ORC Layers +===================================================================== + +.. contents:: + :local: + +**This tutorial is under active development. It is incomplete and details may +change frequently.** Nonetheless we invite you to try it out as it stands, and +we welcome any feedback. + +Chapter 2 Introduction +====================== + +Welcome to Chapter 2 of the "Building an ORC-based JIT in LLVM" tutorial. In +`Chapter 1 `_ of this series we examined a basic JIT +class, KaleidoscopeJIT, that could take LLVM IR modules as input and produce +executable code in memory. KaleidoscopeJIT was able to do this with relatively +little code by composing two off-the-shelf *ORC layers*: IRCompileLayer and +ObjectLinkingLayer, to do much of the heavy lifting. + +In this layer we'll learn more about the ORC layer concept by using a new layer, +IRTransformLayer, to add IR optimization support to KaleidoscopeJIT. + +Optimizing Modules using the IRTransformLayer +============================================= + +In `Chapter 4 `_ of the "Implementing a language with LLVM" +tutorial series the llvm *FunctionPassManager* is introduced as a means for +optimizing LLVM IR. Interested readers may read that chapter for details, but +in short: to optimize a Module we create an llvm::FunctionPassManager +instance, configure it with a set of optimizations, then run the PassManager on +a Module to mutate it into a (hopefully) more optimized but semantically +equivalent form. In the original tutorial series the FunctionPassManager was +created outside the KaleidoscopeJIT and modules were optimized before being +added to it. In this Chapter we will make optimization a phase of our JIT +instead. For now this will provide us a motivation to learn more about ORC +layers, but in the long term making optimization part of our JIT will yield an +important benefit: When we begin lazily compiling code (i.e. deferring +compilation of each function until the first time it's run), having +optimization managed by our JIT will allow us to optimize lazily too, rather +than having to do all our optimization up-front. + +To add optimization support to our JIT we will take the KaleidoscopeJIT from +Chapter 1 and compose an ORC *IRTransformLayer* on top. We will look at how the +IRTransformLayer works in more detail below, but the interface is simple: the +constructor for this layer takes a reference to the layer below (as all layers +do) plus an *IR optimization function* that it will apply to each Module that +is added via addModuleSet: + +.. code-block:: c++ + + class KaleidoscopeJIT { + private: + std::unique_ptr TM; + const DataLayout DL; + ObjectLinkingLayer<> ObjectLayer; + IRCompileLayer CompileLayer; + + typedef std::function(std::unique_ptr)> + OptimizeFunction; + + IRTransformLayer OptimizeLayer; + + public: + typedef decltype(OptimizeLayer)::ModuleSetHandleT ModuleHandle; + + KaleidoscopeJIT() + : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), + CompileLayer(ObjectLayer, SimpleCompiler(*TM)), + OptimizeLayer(CompileLayer, + [this](std::unique_ptr M) { + return optimizeModule(std::move(M)); + }) { + llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + } + +Our extended KaleidoscopeJIT class starts out the same as it did in Chapter 1, +but after the CompileLayer we introduce a typedef for our optimization function. +In this case we use a std::function (a handy wrapper for "function-like" things) +from a single unique_ptr input to a std::unique_ptr output. With +our optimization function typedef in place we can declare our OptimizeLayer, +which sits on top of our CompileLayer. + +To initialize our OptimizeLayer we pass it a reference to the CompileLayer +below (standard practice for layers), and we initialize the OptimizeFunction +using a lambda that calls out to an "optimizeModule" function that we will +define below. + +.. code-block:: c++ + + // ... + auto Resolver = createLambdaResolver( + [&](const std::string &Name) { + if (auto Sym = OptimizeLayer.findSymbol(Name, false)) + return Sym.toRuntimeDyldSymbol(); + return RuntimeDyld::SymbolInfo(nullptr); + }, + // ... + +.. code-block:: c++ + + // ... + return OptimizeLayer.addModuleSet(std::move(Ms), + make_unique(), + std::move(Resolver)); + // ... + +.. code-block:: c++ + + // ... + return OptimizeLayer.findSymbol(MangledNameStream.str(), true); + // ... + +.. code-block:: c++ + + // ... + OptimizeLayer.removeModuleSet(H); + // ... + +Next we need to replace references to 'CompileLayer' with references to +OptimizeLayer in our key methods: addModule, findSymbol, and removeModule. In +addModule we need to be careful to replace both references: the findSymbol call +inside our resolver, and the call through to addModuleSet. + +.. code-block:: c++ + + std::unique_ptr optimizeModule(std::unique_ptr M) { + // Create a function pass manager. + auto FPM = llvm::make_unique(M.get()); + + // Add some optimizations. + FPM->add(createInstructionCombiningPass()); + FPM->add(createReassociatePass()); + FPM->add(createGVNPass()); + FPM->add(createCFGSimplificationPass()); + FPM->doInitialization(); + + // Run the optimizations over all functions in the module being added to + // the JIT. + for (auto &F : *M) + FPM->run(F); + + return M; + } + +At the bottom of our JIT we add a private method to do the actual optimization: +*optimizeModule*. This function sets up a FunctionPassManager, adds some passes +to it, runs it over every function in the module, and then returns the mutated +module. The specific optimizations are the same ones used in +`Chapter 4 `_ of the "Implementing a language with LLVM" +tutorial series. Readers may visit that chapter for a more in-depth +discussion of these, and of IR optimization in general. + +And that's it in terms of changes to KaleidoscopeJIT: When a module is added via +addModule the OptimizeLayer will call our optimizeModule function before passing +the transformed module on to the CompileLayer below. Of course, we could have +called optimizeModule directly in our addModule function and not gone to the +bother of using the IRTransformLayer, but doing so gives us another opportunity +to see how layers compose. It also provides a neat entry point to the *layer* +concept itself, because IRTransformLayer turns out to be one of the simplest +implementations of the layer concept that can be devised: + +.. code-block:: c++ + + template + class IRTransformLayer { + public: + typedef typename BaseLayerT::ModuleSetHandleT ModuleSetHandleT; + + IRTransformLayer(BaseLayerT &BaseLayer, + TransformFtor Transform = TransformFtor()) + : BaseLayer(BaseLayer), Transform(std::move(Transform)) {} + + template + ModuleSetHandleT addModuleSet(ModuleSetT Ms, + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { + + for (auto I = Ms.begin(), E = Ms.end(); I != E; ++I) + *I = Transform(std::move(*I)); + + return BaseLayer.addModuleSet(std::move(Ms), std::move(MemMgr), + std::move(Resolver)); + } + + void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeModuleSet(H); } + + JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { + return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); + } + + JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name, + bool ExportedSymbolsOnly) { + return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly); + } + + void emitAndFinalize(ModuleSetHandleT H) { + BaseLayer.emitAndFinalize(H); + } + + TransformFtor& getTransform() { return Transform; } + + const TransformFtor& getTransform() const { return Transform; } + + private: + BaseLayerT &BaseLayer; + TransformFtor Transform; + }; + +This is the whole definition of IRTransformLayer, from +``llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h``, stripped of its +comments. It is a template class with two template arguments: ``BaesLayerT`` and +``TransformFtor`` that provide the type of the base layer and the type of the +"transform functor" (in our case a std::function) respectively. This class is +concerned with two very simple jobs: (1) Running every IR Module that is added +with addModuleSet through the transform functor, and (2) conforming to the ORC +layer interface. The interface consists of one typedef and five methods: + ++------------------+-----------------------------------------------------------+ +| Interface | Description | ++==================+===========================================================+ +| | Provides a handle that can be used to identify a module | +| ModuleSetHandleT | set when calling findSymbolIn, removeModuleSet, or | +| | emitAndFinalize. | ++------------------+-----------------------------------------------------------+ +| | Takes a given set of Modules and makes them "available | +| | for execution. This means that symbols in those modules | +| | should be searchable via findSymbol and findSymbolIn, and | +| | the address of the symbols should be read/writable (for | +| | data symbols), or executable (for function symbols) after | +| | JITSymbol::getAddress() is called. Note: This means that | +| addModuleSet | addModuleSet doesn't have to compile (or do any other | +| | work) up-front. It *can*, like IRCompileLayer, act | +| | eagerly, but it can also simply record the module and | +| | take no further action until somebody calls | +| | JITSymbol::getAddress(). In IRTransformLayer's case | +| | addModuleSet eagerly applies the transform functor to | +| | each module in the set, then passes the resulting set | +| | of mutated modules down to the layer below. | ++------------------+-----------------------------------------------------------+ +| | Removes a set of modules from the JIT. Code or data | +| removeModuleSet | defined in these modules will no longer be available, and | +| | the memory holding the JIT'd definitions will be freed. | ++------------------+-----------------------------------------------------------+ +| | Searches for the named symbol in all modules that have | +| | previously been added via addModuleSet (and not yet | +| findSymbol | removed by a call to removeModuleSet). In | +| | IRTransformLayer we just pass the query on to the layer | +| | below. In our REPL this is our default way to search for | +| | function definitions. | ++------------------+-----------------------------------------------------------+ +| | Searches for the named symbol in the module set indicated | +| | by the given ModuleSetHandleT. This is just an optimized | +| | search, better for lookup-speed when you know exactly | +| | a symbol definition should be found. In IRTransformLayer | +| findSymbolIn | we just pass this query on to the layer below. In our | +| | REPL we use this method to search for functions | +| | representing top-level expressions, since we know exactly | +| | where we'll find them: in the top-level expression module | +| | we just added. | ++------------------+-----------------------------------------------------------+ +| | Forces all of the actions required to make the code and | +| | data in a module set (represented by a ModuleSetHandleT) | +| | accessible. Behaves as if some symbol in the set had been | +| | searched for and JITSymbol::getSymbolAddress called. This | +| emitAndFinalize | is rarely needed, but can be useful when dealing with | +| | layers that usually behave lazily if the user wants to | +| | trigger early compilation (for example, to use idle CPU | +| | time to eagerly compile code in the background). | ++------------------+-----------------------------------------------------------+ + +This interface attempts to capture the natural operations of a JIT (with some +wrinkles like emitAndFinalize for performance), similar to the basic JIT API +operations we identified in Chapter 1. Conforming to the layer concept allows +classes to compose neatly by implementing their behaviors in terms of the these +same operations, carried out on the layer below. For example, an eager layer +(like IRTransformLayer) can implement addModuleSet by running each module in the +set through its transform up-front and immediately passing the result to the +layer below. A lazy layer, by contrast, could implement addModuleSet by +squirreling away the modules doing no other up-front work, but applying the +transform (and calling addModuleSet on the layer below) when the client calls +findSymbol instead. The JIT'd program behavior will be the same either way, but +these choices will have different performance characteristics: Doing work +eagerly means the JIT takes longer up-front, but proceeds smoothly once this is +done. Deferring work allows the JIT to get up-and-running quickly, but will +force the JIT to pause and wait whenever some code or data is needed that hasn't +already been processed. + +Our current REPL is eager: Each function definition is optimized and compiled as +soon as it's typed in. If we were to make the transform layer lazy (but not +change things otherwise) we could defer optimization until the first time we +reference a function in a top-level expression (see if you can figure out why, +then check out the answer below [1]_). In the next chapter, however we'll +introduce fully lazy compilation, in which function's aren't compiled until +they're first called at run-time. At this point the trade-offs get much more +interesting: the lazier we are, the quicker we can start executing the first +function, but the more often we'll have to pause to compile newly encountered +functions. If we only code-gen lazily, but optimize eagerly, we'll have a slow +startup (which everything is optimized) but relatively short pauses as each +function just passes through code-gen. If we both optimize and code-gen lazily +we can start executing the first function more quickly, but we'll have longer +pauses as each function has to be both optimized and code-gen'd when it's first +executed. Things become even more interesting if we consider interproceedural +optimizations like inlining, which must be performed eagerly. These are +complex trade-offs, and there is no one-size-fits all solution to them, but by +providing composable layers we leave the decisions to the person implementing +the JIT, and make it easy for them to experiment with different configurations. + +`Next: Adding Per-function Lazy Compilation `_ + +Full Code Listing +================= + +Here is the complete code listing for our running example with an +IRTransformLayer added to enable optimization. To build this example, use: + +.. code-block:: bash + + # Compile + clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orc native` -O3 -o toy + # Run + ./toy + +Here is the code: + +.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h + :language: c++ + +.. [1] When we add our top-level expression to the JIT, any calls to functions + that we defined earlier will appear to the ObjectLinkingLayer as + external symbols. The ObjectLinkingLayer will call the SymbolResolver + that we defined in addModuleSet, which in turn calls findSymbol on the + OptimizeLayer, at which point even a lazy transform layer will have to + do its work. diff --git a/docs/tutorial/BuildingAJIT3.rst b/docs/tutorial/BuildingAJIT3.rst new file mode 100644 index 0000000000000000000000000000000000000000..35b0e24dc74636e550fbffa62b41718cf56f6559 --- /dev/null +++ b/docs/tutorial/BuildingAJIT3.rst @@ -0,0 +1,47 @@ +============================================= +Building a JIT: Per-function Lazy Compilation +============================================= + +.. contents:: + :local: + +**This tutorial is under active development. It is incomplete and details may +change frequently.** Nonetheless we invite you to try it out as it stands, and +we welcome any feedback. + +Chapter 3 Introduction +====================== + +Welcome to Chapter 3 of the "Building an ORC-based JIT in LLVM" tutorial. This +chapter discusses lazy JITing and shows you how to enable it by adding an ORC +CompileOnDemand layer the JIT from `Chapter 2 `_. + +**To be done:** + +**(1) Describe lazy function-at-a-time JITing and how it differs from the kind +of eager module-at-a-time JITing that we've been doing so far.** + +**(2) Discuss CompileCallbackManagers and IndirectStubManagers.** + +**(3) Describe CompileOnDemandLayer (automates these components and builds stubs +and lazy compilation callbacks for IR) and how to add it to the JIT.** + +Full Code Listing +================= + +Here is the complete code listing for our running example with a CompileOnDemand +layer added to enable lazy function-at-a-time compilation. To build this example, use: + +.. code-block:: bash + + # Compile + clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orc native` -O3 -o toy + # Run + ./toy + +Here is the code: + +.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h + :language: c++ + +`Next: Extreme Laziness -- Using Compile Callbacks to JIT directly from ASTs `_ diff --git a/docs/tutorial/BuildingAJIT4.rst b/docs/tutorial/BuildingAJIT4.rst new file mode 100644 index 0000000000000000000000000000000000000000..39d9198a85c3d5eb8489969a735318a96152eeab --- /dev/null +++ b/docs/tutorial/BuildingAJIT4.rst @@ -0,0 +1,48 @@ +=========================================================================== +Building a JIT: Extreme Laziness - Using Compile Callbacks to JIT from ASTs +=========================================================================== + +.. contents:: + :local: + +**This tutorial is under active development. It is incomplete and details may +change frequently.** Nonetheless we invite you to try it out as it stands, and +we welcome any feedback. + +Chapter 4 Introduction +====================== + +Welcome to Chapter 4 of the "Building an ORC-based JIT in LLVM" tutorial. This +chapter introduces the Compile Callbacks and Indirect Stubs APIs and shows how +they can be used to replace the CompileOnDemand layer from +`Chapter 3 `_ with a custom lazy-JITing scheme that JITs +directly from Kaleidoscope ASTs. + +**To be done:** + +**(1) Describe the drawbacks of JITing from IR (have to compile to IR first, +which reduces the benefits of laziness).** + +**(2) Describe CompileCallbackManagers and IndirectStubManagers in detail.** + +**(3) Run through the implementation of addFunctionAST.** + +Full Code Listing +================= + +Here is the complete code listing for our running example that JITs lazily from +Kaleidoscope ASTS. To build this example, use: + +.. code-block:: bash + + # Compile + clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orc native` -O3 -o toy + # Run + ./toy + +Here is the code: + +.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h + :language: c++ + +`Next: Remote-JITing -- Process-isolation and laziness-at-a-distance `_ diff --git a/docs/tutorial/BuildingAJIT5.rst b/docs/tutorial/BuildingAJIT5.rst new file mode 100644 index 0000000000000000000000000000000000000000..94ea92ce5ad2bb599d12592e77157f35cc3492ec --- /dev/null +++ b/docs/tutorial/BuildingAJIT5.rst @@ -0,0 +1,55 @@ +============================================================================= +Building a JIT: Remote-JITing -- Process Isolation and Laziness at a Distance +============================================================================= + +.. contents:: + :local: + +**This tutorial is under active development. It is incomplete and details may +change frequently.** Nonetheless we invite you to try it out as it stands, and +we welcome any feedback. + +Chapter 5 Introduction +====================== + +Welcome to Chapter 5 of the "Building an ORC-based JIT in LLVM" tutorial. This +chapter introduces the ORC RemoteJIT Client/Server APIs and shows how to use +them to build a JIT stack that will execute its code via a communications +channel with a different process. This can be a separate process on the same +machine, a process on a different machine, or even a process on a different +platform/architecture. The code builds on top of the lazy-AST-compiling JIT +stack from `Chapter 4 `_. + +**To be done -- this is going to be a long one:** + +**(1) Introduce channels, RPC, RemoteJIT Client and Server APIs** + +**(2) Describe the client code in greater detail. Discuss modifications of the +KaleidoscopeJIT class, and the REPL itself.** + +**(3) Describe the server code.** + +**(4) Describe how to run the demo.** + +Full Code Listing +================= + +Here is the complete code listing for our running example that JITs lazily from +Kaleidoscope ASTS. To build this example, use: + +.. code-block:: bash + + # Compile + clang++ -g toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core orc native` -O3 -o toy + # Run + ./toy + +Here is the code for the modified KaleidoscopeJIT: + +.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h + :language: c++ + +And the code for the JIT server: + +.. literalinclude:: ../../examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/server.cpp + :language: c++ diff --git a/docs/tutorial/LangImpl1.rst b/docs/tutorial/LangImpl01.rst similarity index 91% rename from docs/tutorial/LangImpl1.rst rename to docs/tutorial/LangImpl01.rst index b04cde10274e05fa6a8fee964698e70716884112..f7fbd150ef11af265a31c19177f6e7681d0a5dfc 100644 --- a/docs/tutorial/LangImpl1.rst +++ b/docs/tutorial/LangImpl01.rst @@ -42,45 +42,48 @@ in the various pieces. The structure of the tutorial is: to implement everything in C++ instead of using lexer and parser generators. LLVM obviously works just fine with such tools, feel free to use one if you prefer. -- `Chapter #2 `_: Implementing a Parser and AST - +- `Chapter #2 `_: Implementing a Parser and AST - With the lexer in place, we can talk about parsing techniques and basic AST construction. This tutorial describes recursive descent parsing and operator precedence parsing. Nothing in Chapters 1 or 2 is LLVM-specific, the code doesn't even link in LLVM at this point. :) -- `Chapter #3 `_: Code generation to LLVM IR - With +- `Chapter #3 `_: Code generation to LLVM IR - With the AST ready, we can show off how easy generation of LLVM IR really is. -- `Chapter #4 `_: Adding JIT and Optimizer Support +- `Chapter #4 `_: Adding JIT and Optimizer Support - Because a lot of people are interested in using LLVM as a JIT, we'll dive right into it and show you the 3 lines it takes to add JIT support. LLVM is also useful in many other ways, but this is one simple and "sexy" way to show off its power. :) -- `Chapter #5 `_: Extending the Language: Control +- `Chapter #5 `_: Extending the Language: Control Flow - With the language up and running, we show how to extend it with control flow operations (if/then/else and a 'for' loop). This gives us a chance to talk about simple SSA construction and control flow. -- `Chapter #6 `_: Extending the Language: +- `Chapter #6 `_: Extending the Language: User-defined Operators - This is a silly but fun chapter that talks about extending the language to let the user program define their own arbitrary unary and binary operators (with assignable precedence!). This lets us build a significant piece of the "language" as library routines. -- `Chapter #7 `_: Extending the Language: Mutable +- `Chapter #7 `_: Extending the Language: Mutable Variables - This chapter talks about adding user-defined local variables along with an assignment operator. The interesting part about this is how easy and trivial it is to construct SSA form in LLVM: no, LLVM does *not* require your front-end to construct SSA form! -- `Chapter #8 `_: Extending the Language: Debug +- `Chapter #8 `_: Compiling to Object Files - This + chapter explains how to take LLVM IR and compile it down to object + files. +- `Chapter #9 `_: Extending the Language: Debug Information - Having built a decent little programming language with control flow, functions and mutable variables, we consider what it takes to add debug information to standalone executables. This debug information will allow you to set breakpoints in Kaleidoscope functions, print out argument variables, and call functions - all from within the debugger! -- `Chapter #9 `_: Conclusion and other useful LLVM +- `Chapter #10 `_: Conclusion and other useful LLVM tidbits - This chapter wraps up the series by talking about potential ways to extend the language, but also includes a bunch of pointers to info about "special topics" like adding garbage @@ -146,7 +149,7 @@ useful for mutually recursive functions). For example: A more interesting example is included in Chapter 6 where we write a little Kaleidoscope application that `displays a Mandelbrot -Set `_ at various levels of magnification. +Set `_ at various levels of magnification. Lets dive into the implementation of this language! @@ -280,11 +283,11 @@ file. These are handled with this code: } With this, we have the complete lexer for the basic Kaleidoscope -language (the `full code listing `_ for the Lexer -is available in the `next chapter `_ of the tutorial). +language (the `full code listing `_ for the Lexer +is available in the `next chapter `_ of the tutorial). Next we'll `build a simple parser that uses this to build an Abstract -Syntax Tree `_. When we have that, we'll include a +Syntax Tree `_. When we have that, we'll include a driver so that you can use the lexer and parser together. -`Next: Implementing a Parser and AST `_ +`Next: Implementing a Parser and AST `_ diff --git a/docs/tutorial/LangImpl2.rst b/docs/tutorial/LangImpl02.rst similarity index 99% rename from docs/tutorial/LangImpl2.rst rename to docs/tutorial/LangImpl02.rst index f01e3f90f20d2ce6c11a1659890bc080eabec134..701cbc9611363bbe0d72c104327b3361406e75ca 100644 --- a/docs/tutorial/LangImpl2.rst +++ b/docs/tutorial/LangImpl02.rst @@ -731,5 +731,5 @@ Here is the code: .. literalinclude:: ../../examples/Kaleidoscope/Chapter2/toy.cpp :language: c++ -`Next: Implementing Code Generation to LLVM IR `_ +`Next: Implementing Code Generation to LLVM IR `_ diff --git a/docs/tutorial/LangImpl3.rst b/docs/tutorial/LangImpl03.rst similarity index 94% rename from docs/tutorial/LangImpl3.rst rename to docs/tutorial/LangImpl03.rst index 89ecee9d729ab5ff50d665dd3b01912ec96516c4..2bb3a300026e0ea1c29fc56f8a87f250dff10d53 100644 --- a/docs/tutorial/LangImpl3.rst +++ b/docs/tutorial/LangImpl03.rst @@ -73,20 +73,20 @@ parser, which will be used to report errors found during code generation .. code-block:: c++ - static std::unique_ptr *TheModule; - static IRBuilder<> Builder(getGlobalContext()); - static std::map NamedValues; + static LLVMContext TheContext; + static IRBuilder<> Builder(TheContext); + static std::unique_ptr TheModule; + static std::map NamedValues; Value *LogErrorV(const char *Str) { LogError(Str); return nullptr; } -The static variables will be used during code generation. ``TheModule`` -is an LLVM construct that contains functions and global variables. In many -ways, it is the top-level structure that the LLVM IR uses to contain code. -It will own the memory for all of the IR that we generate, which is why -the codegen() method returns a raw Value\*, rather than a unique_ptr. +The static variables will be used during code generation. ``TheContext`` +is an opaque object that owns a lot of core LLVM data structures, such as +the type and constant value tables. We don't need to understand it in +detail, we just need a single instance to pass into APIs that require it. The ``Builder`` object is a helper object that makes it easy to generate LLVM instructions. Instances of the @@ -94,6 +94,12 @@ LLVM instructions. Instances of the class template keep track of the current place to insert instructions and has methods to create new instructions. +``TheModule`` is an LLVM construct that contains functions and global +variables. In many ways, it is the top-level structure that the LLVM IR +uses to contain code. It will own the memory for all of the IR that we +generate, which is why the codegen() method returns a raw Value\*, +rather than a unique_ptr. + The ``NamedValues`` map keeps track of which values are defined in the current scope and what their LLVM representation is. (In other words, it is a symbol table for the code). In this form of Kaleidoscope, the only @@ -116,7 +122,7 @@ First we'll do numeric literals: .. code-block:: c++ Value *NumberExprAST::codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(LLVMContext, APFloat(Val)); } In the LLVM IR, numeric constants are represented with the @@ -165,7 +171,7 @@ variables `_. case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), + return Builder.CreateUIToFP(L, Type::getDoubleTy(LLVMContext), "booltmp"); default: return LogErrorV("invalid binary operator"); @@ -264,9 +270,9 @@ with: Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); + Type::getDoubleTy(LLVMContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles, false); + FunctionType::get(Type::getDoubleTy(LLVMContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule); @@ -340,7 +346,7 @@ assert that the function is empty (i.e. has no body yet) before we start. .. code-block:: c++ // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(LLVMContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Record the function arguments in the NamedValues map. @@ -557,5 +563,5 @@ Here is the code: .. literalinclude:: ../../examples/Kaleidoscope/Chapter3/toy.cpp :language: c++ -`Next: Adding JIT and Optimizer Support `_ +`Next: Adding JIT and Optimizer Support `_ diff --git a/docs/tutorial/LangImpl4.rst b/docs/tutorial/LangImpl04.rst similarity index 99% rename from docs/tutorial/LangImpl4.rst rename to docs/tutorial/LangImpl04.rst index a671d0c37f9d830e689989fafe61427aa671ec42..78596cd8eee5d435d620d5883e0310245e7bc23d 100644 --- a/docs/tutorial/LangImpl4.rst +++ b/docs/tutorial/LangImpl04.rst @@ -131,7 +131,8 @@ for us: void InitializeModuleAndPassManager(void) { // Open a new module. - TheModule = llvm::make_unique("my cool jit", getGlobalContext()); + Context LLVMContext; + TheModule = llvm::make_unique("my cool jit", LLVMContext); TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); // Create a new pass manager attached to it. @@ -605,5 +606,5 @@ Here is the code: .. literalinclude:: ../../examples/Kaleidoscope/Chapter4/toy.cpp :language: c++ -`Next: Extending the language: control flow `_ +`Next: Extending the language: control flow `_ diff --git a/docs/tutorial/LangImpl5-cfg.png b/docs/tutorial/LangImpl05-cfg.png similarity index 100% rename from docs/tutorial/LangImpl5-cfg.png rename to docs/tutorial/LangImpl05-cfg.png diff --git a/docs/tutorial/LangImpl5.rst b/docs/tutorial/LangImpl05.rst similarity index 96% rename from docs/tutorial/LangImpl5.rst rename to docs/tutorial/LangImpl05.rst index e4dc8ab7d854c2a8ea9cff1e0d7dae8d482a75f3..ae0935d9ba1f976a7812b4654954f7b9c2e31806 100644 --- a/docs/tutorial/LangImpl5.rst +++ b/docs/tutorial/LangImpl05.rst @@ -217,7 +217,7 @@ IR into "t.ll" and run "``llvm-as < t.ll | opt -analyze -view-cfg``", `a window will pop up <../ProgrammersManual.html#viewing-graphs-while-debugging-code>`_ and you'll see this graph: -.. figure:: LangImpl5-cfg.png +.. figure:: LangImpl05-cfg.png :align: center :alt: Example CFG @@ -292,7 +292,7 @@ for ``IfExprAST``: // Convert condition to a bool by comparing equal to 0.0. CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "ifcond"); + CondV, ConstantFP::get(LLVMContext, APFloat(0.0)), "ifcond"); This code is straightforward and similar to what we saw before. We emit the expression for the condition, then compare that value to zero to get @@ -305,9 +305,9 @@ a truth value as a 1-bit (bool) value. // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. BasicBlock *ThenBB = - BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); + BasicBlock::Create(LLVMContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(LLVMContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(LLVMContext, "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); @@ -400,7 +400,7 @@ code: TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); PHINode *PN = - Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, "iftmp"); + Builder.CreatePHI(Type::getDoubleTy(LLVMContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -625,7 +625,7 @@ expression). Function *TheFunction = Builder.GetInsertBlock()->getParent(); BasicBlock *PreheaderBB = Builder.GetInsertBlock(); BasicBlock *LoopBB = - BasicBlock::Create(getGlobalContext(), "loop", TheFunction); + BasicBlock::Create(LLVMContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -642,7 +642,7 @@ the two blocks. Builder.SetInsertPoint(LoopBB); // Start the PHI node with an entry for Start. - PHINode *Variable = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), + PHINode *Variable = Builder.CreatePHI(Type::getDoubleTy(LLVMContext), 2, VarName.c_str()); Variable->addIncoming(StartVal, PreheaderBB); @@ -693,7 +693,7 @@ table. return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(LLVMContext, APFloat(1.0)); } Value *NextVar = Builder.CreateFAdd(Variable, StepVal, "nextvar"); @@ -712,7 +712,7 @@ iteration of the loop. // Convert condition to a bool by comparing equal to 0.0. EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "loopcond"); + EndCond, ConstantFP::get(LLVMContext, APFloat(0.0)), "loopcond"); Finally, we evaluate the exit value of the loop, to determine whether the loop should exit. This mirrors the condition evaluation for the @@ -723,7 +723,7 @@ if/then/else statement. // Create the "after loop" block and insert it. BasicBlock *LoopEndBB = Builder.GetInsertBlock(); BasicBlock *AfterBB = - BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); + BasicBlock::Create(LLVMContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -751,7 +751,7 @@ insertion position to it. NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(LLVMContext)); } The final code handles various cleanups: now that we have the "NextVar" @@ -786,5 +786,5 @@ Here is the code: .. literalinclude:: ../../examples/Kaleidoscope/Chapter5/toy.cpp :language: c++ -`Next: Extending the language: user-defined operators `_ +`Next: Extending the language: user-defined operators `_ diff --git a/docs/tutorial/LangImpl6.rst b/docs/tutorial/LangImpl06.rst similarity index 98% rename from docs/tutorial/LangImpl6.rst rename to docs/tutorial/LangImpl06.rst index 5a77d6dcd72ab4b119706cdac8d8f8db98e1b4b5..7c9a2123e8f3801ae4bf997da2727a573634f725 100644 --- a/docs/tutorial/LangImpl6.rst +++ b/docs/tutorial/LangImpl06.rst @@ -251,7 +251,7 @@ default case for our existing binary operator node: case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), + return Builder.CreateUIToFP(L, Type::getDoubleTy(LLVMContext), "booltmp"); default: break; @@ -288,7 +288,7 @@ The final piece of code we are missing, is a bit of top-level magic: BinopPrecedence[Proto->getOperatorName()] = Proto->getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(LLVMContext, "entry", TheFunction); Builder.SetInsertPoint(BB); if (Value *RetVal = Body->codegen()) { @@ -546,17 +546,17 @@ converge: # Determine whether the specific location diverges. # Solve for z = z^2 + c in the complex plane. - def mandleconverger(real imag iters creal cimag) + def mandelconverger(real imag iters creal cimag) if iters > 255 | (real*real + imag*imag > 4) then iters else - mandleconverger(real*real - imag*imag + creal, + mandelconverger(real*real - imag*imag + creal, 2*real*imag + cimag, iters+1, creal, cimag); # Return the number of iterations required for the iteration to escape - def mandleconverge(real imag) - mandleconverger(real, imag, 0, real, imag); + def mandelconverge(real imag) + mandelconverger(real, imag, 0, real, imag); This "``z = z2 + c``" function is a beautiful little creature that is the basis for computation of the `Mandelbrot @@ -570,12 +570,12 @@ but we can whip together something using the density plotter above: :: - # Compute and plot the mandlebrot set with the specified 2 dimensional range + # Compute and plot the mandelbrot set with the specified 2 dimensional range # info. def mandelhelp(xmin xmax xstep ymin ymax ystep) for y = ymin, y < ymax, ystep in ( (for x = xmin, x < xmax, xstep in - printdensity(mandleconverge(x,y))) + printdensity(mandelconverge(x,y))) : putchard(10) ) @@ -585,7 +585,7 @@ but we can whip together something using the density plotter above: mandelhelp(realstart, realstart+realmag*78, realmag, imagstart, imagstart+imagmag*40, imagmag); -Given this, we can try plotting out the mandlebrot set! Lets try it out: +Given this, we can try plotting out the mandelbrot set! Lets try it out: :: @@ -764,5 +764,5 @@ Here is the code: :language: c++ `Next: Extending the language: mutable variables / SSA -construction `_ +construction `_ diff --git a/docs/tutorial/LangImpl7.rst b/docs/tutorial/LangImpl07.rst similarity index 99% rename from docs/tutorial/LangImpl7.rst rename to docs/tutorial/LangImpl07.rst index 5d536bf8572184227b27270a707b93ddfd67b3ee..4d86ecad38aaa342fc0f67dba6c31788842f0c4e 100644 --- a/docs/tutorial/LangImpl7.rst +++ b/docs/tutorial/LangImpl07.rst @@ -224,7 +224,7 @@ variables in certain circumstances: class <../LangRef.html#first-class-types>`_ values (such as pointers, scalars and vectors), and only if the array size of the allocation is 1 (or missing in the .ll file). mem2reg is not capable of promoting - structs or arrays to registers. Note that the "scalarrepl" pass is + structs or arrays to registers. Note that the "sroa" pass is more powerful and can promote structs, "unions", and arrays in many cases. @@ -339,7 +339,7 @@ the function: const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), 0, + return TmpB.CreateAlloca(Type::getDoubleTy(LLVMContext), 0, VarName.c_str()); } @@ -812,7 +812,7 @@ previous value that we replace in OldBindings. if (!InitVal) return nullptr; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); + InitVal = ConstantFP::get(LLVMContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -877,5 +877,5 @@ Here is the code: .. literalinclude:: ../../examples/Kaleidoscope/Chapter7/toy.cpp :language: c++ -`Next: Adding Debug Information `_ +`Next: Compiling to Object Code `_ diff --git a/docs/tutorial/LangImpl08.rst b/docs/tutorial/LangImpl08.rst new file mode 100644 index 0000000000000000000000000000000000000000..96eccaebd3295406e9848649d685d4bc9df42d91 --- /dev/null +++ b/docs/tutorial/LangImpl08.rst @@ -0,0 +1,218 @@ +======================================== + Kaleidoscope: Compiling to Object Code +======================================== + +.. contents:: + :local: + +Chapter 8 Introduction +====================== + +Welcome to Chapter 8 of the "`Implementing a language with LLVM +`_" tutorial. This chapter describes how to compile our +language down to object files. + +Choosing a target +================= + +LLVM has native support for cross-compilation. You can compile to the +architecture of your current machine, or just as easily compile for +other architectures. In this tutorial, we'll target the current +machine. + +To specify the architecture that you want to target, we use a string +called a "target triple". This takes the form +``---`` (see the `cross compilation docs +`_). + +As an example, we can see what clang thinks is our current target +triple: + +:: + + $ clang --version | grep Target + Target: x86_64-unknown-linux-gnu + +Running this command may show something different on your machine as +you might be using a different architecture or operating system to me. + +Fortunately, we don't need to hard-code a target triple to target the +current machine. LLVM provides ``sys::getDefaultTargetTriple``, which +returns the target triple of the current machine. + +.. code-block:: c++ + + auto TargetTriple = sys::getDefaultTargetTriple(); + +LLVM doesn't require us to to link in all the target +functionality. For example, if we're just using the JIT, we don't need +the assembly printers. Similarly, if we're only targeting certain +architectures, we can only link in the functionality for those +architectures. + +For this example, we'll initialize all the targets for emitting object +code. + +.. code-block:: c++ + + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmParsers(); + InitializeAllAsmPrinters(); + +We can now use our target triple to get a ``Target``: + +.. code-block:: c++ + + std::string Error; + auto Target = TargetRegistry::lookupTarget(TargetTriple, Error); + + // Print an error and exit if we couldn't find the requested target. + // This generally occurs if we've forgotten to initialise the + // TargetRegistry or we have a bogus target triple. + if (!Target) { + errs() << Error; + return 1; + } + +Target Machine +============== + +We will also need a ``TargetMachine``. This class provides a complete +machine description of the machine we're targeting. If we want to +target a specific feature (such as SSE) or a specific CPU (such as +Intel's Sandylake), we do so now. + +To see which features and CPUs that LLVM knows about, we can use +``llc``. For example, let's look at x86: + +:: + + $ llvm-as < /dev/null | llc -march=x86 -mattr=help + Available CPUs for this target: + + amdfam10 - Select the amdfam10 processor. + athlon - Select the athlon processor. + athlon-4 - Select the athlon-4 processor. + ... + + Available features for this target: + + 16bit-mode - 16-bit mode (i8086). + 32bit-mode - 32-bit mode (80386). + 3dnow - Enable 3DNow! instructions. + 3dnowa - Enable 3DNow! Athlon instructions. + ... + +For our example, we'll use the generic CPU without any additional +features, options or relocation model. + +.. code-block:: c++ + + auto CPU = "generic"; + auto Features = ""; + + TargetOptions opt; + auto RM = Optional(); + auto TargetMachine = Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM); + + +Configuring the Module +====================== + +We're now ready to configure our module, to specify the target and +data layout. This isn't strictly necessary, but the `frontend +performance guide <../Frontend/PerformanceTips.html>`_ recommends +this. Optimizations benefit from knowing about the target and data +layout. + +.. code-block:: c++ + + TheModule->setDataLayout(TargetMachine->createDataLayout()); + TheModule->setTargetTriple(TargetTriple); + +Emit Object Code +================ + +We're ready to emit object code! Let's define where we want to write +our file to: + +.. code-block:: c++ + + auto Filename = "output.o"; + std::error_code EC; + raw_fd_ostream dest(Filename, EC, sys::fs::F_None); + + if (EC) { + errs() << "Could not open file: " << EC.message(); + return 1; + } + +Finally, we define a pass that emits object code, then we run that +pass: + +.. code-block:: c++ + + legacy::PassManager pass; + auto FileType = TargetMachine::CGFT_ObjectFile; + + if (TargetMachine->addPassesToEmitFile(pass, dest, FileType)) { + errs() << "TargetMachine can't emit a file of this type"; + return 1; + } + + pass.run(*TheModule); + dest.flush(); + +Putting It All Together +======================= + +Does it work? Let's give it a try. We need to compile our code, but +note that the arguments to ``llvm-config`` are different to the previous chapters. + +:: + + $ clang++ -g -O3 toy.cpp `llvm-config --cxxflags --ldflags --system-libs --libs all` -o toy + +Let's run it, and define a simple ``average`` function. Press Ctrl-D +when you're done. + +:: + + $ ./toy + ready> def average(x y) (x + y) * 0.5; + ^D + Wrote output.o + +We have an object file! To test it, let's write a simple program and +link it with our output. Here's the source code: + +.. code-block:: c++ + + #include + + extern "C" { + double average(double, double); + } + + int main() { + std::cout << "average of 3.0 and 4.0: " << average(3.0, 4.0) << std::endl; + } + +We link our program to output.o and check the result is what we +expected: + +:: + + $ clang++ main.cpp output.o -o main + $ ./main + average of 3.0 and 4.0: 3.5 + +Full Code Listing +================= + +.. literalinclude:: ../../examples/Kaleidoscope/Chapter8/toy.cpp + :language: c++ + +`Next: Adding Debug Information `_ diff --git a/docs/tutorial/LangImpl8.rst b/docs/tutorial/LangImpl09.rst similarity index 98% rename from docs/tutorial/LangImpl8.rst rename to docs/tutorial/LangImpl09.rst index 3b0f443f08d5439f11a6c9f0c8bfae416b54c459..0053960756d29489c25f8e329a49ed5d39714006 100644 --- a/docs/tutorial/LangImpl8.rst +++ b/docs/tutorial/LangImpl09.rst @@ -5,11 +5,11 @@ Kaleidoscope: Adding Debug Information .. contents:: :local: -Chapter 8 Introduction +Chapter 9 Introduction ====================== -Welcome to Chapter 8 of the "`Implementing a language with -LLVM `_" tutorial. In chapters 1 through 7, we've built a +Welcome to Chapter 9 of the "`Implementing a language with +LLVM `_" tutorial. In chapters 1 through 8, we've built a decent little programming language with functions and variables. What happens if something goes wrong though, how do you debug your program? @@ -149,7 +149,7 @@ command line: .. code-block:: bash - Kaleidoscope-Ch8 < fib.ks | & clang -x ir - + Kaleidoscope-Ch9 < fib.ks | & clang -x ir - which gives an a.out/a.exe in the current working directory. @@ -455,8 +455,8 @@ debug information. To build this example, use: Here is the code: -.. literalinclude:: ../../examples/Kaleidoscope/Chapter8/toy.cpp +.. literalinclude:: ../../examples/Kaleidoscope/Chapter9/toy.cpp :language: c++ -`Next: Conclusion and other useful LLVM tidbits `_ +`Next: Conclusion and other useful LLVM tidbits `_ diff --git a/docs/tutorial/LangImpl9.rst b/docs/tutorial/LangImpl10.rst similarity index 100% rename from docs/tutorial/LangImpl9.rst rename to docs/tutorial/LangImpl10.rst diff --git a/docs/tutorial/OCamlLangImpl5.rst b/docs/tutorial/OCamlLangImpl5.rst index 675b9bc1978b09e23ca7799ed2c91272c0c10d51..3a135b23337339ce6665c6e41a11b7b95253be5f 100644 --- a/docs/tutorial/OCamlLangImpl5.rst +++ b/docs/tutorial/OCamlLangImpl5.rst @@ -178,7 +178,7 @@ IR into "t.ll" and run "``llvm-as < t.ll | opt -analyze -view-cfg``", `a window will pop up <../ProgrammersManual.html#viewing-graphs-while-debugging-code>`_ and you'll see this graph: -.. figure:: LangImpl5-cfg.png +.. figure:: LangImpl05-cfg.png :align: center :alt: Example CFG diff --git a/docs/tutorial/OCamlLangImpl6.rst b/docs/tutorial/OCamlLangImpl6.rst index a3ae11fd7e549011139be913c45e87da855697de..2fa25f5c22fb582fb625546625957ecd0fa9817d 100644 --- a/docs/tutorial/OCamlLangImpl6.rst +++ b/docs/tutorial/OCamlLangImpl6.rst @@ -496,17 +496,17 @@ converge: # determine whether the specific location diverges. # Solve for z = z^2 + c in the complex plane. - def mandleconverger(real imag iters creal cimag) + def mandelconverger(real imag iters creal cimag) if iters > 255 | (real*real + imag*imag > 4) then iters else - mandleconverger(real*real - imag*imag + creal, + mandelconverger(real*real - imag*imag + creal, 2*real*imag + cimag, iters+1, creal, cimag); # return the number of iterations required for the iteration to escape - def mandleconverge(real imag) - mandleconverger(real, imag, 0, real, imag); + def mandelconverge(real imag) + mandelconverger(real, imag, 0, real, imag); This "z = z\ :sup:`2`\ + c" function is a beautiful little creature that is the basis for computation of the `Mandelbrot @@ -520,12 +520,12 @@ but we can whip together something using the density plotter above: :: - # compute and plot the mandlebrot set with the specified 2 dimensional range + # compute and plot the mandelbrot set with the specified 2 dimensional range # info. def mandelhelp(xmin xmax xstep ymin ymax ystep) for y = ymin, y < ymax, ystep in ( (for x = xmin, x < xmax, xstep in - printdensity(mandleconverge(x,y))) + printdensity(mandelconverge(x,y))) : putchard(10) ) @@ -535,7 +535,7 @@ but we can whip together something using the density plotter above: mandelhelp(realstart, realstart+realmag*78, realmag, imagstart, imagstart+imagmag*40, imagmag); -Given this, we can try plotting out the mandlebrot set! Lets try it out: +Given this, we can try plotting out the mandelbrot set! Lets try it out: :: diff --git a/docs/tutorial/OCamlLangImpl7.rst b/docs/tutorial/OCamlLangImpl7.rst index c8c701b91012dbaa8525b492dd32a1b9e0d0e2d3..f36845c523434938b0b7ba3d4dc17bc03e42abdd 100644 --- a/docs/tutorial/OCamlLangImpl7.rst +++ b/docs/tutorial/OCamlLangImpl7.rst @@ -224,7 +224,7 @@ variables in certain circumstances: class <../LangRef.html#first-class-types>`_ values (such as pointers, scalars and vectors), and only if the array size of the allocation is 1 (or missing in the .ll file). mem2reg is not capable of promoting - structs or arrays to registers. Note that the "scalarrepl" pass is + structs or arrays to registers. Note that the "sroa" pass is more powerful and can promote structs, "unions", and arrays in many cases. diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst index dde53badd3ad8cbd26127c51f930360b3e580a35..494cfd0a33a773f83b5df86914a506b1fcbc6b61 100644 --- a/docs/tutorial/index.rst +++ b/docs/tutorial/index.rst @@ -22,6 +22,16 @@ Kaleidoscope: Implementing a Language with LLVM in Objective Caml OCamlLangImpl* +Building a JIT in LLVM +=============================================== + +.. toctree:: + :titlesonly: + :glob: + :numbered: + + BuildingAJIT* + External Tutorials ================== diff --git a/examples/BrainF/BrainF.cpp b/examples/BrainF/BrainF.cpp index d8c54b50b854902cd78f7e3b35a6c8e6468f22c0..97ecdab0fe95010634b827ef59dd0b2cf42e9024 100644 --- a/examples/BrainF/BrainF.cpp +++ b/examples/BrainF/BrainF.cpp @@ -1,11 +1,11 @@ -//===-- BrainF.cpp - BrainF compiler example ----------------------------===// +//===-- BrainF.cpp - BrainF compiler example ------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // // This class compiles the BrainF language into LLVM assembly. // @@ -21,13 +21,25 @@ // [ while(*h) { Start loop // ] } End loop // -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "BrainF.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/APInt.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/Casting.h" +#include #include using namespace llvm; diff --git a/examples/BrainF/BrainF.h b/examples/BrainF/BrainF.h index 15e9e0847141fa57b84e31c61eb58bfbfea4122e..587be141b98f0728ae7b49a27aa9ce10228e47f6 100644 --- a/examples/BrainF/BrainF.h +++ b/examples/BrainF/BrainF.h @@ -1,16 +1,16 @@ -//===-- BrainF.h - BrainF compiler class ----------------------*- C++ -*-===// +//===-- BrainF.h - BrainF compiler class ------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // // This class stores the data for the BrainF compiler so it doesn't have // to pass all of it around. The main method is parse. // -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #ifndef BRAINF_H #define BRAINF_H @@ -18,6 +18,7 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include using namespace llvm; @@ -91,4 +92,4 @@ class BrainF { Value *curhead; }; -#endif +#endif // BRAINF_H diff --git a/examples/BrainF/BrainFDriver.cpp b/examples/BrainF/BrainFDriver.cpp index 1a38c67b0d4a0fc23b46dea5188a8266268435a8..d19427add876af4f2e638e576d90236ebf60475e 100644 --- a/examples/BrainF/BrainFDriver.cpp +++ b/examples/BrainF/BrainFDriver.cpp @@ -1,11 +1,11 @@ -//===-- BrainFDriver.cpp - BrainF compiler driver -----------------------===// +//===-- BrainFDriver.cpp - BrainF compiler driver -------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // // This program converts the BrainF language into LLVM assembly, // which it can then run using the JIT or output as BitCode. @@ -22,21 +22,37 @@ // // lli prog.bf.bc #Run generated BitCode // -//===--------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "BrainF.h" +#include "llvm/ADT/APInt.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Value.h" #include "llvm/IR/Verifier.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" +#include +#include #include #include +#include +#include +#include +#include + using namespace llvm; //Command line options @@ -53,7 +69,6 @@ ArrayBoundsChecking("abc", cl::desc("Enable array bounds checking")); static cl::opt JIT("jit", cl::desc("Run program Just-In-Time")); - //Add main function so can be fully compiled void addMainFunction(Module *mod) { //define i32 @main(i32 %argc, i8 **%argv) @@ -88,7 +103,7 @@ void addMainFunction(Module *mod) { int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, " BrainF compiler\n"); - LLVMContext &Context = getGlobalContext(); + LLVMContext Context; if (InputFilename == "") { errs() << "Error: You must specify the filename of the program to " diff --git a/examples/ExceptionDemo/ExceptionDemo.cpp b/examples/ExceptionDemo/ExceptionDemo.cpp index 444ee2649fa734f2c700d55c61a85a66948345ae..0afc3fdf59aa4e315c5acc293208e18b5d8dca8d 100644 --- a/examples/ExceptionDemo/ExceptionDemo.cpp +++ b/examples/ExceptionDemo/ExceptionDemo.cpp @@ -1951,12 +1951,12 @@ int main(int argc, char *argv[]) { llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); - llvm::LLVMContext &context = llvm::getGlobalContext(); - llvm::IRBuilder<> theBuilder(context); + llvm::LLVMContext Context; + llvm::IRBuilder<> theBuilder(Context); // Make the module, which holds all the code. std::unique_ptr Owner = - llvm::make_unique("my cool jit", context); + llvm::make_unique("my cool jit", Context); llvm::Module *module = Owner.get(); std::unique_ptr MemMgr(new llvm::SectionMemoryManager()); diff --git a/examples/Fibonacci/CMakeLists.txt b/examples/Fibonacci/CMakeLists.txt index 087ccdd7d841d668769c690b51601be834c3fa0b..e294a2523759a9a08ad2171e9ec3c20aa876a42f 100644 --- a/examples/Fibonacci/CMakeLists.txt +++ b/examples/Fibonacci/CMakeLists.txt @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS ExecutionEngine Interpreter MC + MCJIT Support nativecodegen ) diff --git a/examples/Fibonacci/fibonacci.cpp b/examples/Fibonacci/fibonacci.cpp index ecb49eb92e1ac9b3f41e7edd47d1f799c5cc0cd4..16e52bf04099053916b76ba2add86b9381dcff87 100644 --- a/examples/Fibonacci/fibonacci.cpp +++ b/examples/Fibonacci/fibonacci.cpp @@ -23,16 +23,29 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/APInt.h" #include "llvm/IR/Verifier.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/Interpreter.h" +#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/IR/Argument.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include using namespace llvm; @@ -77,7 +90,6 @@ static Function *CreateFibFunction(Module *M, LLVMContext &Context) { CallInst *CallFibX2 = CallInst::Create(FibF, Sub, "fibx2", RecurseBB); CallFibX2->setTailCall(); - // fib(x-1)+fib(x-2) Value *Sum = BinaryOperator::CreateAdd(CallFibX1, CallFibX2, "addresult", RecurseBB); @@ -92,6 +104,7 @@ int main(int argc, char **argv) { int n = argc > 1 ? atol(argv[1]) : 24; InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); LLVMContext Context; // Create some module to put our function into it. diff --git a/examples/HowToUseJIT/HowToUseJIT.cpp b/examples/HowToUseJIT/HowToUseJIT.cpp index e0bf6a00bf017d84c0d1dac409a0f77d9c03108d..0050d27b45d7fbbbca446fab128c0a14c9d4a7d3 100644 --- a/examples/HowToUseJIT/HowToUseJIT.cpp +++ b/examples/HowToUseJIT/HowToUseJIT.cpp @@ -35,22 +35,30 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/Interpreter.h" +#include "llvm/IR/Argument.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include using namespace llvm; int main() { - InitializeNativeTarget(); LLVMContext Context; diff --git a/examples/Kaleidoscope/BuildingAJIT/CMakeLists.txt b/examples/Kaleidoscope/BuildingAJIT/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..947b5a3a3271ef394e0e12a8ee3cf20f755feecd --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/CMakeLists.txt @@ -0,0 +1,8 @@ +add_subdirectory(Chapter1) +add_subdirectory(Chapter2) +add_subdirectory(Chapter3) +add_subdirectory(Chapter4) + +if (NOT WIN32) + add_subdirectory(Chapter5) +endif() diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter1/CMakeLists.txt b/examples/Kaleidoscope/BuildingAJIT/Chapter1/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..657a14be87d0f2d0fd387f3a57b27a3d5f27b8af --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter1/CMakeLists.txt @@ -0,0 +1,17 @@ +set(LLVM_LINK_COMPONENTS + Analysis + Core + ExecutionEngine + InstCombine + Object + RuntimeDyld + ScalarOpts + Support + native + ) + +add_kaleidoscope_chapter(BuildingAJIT-Ch1 + toy.cpp + ) + +export_executable_symbols(BuildingAJIT-Ch1) diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h b/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h new file mode 100644 index 0000000000000000000000000000000000000000..35c871affec8bae2c06eb38354a6d3548448bf0f --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter1/KaleidoscopeJIT.h @@ -0,0 +1,102 @@ +//===----- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Contains a simple JIT definition for use in the kaleidoscope tutorials. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H +#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include +#include +#include +#include + +namespace llvm { +namespace orc { + +class KaleidoscopeJIT { +private: + std::unique_ptr TM; + const DataLayout DL; + ObjectLinkingLayer<> ObjectLayer; + IRCompileLayer CompileLayer; + +public: + typedef decltype(CompileLayer)::ModuleSetHandleT ModuleHandle; + + KaleidoscopeJIT() + : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), + CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { + llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + } + + TargetMachine &getTargetMachine() { return *TM; } + + ModuleHandle addModule(std::unique_ptr M) { + // Build our symbol resolver: + // Lambda 1: Look back into the JIT itself to find symbols that are part of + // the same "logical dylib". + // Lambda 2: Search for external symbols in the host process. + auto Resolver = createLambdaResolver( + [&](const std::string &Name) { + if (auto Sym = CompileLayer.findSymbol(Name, false)) + return Sym.toRuntimeDyldSymbol(); + return RuntimeDyld::SymbolInfo(nullptr); + }, + [](const std::string &Name) { + if (auto SymAddr = + RTDyldMemoryManager::getSymbolAddressInProcess(Name)) + return RuntimeDyld::SymbolInfo(SymAddr, JITSymbolFlags::Exported); + return RuntimeDyld::SymbolInfo(nullptr); + }); + + // Build a singlton module set to hold our module. + std::vector> Ms; + Ms.push_back(std::move(M)); + + // Add the set to the JIT with the resolver we created above and a newly + // created SectionMemoryManager. + return CompileLayer.addModuleSet(std::move(Ms), + make_unique(), + std::move(Resolver)); + } + + JITSymbol findSymbol(const std::string Name) { + std::string MangledName; + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + return CompileLayer.findSymbol(MangledNameStream.str(), true); + } + + void removeModule(ModuleHandle H) { + CompileLayer.removeModuleSet(H); + } + +}; + +} // end namespace orc +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter1/toy.cpp b/examples/Kaleidoscope/BuildingAJIT/Chapter1/toy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22b0819cd71a940ca824df68f597133546c96ccf --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter1/toy.cpp @@ -0,0 +1,1219 @@ +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/GVN.h" +#include "KaleidoscopeJIT.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::orc; + +//===----------------------------------------------------------------------===// +// Lexer +//===----------------------------------------------------------------------===// + +// The lexer returns tokens [0-255] if it is an unknown character, otherwise one +// of these for known things. +enum Token { + tok_eof = -1, + + // commands + tok_def = -2, + tok_extern = -3, + + // primary + tok_identifier = -4, + tok_number = -5, + + // control + tok_if = -6, + tok_then = -7, + tok_else = -8, + tok_for = -9, + tok_in = -10, + + // operators + tok_binary = -11, + tok_unary = -12, + + // var definition + tok_var = -13 +}; + +static std::string IdentifierStr; // Filled in if tok_identifier +static double NumVal; // Filled in if tok_number + +/// gettok - Return the next token from standard input. +static int gettok() { + static int LastChar = ' '; + + // Skip any whitespace. + while (isspace(LastChar)) + LastChar = getchar(); + + if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* + IdentifierStr = LastChar; + while (isalnum((LastChar = getchar()))) + IdentifierStr += LastChar; + + if (IdentifierStr == "def") + return tok_def; + if (IdentifierStr == "extern") + return tok_extern; + if (IdentifierStr == "if") + return tok_if; + if (IdentifierStr == "then") + return tok_then; + if (IdentifierStr == "else") + return tok_else; + if (IdentifierStr == "for") + return tok_for; + if (IdentifierStr == "in") + return tok_in; + if (IdentifierStr == "binary") + return tok_binary; + if (IdentifierStr == "unary") + return tok_unary; + if (IdentifierStr == "var") + return tok_var; + return tok_identifier; + } + + if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ + std::string NumStr; + do { + NumStr += LastChar; + LastChar = getchar(); + } while (isdigit(LastChar) || LastChar == '.'); + + NumVal = strtod(NumStr.c_str(), nullptr); + return tok_number; + } + + if (LastChar == '#') { + // Comment until end of line. + do + LastChar = getchar(); + while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); + + if (LastChar != EOF) + return gettok(); + } + + // Check for end of file. Don't eat the EOF. + if (LastChar == EOF) + return tok_eof; + + // Otherwise, just return the character as its ascii value. + int ThisChar = LastChar; + LastChar = getchar(); + return ThisChar; +} + +//===----------------------------------------------------------------------===// +// Abstract Syntax Tree (aka Parse Tree) +//===----------------------------------------------------------------------===// +namespace { +/// ExprAST - Base class for all expression nodes. +class ExprAST { +public: + virtual ~ExprAST() {} + virtual Value *codegen() = 0; +}; + +/// NumberExprAST - Expression class for numeric literals like "1.0". +class NumberExprAST : public ExprAST { + double Val; + +public: + NumberExprAST(double Val) : Val(Val) {} + Value *codegen() override; +}; + +/// VariableExprAST - Expression class for referencing a variable, like "a". +class VariableExprAST : public ExprAST { + std::string Name; + +public: + VariableExprAST(const std::string &Name) : Name(Name) {} + const std::string &getName() const { return Name; } + Value *codegen() override; +}; + +/// UnaryExprAST - Expression class for a unary operator. +class UnaryExprAST : public ExprAST { + char Opcode; + std::unique_ptr Operand; + +public: + UnaryExprAST(char Opcode, std::unique_ptr Operand) + : Opcode(Opcode), Operand(std::move(Operand)) {} + Value *codegen() override; +}; + +/// BinaryExprAST - Expression class for a binary operator. +class BinaryExprAST : public ExprAST { + char Op; + std::unique_ptr LHS, RHS; + +public: + BinaryExprAST(char Op, std::unique_ptr LHS, + std::unique_ptr RHS) + : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} + Value *codegen() override; +}; + +/// CallExprAST - Expression class for function calls. +class CallExprAST : public ExprAST { + std::string Callee; + std::vector> Args; + +public: + CallExprAST(const std::string &Callee, + std::vector> Args) + : Callee(Callee), Args(std::move(Args)) {} + Value *codegen() override; +}; + +/// IfExprAST - Expression class for if/then/else. +class IfExprAST : public ExprAST { + std::unique_ptr Cond, Then, Else; + +public: + IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, + std::unique_ptr Else) + : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} + Value *codegen() override; +}; + +/// ForExprAST - Expression class for for/in. +class ForExprAST : public ExprAST { + std::string VarName; + std::unique_ptr Start, End, Step, Body; + +public: + ForExprAST(const std::string &VarName, std::unique_ptr Start, + std::unique_ptr End, std::unique_ptr Step, + std::unique_ptr Body) + : VarName(VarName), Start(std::move(Start)), End(std::move(End)), + Step(std::move(Step)), Body(std::move(Body)) {} + Value *codegen() override; +}; + +/// VarExprAST - Expression class for var/in +class VarExprAST : public ExprAST { + std::vector>> VarNames; + std::unique_ptr Body; + +public: + VarExprAST( + std::vector>> VarNames, + std::unique_ptr Body) + : VarNames(std::move(VarNames)), Body(std::move(Body)) {} + Value *codegen() override; +}; + +/// PrototypeAST - This class represents the "prototype" for a function, +/// which captures its name, and its argument names (thus implicitly the number +/// of arguments the function takes), as well as if it is an operator. +class PrototypeAST { + std::string Name; + std::vector Args; + bool IsOperator; + unsigned Precedence; // Precedence if a binary op. + +public: + PrototypeAST(const std::string &Name, std::vector Args, + bool IsOperator = false, unsigned Prec = 0) + : Name(Name), Args(std::move(Args)), IsOperator(IsOperator), + Precedence(Prec) {} + Function *codegen(); + const std::string &getName() const { return Name; } + + bool isUnaryOp() const { return IsOperator && Args.size() == 1; } + bool isBinaryOp() const { return IsOperator && Args.size() == 2; } + + char getOperatorName() const { + assert(isUnaryOp() || isBinaryOp()); + return Name[Name.size() - 1]; + } + + unsigned getBinaryPrecedence() const { return Precedence; } +}; + +/// FunctionAST - This class represents a function definition itself. +class FunctionAST { + std::unique_ptr Proto; + std::unique_ptr Body; + +public: + FunctionAST(std::unique_ptr Proto, + std::unique_ptr Body) + : Proto(std::move(Proto)), Body(std::move(Body)) {} + Function *codegen(); +}; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Parser +//===----------------------------------------------------------------------===// + +/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current +/// token the parser is looking at. getNextToken reads another token from the +/// lexer and updates CurTok with its results. +static int CurTok; +static int getNextToken() { return CurTok = gettok(); } + +/// BinopPrecedence - This holds the precedence for each binary operator that is +/// defined. +static std::map BinopPrecedence; + +/// GetTokPrecedence - Get the precedence of the pending binary operator token. +static int GetTokPrecedence() { + if (!isascii(CurTok)) + return -1; + + // Make sure it's a declared binop. + int TokPrec = BinopPrecedence[CurTok]; + if (TokPrec <= 0) + return -1; + return TokPrec; +} + +/// LogError* - These are little helper functions for error handling. +std::unique_ptr LogError(const char *Str) { + fprintf(stderr, "Error: %s\n", Str); + return nullptr; +} + +std::unique_ptr LogErrorP(const char *Str) { + LogError(Str); + return nullptr; +} + +static std::unique_ptr ParseExpression(); + +/// numberexpr ::= number +static std::unique_ptr ParseNumberExpr() { + auto Result = llvm::make_unique(NumVal); + getNextToken(); // consume the number + return std::move(Result); +} + +/// parenexpr ::= '(' expression ')' +static std::unique_ptr ParseParenExpr() { + getNextToken(); // eat (. + auto V = ParseExpression(); + if (!V) + return nullptr; + + if (CurTok != ')') + return LogError("expected ')'"); + getNextToken(); // eat ). + return V; +} + +/// identifierexpr +/// ::= identifier +/// ::= identifier '(' expression* ')' +static std::unique_ptr ParseIdentifierExpr() { + std::string IdName = IdentifierStr; + + getNextToken(); // eat identifier. + + if (CurTok != '(') // Simple variable ref. + return llvm::make_unique(IdName); + + // Call. + getNextToken(); // eat ( + std::vector> Args; + if (CurTok != ')') { + while (true) { + if (auto Arg = ParseExpression()) + Args.push_back(std::move(Arg)); + else + return nullptr; + + if (CurTok == ')') + break; + + if (CurTok != ',') + return LogError("Expected ')' or ',' in argument list"); + getNextToken(); + } + } + + // Eat the ')'. + getNextToken(); + + return llvm::make_unique(IdName, std::move(Args)); +} + +/// ifexpr ::= 'if' expression 'then' expression 'else' expression +static std::unique_ptr ParseIfExpr() { + getNextToken(); // eat the if. + + // condition. + auto Cond = ParseExpression(); + if (!Cond) + return nullptr; + + if (CurTok != tok_then) + return LogError("expected then"); + getNextToken(); // eat the then + + auto Then = ParseExpression(); + if (!Then) + return nullptr; + + if (CurTok != tok_else) + return LogError("expected else"); + + getNextToken(); + + auto Else = ParseExpression(); + if (!Else) + return nullptr; + + return llvm::make_unique(std::move(Cond), std::move(Then), + std::move(Else)); +} + +/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression +static std::unique_ptr ParseForExpr() { + getNextToken(); // eat the for. + + if (CurTok != tok_identifier) + return LogError("expected identifier after for"); + + std::string IdName = IdentifierStr; + getNextToken(); // eat identifier. + + if (CurTok != '=') + return LogError("expected '=' after for"); + getNextToken(); // eat '='. + + auto Start = ParseExpression(); + if (!Start) + return nullptr; + if (CurTok != ',') + return LogError("expected ',' after for start value"); + getNextToken(); + + auto End = ParseExpression(); + if (!End) + return nullptr; + + // The step value is optional. + std::unique_ptr Step; + if (CurTok == ',') { + getNextToken(); + Step = ParseExpression(); + if (!Step) + return nullptr; + } + + if (CurTok != tok_in) + return LogError("expected 'in' after for"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(IdName, std::move(Start), std::move(End), + std::move(Step), std::move(Body)); +} + +/// varexpr ::= 'var' identifier ('=' expression)? +// (',' identifier ('=' expression)?)* 'in' expression +static std::unique_ptr ParseVarExpr() { + getNextToken(); // eat the var. + + std::vector>> VarNames; + + // At least one variable name is required. + if (CurTok != tok_identifier) + return LogError("expected identifier after var"); + + while (true) { + std::string Name = IdentifierStr; + getNextToken(); // eat identifier. + + // Read the optional initializer. + std::unique_ptr Init = nullptr; + if (CurTok == '=') { + getNextToken(); // eat the '='. + + Init = ParseExpression(); + if (!Init) + return nullptr; + } + + VarNames.push_back(std::make_pair(Name, std::move(Init))); + + // End of var list, exit loop. + if (CurTok != ',') + break; + getNextToken(); // eat the ','. + + if (CurTok != tok_identifier) + return LogError("expected identifier list after var"); + } + + // At this point, we have to have 'in'. + if (CurTok != tok_in) + return LogError("expected 'in' keyword after 'var'"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(std::move(VarNames), std::move(Body)); +} + +/// primary +/// ::= identifierexpr +/// ::= numberexpr +/// ::= parenexpr +/// ::= ifexpr +/// ::= forexpr +/// ::= varexpr +static std::unique_ptr ParsePrimary() { + switch (CurTok) { + default: + return LogError("unknown token when expecting an expression"); + case tok_identifier: + return ParseIdentifierExpr(); + case tok_number: + return ParseNumberExpr(); + case '(': + return ParseParenExpr(); + case tok_if: + return ParseIfExpr(); + case tok_for: + return ParseForExpr(); + case tok_var: + return ParseVarExpr(); + } +} + +/// unary +/// ::= primary +/// ::= '!' unary +static std::unique_ptr ParseUnary() { + // If the current token is not an operator, it must be a primary expr. + if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') + return ParsePrimary(); + + // If this is a unary operator, read it. + int Opc = CurTok; + getNextToken(); + if (auto Operand = ParseUnary()) + return llvm::make_unique(Opc, std::move(Operand)); + return nullptr; +} + +/// binoprhs +/// ::= ('+' unary)* +static std::unique_ptr ParseBinOpRHS(int ExprPrec, + std::unique_ptr LHS) { + // If this is a binop, find its precedence. + while (true) { + int TokPrec = GetTokPrecedence(); + + // If this is a binop that binds at least as tightly as the current binop, + // consume it, otherwise we are done. + if (TokPrec < ExprPrec) + return LHS; + + // Okay, we know this is a binop. + int BinOp = CurTok; + getNextToken(); // eat binop + + // Parse the unary expression after the binary operator. + auto RHS = ParseUnary(); + if (!RHS) + return nullptr; + + // If BinOp binds less tightly with RHS than the operator after RHS, let + // the pending operator take RHS as its LHS. + int NextPrec = GetTokPrecedence(); + if (TokPrec < NextPrec) { + RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); + if (!RHS) + return nullptr; + } + + // Merge LHS/RHS. + LHS = + llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); + } +} + +/// expression +/// ::= unary binoprhs +/// +static std::unique_ptr ParseExpression() { + auto LHS = ParseUnary(); + if (!LHS) + return nullptr; + + return ParseBinOpRHS(0, std::move(LHS)); +} + +/// prototype +/// ::= id '(' id* ')' +/// ::= binary LETTER number? (id, id) +/// ::= unary LETTER (id) +static std::unique_ptr ParsePrototype() { + std::string FnName; + + unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. + unsigned BinaryPrecedence = 30; + + switch (CurTok) { + default: + return LogErrorP("Expected function name in prototype"); + case tok_identifier: + FnName = IdentifierStr; + Kind = 0; + getNextToken(); + break; + case tok_unary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected unary operator"); + FnName = "unary"; + FnName += (char)CurTok; + Kind = 1; + getNextToken(); + break; + case tok_binary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected binary operator"); + FnName = "binary"; + FnName += (char)CurTok; + Kind = 2; + getNextToken(); + + // Read the precedence if present. + if (CurTok == tok_number) { + if (NumVal < 1 || NumVal > 100) + return LogErrorP("Invalid precedecnce: must be 1..100"); + BinaryPrecedence = (unsigned)NumVal; + getNextToken(); + } + break; + } + + if (CurTok != '(') + return LogErrorP("Expected '(' in prototype"); + + std::vector ArgNames; + while (getNextToken() == tok_identifier) + ArgNames.push_back(IdentifierStr); + if (CurTok != ')') + return LogErrorP("Expected ')' in prototype"); + + // success. + getNextToken(); // eat ')'. + + // Verify right number of names for operator. + if (Kind && ArgNames.size() != Kind) + return LogErrorP("Invalid number of operands for operator"); + + return llvm::make_unique(FnName, ArgNames, Kind != 0, + BinaryPrecedence); +} + +/// definition ::= 'def' prototype expression +static std::unique_ptr ParseDefinition() { + getNextToken(); // eat def. + auto Proto = ParsePrototype(); + if (!Proto) + return nullptr; + + if (auto E = ParseExpression()) + return llvm::make_unique(std::move(Proto), std::move(E)); + return nullptr; +} + +/// toplevelexpr ::= expression +static std::unique_ptr ParseTopLevelExpr() { + if (auto E = ParseExpression()) { + // Make an anonymous proto. + auto Proto = llvm::make_unique("__anon_expr", + std::vector()); + return llvm::make_unique(std::move(Proto), std::move(E)); + } + return nullptr; +} + +/// external ::= 'extern' prototype +static std::unique_ptr ParseExtern() { + getNextToken(); // eat extern. + return ParsePrototype(); +} + +//===----------------------------------------------------------------------===// +// Code Generation +//===----------------------------------------------------------------------===// + +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheModule; +static std::map NamedValues; +static std::unique_ptr TheJIT; +static std::map> FunctionProtos; + +Value *LogErrorV(const char *Str) { + LogError(Str); + return nullptr; +} + +Function *getFunction(std::string Name) { + // First, see if the function has already been added to the current module. + if (auto *F = TheModule->getFunction(Name)) + return F; + + // If not, check whether we can codegen the declaration from some existing + // prototype. + auto FI = FunctionProtos.find(Name); + if (FI != FunctionProtos.end()) + return FI->second->codegen(); + + // If no existing prototype exists, return null. + return nullptr; +} + +/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of +/// the function. This is used for mutable variables etc. +static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, + const std::string &VarName) { + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), + TheFunction->getEntryBlock().begin()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); +} + +Value *NumberExprAST::codegen() { + return ConstantFP::get(TheContext, APFloat(Val)); +} + +Value *VariableExprAST::codegen() { + // Look this variable up in the function. + Value *V = NamedValues[Name]; + if (!V) + return LogErrorV("Unknown variable name"); + + // Load the value. + return Builder.CreateLoad(V, Name.c_str()); +} + +Value *UnaryExprAST::codegen() { + Value *OperandV = Operand->codegen(); + if (!OperandV) + return nullptr; + + Function *F = getFunction(std::string("unary") + Opcode); + if (!F) + return LogErrorV("Unknown unary operator"); + + return Builder.CreateCall(F, OperandV, "unop"); +} + +Value *BinaryExprAST::codegen() { + // Special case '=' because we don't want to emit the LHS as an expression. + if (Op == '=') { + // Assignment requires the LHS to be an identifier. + // This assume we're building without RTTI because LLVM builds that way by + // default. If you build LLVM with RTTI this can be changed to a + // dynamic_cast for automatic error checking. + VariableExprAST *LHSE = static_cast(LHS.get()); + if (!LHSE) + return LogErrorV("destination of '=' must be a variable"); + // Codegen the RHS. + Value *Val = RHS->codegen(); + if (!Val) + return nullptr; + + // Look up the name. + Value *Variable = NamedValues[LHSE->getName()]; + if (!Variable) + return LogErrorV("Unknown variable name"); + + Builder.CreateStore(Val, Variable); + return Val; + } + + Value *L = LHS->codegen(); + Value *R = RHS->codegen(); + if (!L || !R) + return nullptr; + + switch (Op) { + case '+': + return Builder.CreateFAdd(L, R, "addtmp"); + case '-': + return Builder.CreateFSub(L, R, "subtmp"); + case '*': + return Builder.CreateFMul(L, R, "multmp"); + case '<': + L = Builder.CreateFCmpULT(L, R, "cmptmp"); + // Convert bool 0/1 to double 0.0 or 1.0 + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + default: + break; + } + + // If it wasn't a builtin binary operator, it must be a user defined one. Emit + // a call to it. + Function *F = getFunction(std::string("binary") + Op); + assert(F && "binary operator not found!"); + + Value *Ops[] = {L, R}; + return Builder.CreateCall(F, Ops, "binop"); +} + +Value *CallExprAST::codegen() { + // Look up the name in the global module table. + Function *CalleeF = getFunction(Callee); + if (!CalleeF) + return LogErrorV("Unknown function referenced"); + + // If argument mismatch error. + if (CalleeF->arg_size() != Args.size()) + return LogErrorV("Incorrect # arguments passed"); + + std::vector ArgsV; + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + ArgsV.push_back(Args[i]->codegen()); + if (!ArgsV.back()) + return nullptr; + } + + return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); +} + +Value *IfExprAST::codegen() { + Value *CondV = Cond->codegen(); + if (!CondV) + return nullptr; + + // Convert condition to a bool by comparing equal to 0.0. + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create blocks for the then and else cases. Insert the 'then' block at the + // end of the function. + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + + Builder.CreateCondBr(CondV, ThenBB, ElseBB); + + // Emit then value. + Builder.SetInsertPoint(ThenBB); + + Value *ThenV = Then->codegen(); + if (!ThenV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Then' can change the current block, update ThenBB for the PHI. + ThenBB = Builder.GetInsertBlock(); + + // Emit else block. + TheFunction->getBasicBlockList().push_back(ElseBB); + Builder.SetInsertPoint(ElseBB); + + Value *ElseV = Else->codegen(); + if (!ElseV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Else' can change the current block, update ElseBB for the PHI. + ElseBB = Builder.GetInsertBlock(); + + // Emit merge block. + TheFunction->getBasicBlockList().push_back(MergeBB); + Builder.SetInsertPoint(MergeBB); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + + PN->addIncoming(ThenV, ThenBB); + PN->addIncoming(ElseV, ElseBB); + return PN; +} + +// Output for-loop as: +// var = alloca double +// ... +// start = startexpr +// store start -> var +// goto loop +// loop: +// ... +// bodyexpr +// ... +// loopend: +// step = stepexpr +// endcond = endexpr +// +// curvar = load var +// nextvar = curvar + step +// store nextvar -> var +// br endcond, loop, endloop +// outloop: +Value *ForExprAST::codegen() { + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create an alloca for the variable in the entry block. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + + // Emit the start code first, without 'variable' in scope. + Value *StartVal = Start->codegen(); + if (!StartVal) + return nullptr; + + // Store the value into the alloca. + Builder.CreateStore(StartVal, Alloca); + + // Make the new basic block for the loop header, inserting after current + // block. + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + + // Insert an explicit fall through from the current block to the LoopBB. + Builder.CreateBr(LoopBB); + + // Start insertion in LoopBB. + Builder.SetInsertPoint(LoopBB); + + // Within the loop, the variable is defined equal to the PHI node. If it + // shadows an existing variable, we have to restore it, so save it now. + AllocaInst *OldVal = NamedValues[VarName]; + NamedValues[VarName] = Alloca; + + // Emit the body of the loop. This, like any other expr, can change the + // current BB. Note that we ignore the value computed by the body, but don't + // allow an error. + if (!Body->codegen()) + return nullptr; + + // Emit the step value. + Value *StepVal = nullptr; + if (Step) { + StepVal = Step->codegen(); + if (!StepVal) + return nullptr; + } else { + // If not specified, use 1.0. + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + } + + // Compute the end condition. + Value *EndCond = End->codegen(); + if (!EndCond) + return nullptr; + + // Reload, increment, and restore the alloca. This handles the case where + // the body of the loop mutates the variable. + Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); + Builder.CreateStore(NextVar, Alloca); + + // Convert condition to a bool by comparing equal to 0.0. + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + + // Create the "after loop" block and insert it. + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); + + // Insert the conditional branch into the end of LoopEndBB. + Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + + // Any new code will be inserted in AfterBB. + Builder.SetInsertPoint(AfterBB); + + // Restore the unshadowed variable. + if (OldVal) + NamedValues[VarName] = OldVal; + else + NamedValues.erase(VarName); + + // for expr always returns 0.0. + return Constant::getNullValue(Type::getDoubleTy(TheContext)); +} + +Value *VarExprAST::codegen() { + std::vector OldBindings; + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Register all variables and emit their initializer. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { + const std::string &VarName = VarNames[i].first; + ExprAST *Init = VarNames[i].second.get(); + + // Emit the initializer before adding the variable to scope, this prevents + // the initializer from referencing the variable itself, and permits stuff + // like this: + // var a = 1 in + // var a = a in ... # refers to outer 'a'. + Value *InitVal; + if (Init) { + InitVal = Init->codegen(); + if (!InitVal) + return nullptr; + } else { // If not specified, use 0.0. + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + } + + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + Builder.CreateStore(InitVal, Alloca); + + // Remember the old variable binding so that we can restore the binding when + // we unrecurse. + OldBindings.push_back(NamedValues[VarName]); + + // Remember this binding. + NamedValues[VarName] = Alloca; + } + + // Codegen the body, now that all vars are in scope. + Value *BodyVal = Body->codegen(); + if (!BodyVal) + return nullptr; + + // Pop all our variables from scope. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) + NamedValues[VarNames[i].first] = OldBindings[i]; + + // Return the body computation. + return BodyVal; +} + +Function *PrototypeAST::codegen() { + // Make the function type: double(double,double) etc. + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + + Function *F = + Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); + + // Set names for all arguments. + unsigned Idx = 0; + for (auto &Arg : F->args()) + Arg.setName(Args[Idx++]); + + return F; +} + +Function *FunctionAST::codegen() { + // Transfer ownership of the prototype to the FunctionProtos map, but keep a + // reference to it for use below. + auto &P = *Proto; + FunctionProtos[Proto->getName()] = std::move(Proto); + Function *TheFunction = getFunction(P.getName()); + if (!TheFunction) + return nullptr; + + // If this is an operator, install it. + if (P.isBinaryOp()) + BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); + + // Create a new basic block to start insertion into. + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); + Builder.SetInsertPoint(BB); + + // Record the function arguments in the NamedValues map. + NamedValues.clear(); + for (auto &Arg : TheFunction->args()) { + // Create an alloca for this variable. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); + + // Store the initial value into the alloca. + Builder.CreateStore(&Arg, Alloca); + + // Add arguments to variable symbol table. + NamedValues[Arg.getName()] = Alloca; + } + + if (Value *RetVal = Body->codegen()) { + // Finish off the function. + Builder.CreateRet(RetVal); + + // Validate the generated code, checking for consistency. + verifyFunction(*TheFunction); + + return TheFunction; + } + + // Error reading body, remove function. + TheFunction->eraseFromParent(); + + if (P.isBinaryOp()) + BinopPrecedence.erase(Proto->getOperatorName()); + return nullptr; +} + +//===----------------------------------------------------------------------===// +// Top-Level parsing and JIT Driver +//===----------------------------------------------------------------------===// + +static void InitializeModule() { + // Open a new module. + TheModule = llvm::make_unique("my cool jit", TheContext); + TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); +} + +static void HandleDefinition() { + if (auto FnAST = ParseDefinition()) { + if (auto *FnIR = FnAST->codegen()) { + fprintf(stderr, "Read function definition:"); + FnIR->dump(); + TheJIT->addModule(std::move(TheModule)); + InitializeModule(); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleExtern() { + if (auto ProtoAST = ParseExtern()) { + if (auto *FnIR = ProtoAST->codegen()) { + fprintf(stderr, "Read extern: "); + FnIR->dump(); + FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleTopLevelExpression() { + // Evaluate a top-level expression into an anonymous function. + if (auto FnAST = ParseTopLevelExpr()) { + if (FnAST->codegen()) { + // JIT the module containing the anonymous expression, keeping a handle so + // we can free it later. + auto H = TheJIT->addModule(std::move(TheModule)); + InitializeModule(); + + // Search the JIT for the __anon_expr symbol. + auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); + assert(ExprSymbol && "Function not found"); + + // Get the symbol's address and cast it to the right type (takes no + // arguments, returns a double) so we can call it as a native function. + double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); + fprintf(stderr, "Evaluated to %f\n", FP()); + + // Delete the anonymous expression module from the JIT. + TheJIT->removeModule(H); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +/// top ::= definition | external | expression | ';' +static void MainLoop() { + while (true) { + fprintf(stderr, "ready> "); + switch (CurTok) { + case tok_eof: + return; + case ';': // ignore top-level semicolons. + getNextToken(); + break; + case tok_def: + HandleDefinition(); + break; + case tok_extern: + HandleExtern(); + break; + default: + HandleTopLevelExpression(); + break; + } + } +} + +//===----------------------------------------------------------------------===// +// "Library" functions that can be "extern'd" from user code. +//===----------------------------------------------------------------------===// + +/// putchard - putchar that takes a double and returns 0. +extern "C" double putchard(double X) { + fputc((char)X, stderr); + return 0; +} + +/// printd - printf that takes a double prints it as "%f\n", returning 0. +extern "C" double printd(double X) { + fprintf(stderr, "%f\n", X); + return 0; +} + +//===----------------------------------------------------------------------===// +// Main driver code. +//===----------------------------------------------------------------------===// + +int main() { + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetAsmParser(); + + // Install standard binary operators. + // 1 is lowest precedence. + BinopPrecedence['='] = 2; + BinopPrecedence['<'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; // highest. + + // Prime the first token. + fprintf(stderr, "ready> "); + getNextToken(); + + TheJIT = llvm::make_unique(); + + InitializeModule(); + + // Run the main "interpreter loop" now. + MainLoop(); + + return 0; +} diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter2/CMakeLists.txt b/examples/Kaleidoscope/BuildingAJIT/Chapter2/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ea5bc05fa00a1854ee648c6ccf4b9ab7dfa10cd2 --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter2/CMakeLists.txt @@ -0,0 +1,17 @@ +set(LLVM_LINK_COMPONENTS + Analysis + Core + ExecutionEngine + InstCombine + Object + RuntimeDyld + ScalarOpts + Support + native + ) + +add_kaleidoscope_chapter(BuildingAJIT-Ch2 + toy.cpp + ) + +export_executable_symbols(BuildingAJIT-Ch2) diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h b/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h new file mode 100644 index 0000000000000000000000000000000000000000..30cfed6af95ec37697e2a013d3a67fc567f9c018 --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter2/KaleidoscopeJIT.h @@ -0,0 +1,133 @@ +//===----- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Contains a simple JIT definition for use in the kaleidoscope tutorials. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H +#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" +#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include +#include +#include +#include + +namespace llvm { +namespace orc { + +class KaleidoscopeJIT { +private: + std::unique_ptr TM; + const DataLayout DL; + ObjectLinkingLayer<> ObjectLayer; + IRCompileLayer CompileLayer; + + typedef std::function(std::unique_ptr)> + OptimizeFunction; + + IRTransformLayer OptimizeLayer; + +public: + typedef decltype(OptimizeLayer)::ModuleSetHandleT ModuleHandle; + + KaleidoscopeJIT() + : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), + CompileLayer(ObjectLayer, SimpleCompiler(*TM)), + OptimizeLayer(CompileLayer, + [this](std::unique_ptr M) { + return optimizeModule(std::move(M)); + }) { + llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + } + + TargetMachine &getTargetMachine() { return *TM; } + + ModuleHandle addModule(std::unique_ptr M) { + // Build our symbol resolver: + // Lambda 1: Look back into the JIT itself to find symbols that are part of + // the same "logical dylib". + // Lambda 2: Search for external symbols in the host process. + auto Resolver = createLambdaResolver( + [&](const std::string &Name) { + if (auto Sym = OptimizeLayer.findSymbol(Name, false)) + return Sym.toRuntimeDyldSymbol(); + return RuntimeDyld::SymbolInfo(nullptr); + }, + [](const std::string &Name) { + if (auto SymAddr = + RTDyldMemoryManager::getSymbolAddressInProcess(Name)) + return RuntimeDyld::SymbolInfo(SymAddr, JITSymbolFlags::Exported); + return RuntimeDyld::SymbolInfo(nullptr); + }); + + // Build a singlton module set to hold our module. + std::vector> Ms; + Ms.push_back(std::move(M)); + + // Add the set to the JIT with the resolver we created above and a newly + // created SectionMemoryManager. + return OptimizeLayer.addModuleSet(std::move(Ms), + make_unique(), + std::move(Resolver)); + } + + JITSymbol findSymbol(const std::string Name) { + std::string MangledName; + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + return OptimizeLayer.findSymbol(MangledNameStream.str(), true); + } + + void removeModule(ModuleHandle H) { + OptimizeLayer.removeModuleSet(H); + } + +private: + + std::unique_ptr optimizeModule(std::unique_ptr M) { + // Create a function pass manager. + auto FPM = llvm::make_unique(M.get()); + + // Add some optimizations. + FPM->add(createInstructionCombiningPass()); + FPM->add(createReassociatePass()); + FPM->add(createGVNPass()); + FPM->add(createCFGSimplificationPass()); + FPM->doInitialization(); + + // Run the optimizations over all functions in the module being added to + // the JIT. + for (auto &F : *M) + FPM->run(F); + + return M; + } + +}; + +} // end namespace orc +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter2/toy.cpp b/examples/Kaleidoscope/BuildingAJIT/Chapter2/toy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22b0819cd71a940ca824df68f597133546c96ccf --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter2/toy.cpp @@ -0,0 +1,1219 @@ +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/GVN.h" +#include "KaleidoscopeJIT.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::orc; + +//===----------------------------------------------------------------------===// +// Lexer +//===----------------------------------------------------------------------===// + +// The lexer returns tokens [0-255] if it is an unknown character, otherwise one +// of these for known things. +enum Token { + tok_eof = -1, + + // commands + tok_def = -2, + tok_extern = -3, + + // primary + tok_identifier = -4, + tok_number = -5, + + // control + tok_if = -6, + tok_then = -7, + tok_else = -8, + tok_for = -9, + tok_in = -10, + + // operators + tok_binary = -11, + tok_unary = -12, + + // var definition + tok_var = -13 +}; + +static std::string IdentifierStr; // Filled in if tok_identifier +static double NumVal; // Filled in if tok_number + +/// gettok - Return the next token from standard input. +static int gettok() { + static int LastChar = ' '; + + // Skip any whitespace. + while (isspace(LastChar)) + LastChar = getchar(); + + if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* + IdentifierStr = LastChar; + while (isalnum((LastChar = getchar()))) + IdentifierStr += LastChar; + + if (IdentifierStr == "def") + return tok_def; + if (IdentifierStr == "extern") + return tok_extern; + if (IdentifierStr == "if") + return tok_if; + if (IdentifierStr == "then") + return tok_then; + if (IdentifierStr == "else") + return tok_else; + if (IdentifierStr == "for") + return tok_for; + if (IdentifierStr == "in") + return tok_in; + if (IdentifierStr == "binary") + return tok_binary; + if (IdentifierStr == "unary") + return tok_unary; + if (IdentifierStr == "var") + return tok_var; + return tok_identifier; + } + + if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ + std::string NumStr; + do { + NumStr += LastChar; + LastChar = getchar(); + } while (isdigit(LastChar) || LastChar == '.'); + + NumVal = strtod(NumStr.c_str(), nullptr); + return tok_number; + } + + if (LastChar == '#') { + // Comment until end of line. + do + LastChar = getchar(); + while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); + + if (LastChar != EOF) + return gettok(); + } + + // Check for end of file. Don't eat the EOF. + if (LastChar == EOF) + return tok_eof; + + // Otherwise, just return the character as its ascii value. + int ThisChar = LastChar; + LastChar = getchar(); + return ThisChar; +} + +//===----------------------------------------------------------------------===// +// Abstract Syntax Tree (aka Parse Tree) +//===----------------------------------------------------------------------===// +namespace { +/// ExprAST - Base class for all expression nodes. +class ExprAST { +public: + virtual ~ExprAST() {} + virtual Value *codegen() = 0; +}; + +/// NumberExprAST - Expression class for numeric literals like "1.0". +class NumberExprAST : public ExprAST { + double Val; + +public: + NumberExprAST(double Val) : Val(Val) {} + Value *codegen() override; +}; + +/// VariableExprAST - Expression class for referencing a variable, like "a". +class VariableExprAST : public ExprAST { + std::string Name; + +public: + VariableExprAST(const std::string &Name) : Name(Name) {} + const std::string &getName() const { return Name; } + Value *codegen() override; +}; + +/// UnaryExprAST - Expression class for a unary operator. +class UnaryExprAST : public ExprAST { + char Opcode; + std::unique_ptr Operand; + +public: + UnaryExprAST(char Opcode, std::unique_ptr Operand) + : Opcode(Opcode), Operand(std::move(Operand)) {} + Value *codegen() override; +}; + +/// BinaryExprAST - Expression class for a binary operator. +class BinaryExprAST : public ExprAST { + char Op; + std::unique_ptr LHS, RHS; + +public: + BinaryExprAST(char Op, std::unique_ptr LHS, + std::unique_ptr RHS) + : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} + Value *codegen() override; +}; + +/// CallExprAST - Expression class for function calls. +class CallExprAST : public ExprAST { + std::string Callee; + std::vector> Args; + +public: + CallExprAST(const std::string &Callee, + std::vector> Args) + : Callee(Callee), Args(std::move(Args)) {} + Value *codegen() override; +}; + +/// IfExprAST - Expression class for if/then/else. +class IfExprAST : public ExprAST { + std::unique_ptr Cond, Then, Else; + +public: + IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, + std::unique_ptr Else) + : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} + Value *codegen() override; +}; + +/// ForExprAST - Expression class for for/in. +class ForExprAST : public ExprAST { + std::string VarName; + std::unique_ptr Start, End, Step, Body; + +public: + ForExprAST(const std::string &VarName, std::unique_ptr Start, + std::unique_ptr End, std::unique_ptr Step, + std::unique_ptr Body) + : VarName(VarName), Start(std::move(Start)), End(std::move(End)), + Step(std::move(Step)), Body(std::move(Body)) {} + Value *codegen() override; +}; + +/// VarExprAST - Expression class for var/in +class VarExprAST : public ExprAST { + std::vector>> VarNames; + std::unique_ptr Body; + +public: + VarExprAST( + std::vector>> VarNames, + std::unique_ptr Body) + : VarNames(std::move(VarNames)), Body(std::move(Body)) {} + Value *codegen() override; +}; + +/// PrototypeAST - This class represents the "prototype" for a function, +/// which captures its name, and its argument names (thus implicitly the number +/// of arguments the function takes), as well as if it is an operator. +class PrototypeAST { + std::string Name; + std::vector Args; + bool IsOperator; + unsigned Precedence; // Precedence if a binary op. + +public: + PrototypeAST(const std::string &Name, std::vector Args, + bool IsOperator = false, unsigned Prec = 0) + : Name(Name), Args(std::move(Args)), IsOperator(IsOperator), + Precedence(Prec) {} + Function *codegen(); + const std::string &getName() const { return Name; } + + bool isUnaryOp() const { return IsOperator && Args.size() == 1; } + bool isBinaryOp() const { return IsOperator && Args.size() == 2; } + + char getOperatorName() const { + assert(isUnaryOp() || isBinaryOp()); + return Name[Name.size() - 1]; + } + + unsigned getBinaryPrecedence() const { return Precedence; } +}; + +/// FunctionAST - This class represents a function definition itself. +class FunctionAST { + std::unique_ptr Proto; + std::unique_ptr Body; + +public: + FunctionAST(std::unique_ptr Proto, + std::unique_ptr Body) + : Proto(std::move(Proto)), Body(std::move(Body)) {} + Function *codegen(); +}; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Parser +//===----------------------------------------------------------------------===// + +/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current +/// token the parser is looking at. getNextToken reads another token from the +/// lexer and updates CurTok with its results. +static int CurTok; +static int getNextToken() { return CurTok = gettok(); } + +/// BinopPrecedence - This holds the precedence for each binary operator that is +/// defined. +static std::map BinopPrecedence; + +/// GetTokPrecedence - Get the precedence of the pending binary operator token. +static int GetTokPrecedence() { + if (!isascii(CurTok)) + return -1; + + // Make sure it's a declared binop. + int TokPrec = BinopPrecedence[CurTok]; + if (TokPrec <= 0) + return -1; + return TokPrec; +} + +/// LogError* - These are little helper functions for error handling. +std::unique_ptr LogError(const char *Str) { + fprintf(stderr, "Error: %s\n", Str); + return nullptr; +} + +std::unique_ptr LogErrorP(const char *Str) { + LogError(Str); + return nullptr; +} + +static std::unique_ptr ParseExpression(); + +/// numberexpr ::= number +static std::unique_ptr ParseNumberExpr() { + auto Result = llvm::make_unique(NumVal); + getNextToken(); // consume the number + return std::move(Result); +} + +/// parenexpr ::= '(' expression ')' +static std::unique_ptr ParseParenExpr() { + getNextToken(); // eat (. + auto V = ParseExpression(); + if (!V) + return nullptr; + + if (CurTok != ')') + return LogError("expected ')'"); + getNextToken(); // eat ). + return V; +} + +/// identifierexpr +/// ::= identifier +/// ::= identifier '(' expression* ')' +static std::unique_ptr ParseIdentifierExpr() { + std::string IdName = IdentifierStr; + + getNextToken(); // eat identifier. + + if (CurTok != '(') // Simple variable ref. + return llvm::make_unique(IdName); + + // Call. + getNextToken(); // eat ( + std::vector> Args; + if (CurTok != ')') { + while (true) { + if (auto Arg = ParseExpression()) + Args.push_back(std::move(Arg)); + else + return nullptr; + + if (CurTok == ')') + break; + + if (CurTok != ',') + return LogError("Expected ')' or ',' in argument list"); + getNextToken(); + } + } + + // Eat the ')'. + getNextToken(); + + return llvm::make_unique(IdName, std::move(Args)); +} + +/// ifexpr ::= 'if' expression 'then' expression 'else' expression +static std::unique_ptr ParseIfExpr() { + getNextToken(); // eat the if. + + // condition. + auto Cond = ParseExpression(); + if (!Cond) + return nullptr; + + if (CurTok != tok_then) + return LogError("expected then"); + getNextToken(); // eat the then + + auto Then = ParseExpression(); + if (!Then) + return nullptr; + + if (CurTok != tok_else) + return LogError("expected else"); + + getNextToken(); + + auto Else = ParseExpression(); + if (!Else) + return nullptr; + + return llvm::make_unique(std::move(Cond), std::move(Then), + std::move(Else)); +} + +/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression +static std::unique_ptr ParseForExpr() { + getNextToken(); // eat the for. + + if (CurTok != tok_identifier) + return LogError("expected identifier after for"); + + std::string IdName = IdentifierStr; + getNextToken(); // eat identifier. + + if (CurTok != '=') + return LogError("expected '=' after for"); + getNextToken(); // eat '='. + + auto Start = ParseExpression(); + if (!Start) + return nullptr; + if (CurTok != ',') + return LogError("expected ',' after for start value"); + getNextToken(); + + auto End = ParseExpression(); + if (!End) + return nullptr; + + // The step value is optional. + std::unique_ptr Step; + if (CurTok == ',') { + getNextToken(); + Step = ParseExpression(); + if (!Step) + return nullptr; + } + + if (CurTok != tok_in) + return LogError("expected 'in' after for"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(IdName, std::move(Start), std::move(End), + std::move(Step), std::move(Body)); +} + +/// varexpr ::= 'var' identifier ('=' expression)? +// (',' identifier ('=' expression)?)* 'in' expression +static std::unique_ptr ParseVarExpr() { + getNextToken(); // eat the var. + + std::vector>> VarNames; + + // At least one variable name is required. + if (CurTok != tok_identifier) + return LogError("expected identifier after var"); + + while (true) { + std::string Name = IdentifierStr; + getNextToken(); // eat identifier. + + // Read the optional initializer. + std::unique_ptr Init = nullptr; + if (CurTok == '=') { + getNextToken(); // eat the '='. + + Init = ParseExpression(); + if (!Init) + return nullptr; + } + + VarNames.push_back(std::make_pair(Name, std::move(Init))); + + // End of var list, exit loop. + if (CurTok != ',') + break; + getNextToken(); // eat the ','. + + if (CurTok != tok_identifier) + return LogError("expected identifier list after var"); + } + + // At this point, we have to have 'in'. + if (CurTok != tok_in) + return LogError("expected 'in' keyword after 'var'"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(std::move(VarNames), std::move(Body)); +} + +/// primary +/// ::= identifierexpr +/// ::= numberexpr +/// ::= parenexpr +/// ::= ifexpr +/// ::= forexpr +/// ::= varexpr +static std::unique_ptr ParsePrimary() { + switch (CurTok) { + default: + return LogError("unknown token when expecting an expression"); + case tok_identifier: + return ParseIdentifierExpr(); + case tok_number: + return ParseNumberExpr(); + case '(': + return ParseParenExpr(); + case tok_if: + return ParseIfExpr(); + case tok_for: + return ParseForExpr(); + case tok_var: + return ParseVarExpr(); + } +} + +/// unary +/// ::= primary +/// ::= '!' unary +static std::unique_ptr ParseUnary() { + // If the current token is not an operator, it must be a primary expr. + if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') + return ParsePrimary(); + + // If this is a unary operator, read it. + int Opc = CurTok; + getNextToken(); + if (auto Operand = ParseUnary()) + return llvm::make_unique(Opc, std::move(Operand)); + return nullptr; +} + +/// binoprhs +/// ::= ('+' unary)* +static std::unique_ptr ParseBinOpRHS(int ExprPrec, + std::unique_ptr LHS) { + // If this is a binop, find its precedence. + while (true) { + int TokPrec = GetTokPrecedence(); + + // If this is a binop that binds at least as tightly as the current binop, + // consume it, otherwise we are done. + if (TokPrec < ExprPrec) + return LHS; + + // Okay, we know this is a binop. + int BinOp = CurTok; + getNextToken(); // eat binop + + // Parse the unary expression after the binary operator. + auto RHS = ParseUnary(); + if (!RHS) + return nullptr; + + // If BinOp binds less tightly with RHS than the operator after RHS, let + // the pending operator take RHS as its LHS. + int NextPrec = GetTokPrecedence(); + if (TokPrec < NextPrec) { + RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); + if (!RHS) + return nullptr; + } + + // Merge LHS/RHS. + LHS = + llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); + } +} + +/// expression +/// ::= unary binoprhs +/// +static std::unique_ptr ParseExpression() { + auto LHS = ParseUnary(); + if (!LHS) + return nullptr; + + return ParseBinOpRHS(0, std::move(LHS)); +} + +/// prototype +/// ::= id '(' id* ')' +/// ::= binary LETTER number? (id, id) +/// ::= unary LETTER (id) +static std::unique_ptr ParsePrototype() { + std::string FnName; + + unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. + unsigned BinaryPrecedence = 30; + + switch (CurTok) { + default: + return LogErrorP("Expected function name in prototype"); + case tok_identifier: + FnName = IdentifierStr; + Kind = 0; + getNextToken(); + break; + case tok_unary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected unary operator"); + FnName = "unary"; + FnName += (char)CurTok; + Kind = 1; + getNextToken(); + break; + case tok_binary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected binary operator"); + FnName = "binary"; + FnName += (char)CurTok; + Kind = 2; + getNextToken(); + + // Read the precedence if present. + if (CurTok == tok_number) { + if (NumVal < 1 || NumVal > 100) + return LogErrorP("Invalid precedecnce: must be 1..100"); + BinaryPrecedence = (unsigned)NumVal; + getNextToken(); + } + break; + } + + if (CurTok != '(') + return LogErrorP("Expected '(' in prototype"); + + std::vector ArgNames; + while (getNextToken() == tok_identifier) + ArgNames.push_back(IdentifierStr); + if (CurTok != ')') + return LogErrorP("Expected ')' in prototype"); + + // success. + getNextToken(); // eat ')'. + + // Verify right number of names for operator. + if (Kind && ArgNames.size() != Kind) + return LogErrorP("Invalid number of operands for operator"); + + return llvm::make_unique(FnName, ArgNames, Kind != 0, + BinaryPrecedence); +} + +/// definition ::= 'def' prototype expression +static std::unique_ptr ParseDefinition() { + getNextToken(); // eat def. + auto Proto = ParsePrototype(); + if (!Proto) + return nullptr; + + if (auto E = ParseExpression()) + return llvm::make_unique(std::move(Proto), std::move(E)); + return nullptr; +} + +/// toplevelexpr ::= expression +static std::unique_ptr ParseTopLevelExpr() { + if (auto E = ParseExpression()) { + // Make an anonymous proto. + auto Proto = llvm::make_unique("__anon_expr", + std::vector()); + return llvm::make_unique(std::move(Proto), std::move(E)); + } + return nullptr; +} + +/// external ::= 'extern' prototype +static std::unique_ptr ParseExtern() { + getNextToken(); // eat extern. + return ParsePrototype(); +} + +//===----------------------------------------------------------------------===// +// Code Generation +//===----------------------------------------------------------------------===// + +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheModule; +static std::map NamedValues; +static std::unique_ptr TheJIT; +static std::map> FunctionProtos; + +Value *LogErrorV(const char *Str) { + LogError(Str); + return nullptr; +} + +Function *getFunction(std::string Name) { + // First, see if the function has already been added to the current module. + if (auto *F = TheModule->getFunction(Name)) + return F; + + // If not, check whether we can codegen the declaration from some existing + // prototype. + auto FI = FunctionProtos.find(Name); + if (FI != FunctionProtos.end()) + return FI->second->codegen(); + + // If no existing prototype exists, return null. + return nullptr; +} + +/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of +/// the function. This is used for mutable variables etc. +static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, + const std::string &VarName) { + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), + TheFunction->getEntryBlock().begin()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); +} + +Value *NumberExprAST::codegen() { + return ConstantFP::get(TheContext, APFloat(Val)); +} + +Value *VariableExprAST::codegen() { + // Look this variable up in the function. + Value *V = NamedValues[Name]; + if (!V) + return LogErrorV("Unknown variable name"); + + // Load the value. + return Builder.CreateLoad(V, Name.c_str()); +} + +Value *UnaryExprAST::codegen() { + Value *OperandV = Operand->codegen(); + if (!OperandV) + return nullptr; + + Function *F = getFunction(std::string("unary") + Opcode); + if (!F) + return LogErrorV("Unknown unary operator"); + + return Builder.CreateCall(F, OperandV, "unop"); +} + +Value *BinaryExprAST::codegen() { + // Special case '=' because we don't want to emit the LHS as an expression. + if (Op == '=') { + // Assignment requires the LHS to be an identifier. + // This assume we're building without RTTI because LLVM builds that way by + // default. If you build LLVM with RTTI this can be changed to a + // dynamic_cast for automatic error checking. + VariableExprAST *LHSE = static_cast(LHS.get()); + if (!LHSE) + return LogErrorV("destination of '=' must be a variable"); + // Codegen the RHS. + Value *Val = RHS->codegen(); + if (!Val) + return nullptr; + + // Look up the name. + Value *Variable = NamedValues[LHSE->getName()]; + if (!Variable) + return LogErrorV("Unknown variable name"); + + Builder.CreateStore(Val, Variable); + return Val; + } + + Value *L = LHS->codegen(); + Value *R = RHS->codegen(); + if (!L || !R) + return nullptr; + + switch (Op) { + case '+': + return Builder.CreateFAdd(L, R, "addtmp"); + case '-': + return Builder.CreateFSub(L, R, "subtmp"); + case '*': + return Builder.CreateFMul(L, R, "multmp"); + case '<': + L = Builder.CreateFCmpULT(L, R, "cmptmp"); + // Convert bool 0/1 to double 0.0 or 1.0 + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + default: + break; + } + + // If it wasn't a builtin binary operator, it must be a user defined one. Emit + // a call to it. + Function *F = getFunction(std::string("binary") + Op); + assert(F && "binary operator not found!"); + + Value *Ops[] = {L, R}; + return Builder.CreateCall(F, Ops, "binop"); +} + +Value *CallExprAST::codegen() { + // Look up the name in the global module table. + Function *CalleeF = getFunction(Callee); + if (!CalleeF) + return LogErrorV("Unknown function referenced"); + + // If argument mismatch error. + if (CalleeF->arg_size() != Args.size()) + return LogErrorV("Incorrect # arguments passed"); + + std::vector ArgsV; + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + ArgsV.push_back(Args[i]->codegen()); + if (!ArgsV.back()) + return nullptr; + } + + return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); +} + +Value *IfExprAST::codegen() { + Value *CondV = Cond->codegen(); + if (!CondV) + return nullptr; + + // Convert condition to a bool by comparing equal to 0.0. + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create blocks for the then and else cases. Insert the 'then' block at the + // end of the function. + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + + Builder.CreateCondBr(CondV, ThenBB, ElseBB); + + // Emit then value. + Builder.SetInsertPoint(ThenBB); + + Value *ThenV = Then->codegen(); + if (!ThenV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Then' can change the current block, update ThenBB for the PHI. + ThenBB = Builder.GetInsertBlock(); + + // Emit else block. + TheFunction->getBasicBlockList().push_back(ElseBB); + Builder.SetInsertPoint(ElseBB); + + Value *ElseV = Else->codegen(); + if (!ElseV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Else' can change the current block, update ElseBB for the PHI. + ElseBB = Builder.GetInsertBlock(); + + // Emit merge block. + TheFunction->getBasicBlockList().push_back(MergeBB); + Builder.SetInsertPoint(MergeBB); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + + PN->addIncoming(ThenV, ThenBB); + PN->addIncoming(ElseV, ElseBB); + return PN; +} + +// Output for-loop as: +// var = alloca double +// ... +// start = startexpr +// store start -> var +// goto loop +// loop: +// ... +// bodyexpr +// ... +// loopend: +// step = stepexpr +// endcond = endexpr +// +// curvar = load var +// nextvar = curvar + step +// store nextvar -> var +// br endcond, loop, endloop +// outloop: +Value *ForExprAST::codegen() { + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create an alloca for the variable in the entry block. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + + // Emit the start code first, without 'variable' in scope. + Value *StartVal = Start->codegen(); + if (!StartVal) + return nullptr; + + // Store the value into the alloca. + Builder.CreateStore(StartVal, Alloca); + + // Make the new basic block for the loop header, inserting after current + // block. + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + + // Insert an explicit fall through from the current block to the LoopBB. + Builder.CreateBr(LoopBB); + + // Start insertion in LoopBB. + Builder.SetInsertPoint(LoopBB); + + // Within the loop, the variable is defined equal to the PHI node. If it + // shadows an existing variable, we have to restore it, so save it now. + AllocaInst *OldVal = NamedValues[VarName]; + NamedValues[VarName] = Alloca; + + // Emit the body of the loop. This, like any other expr, can change the + // current BB. Note that we ignore the value computed by the body, but don't + // allow an error. + if (!Body->codegen()) + return nullptr; + + // Emit the step value. + Value *StepVal = nullptr; + if (Step) { + StepVal = Step->codegen(); + if (!StepVal) + return nullptr; + } else { + // If not specified, use 1.0. + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + } + + // Compute the end condition. + Value *EndCond = End->codegen(); + if (!EndCond) + return nullptr; + + // Reload, increment, and restore the alloca. This handles the case where + // the body of the loop mutates the variable. + Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); + Builder.CreateStore(NextVar, Alloca); + + // Convert condition to a bool by comparing equal to 0.0. + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + + // Create the "after loop" block and insert it. + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); + + // Insert the conditional branch into the end of LoopEndBB. + Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + + // Any new code will be inserted in AfterBB. + Builder.SetInsertPoint(AfterBB); + + // Restore the unshadowed variable. + if (OldVal) + NamedValues[VarName] = OldVal; + else + NamedValues.erase(VarName); + + // for expr always returns 0.0. + return Constant::getNullValue(Type::getDoubleTy(TheContext)); +} + +Value *VarExprAST::codegen() { + std::vector OldBindings; + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Register all variables and emit their initializer. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { + const std::string &VarName = VarNames[i].first; + ExprAST *Init = VarNames[i].second.get(); + + // Emit the initializer before adding the variable to scope, this prevents + // the initializer from referencing the variable itself, and permits stuff + // like this: + // var a = 1 in + // var a = a in ... # refers to outer 'a'. + Value *InitVal; + if (Init) { + InitVal = Init->codegen(); + if (!InitVal) + return nullptr; + } else { // If not specified, use 0.0. + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + } + + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + Builder.CreateStore(InitVal, Alloca); + + // Remember the old variable binding so that we can restore the binding when + // we unrecurse. + OldBindings.push_back(NamedValues[VarName]); + + // Remember this binding. + NamedValues[VarName] = Alloca; + } + + // Codegen the body, now that all vars are in scope. + Value *BodyVal = Body->codegen(); + if (!BodyVal) + return nullptr; + + // Pop all our variables from scope. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) + NamedValues[VarNames[i].first] = OldBindings[i]; + + // Return the body computation. + return BodyVal; +} + +Function *PrototypeAST::codegen() { + // Make the function type: double(double,double) etc. + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + + Function *F = + Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); + + // Set names for all arguments. + unsigned Idx = 0; + for (auto &Arg : F->args()) + Arg.setName(Args[Idx++]); + + return F; +} + +Function *FunctionAST::codegen() { + // Transfer ownership of the prototype to the FunctionProtos map, but keep a + // reference to it for use below. + auto &P = *Proto; + FunctionProtos[Proto->getName()] = std::move(Proto); + Function *TheFunction = getFunction(P.getName()); + if (!TheFunction) + return nullptr; + + // If this is an operator, install it. + if (P.isBinaryOp()) + BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); + + // Create a new basic block to start insertion into. + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); + Builder.SetInsertPoint(BB); + + // Record the function arguments in the NamedValues map. + NamedValues.clear(); + for (auto &Arg : TheFunction->args()) { + // Create an alloca for this variable. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); + + // Store the initial value into the alloca. + Builder.CreateStore(&Arg, Alloca); + + // Add arguments to variable symbol table. + NamedValues[Arg.getName()] = Alloca; + } + + if (Value *RetVal = Body->codegen()) { + // Finish off the function. + Builder.CreateRet(RetVal); + + // Validate the generated code, checking for consistency. + verifyFunction(*TheFunction); + + return TheFunction; + } + + // Error reading body, remove function. + TheFunction->eraseFromParent(); + + if (P.isBinaryOp()) + BinopPrecedence.erase(Proto->getOperatorName()); + return nullptr; +} + +//===----------------------------------------------------------------------===// +// Top-Level parsing and JIT Driver +//===----------------------------------------------------------------------===// + +static void InitializeModule() { + // Open a new module. + TheModule = llvm::make_unique("my cool jit", TheContext); + TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); +} + +static void HandleDefinition() { + if (auto FnAST = ParseDefinition()) { + if (auto *FnIR = FnAST->codegen()) { + fprintf(stderr, "Read function definition:"); + FnIR->dump(); + TheJIT->addModule(std::move(TheModule)); + InitializeModule(); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleExtern() { + if (auto ProtoAST = ParseExtern()) { + if (auto *FnIR = ProtoAST->codegen()) { + fprintf(stderr, "Read extern: "); + FnIR->dump(); + FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleTopLevelExpression() { + // Evaluate a top-level expression into an anonymous function. + if (auto FnAST = ParseTopLevelExpr()) { + if (FnAST->codegen()) { + // JIT the module containing the anonymous expression, keeping a handle so + // we can free it later. + auto H = TheJIT->addModule(std::move(TheModule)); + InitializeModule(); + + // Search the JIT for the __anon_expr symbol. + auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); + assert(ExprSymbol && "Function not found"); + + // Get the symbol's address and cast it to the right type (takes no + // arguments, returns a double) so we can call it as a native function. + double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); + fprintf(stderr, "Evaluated to %f\n", FP()); + + // Delete the anonymous expression module from the JIT. + TheJIT->removeModule(H); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +/// top ::= definition | external | expression | ';' +static void MainLoop() { + while (true) { + fprintf(stderr, "ready> "); + switch (CurTok) { + case tok_eof: + return; + case ';': // ignore top-level semicolons. + getNextToken(); + break; + case tok_def: + HandleDefinition(); + break; + case tok_extern: + HandleExtern(); + break; + default: + HandleTopLevelExpression(); + break; + } + } +} + +//===----------------------------------------------------------------------===// +// "Library" functions that can be "extern'd" from user code. +//===----------------------------------------------------------------------===// + +/// putchard - putchar that takes a double and returns 0. +extern "C" double putchard(double X) { + fputc((char)X, stderr); + return 0; +} + +/// printd - printf that takes a double prints it as "%f\n", returning 0. +extern "C" double printd(double X) { + fprintf(stderr, "%f\n", X); + return 0; +} + +//===----------------------------------------------------------------------===// +// Main driver code. +//===----------------------------------------------------------------------===// + +int main() { + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetAsmParser(); + + // Install standard binary operators. + // 1 is lowest precedence. + BinopPrecedence['='] = 2; + BinopPrecedence['<'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; // highest. + + // Prime the first token. + fprintf(stderr, "ready> "); + getNextToken(); + + TheJIT = llvm::make_unique(); + + InitializeModule(); + + // Run the main "interpreter loop" now. + MainLoop(); + + return 0; +} diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter3/CMakeLists.txt b/examples/Kaleidoscope/BuildingAJIT/Chapter3/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..51800a64b1e30c967d54880f1c117b60827188d9 --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter3/CMakeLists.txt @@ -0,0 +1,19 @@ +set(LLVM_LINK_COMPONENTS + Analysis + Core + ExecutionEngine + InstCombine + Object + OrcJIT + RuntimeDyld + ScalarOpts + Support + TransformUtils + native + ) + +add_kaleidoscope_chapter(BuildingAJIT-Ch3 + toy.cpp + ) + +export_executable_symbols(BuildingAJIT-Ch3) diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h b/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h new file mode 100644 index 0000000000000000000000000000000000000000..7ef1d07d8790cd58e0b7c3a1cfcf828ab2aed2cd --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter3/KaleidoscopeJIT.h @@ -0,0 +1,143 @@ +//===----- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Contains a simple JIT definition for use in the kaleidoscope tutorials. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H +#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" +#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include +#include +#include +#include + +namespace llvm { +namespace orc { + +class KaleidoscopeJIT { +private: + std::unique_ptr TM; + const DataLayout DL; + std::unique_ptr CompileCallbackManager; + ObjectLinkingLayer<> ObjectLayer; + IRCompileLayer CompileLayer; + + typedef std::function(std::unique_ptr)> + OptimizeFunction; + + IRTransformLayer OptimizeLayer; + CompileOnDemandLayer CODLayer; + +public: + typedef decltype(CODLayer)::ModuleSetHandleT ModuleHandle; + + KaleidoscopeJIT() + : TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), + CompileCallbackManager( + orc::createLocalCompileCallbackManager(TM->getTargetTriple(), 0)), + CompileLayer(ObjectLayer, SimpleCompiler(*TM)), + OptimizeLayer(CompileLayer, + [this](std::unique_ptr M) { + return optimizeModule(std::move(M)); + }), + CODLayer(OptimizeLayer, + [this](Function &F) { return std::set({&F}); }, + *CompileCallbackManager, + orc::createLocalIndirectStubsManagerBuilder( + TM->getTargetTriple())) { + llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + } + + TargetMachine &getTargetMachine() { return *TM; } + + ModuleHandle addModule(std::unique_ptr M) { + // Build our symbol resolver: + // Lambda 1: Look back into the JIT itself to find symbols that are part of + // the same "logical dylib". + // Lambda 2: Search for external symbols in the host process. + auto Resolver = createLambdaResolver( + [&](const std::string &Name) { + if (auto Sym = CODLayer.findSymbol(Name, false)) + return Sym.toRuntimeDyldSymbol(); + return RuntimeDyld::SymbolInfo(nullptr); + }, + [](const std::string &Name) { + if (auto SymAddr = + RTDyldMemoryManager::getSymbolAddressInProcess(Name)) + return RuntimeDyld::SymbolInfo(SymAddr, JITSymbolFlags::Exported); + return RuntimeDyld::SymbolInfo(nullptr); + }); + + // Build a singlton module set to hold our module. + std::vector> Ms; + Ms.push_back(std::move(M)); + + // Add the set to the JIT with the resolver we created above and a newly + // created SectionMemoryManager. + return CODLayer.addModuleSet(std::move(Ms), + make_unique(), + std::move(Resolver)); + } + + JITSymbol findSymbol(const std::string Name) { + std::string MangledName; + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + return CODLayer.findSymbol(MangledNameStream.str(), true); + } + + void removeModule(ModuleHandle H) { + CODLayer.removeModuleSet(H); + } + +private: + + std::unique_ptr optimizeModule(std::unique_ptr M) { + // Create a function pass manager. + auto FPM = llvm::make_unique(M.get()); + + // Add some optimizations. + FPM->add(createInstructionCombiningPass()); + FPM->add(createReassociatePass()); + FPM->add(createGVNPass()); + FPM->add(createCFGSimplificationPass()); + FPM->doInitialization(); + + // Run the optimizations over all functions in the module being added to + // the JIT. + for (auto &F : *M) + FPM->run(F); + + return M; + } + +}; + +} // end namespace orc +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter3/toy.cpp b/examples/Kaleidoscope/BuildingAJIT/Chapter3/toy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22b0819cd71a940ca824df68f597133546c96ccf --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter3/toy.cpp @@ -0,0 +1,1219 @@ +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/GVN.h" +#include "KaleidoscopeJIT.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::orc; + +//===----------------------------------------------------------------------===// +// Lexer +//===----------------------------------------------------------------------===// + +// The lexer returns tokens [0-255] if it is an unknown character, otherwise one +// of these for known things. +enum Token { + tok_eof = -1, + + // commands + tok_def = -2, + tok_extern = -3, + + // primary + tok_identifier = -4, + tok_number = -5, + + // control + tok_if = -6, + tok_then = -7, + tok_else = -8, + tok_for = -9, + tok_in = -10, + + // operators + tok_binary = -11, + tok_unary = -12, + + // var definition + tok_var = -13 +}; + +static std::string IdentifierStr; // Filled in if tok_identifier +static double NumVal; // Filled in if tok_number + +/// gettok - Return the next token from standard input. +static int gettok() { + static int LastChar = ' '; + + // Skip any whitespace. + while (isspace(LastChar)) + LastChar = getchar(); + + if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* + IdentifierStr = LastChar; + while (isalnum((LastChar = getchar()))) + IdentifierStr += LastChar; + + if (IdentifierStr == "def") + return tok_def; + if (IdentifierStr == "extern") + return tok_extern; + if (IdentifierStr == "if") + return tok_if; + if (IdentifierStr == "then") + return tok_then; + if (IdentifierStr == "else") + return tok_else; + if (IdentifierStr == "for") + return tok_for; + if (IdentifierStr == "in") + return tok_in; + if (IdentifierStr == "binary") + return tok_binary; + if (IdentifierStr == "unary") + return tok_unary; + if (IdentifierStr == "var") + return tok_var; + return tok_identifier; + } + + if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ + std::string NumStr; + do { + NumStr += LastChar; + LastChar = getchar(); + } while (isdigit(LastChar) || LastChar == '.'); + + NumVal = strtod(NumStr.c_str(), nullptr); + return tok_number; + } + + if (LastChar == '#') { + // Comment until end of line. + do + LastChar = getchar(); + while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); + + if (LastChar != EOF) + return gettok(); + } + + // Check for end of file. Don't eat the EOF. + if (LastChar == EOF) + return tok_eof; + + // Otherwise, just return the character as its ascii value. + int ThisChar = LastChar; + LastChar = getchar(); + return ThisChar; +} + +//===----------------------------------------------------------------------===// +// Abstract Syntax Tree (aka Parse Tree) +//===----------------------------------------------------------------------===// +namespace { +/// ExprAST - Base class for all expression nodes. +class ExprAST { +public: + virtual ~ExprAST() {} + virtual Value *codegen() = 0; +}; + +/// NumberExprAST - Expression class for numeric literals like "1.0". +class NumberExprAST : public ExprAST { + double Val; + +public: + NumberExprAST(double Val) : Val(Val) {} + Value *codegen() override; +}; + +/// VariableExprAST - Expression class for referencing a variable, like "a". +class VariableExprAST : public ExprAST { + std::string Name; + +public: + VariableExprAST(const std::string &Name) : Name(Name) {} + const std::string &getName() const { return Name; } + Value *codegen() override; +}; + +/// UnaryExprAST - Expression class for a unary operator. +class UnaryExprAST : public ExprAST { + char Opcode; + std::unique_ptr Operand; + +public: + UnaryExprAST(char Opcode, std::unique_ptr Operand) + : Opcode(Opcode), Operand(std::move(Operand)) {} + Value *codegen() override; +}; + +/// BinaryExprAST - Expression class for a binary operator. +class BinaryExprAST : public ExprAST { + char Op; + std::unique_ptr LHS, RHS; + +public: + BinaryExprAST(char Op, std::unique_ptr LHS, + std::unique_ptr RHS) + : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} + Value *codegen() override; +}; + +/// CallExprAST - Expression class for function calls. +class CallExprAST : public ExprAST { + std::string Callee; + std::vector> Args; + +public: + CallExprAST(const std::string &Callee, + std::vector> Args) + : Callee(Callee), Args(std::move(Args)) {} + Value *codegen() override; +}; + +/// IfExprAST - Expression class for if/then/else. +class IfExprAST : public ExprAST { + std::unique_ptr Cond, Then, Else; + +public: + IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, + std::unique_ptr Else) + : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} + Value *codegen() override; +}; + +/// ForExprAST - Expression class for for/in. +class ForExprAST : public ExprAST { + std::string VarName; + std::unique_ptr Start, End, Step, Body; + +public: + ForExprAST(const std::string &VarName, std::unique_ptr Start, + std::unique_ptr End, std::unique_ptr Step, + std::unique_ptr Body) + : VarName(VarName), Start(std::move(Start)), End(std::move(End)), + Step(std::move(Step)), Body(std::move(Body)) {} + Value *codegen() override; +}; + +/// VarExprAST - Expression class for var/in +class VarExprAST : public ExprAST { + std::vector>> VarNames; + std::unique_ptr Body; + +public: + VarExprAST( + std::vector>> VarNames, + std::unique_ptr Body) + : VarNames(std::move(VarNames)), Body(std::move(Body)) {} + Value *codegen() override; +}; + +/// PrototypeAST - This class represents the "prototype" for a function, +/// which captures its name, and its argument names (thus implicitly the number +/// of arguments the function takes), as well as if it is an operator. +class PrototypeAST { + std::string Name; + std::vector Args; + bool IsOperator; + unsigned Precedence; // Precedence if a binary op. + +public: + PrototypeAST(const std::string &Name, std::vector Args, + bool IsOperator = false, unsigned Prec = 0) + : Name(Name), Args(std::move(Args)), IsOperator(IsOperator), + Precedence(Prec) {} + Function *codegen(); + const std::string &getName() const { return Name; } + + bool isUnaryOp() const { return IsOperator && Args.size() == 1; } + bool isBinaryOp() const { return IsOperator && Args.size() == 2; } + + char getOperatorName() const { + assert(isUnaryOp() || isBinaryOp()); + return Name[Name.size() - 1]; + } + + unsigned getBinaryPrecedence() const { return Precedence; } +}; + +/// FunctionAST - This class represents a function definition itself. +class FunctionAST { + std::unique_ptr Proto; + std::unique_ptr Body; + +public: + FunctionAST(std::unique_ptr Proto, + std::unique_ptr Body) + : Proto(std::move(Proto)), Body(std::move(Body)) {} + Function *codegen(); +}; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Parser +//===----------------------------------------------------------------------===// + +/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current +/// token the parser is looking at. getNextToken reads another token from the +/// lexer and updates CurTok with its results. +static int CurTok; +static int getNextToken() { return CurTok = gettok(); } + +/// BinopPrecedence - This holds the precedence for each binary operator that is +/// defined. +static std::map BinopPrecedence; + +/// GetTokPrecedence - Get the precedence of the pending binary operator token. +static int GetTokPrecedence() { + if (!isascii(CurTok)) + return -1; + + // Make sure it's a declared binop. + int TokPrec = BinopPrecedence[CurTok]; + if (TokPrec <= 0) + return -1; + return TokPrec; +} + +/// LogError* - These are little helper functions for error handling. +std::unique_ptr LogError(const char *Str) { + fprintf(stderr, "Error: %s\n", Str); + return nullptr; +} + +std::unique_ptr LogErrorP(const char *Str) { + LogError(Str); + return nullptr; +} + +static std::unique_ptr ParseExpression(); + +/// numberexpr ::= number +static std::unique_ptr ParseNumberExpr() { + auto Result = llvm::make_unique(NumVal); + getNextToken(); // consume the number + return std::move(Result); +} + +/// parenexpr ::= '(' expression ')' +static std::unique_ptr ParseParenExpr() { + getNextToken(); // eat (. + auto V = ParseExpression(); + if (!V) + return nullptr; + + if (CurTok != ')') + return LogError("expected ')'"); + getNextToken(); // eat ). + return V; +} + +/// identifierexpr +/// ::= identifier +/// ::= identifier '(' expression* ')' +static std::unique_ptr ParseIdentifierExpr() { + std::string IdName = IdentifierStr; + + getNextToken(); // eat identifier. + + if (CurTok != '(') // Simple variable ref. + return llvm::make_unique(IdName); + + // Call. + getNextToken(); // eat ( + std::vector> Args; + if (CurTok != ')') { + while (true) { + if (auto Arg = ParseExpression()) + Args.push_back(std::move(Arg)); + else + return nullptr; + + if (CurTok == ')') + break; + + if (CurTok != ',') + return LogError("Expected ')' or ',' in argument list"); + getNextToken(); + } + } + + // Eat the ')'. + getNextToken(); + + return llvm::make_unique(IdName, std::move(Args)); +} + +/// ifexpr ::= 'if' expression 'then' expression 'else' expression +static std::unique_ptr ParseIfExpr() { + getNextToken(); // eat the if. + + // condition. + auto Cond = ParseExpression(); + if (!Cond) + return nullptr; + + if (CurTok != tok_then) + return LogError("expected then"); + getNextToken(); // eat the then + + auto Then = ParseExpression(); + if (!Then) + return nullptr; + + if (CurTok != tok_else) + return LogError("expected else"); + + getNextToken(); + + auto Else = ParseExpression(); + if (!Else) + return nullptr; + + return llvm::make_unique(std::move(Cond), std::move(Then), + std::move(Else)); +} + +/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression +static std::unique_ptr ParseForExpr() { + getNextToken(); // eat the for. + + if (CurTok != tok_identifier) + return LogError("expected identifier after for"); + + std::string IdName = IdentifierStr; + getNextToken(); // eat identifier. + + if (CurTok != '=') + return LogError("expected '=' after for"); + getNextToken(); // eat '='. + + auto Start = ParseExpression(); + if (!Start) + return nullptr; + if (CurTok != ',') + return LogError("expected ',' after for start value"); + getNextToken(); + + auto End = ParseExpression(); + if (!End) + return nullptr; + + // The step value is optional. + std::unique_ptr Step; + if (CurTok == ',') { + getNextToken(); + Step = ParseExpression(); + if (!Step) + return nullptr; + } + + if (CurTok != tok_in) + return LogError("expected 'in' after for"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(IdName, std::move(Start), std::move(End), + std::move(Step), std::move(Body)); +} + +/// varexpr ::= 'var' identifier ('=' expression)? +// (',' identifier ('=' expression)?)* 'in' expression +static std::unique_ptr ParseVarExpr() { + getNextToken(); // eat the var. + + std::vector>> VarNames; + + // At least one variable name is required. + if (CurTok != tok_identifier) + return LogError("expected identifier after var"); + + while (true) { + std::string Name = IdentifierStr; + getNextToken(); // eat identifier. + + // Read the optional initializer. + std::unique_ptr Init = nullptr; + if (CurTok == '=') { + getNextToken(); // eat the '='. + + Init = ParseExpression(); + if (!Init) + return nullptr; + } + + VarNames.push_back(std::make_pair(Name, std::move(Init))); + + // End of var list, exit loop. + if (CurTok != ',') + break; + getNextToken(); // eat the ','. + + if (CurTok != tok_identifier) + return LogError("expected identifier list after var"); + } + + // At this point, we have to have 'in'. + if (CurTok != tok_in) + return LogError("expected 'in' keyword after 'var'"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(std::move(VarNames), std::move(Body)); +} + +/// primary +/// ::= identifierexpr +/// ::= numberexpr +/// ::= parenexpr +/// ::= ifexpr +/// ::= forexpr +/// ::= varexpr +static std::unique_ptr ParsePrimary() { + switch (CurTok) { + default: + return LogError("unknown token when expecting an expression"); + case tok_identifier: + return ParseIdentifierExpr(); + case tok_number: + return ParseNumberExpr(); + case '(': + return ParseParenExpr(); + case tok_if: + return ParseIfExpr(); + case tok_for: + return ParseForExpr(); + case tok_var: + return ParseVarExpr(); + } +} + +/// unary +/// ::= primary +/// ::= '!' unary +static std::unique_ptr ParseUnary() { + // If the current token is not an operator, it must be a primary expr. + if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') + return ParsePrimary(); + + // If this is a unary operator, read it. + int Opc = CurTok; + getNextToken(); + if (auto Operand = ParseUnary()) + return llvm::make_unique(Opc, std::move(Operand)); + return nullptr; +} + +/// binoprhs +/// ::= ('+' unary)* +static std::unique_ptr ParseBinOpRHS(int ExprPrec, + std::unique_ptr LHS) { + // If this is a binop, find its precedence. + while (true) { + int TokPrec = GetTokPrecedence(); + + // If this is a binop that binds at least as tightly as the current binop, + // consume it, otherwise we are done. + if (TokPrec < ExprPrec) + return LHS; + + // Okay, we know this is a binop. + int BinOp = CurTok; + getNextToken(); // eat binop + + // Parse the unary expression after the binary operator. + auto RHS = ParseUnary(); + if (!RHS) + return nullptr; + + // If BinOp binds less tightly with RHS than the operator after RHS, let + // the pending operator take RHS as its LHS. + int NextPrec = GetTokPrecedence(); + if (TokPrec < NextPrec) { + RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); + if (!RHS) + return nullptr; + } + + // Merge LHS/RHS. + LHS = + llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); + } +} + +/// expression +/// ::= unary binoprhs +/// +static std::unique_ptr ParseExpression() { + auto LHS = ParseUnary(); + if (!LHS) + return nullptr; + + return ParseBinOpRHS(0, std::move(LHS)); +} + +/// prototype +/// ::= id '(' id* ')' +/// ::= binary LETTER number? (id, id) +/// ::= unary LETTER (id) +static std::unique_ptr ParsePrototype() { + std::string FnName; + + unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. + unsigned BinaryPrecedence = 30; + + switch (CurTok) { + default: + return LogErrorP("Expected function name in prototype"); + case tok_identifier: + FnName = IdentifierStr; + Kind = 0; + getNextToken(); + break; + case tok_unary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected unary operator"); + FnName = "unary"; + FnName += (char)CurTok; + Kind = 1; + getNextToken(); + break; + case tok_binary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected binary operator"); + FnName = "binary"; + FnName += (char)CurTok; + Kind = 2; + getNextToken(); + + // Read the precedence if present. + if (CurTok == tok_number) { + if (NumVal < 1 || NumVal > 100) + return LogErrorP("Invalid precedecnce: must be 1..100"); + BinaryPrecedence = (unsigned)NumVal; + getNextToken(); + } + break; + } + + if (CurTok != '(') + return LogErrorP("Expected '(' in prototype"); + + std::vector ArgNames; + while (getNextToken() == tok_identifier) + ArgNames.push_back(IdentifierStr); + if (CurTok != ')') + return LogErrorP("Expected ')' in prototype"); + + // success. + getNextToken(); // eat ')'. + + // Verify right number of names for operator. + if (Kind && ArgNames.size() != Kind) + return LogErrorP("Invalid number of operands for operator"); + + return llvm::make_unique(FnName, ArgNames, Kind != 0, + BinaryPrecedence); +} + +/// definition ::= 'def' prototype expression +static std::unique_ptr ParseDefinition() { + getNextToken(); // eat def. + auto Proto = ParsePrototype(); + if (!Proto) + return nullptr; + + if (auto E = ParseExpression()) + return llvm::make_unique(std::move(Proto), std::move(E)); + return nullptr; +} + +/// toplevelexpr ::= expression +static std::unique_ptr ParseTopLevelExpr() { + if (auto E = ParseExpression()) { + // Make an anonymous proto. + auto Proto = llvm::make_unique("__anon_expr", + std::vector()); + return llvm::make_unique(std::move(Proto), std::move(E)); + } + return nullptr; +} + +/// external ::= 'extern' prototype +static std::unique_ptr ParseExtern() { + getNextToken(); // eat extern. + return ParsePrototype(); +} + +//===----------------------------------------------------------------------===// +// Code Generation +//===----------------------------------------------------------------------===// + +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheModule; +static std::map NamedValues; +static std::unique_ptr TheJIT; +static std::map> FunctionProtos; + +Value *LogErrorV(const char *Str) { + LogError(Str); + return nullptr; +} + +Function *getFunction(std::string Name) { + // First, see if the function has already been added to the current module. + if (auto *F = TheModule->getFunction(Name)) + return F; + + // If not, check whether we can codegen the declaration from some existing + // prototype. + auto FI = FunctionProtos.find(Name); + if (FI != FunctionProtos.end()) + return FI->second->codegen(); + + // If no existing prototype exists, return null. + return nullptr; +} + +/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of +/// the function. This is used for mutable variables etc. +static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, + const std::string &VarName) { + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), + TheFunction->getEntryBlock().begin()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); +} + +Value *NumberExprAST::codegen() { + return ConstantFP::get(TheContext, APFloat(Val)); +} + +Value *VariableExprAST::codegen() { + // Look this variable up in the function. + Value *V = NamedValues[Name]; + if (!V) + return LogErrorV("Unknown variable name"); + + // Load the value. + return Builder.CreateLoad(V, Name.c_str()); +} + +Value *UnaryExprAST::codegen() { + Value *OperandV = Operand->codegen(); + if (!OperandV) + return nullptr; + + Function *F = getFunction(std::string("unary") + Opcode); + if (!F) + return LogErrorV("Unknown unary operator"); + + return Builder.CreateCall(F, OperandV, "unop"); +} + +Value *BinaryExprAST::codegen() { + // Special case '=' because we don't want to emit the LHS as an expression. + if (Op == '=') { + // Assignment requires the LHS to be an identifier. + // This assume we're building without RTTI because LLVM builds that way by + // default. If you build LLVM with RTTI this can be changed to a + // dynamic_cast for automatic error checking. + VariableExprAST *LHSE = static_cast(LHS.get()); + if (!LHSE) + return LogErrorV("destination of '=' must be a variable"); + // Codegen the RHS. + Value *Val = RHS->codegen(); + if (!Val) + return nullptr; + + // Look up the name. + Value *Variable = NamedValues[LHSE->getName()]; + if (!Variable) + return LogErrorV("Unknown variable name"); + + Builder.CreateStore(Val, Variable); + return Val; + } + + Value *L = LHS->codegen(); + Value *R = RHS->codegen(); + if (!L || !R) + return nullptr; + + switch (Op) { + case '+': + return Builder.CreateFAdd(L, R, "addtmp"); + case '-': + return Builder.CreateFSub(L, R, "subtmp"); + case '*': + return Builder.CreateFMul(L, R, "multmp"); + case '<': + L = Builder.CreateFCmpULT(L, R, "cmptmp"); + // Convert bool 0/1 to double 0.0 or 1.0 + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + default: + break; + } + + // If it wasn't a builtin binary operator, it must be a user defined one. Emit + // a call to it. + Function *F = getFunction(std::string("binary") + Op); + assert(F && "binary operator not found!"); + + Value *Ops[] = {L, R}; + return Builder.CreateCall(F, Ops, "binop"); +} + +Value *CallExprAST::codegen() { + // Look up the name in the global module table. + Function *CalleeF = getFunction(Callee); + if (!CalleeF) + return LogErrorV("Unknown function referenced"); + + // If argument mismatch error. + if (CalleeF->arg_size() != Args.size()) + return LogErrorV("Incorrect # arguments passed"); + + std::vector ArgsV; + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + ArgsV.push_back(Args[i]->codegen()); + if (!ArgsV.back()) + return nullptr; + } + + return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); +} + +Value *IfExprAST::codegen() { + Value *CondV = Cond->codegen(); + if (!CondV) + return nullptr; + + // Convert condition to a bool by comparing equal to 0.0. + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create blocks for the then and else cases. Insert the 'then' block at the + // end of the function. + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + + Builder.CreateCondBr(CondV, ThenBB, ElseBB); + + // Emit then value. + Builder.SetInsertPoint(ThenBB); + + Value *ThenV = Then->codegen(); + if (!ThenV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Then' can change the current block, update ThenBB for the PHI. + ThenBB = Builder.GetInsertBlock(); + + // Emit else block. + TheFunction->getBasicBlockList().push_back(ElseBB); + Builder.SetInsertPoint(ElseBB); + + Value *ElseV = Else->codegen(); + if (!ElseV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Else' can change the current block, update ElseBB for the PHI. + ElseBB = Builder.GetInsertBlock(); + + // Emit merge block. + TheFunction->getBasicBlockList().push_back(MergeBB); + Builder.SetInsertPoint(MergeBB); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + + PN->addIncoming(ThenV, ThenBB); + PN->addIncoming(ElseV, ElseBB); + return PN; +} + +// Output for-loop as: +// var = alloca double +// ... +// start = startexpr +// store start -> var +// goto loop +// loop: +// ... +// bodyexpr +// ... +// loopend: +// step = stepexpr +// endcond = endexpr +// +// curvar = load var +// nextvar = curvar + step +// store nextvar -> var +// br endcond, loop, endloop +// outloop: +Value *ForExprAST::codegen() { + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create an alloca for the variable in the entry block. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + + // Emit the start code first, without 'variable' in scope. + Value *StartVal = Start->codegen(); + if (!StartVal) + return nullptr; + + // Store the value into the alloca. + Builder.CreateStore(StartVal, Alloca); + + // Make the new basic block for the loop header, inserting after current + // block. + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + + // Insert an explicit fall through from the current block to the LoopBB. + Builder.CreateBr(LoopBB); + + // Start insertion in LoopBB. + Builder.SetInsertPoint(LoopBB); + + // Within the loop, the variable is defined equal to the PHI node. If it + // shadows an existing variable, we have to restore it, so save it now. + AllocaInst *OldVal = NamedValues[VarName]; + NamedValues[VarName] = Alloca; + + // Emit the body of the loop. This, like any other expr, can change the + // current BB. Note that we ignore the value computed by the body, but don't + // allow an error. + if (!Body->codegen()) + return nullptr; + + // Emit the step value. + Value *StepVal = nullptr; + if (Step) { + StepVal = Step->codegen(); + if (!StepVal) + return nullptr; + } else { + // If not specified, use 1.0. + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + } + + // Compute the end condition. + Value *EndCond = End->codegen(); + if (!EndCond) + return nullptr; + + // Reload, increment, and restore the alloca. This handles the case where + // the body of the loop mutates the variable. + Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); + Builder.CreateStore(NextVar, Alloca); + + // Convert condition to a bool by comparing equal to 0.0. + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + + // Create the "after loop" block and insert it. + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); + + // Insert the conditional branch into the end of LoopEndBB. + Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + + // Any new code will be inserted in AfterBB. + Builder.SetInsertPoint(AfterBB); + + // Restore the unshadowed variable. + if (OldVal) + NamedValues[VarName] = OldVal; + else + NamedValues.erase(VarName); + + // for expr always returns 0.0. + return Constant::getNullValue(Type::getDoubleTy(TheContext)); +} + +Value *VarExprAST::codegen() { + std::vector OldBindings; + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Register all variables and emit their initializer. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { + const std::string &VarName = VarNames[i].first; + ExprAST *Init = VarNames[i].second.get(); + + // Emit the initializer before adding the variable to scope, this prevents + // the initializer from referencing the variable itself, and permits stuff + // like this: + // var a = 1 in + // var a = a in ... # refers to outer 'a'. + Value *InitVal; + if (Init) { + InitVal = Init->codegen(); + if (!InitVal) + return nullptr; + } else { // If not specified, use 0.0. + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + } + + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + Builder.CreateStore(InitVal, Alloca); + + // Remember the old variable binding so that we can restore the binding when + // we unrecurse. + OldBindings.push_back(NamedValues[VarName]); + + // Remember this binding. + NamedValues[VarName] = Alloca; + } + + // Codegen the body, now that all vars are in scope. + Value *BodyVal = Body->codegen(); + if (!BodyVal) + return nullptr; + + // Pop all our variables from scope. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) + NamedValues[VarNames[i].first] = OldBindings[i]; + + // Return the body computation. + return BodyVal; +} + +Function *PrototypeAST::codegen() { + // Make the function type: double(double,double) etc. + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + + Function *F = + Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); + + // Set names for all arguments. + unsigned Idx = 0; + for (auto &Arg : F->args()) + Arg.setName(Args[Idx++]); + + return F; +} + +Function *FunctionAST::codegen() { + // Transfer ownership of the prototype to the FunctionProtos map, but keep a + // reference to it for use below. + auto &P = *Proto; + FunctionProtos[Proto->getName()] = std::move(Proto); + Function *TheFunction = getFunction(P.getName()); + if (!TheFunction) + return nullptr; + + // If this is an operator, install it. + if (P.isBinaryOp()) + BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); + + // Create a new basic block to start insertion into. + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); + Builder.SetInsertPoint(BB); + + // Record the function arguments in the NamedValues map. + NamedValues.clear(); + for (auto &Arg : TheFunction->args()) { + // Create an alloca for this variable. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); + + // Store the initial value into the alloca. + Builder.CreateStore(&Arg, Alloca); + + // Add arguments to variable symbol table. + NamedValues[Arg.getName()] = Alloca; + } + + if (Value *RetVal = Body->codegen()) { + // Finish off the function. + Builder.CreateRet(RetVal); + + // Validate the generated code, checking for consistency. + verifyFunction(*TheFunction); + + return TheFunction; + } + + // Error reading body, remove function. + TheFunction->eraseFromParent(); + + if (P.isBinaryOp()) + BinopPrecedence.erase(Proto->getOperatorName()); + return nullptr; +} + +//===----------------------------------------------------------------------===// +// Top-Level parsing and JIT Driver +//===----------------------------------------------------------------------===// + +static void InitializeModule() { + // Open a new module. + TheModule = llvm::make_unique("my cool jit", TheContext); + TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); +} + +static void HandleDefinition() { + if (auto FnAST = ParseDefinition()) { + if (auto *FnIR = FnAST->codegen()) { + fprintf(stderr, "Read function definition:"); + FnIR->dump(); + TheJIT->addModule(std::move(TheModule)); + InitializeModule(); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleExtern() { + if (auto ProtoAST = ParseExtern()) { + if (auto *FnIR = ProtoAST->codegen()) { + fprintf(stderr, "Read extern: "); + FnIR->dump(); + FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleTopLevelExpression() { + // Evaluate a top-level expression into an anonymous function. + if (auto FnAST = ParseTopLevelExpr()) { + if (FnAST->codegen()) { + // JIT the module containing the anonymous expression, keeping a handle so + // we can free it later. + auto H = TheJIT->addModule(std::move(TheModule)); + InitializeModule(); + + // Search the JIT for the __anon_expr symbol. + auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); + assert(ExprSymbol && "Function not found"); + + // Get the symbol's address and cast it to the right type (takes no + // arguments, returns a double) so we can call it as a native function. + double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); + fprintf(stderr, "Evaluated to %f\n", FP()); + + // Delete the anonymous expression module from the JIT. + TheJIT->removeModule(H); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +/// top ::= definition | external | expression | ';' +static void MainLoop() { + while (true) { + fprintf(stderr, "ready> "); + switch (CurTok) { + case tok_eof: + return; + case ';': // ignore top-level semicolons. + getNextToken(); + break; + case tok_def: + HandleDefinition(); + break; + case tok_extern: + HandleExtern(); + break; + default: + HandleTopLevelExpression(); + break; + } + } +} + +//===----------------------------------------------------------------------===// +// "Library" functions that can be "extern'd" from user code. +//===----------------------------------------------------------------------===// + +/// putchard - putchar that takes a double and returns 0. +extern "C" double putchard(double X) { + fputc((char)X, stderr); + return 0; +} + +/// printd - printf that takes a double prints it as "%f\n", returning 0. +extern "C" double printd(double X) { + fprintf(stderr, "%f\n", X); + return 0; +} + +//===----------------------------------------------------------------------===// +// Main driver code. +//===----------------------------------------------------------------------===// + +int main() { + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetAsmParser(); + + // Install standard binary operators. + // 1 is lowest precedence. + BinopPrecedence['='] = 2; + BinopPrecedence['<'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; // highest. + + // Prime the first token. + fprintf(stderr, "ready> "); + getNextToken(); + + TheJIT = llvm::make_unique(); + + InitializeModule(); + + // Run the main "interpreter loop" now. + MainLoop(); + + return 0; +} diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter4/CMakeLists.txt b/examples/Kaleidoscope/BuildingAJIT/Chapter4/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7cd40a1da60dc2c1af054fa94063c31641cd3a47 --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter4/CMakeLists.txt @@ -0,0 +1,19 @@ +set(LLVM_LINK_COMPONENTS + Analysis + Core + ExecutionEngine + InstCombine + Object + OrcJIT + RuntimeDyld + ScalarOpts + Support + TransformUtils + native + ) + +add_kaleidoscope_chapter(BuildingAJIT-Ch4 + toy.cpp + ) + +export_executable_symbols(BuildingAJIT-Ch4) diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h b/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h new file mode 100644 index 0000000000000000000000000000000000000000..b856bb5e4f3b901977a9e64eb3329bf2ad9c9d2f --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter4/KaleidoscopeJIT.h @@ -0,0 +1,231 @@ +//===----- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Contains a simple JIT definition for use in the kaleidoscope tutorials. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H +#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" +#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include +#include +#include +#include + +class PrototypeAST; +class ExprAST; + +/// FunctionAST - This class represents a function definition itself. +class FunctionAST { + std::unique_ptr Proto; + std::unique_ptr Body; + +public: + FunctionAST(std::unique_ptr Proto, + std::unique_ptr Body) + : Proto(std::move(Proto)), Body(std::move(Body)) {} + const PrototypeAST& getProto() const; + const std::string& getName() const; + llvm::Function *codegen(); +}; + +/// This will compile FnAST to IR, rename the function to add the given +/// suffix (needed to prevent a name-clash with the function's stub), +/// and then take ownership of the module that the function was compiled +/// into. +std::unique_ptr +irgenAndTakeOwnership(FunctionAST &FnAST, const std::string &Suffix); + +namespace llvm { +namespace orc { + +class KaleidoscopeJIT { +private: + std::unique_ptr TM; + const DataLayout DL; + std::unique_ptr CompileCallbackMgr; + std::unique_ptr IndirectStubsMgr; + ObjectLinkingLayer<> ObjectLayer; + IRCompileLayer CompileLayer; + + typedef std::function(std::unique_ptr)> + OptimizeFunction; + + IRTransformLayer OptimizeLayer; + +public: + typedef decltype(OptimizeLayer)::ModuleSetHandleT ModuleHandle; + + KaleidoscopeJIT() + : TM(EngineBuilder().selectTarget()), + DL(TM->createDataLayout()), + CompileCallbackMgr( + orc::createLocalCompileCallbackManager(TM->getTargetTriple(), 0)), + CompileLayer(ObjectLayer, SimpleCompiler(*TM)), + OptimizeLayer(CompileLayer, + [this](std::unique_ptr M) { + return optimizeModule(std::move(M)); + }) { + auto IndirectStubsMgrBuilder = + orc::createLocalIndirectStubsManagerBuilder(TM->getTargetTriple()); + IndirectStubsMgr = IndirectStubsMgrBuilder(); + llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + } + + TargetMachine &getTargetMachine() { return *TM; } + + ModuleHandle addModule(std::unique_ptr M) { + + // Build our symbol resolver: + // Lambda 1: Look back into the JIT itself to find symbols that are part of + // the same "logical dylib". + // Lambda 2: Search for external symbols in the host process. + auto Resolver = createLambdaResolver( + [&](const std::string &Name) { + if (auto Sym = IndirectStubsMgr->findStub(Name, false)) + return Sym.toRuntimeDyldSymbol(); + if (auto Sym = OptimizeLayer.findSymbol(Name, false)) + return Sym.toRuntimeDyldSymbol(); + return RuntimeDyld::SymbolInfo(nullptr); + }, + [](const std::string &Name) { + if (auto SymAddr = + RTDyldMemoryManager::getSymbolAddressInProcess(Name)) + return RuntimeDyld::SymbolInfo(SymAddr, JITSymbolFlags::Exported); + return RuntimeDyld::SymbolInfo(nullptr); + }); + + // Build a singlton module set to hold our module. + std::vector> Ms; + Ms.push_back(std::move(M)); + + // Add the set to the JIT with the resolver we created above and a newly + // created SectionMemoryManager. + return OptimizeLayer.addModuleSet(std::move(Ms), + make_unique(), + std::move(Resolver)); + } + + Error addFunctionAST(std::unique_ptr FnAST) { + // Create a CompileCallback - this is the re-entry point into the compiler + // for functions that haven't been compiled yet. + auto CCInfo = CompileCallbackMgr->getCompileCallback(); + + // Create an indirect stub. This serves as the functions "canonical + // definition" - an unchanging (constant address) entry point to the + // function implementation. + // Initially we point the stub's function-pointer at the compile callback + // that we just created. In the compile action for the callback (see below) + // we will update the stub's function pointer to point at the function + // implementation that we just implemented. + if (auto Err = IndirectStubsMgr->createStub(mangle(FnAST->getName()), + CCInfo.getAddress(), + JITSymbolFlags::Exported)) + return Err; + + // Move ownership of FnAST to a shared pointer - C++11 lambdas don't support + // capture-by-move, which is be required for unique_ptr. + auto SharedFnAST = std::shared_ptr(std::move(FnAST)); + + // Set the action to compile our AST. This lambda will be run if/when + // execution hits the compile callback (via the stub). + // + // The steps to compile are: + // (1) IRGen the function. + // (2) Add the IR module to the JIT to make it executable like any other + // module. + // (3) Use findSymbol to get the address of the compiled function. + // (4) Update the stub pointer to point at the implementation so that + /// subsequent calls go directly to it and bypass the compiler. + // (5) Return the address of the implementation: this lambda will actually + // be run inside an attempted call to the function, and we need to + // continue on to the implementation to complete the attempted call. + // The JIT runtime (the resolver block) will use the return address of + // this function as the address to continue at once it has reset the + // CPU state to what it was immediately before the call. + CCInfo.setCompileAction( + [this, SharedFnAST]() { + auto M = irgenAndTakeOwnership(*SharedFnAST, "$impl"); + addModule(std::move(M)); + auto Sym = findSymbol(SharedFnAST->getName() + "$impl"); + assert(Sym && "Couldn't find compiled function?"); + TargetAddress SymAddr = Sym.getAddress(); + if (auto Err = + IndirectStubsMgr->updatePointer(mangle(SharedFnAST->getName()), + SymAddr)) { + logAllUnhandledErrors(std::move(Err), errs(), + "Error updating function pointer: "); + exit(1); + } + + return SymAddr; + }); + + return Error::success(); + } + + JITSymbol findSymbol(const std::string Name) { + return OptimizeLayer.findSymbol(mangle(Name), true); + } + + void removeModule(ModuleHandle H) { + OptimizeLayer.removeModuleSet(H); + } + +private: + + std::string mangle(const std::string &Name) { + std::string MangledName; + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + return MangledNameStream.str(); + } + + std::unique_ptr optimizeModule(std::unique_ptr M) { + // Create a function pass manager. + auto FPM = llvm::make_unique(M.get()); + + // Add some optimizations. + FPM->add(createInstructionCombiningPass()); + FPM->add(createReassociatePass()); + FPM->add(createGVNPass()); + FPM->add(createCFGSimplificationPass()); + FPM->doInitialization(); + + // Run the optimizations over all functions in the module being added to + // the JIT. + for (auto &F : *M) + FPM->run(F); + + return M; + } + +}; + +} // end namespace orc +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter4/toy.cpp b/examples/Kaleidoscope/BuildingAJIT/Chapter4/toy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ddce0dc35b25c97c6636961f474ddca1ccf685ab --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter4/toy.cpp @@ -0,0 +1,1228 @@ +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/GVN.h" +#include "KaleidoscopeJIT.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::orc; + +//===----------------------------------------------------------------------===// +// Lexer +//===----------------------------------------------------------------------===// + +// The lexer returns tokens [0-255] if it is an unknown character, otherwise one +// of these for known things. +enum Token { + tok_eof = -1, + + // commands + tok_def = -2, + tok_extern = -3, + + // primary + tok_identifier = -4, + tok_number = -5, + + // control + tok_if = -6, + tok_then = -7, + tok_else = -8, + tok_for = -9, + tok_in = -10, + + // operators + tok_binary = -11, + tok_unary = -12, + + // var definition + tok_var = -13 +}; + +static std::string IdentifierStr; // Filled in if tok_identifier +static double NumVal; // Filled in if tok_number + +/// gettok - Return the next token from standard input. +static int gettok() { + static int LastChar = ' '; + + // Skip any whitespace. + while (isspace(LastChar)) + LastChar = getchar(); + + if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* + IdentifierStr = LastChar; + while (isalnum((LastChar = getchar()))) + IdentifierStr += LastChar; + + if (IdentifierStr == "def") + return tok_def; + if (IdentifierStr == "extern") + return tok_extern; + if (IdentifierStr == "if") + return tok_if; + if (IdentifierStr == "then") + return tok_then; + if (IdentifierStr == "else") + return tok_else; + if (IdentifierStr == "for") + return tok_for; + if (IdentifierStr == "in") + return tok_in; + if (IdentifierStr == "binary") + return tok_binary; + if (IdentifierStr == "unary") + return tok_unary; + if (IdentifierStr == "var") + return tok_var; + return tok_identifier; + } + + if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ + std::string NumStr; + do { + NumStr += LastChar; + LastChar = getchar(); + } while (isdigit(LastChar) || LastChar == '.'); + + NumVal = strtod(NumStr.c_str(), nullptr); + return tok_number; + } + + if (LastChar == '#') { + // Comment until end of line. + do + LastChar = getchar(); + while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); + + if (LastChar != EOF) + return gettok(); + } + + // Check for end of file. Don't eat the EOF. + if (LastChar == EOF) + return tok_eof; + + // Otherwise, just return the character as its ascii value. + int ThisChar = LastChar; + LastChar = getchar(); + return ThisChar; +} + +//===----------------------------------------------------------------------===// +// Abstract Syntax Tree (aka Parse Tree) +//===----------------------------------------------------------------------===// + +/// ExprAST - Base class for all expression nodes. +class ExprAST { +public: + virtual ~ExprAST() {} + virtual Value *codegen() = 0; +}; + +/// NumberExprAST - Expression class for numeric literals like "1.0". +class NumberExprAST : public ExprAST { + double Val; + +public: + NumberExprAST(double Val) : Val(Val) {} + Value *codegen() override; +}; + +/// VariableExprAST - Expression class for referencing a variable, like "a". +class VariableExprAST : public ExprAST { + std::string Name; + +public: + VariableExprAST(const std::string &Name) : Name(Name) {} + const std::string &getName() const { return Name; } + Value *codegen() override; +}; + +/// UnaryExprAST - Expression class for a unary operator. +class UnaryExprAST : public ExprAST { + char Opcode; + std::unique_ptr Operand; + +public: + UnaryExprAST(char Opcode, std::unique_ptr Operand) + : Opcode(Opcode), Operand(std::move(Operand)) {} + Value *codegen() override; +}; + +/// BinaryExprAST - Expression class for a binary operator. +class BinaryExprAST : public ExprAST { + char Op; + std::unique_ptr LHS, RHS; + +public: + BinaryExprAST(char Op, std::unique_ptr LHS, + std::unique_ptr RHS) + : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} + Value *codegen() override; +}; + +/// CallExprAST - Expression class for function calls. +class CallExprAST : public ExprAST { + std::string Callee; + std::vector> Args; + +public: + CallExprAST(const std::string &Callee, + std::vector> Args) + : Callee(Callee), Args(std::move(Args)) {} + Value *codegen() override; +}; + +/// IfExprAST - Expression class for if/then/else. +class IfExprAST : public ExprAST { + std::unique_ptr Cond, Then, Else; + +public: + IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, + std::unique_ptr Else) + : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} + Value *codegen() override; +}; + +/// ForExprAST - Expression class for for/in. +class ForExprAST : public ExprAST { + std::string VarName; + std::unique_ptr Start, End, Step, Body; + +public: + ForExprAST(const std::string &VarName, std::unique_ptr Start, + std::unique_ptr End, std::unique_ptr Step, + std::unique_ptr Body) + : VarName(VarName), Start(std::move(Start)), End(std::move(End)), + Step(std::move(Step)), Body(std::move(Body)) {} + Value *codegen() override; +}; + +/// VarExprAST - Expression class for var/in +class VarExprAST : public ExprAST { + std::vector>> VarNames; + std::unique_ptr Body; + +public: + VarExprAST( + std::vector>> VarNames, + std::unique_ptr Body) + : VarNames(std::move(VarNames)), Body(std::move(Body)) {} + Value *codegen() override; +}; + +/// PrototypeAST - This class represents the "prototype" for a function, +/// which captures its name, and its argument names (thus implicitly the number +/// of arguments the function takes), as well as if it is an operator. +class PrototypeAST { + std::string Name; + std::vector Args; + bool IsOperator; + unsigned Precedence; // Precedence if a binary op. + +public: + PrototypeAST(const std::string &Name, std::vector Args, + bool IsOperator = false, unsigned Prec = 0) + : Name(Name), Args(std::move(Args)), IsOperator(IsOperator), + Precedence(Prec) {} + Function *codegen(); + const std::string &getName() const { return Name; } + + bool isUnaryOp() const { return IsOperator && Args.size() == 1; } + bool isBinaryOp() const { return IsOperator && Args.size() == 2; } + + char getOperatorName() const { + assert(isUnaryOp() || isBinaryOp()); + return Name[Name.size() - 1]; + } + + unsigned getBinaryPrecedence() const { return Precedence; } +}; + +//===----------------------------------------------------------------------===// +// Parser +//===----------------------------------------------------------------------===// + +/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current +/// token the parser is looking at. getNextToken reads another token from the +/// lexer and updates CurTok with its results. +static int CurTok; +static int getNextToken() { return CurTok = gettok(); } + +/// BinopPrecedence - This holds the precedence for each binary operator that is +/// defined. +static std::map BinopPrecedence; + +/// GetTokPrecedence - Get the precedence of the pending binary operator token. +static int GetTokPrecedence() { + if (!isascii(CurTok)) + return -1; + + // Make sure it's a declared binop. + int TokPrec = BinopPrecedence[CurTok]; + if (TokPrec <= 0) + return -1; + return TokPrec; +} + +/// LogError* - These are little helper functions for error handling. +std::unique_ptr LogError(const char *Str) { + fprintf(stderr, "Error: %s\n", Str); + return nullptr; +} + +std::unique_ptr LogErrorP(const char *Str) { + LogError(Str); + return nullptr; +} + +static std::unique_ptr ParseExpression(); + +/// numberexpr ::= number +static std::unique_ptr ParseNumberExpr() { + auto Result = llvm::make_unique(NumVal); + getNextToken(); // consume the number + return std::move(Result); +} + +/// parenexpr ::= '(' expression ')' +static std::unique_ptr ParseParenExpr() { + getNextToken(); // eat (. + auto V = ParseExpression(); + if (!V) + return nullptr; + + if (CurTok != ')') + return LogError("expected ')'"); + getNextToken(); // eat ). + return V; +} + +/// identifierexpr +/// ::= identifier +/// ::= identifier '(' expression* ')' +static std::unique_ptr ParseIdentifierExpr() { + std::string IdName = IdentifierStr; + + getNextToken(); // eat identifier. + + if (CurTok != '(') // Simple variable ref. + return llvm::make_unique(IdName); + + // Call. + getNextToken(); // eat ( + std::vector> Args; + if (CurTok != ')') { + while (true) { + if (auto Arg = ParseExpression()) + Args.push_back(std::move(Arg)); + else + return nullptr; + + if (CurTok == ')') + break; + + if (CurTok != ',') + return LogError("Expected ')' or ',' in argument list"); + getNextToken(); + } + } + + // Eat the ')'. + getNextToken(); + + return llvm::make_unique(IdName, std::move(Args)); +} + +/// ifexpr ::= 'if' expression 'then' expression 'else' expression +static std::unique_ptr ParseIfExpr() { + getNextToken(); // eat the if. + + // condition. + auto Cond = ParseExpression(); + if (!Cond) + return nullptr; + + if (CurTok != tok_then) + return LogError("expected then"); + getNextToken(); // eat the then + + auto Then = ParseExpression(); + if (!Then) + return nullptr; + + if (CurTok != tok_else) + return LogError("expected else"); + + getNextToken(); + + auto Else = ParseExpression(); + if (!Else) + return nullptr; + + return llvm::make_unique(std::move(Cond), std::move(Then), + std::move(Else)); +} + +/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression +static std::unique_ptr ParseForExpr() { + getNextToken(); // eat the for. + + if (CurTok != tok_identifier) + return LogError("expected identifier after for"); + + std::string IdName = IdentifierStr; + getNextToken(); // eat identifier. + + if (CurTok != '=') + return LogError("expected '=' after for"); + getNextToken(); // eat '='. + + auto Start = ParseExpression(); + if (!Start) + return nullptr; + if (CurTok != ',') + return LogError("expected ',' after for start value"); + getNextToken(); + + auto End = ParseExpression(); + if (!End) + return nullptr; + + // The step value is optional. + std::unique_ptr Step; + if (CurTok == ',') { + getNextToken(); + Step = ParseExpression(); + if (!Step) + return nullptr; + } + + if (CurTok != tok_in) + return LogError("expected 'in' after for"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(IdName, std::move(Start), std::move(End), + std::move(Step), std::move(Body)); +} + +/// varexpr ::= 'var' identifier ('=' expression)? +// (',' identifier ('=' expression)?)* 'in' expression +static std::unique_ptr ParseVarExpr() { + getNextToken(); // eat the var. + + std::vector>> VarNames; + + // At least one variable name is required. + if (CurTok != tok_identifier) + return LogError("expected identifier after var"); + + while (true) { + std::string Name = IdentifierStr; + getNextToken(); // eat identifier. + + // Read the optional initializer. + std::unique_ptr Init = nullptr; + if (CurTok == '=') { + getNextToken(); // eat the '='. + + Init = ParseExpression(); + if (!Init) + return nullptr; + } + + VarNames.push_back(std::make_pair(Name, std::move(Init))); + + // End of var list, exit loop. + if (CurTok != ',') + break; + getNextToken(); // eat the ','. + + if (CurTok != tok_identifier) + return LogError("expected identifier list after var"); + } + + // At this point, we have to have 'in'. + if (CurTok != tok_in) + return LogError("expected 'in' keyword after 'var'"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(std::move(VarNames), std::move(Body)); +} + +/// primary +/// ::= identifierexpr +/// ::= numberexpr +/// ::= parenexpr +/// ::= ifexpr +/// ::= forexpr +/// ::= varexpr +static std::unique_ptr ParsePrimary() { + switch (CurTok) { + default: + return LogError("unknown token when expecting an expression"); + case tok_identifier: + return ParseIdentifierExpr(); + case tok_number: + return ParseNumberExpr(); + case '(': + return ParseParenExpr(); + case tok_if: + return ParseIfExpr(); + case tok_for: + return ParseForExpr(); + case tok_var: + return ParseVarExpr(); + } +} + +/// unary +/// ::= primary +/// ::= '!' unary +static std::unique_ptr ParseUnary() { + // If the current token is not an operator, it must be a primary expr. + if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') + return ParsePrimary(); + + // If this is a unary operator, read it. + int Opc = CurTok; + getNextToken(); + if (auto Operand = ParseUnary()) + return llvm::make_unique(Opc, std::move(Operand)); + return nullptr; +} + +/// binoprhs +/// ::= ('+' unary)* +static std::unique_ptr ParseBinOpRHS(int ExprPrec, + std::unique_ptr LHS) { + // If this is a binop, find its precedence. + while (true) { + int TokPrec = GetTokPrecedence(); + + // If this is a binop that binds at least as tightly as the current binop, + // consume it, otherwise we are done. + if (TokPrec < ExprPrec) + return LHS; + + // Okay, we know this is a binop. + int BinOp = CurTok; + getNextToken(); // eat binop + + // Parse the unary expression after the binary operator. + auto RHS = ParseUnary(); + if (!RHS) + return nullptr; + + // If BinOp binds less tightly with RHS than the operator after RHS, let + // the pending operator take RHS as its LHS. + int NextPrec = GetTokPrecedence(); + if (TokPrec < NextPrec) { + RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); + if (!RHS) + return nullptr; + } + + // Merge LHS/RHS. + LHS = + llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); + } +} + +/// expression +/// ::= unary binoprhs +/// +static std::unique_ptr ParseExpression() { + auto LHS = ParseUnary(); + if (!LHS) + return nullptr; + + return ParseBinOpRHS(0, std::move(LHS)); +} + +/// prototype +/// ::= id '(' id* ')' +/// ::= binary LETTER number? (id, id) +/// ::= unary LETTER (id) +static std::unique_ptr ParsePrototype() { + std::string FnName; + + unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. + unsigned BinaryPrecedence = 30; + + switch (CurTok) { + default: + return LogErrorP("Expected function name in prototype"); + case tok_identifier: + FnName = IdentifierStr; + Kind = 0; + getNextToken(); + break; + case tok_unary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected unary operator"); + FnName = "unary"; + FnName += (char)CurTok; + Kind = 1; + getNextToken(); + break; + case tok_binary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected binary operator"); + FnName = "binary"; + FnName += (char)CurTok; + Kind = 2; + getNextToken(); + + // Read the precedence if present. + if (CurTok == tok_number) { + if (NumVal < 1 || NumVal > 100) + return LogErrorP("Invalid precedecnce: must be 1..100"); + BinaryPrecedence = (unsigned)NumVal; + getNextToken(); + } + break; + } + + if (CurTok != '(') + return LogErrorP("Expected '(' in prototype"); + + std::vector ArgNames; + while (getNextToken() == tok_identifier) + ArgNames.push_back(IdentifierStr); + if (CurTok != ')') + return LogErrorP("Expected ')' in prototype"); + + // success. + getNextToken(); // eat ')'. + + // Verify right number of names for operator. + if (Kind && ArgNames.size() != Kind) + return LogErrorP("Invalid number of operands for operator"); + + return llvm::make_unique(FnName, ArgNames, Kind != 0, + BinaryPrecedence); +} + +/// definition ::= 'def' prototype expression +static std::unique_ptr ParseDefinition() { + getNextToken(); // eat def. + auto Proto = ParsePrototype(); + if (!Proto) + return nullptr; + + if (auto E = ParseExpression()) + return llvm::make_unique(std::move(Proto), std::move(E)); + return nullptr; +} + +/// toplevelexpr ::= expression +static std::unique_ptr ParseTopLevelExpr() { + if (auto E = ParseExpression()) { + // Make an anonymous proto. + auto Proto = llvm::make_unique("__anon_expr", + std::vector()); + return llvm::make_unique(std::move(Proto), std::move(E)); + } + return nullptr; +} + +/// external ::= 'extern' prototype +static std::unique_ptr ParseExtern() { + getNextToken(); // eat extern. + return ParsePrototype(); +} + +//===----------------------------------------------------------------------===// +// Code Generation +//===----------------------------------------------------------------------===// + +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheModule; +static std::map NamedValues; +static std::unique_ptr TheJIT; +static std::map> FunctionProtos; +static ExitOnError ExitOnErr; + +Value *LogErrorV(const char *Str) { + LogError(Str); + return nullptr; +} + +Function *getFunction(std::string Name) { + // First, see if the function has already been added to the current module. + if (auto *F = TheModule->getFunction(Name)) + return F; + + // If not, check whether we can codegen the declaration from some existing + // prototype. + auto FI = FunctionProtos.find(Name); + if (FI != FunctionProtos.end()) + return FI->second->codegen(); + + // If no existing prototype exists, return null. + return nullptr; +} + +/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of +/// the function. This is used for mutable variables etc. +static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, + const std::string &VarName) { + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), + TheFunction->getEntryBlock().begin()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); +} + +Value *NumberExprAST::codegen() { + return ConstantFP::get(TheContext, APFloat(Val)); +} + +Value *VariableExprAST::codegen() { + // Look this variable up in the function. + Value *V = NamedValues[Name]; + if (!V) + return LogErrorV("Unknown variable name"); + + // Load the value. + return Builder.CreateLoad(V, Name.c_str()); +} + +Value *UnaryExprAST::codegen() { + Value *OperandV = Operand->codegen(); + if (!OperandV) + return nullptr; + + Function *F = getFunction(std::string("unary") + Opcode); + if (!F) + return LogErrorV("Unknown unary operator"); + + return Builder.CreateCall(F, OperandV, "unop"); +} + +Value *BinaryExprAST::codegen() { + // Special case '=' because we don't want to emit the LHS as an expression. + if (Op == '=') { + // Assignment requires the LHS to be an identifier. + // This assume we're building without RTTI because LLVM builds that way by + // default. If you build LLVM with RTTI this can be changed to a + // dynamic_cast for automatic error checking. + VariableExprAST *LHSE = static_cast(LHS.get()); + if (!LHSE) + return LogErrorV("destination of '=' must be a variable"); + // Codegen the RHS. + Value *Val = RHS->codegen(); + if (!Val) + return nullptr; + + // Look up the name. + Value *Variable = NamedValues[LHSE->getName()]; + if (!Variable) + return LogErrorV("Unknown variable name"); + + Builder.CreateStore(Val, Variable); + return Val; + } + + Value *L = LHS->codegen(); + Value *R = RHS->codegen(); + if (!L || !R) + return nullptr; + + switch (Op) { + case '+': + return Builder.CreateFAdd(L, R, "addtmp"); + case '-': + return Builder.CreateFSub(L, R, "subtmp"); + case '*': + return Builder.CreateFMul(L, R, "multmp"); + case '<': + L = Builder.CreateFCmpULT(L, R, "cmptmp"); + // Convert bool 0/1 to double 0.0 or 1.0 + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + default: + break; + } + + // If it wasn't a builtin binary operator, it must be a user defined one. Emit + // a call to it. + Function *F = getFunction(std::string("binary") + Op); + assert(F && "binary operator not found!"); + + Value *Ops[] = {L, R}; + return Builder.CreateCall(F, Ops, "binop"); +} + +Value *CallExprAST::codegen() { + // Look up the name in the global module table. + Function *CalleeF = getFunction(Callee); + if (!CalleeF) + return LogErrorV("Unknown function referenced"); + + // If argument mismatch error. + if (CalleeF->arg_size() != Args.size()) + return LogErrorV("Incorrect # arguments passed"); + + std::vector ArgsV; + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + ArgsV.push_back(Args[i]->codegen()); + if (!ArgsV.back()) + return nullptr; + } + + return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); +} + +Value *IfExprAST::codegen() { + Value *CondV = Cond->codegen(); + if (!CondV) + return nullptr; + + // Convert condition to a bool by comparing equal to 0.0. + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create blocks for the then and else cases. Insert the 'then' block at the + // end of the function. + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + + Builder.CreateCondBr(CondV, ThenBB, ElseBB); + + // Emit then value. + Builder.SetInsertPoint(ThenBB); + + Value *ThenV = Then->codegen(); + if (!ThenV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Then' can change the current block, update ThenBB for the PHI. + ThenBB = Builder.GetInsertBlock(); + + // Emit else block. + TheFunction->getBasicBlockList().push_back(ElseBB); + Builder.SetInsertPoint(ElseBB); + + Value *ElseV = Else->codegen(); + if (!ElseV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Else' can change the current block, update ElseBB for the PHI. + ElseBB = Builder.GetInsertBlock(); + + // Emit merge block. + TheFunction->getBasicBlockList().push_back(MergeBB); + Builder.SetInsertPoint(MergeBB); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + + PN->addIncoming(ThenV, ThenBB); + PN->addIncoming(ElseV, ElseBB); + return PN; +} + +// Output for-loop as: +// var = alloca double +// ... +// start = startexpr +// store start -> var +// goto loop +// loop: +// ... +// bodyexpr +// ... +// loopend: +// step = stepexpr +// endcond = endexpr +// +// curvar = load var +// nextvar = curvar + step +// store nextvar -> var +// br endcond, loop, endloop +// outloop: +Value *ForExprAST::codegen() { + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create an alloca for the variable in the entry block. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + + // Emit the start code first, without 'variable' in scope. + Value *StartVal = Start->codegen(); + if (!StartVal) + return nullptr; + + // Store the value into the alloca. + Builder.CreateStore(StartVal, Alloca); + + // Make the new basic block for the loop header, inserting after current + // block. + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + + // Insert an explicit fall through from the current block to the LoopBB. + Builder.CreateBr(LoopBB); + + // Start insertion in LoopBB. + Builder.SetInsertPoint(LoopBB); + + // Within the loop, the variable is defined equal to the PHI node. If it + // shadows an existing variable, we have to restore it, so save it now. + AllocaInst *OldVal = NamedValues[VarName]; + NamedValues[VarName] = Alloca; + + // Emit the body of the loop. This, like any other expr, can change the + // current BB. Note that we ignore the value computed by the body, but don't + // allow an error. + if (!Body->codegen()) + return nullptr; + + // Emit the step value. + Value *StepVal = nullptr; + if (Step) { + StepVal = Step->codegen(); + if (!StepVal) + return nullptr; + } else { + // If not specified, use 1.0. + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + } + + // Compute the end condition. + Value *EndCond = End->codegen(); + if (!EndCond) + return nullptr; + + // Reload, increment, and restore the alloca. This handles the case where + // the body of the loop mutates the variable. + Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); + Builder.CreateStore(NextVar, Alloca); + + // Convert condition to a bool by comparing equal to 0.0. + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + + // Create the "after loop" block and insert it. + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); + + // Insert the conditional branch into the end of LoopEndBB. + Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + + // Any new code will be inserted in AfterBB. + Builder.SetInsertPoint(AfterBB); + + // Restore the unshadowed variable. + if (OldVal) + NamedValues[VarName] = OldVal; + else + NamedValues.erase(VarName); + + // for expr always returns 0.0. + return Constant::getNullValue(Type::getDoubleTy(TheContext)); +} + +Value *VarExprAST::codegen() { + std::vector OldBindings; + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Register all variables and emit their initializer. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { + const std::string &VarName = VarNames[i].first; + ExprAST *Init = VarNames[i].second.get(); + + // Emit the initializer before adding the variable to scope, this prevents + // the initializer from referencing the variable itself, and permits stuff + // like this: + // var a = 1 in + // var a = a in ... # refers to outer 'a'. + Value *InitVal; + if (Init) { + InitVal = Init->codegen(); + if (!InitVal) + return nullptr; + } else { // If not specified, use 0.0. + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + } + + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + Builder.CreateStore(InitVal, Alloca); + + // Remember the old variable binding so that we can restore the binding when + // we unrecurse. + OldBindings.push_back(NamedValues[VarName]); + + // Remember this binding. + NamedValues[VarName] = Alloca; + } + + // Codegen the body, now that all vars are in scope. + Value *BodyVal = Body->codegen(); + if (!BodyVal) + return nullptr; + + // Pop all our variables from scope. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) + NamedValues[VarNames[i].first] = OldBindings[i]; + + // Return the body computation. + return BodyVal; +} + +Function *PrototypeAST::codegen() { + // Make the function type: double(double,double) etc. + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + + Function *F = + Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); + + // Set names for all arguments. + unsigned Idx = 0; + for (auto &Arg : F->args()) + Arg.setName(Args[Idx++]); + + return F; +} + +const PrototypeAST& FunctionAST::getProto() const { + return *Proto; +} + +const std::string& FunctionAST::getName() const { + return Proto->getName(); +} + +Function *FunctionAST::codegen() { + // Transfer ownership of the prototype to the FunctionProtos map, but keep a + // reference to it for use below. + auto &P = *Proto; + Function *TheFunction = getFunction(P.getName()); + if (!TheFunction) + return nullptr; + + // If this is an operator, install it. + if (P.isBinaryOp()) + BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); + + // Create a new basic block to start insertion into. + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); + Builder.SetInsertPoint(BB); + + // Record the function arguments in the NamedValues map. + NamedValues.clear(); + for (auto &Arg : TheFunction->args()) { + // Create an alloca for this variable. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); + + // Store the initial value into the alloca. + Builder.CreateStore(&Arg, Alloca); + + // Add arguments to variable symbol table. + NamedValues[Arg.getName()] = Alloca; + } + + if (Value *RetVal = Body->codegen()) { + // Finish off the function. + Builder.CreateRet(RetVal); + + // Validate the generated code, checking for consistency. + verifyFunction(*TheFunction); + + return TheFunction; + } + + // Error reading body, remove function. + TheFunction->eraseFromParent(); + + if (P.isBinaryOp()) + BinopPrecedence.erase(Proto->getOperatorName()); + return nullptr; +} + +//===----------------------------------------------------------------------===// +// Top-Level parsing and JIT Driver +//===----------------------------------------------------------------------===// + +static void InitializeModule() { + // Open a new module. + TheModule = llvm::make_unique("my cool jit", TheContext); + TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); +} + +std::unique_ptr +irgenAndTakeOwnership(FunctionAST &FnAST, const std::string &Suffix) { + if (auto *F = FnAST.codegen()) { + F->setName(F->getName() + Suffix); + auto M = std::move(TheModule); + // Start a new module. + InitializeModule(); + return M; + } else + report_fatal_error("Couldn't compile lazily JIT'd function"); +} + +static void HandleDefinition() { + if (auto FnAST = ParseDefinition()) { + FunctionProtos[FnAST->getProto().getName()] = + llvm::make_unique(FnAST->getProto()); + ExitOnErr(TheJIT->addFunctionAST(std::move(FnAST))); + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleExtern() { + if (auto ProtoAST = ParseExtern()) { + if (auto *FnIR = ProtoAST->codegen()) { + fprintf(stderr, "Read extern: "); + FnIR->dump(); + FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleTopLevelExpression() { + // Evaluate a top-level expression into an anonymous function. + if (auto FnAST = ParseTopLevelExpr()) { + FunctionProtos[FnAST->getName()] = + llvm::make_unique(FnAST->getProto()); + if (FnAST->codegen()) { + // JIT the module containing the anonymous expression, keeping a handle so + // we can free it later. + auto H = TheJIT->addModule(std::move(TheModule)); + InitializeModule(); + + // Search the JIT for the __anon_expr symbol. + auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); + assert(ExprSymbol && "Function not found"); + + // Get the symbol's address and cast it to the right type (takes no + // arguments, returns a double) so we can call it as a native function. + double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); + fprintf(stderr, "Evaluated to %f\n", FP()); + + // Delete the anonymous expression module from the JIT. + TheJIT->removeModule(H); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +/// top ::= definition | external | expression | ';' +static void MainLoop() { + while (true) { + fprintf(stderr, "ready> "); + switch (CurTok) { + case tok_eof: + return; + case ';': // ignore top-level semicolons. + getNextToken(); + break; + case tok_def: + HandleDefinition(); + break; + case tok_extern: + HandleExtern(); + break; + default: + HandleTopLevelExpression(); + break; + } + } +} + +//===----------------------------------------------------------------------===// +// "Library" functions that can be "extern'd" from user code. +//===----------------------------------------------------------------------===// + +/// putchard - putchar that takes a double and returns 0. +extern "C" double putchard(double X) { + fputc((char)X, stderr); + return 0; +} + +/// printd - printf that takes a double prints it as "%f\n", returning 0. +extern "C" double printd(double X) { + fprintf(stderr, "%f\n", X); + return 0; +} + +//===----------------------------------------------------------------------===// +// Main driver code. +//===----------------------------------------------------------------------===// + +int main() { + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetAsmParser(); + + ExitOnErr.setBanner("Kaleidoscope: "); + + // Install standard binary operators. + // 1 is lowest precedence. + BinopPrecedence['='] = 2; + BinopPrecedence['<'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; // highest. + + // Prime the first token. + fprintf(stderr, "ready> "); + getNextToken(); + + TheJIT = llvm::make_unique(); + + InitializeModule(); + + // Run the main "interpreter loop" now. + MainLoop(); + + return 0; +} diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter5/CMakeLists.txt b/examples/Kaleidoscope/BuildingAJIT/Chapter5/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d5b832b495504f785a481a0fcbf1686488c57a5f --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter5/CMakeLists.txt @@ -0,0 +1,21 @@ +add_subdirectory(Server) + +set(LLVM_LINK_COMPONENTS + Analysis + Core + ExecutionEngine + InstCombine + Object + OrcJIT + RuntimeDyld + ScalarOpts + Support + TransformUtils + native + ) + +add_kaleidoscope_chapter(BuildingAJIT-Ch5 + toy.cpp + ) + +export_executable_symbols(BuildingAJIT-Ch5) diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h b/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h new file mode 100644 index 0000000000000000000000000000000000000000..900ad84457354741d2252b9c35b17d5c708b3d2c --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter5/KaleidoscopeJIT.h @@ -0,0 +1,263 @@ +//===----- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Contains a simple JIT definition for use in the kaleidoscope tutorials. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H +#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H + +#include "RemoteJITUtils.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" +#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include +#include +#include +#include + +class PrototypeAST; +class ExprAST; + +/// FunctionAST - This class represents a function definition itself. +class FunctionAST { + std::unique_ptr Proto; + std::unique_ptr Body; + +public: + FunctionAST(std::unique_ptr Proto, + std::unique_ptr Body) + : Proto(std::move(Proto)), Body(std::move(Body)) {} + const PrototypeAST& getProto() const; + const std::string& getName() const; + llvm::Function *codegen(); +}; + +/// This will compile FnAST to IR, rename the function to add the given +/// suffix (needed to prevent a name-clash with the function's stub), +/// and then take ownership of the module that the function was compiled +/// into. +std::unique_ptr +irgenAndTakeOwnership(FunctionAST &FnAST, const std::string &Suffix); + +namespace llvm { +namespace orc { + +// Typedef the remote-client API. +typedef remote::OrcRemoteTargetClient MyRemote; + +class KaleidoscopeJIT { +private: + MyRemote &Remote; + std::unique_ptr TM; + const DataLayout DL; + JITCompileCallbackManager *CompileCallbackMgr; + std::unique_ptr IndirectStubsMgr; + ObjectLinkingLayer<> ObjectLayer; + IRCompileLayer CompileLayer; + + typedef std::function(std::unique_ptr)> + OptimizeFunction; + + IRTransformLayer OptimizeLayer; + +public: + typedef decltype(OptimizeLayer)::ModuleSetHandleT ModuleHandle; + + KaleidoscopeJIT(MyRemote &Remote) + : Remote(Remote), + TM(EngineBuilder().selectTarget()), + DL(TM->createDataLayout()), + CompileLayer(ObjectLayer, SimpleCompiler(*TM)), + OptimizeLayer(CompileLayer, + [this](std::unique_ptr M) { + return optimizeModule(std::move(M)); + }) { + auto CCMgrOrErr = Remote.enableCompileCallbacks(0); + if (!CCMgrOrErr) { + logAllUnhandledErrors(CCMgrOrErr.takeError(), errs(), + "Error enabling remote compile callbacks:"); + exit(1); + } + CompileCallbackMgr = &*CCMgrOrErr; + std::unique_ptr ISM; + if (auto Err = Remote.createIndirectStubsManager(ISM)) { + logAllUnhandledErrors(std::move(Err), errs(), + "Error creating indirect stubs manager:"); + exit(1); + } + IndirectStubsMgr = std::move(ISM); + llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + } + + TargetMachine &getTargetMachine() { return *TM; } + + ModuleHandle addModule(std::unique_ptr M) { + + // Build our symbol resolver: + // Lambda 1: Look back into the JIT itself to find symbols that are part of + // the same "logical dylib". + // Lambda 2: Search for external symbols in the host process. + auto Resolver = createLambdaResolver( + [&](const std::string &Name) { + if (auto Sym = IndirectStubsMgr->findStub(Name, false)) + return Sym.toRuntimeDyldSymbol(); + if (auto Sym = OptimizeLayer.findSymbol(Name, false)) + return Sym.toRuntimeDyldSymbol(); + return RuntimeDyld::SymbolInfo(nullptr); + }, + [&](const std::string &Name) { + if (auto AddrOrErr = Remote.getSymbolAddress(Name)) + return RuntimeDyld::SymbolInfo(*AddrOrErr, + JITSymbolFlags::Exported); + else { + logAllUnhandledErrors(AddrOrErr.takeError(), errs(), + "Error resolving remote symbol:"); + exit(1); + } + return RuntimeDyld::SymbolInfo(nullptr); + }); + + std::unique_ptr MemMgr; + if (auto Err = Remote.createRemoteMemoryManager(MemMgr)) { + logAllUnhandledErrors(std::move(Err), errs(), + "Error creating remote memory manager:"); + exit(1); + } + + // Build a singlton module set to hold our module. + std::vector> Ms; + Ms.push_back(std::move(M)); + + // Add the set to the JIT with the resolver we created above and a newly + // created SectionMemoryManager. + return OptimizeLayer.addModuleSet(std::move(Ms), + std::move(MemMgr), + std::move(Resolver)); + } + + Error addFunctionAST(std::unique_ptr FnAST) { + // Create a CompileCallback - this is the re-entry point into the compiler + // for functions that haven't been compiled yet. + auto CCInfo = CompileCallbackMgr->getCompileCallback(); + + // Create an indirect stub. This serves as the functions "canonical + // definition" - an unchanging (constant address) entry point to the + // function implementation. + // Initially we point the stub's function-pointer at the compile callback + // that we just created. In the compile action for the callback (see below) + // we will update the stub's function pointer to point at the function + // implementation that we just implemented. + if (auto Err = IndirectStubsMgr->createStub(mangle(FnAST->getName()), + CCInfo.getAddress(), + JITSymbolFlags::Exported)) + return Err; + + // Move ownership of FnAST to a shared pointer - C++11 lambdas don't support + // capture-by-move, which is be required for unique_ptr. + auto SharedFnAST = std::shared_ptr(std::move(FnAST)); + + // Set the action to compile our AST. This lambda will be run if/when + // execution hits the compile callback (via the stub). + // + // The steps to compile are: + // (1) IRGen the function. + // (2) Add the IR module to the JIT to make it executable like any other + // module. + // (3) Use findSymbol to get the address of the compiled function. + // (4) Update the stub pointer to point at the implementation so that + /// subsequent calls go directly to it and bypass the compiler. + // (5) Return the address of the implementation: this lambda will actually + // be run inside an attempted call to the function, and we need to + // continue on to the implementation to complete the attempted call. + // The JIT runtime (the resolver block) will use the return address of + // this function as the address to continue at once it has reset the + // CPU state to what it was immediately before the call. + CCInfo.setCompileAction( + [this, SharedFnAST]() { + auto M = irgenAndTakeOwnership(*SharedFnAST, "$impl"); + addModule(std::move(M)); + auto Sym = findSymbol(SharedFnAST->getName() + "$impl"); + assert(Sym && "Couldn't find compiled function?"); + TargetAddress SymAddr = Sym.getAddress(); + if (auto Err = + IndirectStubsMgr->updatePointer(mangle(SharedFnAST->getName()), + SymAddr)) { + logAllUnhandledErrors(std::move(Err), errs(), + "Error updating function pointer: "); + exit(1); + } + + return SymAddr; + }); + + return Error::success(); + } + + Error executeRemoteExpr(TargetAddress ExprAddr) { + return Remote.callVoidVoid(ExprAddr); + } + + JITSymbol findSymbol(const std::string Name) { + return OptimizeLayer.findSymbol(mangle(Name), true); + } + + void removeModule(ModuleHandle H) { + OptimizeLayer.removeModuleSet(H); + } + +private: + + std::string mangle(const std::string &Name) { + std::string MangledName; + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, DL); + return MangledNameStream.str(); + } + + std::unique_ptr optimizeModule(std::unique_ptr M) { + // Create a function pass manager. + auto FPM = llvm::make_unique(M.get()); + + // Add some optimizations. + FPM->add(createInstructionCombiningPass()); + FPM->add(createReassociatePass()); + FPM->add(createGVNPass()); + FPM->add(createCFGSimplificationPass()); + FPM->doInitialization(); + + // Run the optimizations over all functions in the module being added to + // the JIT. + for (auto &F : *M) + FPM->run(F); + + return M; + } + +}; + +} // end namespace orc +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter5/RemoteJITUtils.h b/examples/Kaleidoscope/BuildingAJIT/Chapter5/RemoteJITUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..869d0a7ef39dac20ab704d3a5f56b588d63c4596 --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter5/RemoteJITUtils.h @@ -0,0 +1,74 @@ +//===-- RemoteJITUtils.h - Utilities for remote-JITing with LLI -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Utilities for remote-JITing with LLI. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLI_REMOTEJITUTILS_H +#define LLVM_TOOLS_LLI_REMOTEJITUTILS_H + +#include "llvm/ExecutionEngine/Orc/RPCChannel.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include + +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include +#else +#include +#endif + +/// RPC channel that reads from and writes from file descriptors. +class FDRPCChannel final : public llvm::orc::remote::RPCChannel { +public: + FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {} + + llvm::Error readBytes(char *Dst, unsigned Size) override { + assert(Dst && "Attempt to read into null."); + ssize_t Completed = 0; + while (Completed < static_cast(Size)) { + ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed); + if (Read <= 0) { + auto ErrNo = errno; + if (ErrNo == EAGAIN || ErrNo == EINTR) + continue; + else + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + Completed += Read; + } + return llvm::Error::success(); + } + + llvm::Error appendBytes(const char *Src, unsigned Size) override { + assert(Src && "Attempt to append from null."); + ssize_t Completed = 0; + while (Completed < static_cast(Size)) { + ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed); + if (Written < 0) { + auto ErrNo = errno; + if (ErrNo == EAGAIN || ErrNo == EINTR) + continue; + else + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + Completed += Written; + } + return llvm::Error::success(); + } + + llvm::Error send() override { return llvm::Error::success(); } + +private: + int InFD, OutFD; +}; + +#endif diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/CMakeLists.txt b/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..15dd53516ceb07a46b6e785a94dddb0c25b1db47 --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/CMakeLists.txt @@ -0,0 +1,17 @@ +set(LLVM_LINK_COMPONENTS + Analysis + Core + ExecutionEngine + InstCombine + Object + OrcJIT + RuntimeDyld + ScalarOpts + Support + TransformUtils + native + ) + +add_kaleidoscope_chapter(BuildingAJIT-Ch5-Server + server.cpp + ) diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/server.cpp b/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c53e22fe83ae2292d0026ecd21edd188bc62aff2 --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter5/Server/server.cpp @@ -0,0 +1,119 @@ +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h" +#include "llvm/ExecutionEngine/Orc/OrcABISupport.h" + +#include "../RemoteJITUtils.h" + +#include +#include +#include +#include + + +using namespace llvm; +using namespace llvm::orc; + +// Command line argument for TCP port. +cl::opt Port("port", + cl::desc("TCP port to listen on"), + cl::init(20000)); + +ExitOnError ExitOnErr; + +typedef int (*MainFun)(int, const char*[]); + +template +NativePtrT MakeNative(uint64_t P) { + return reinterpret_cast(static_cast(P)); +} + +extern "C" +void printExprResult(double Val) { + printf("Expression evaluated to: %f\n", Val); +} + +// --- LAZY COMPILE TEST --- +int main(int argc, char* argv[]) { + + if (argc == 0) + ExitOnErr.setBanner("jit_server: "); + else + ExitOnErr.setBanner(std::string(argv[0]) + ": "); + + // --- Initialize LLVM --- + cl::ParseCommandLineOptions(argc, argv, "LLVM lazy JIT example.\n"); + + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetAsmParser(); + + if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) { + errs() << "Error loading program symbols.\n"; + return 1; + } + + // --- Initialize remote connection --- + + int sockfd = socket(PF_INET, SOCK_STREAM, 0); + sockaddr_in servAddr, clientAddr; + socklen_t clientAddrLen = sizeof(clientAddr); + bzero(&servAddr, sizeof(servAddr)); + servAddr.sin_family = PF_INET; + servAddr.sin_family = INADDR_ANY; + servAddr.sin_port = htons(Port); + + { + // avoid "Address already in use" error. + int yes=1; + if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { + errs() << "Error calling setsockopt.\n"; + return 1; + } + } + + if (bind(sockfd, reinterpret_cast(&servAddr), + sizeof(servAddr)) < 0) { + errs() << "Error on binding.\n"; + return 1; + } + listen(sockfd, 1); + int newsockfd = accept(sockfd, reinterpret_cast(&clientAddr), + &clientAddrLen); + + auto SymbolLookup = + [](const std::string &Name) { + return RTDyldMemoryManager::getSymbolAddressInProcess(Name); + }; + + auto RegisterEHFrames = + [](uint8_t *Addr, uint32_t Size) { + RTDyldMemoryManager::registerEHFramesInProcess(Addr, Size); + }; + + auto DeregisterEHFrames = + [](uint8_t *Addr, uint32_t Size) { + RTDyldMemoryManager::deregisterEHFramesInProcess(Addr, Size); + }; + + FDRPCChannel TCPChannel(newsockfd, newsockfd); + typedef remote::OrcRemoteTargetServer MyServerT; + + MyServerT Server(TCPChannel, SymbolLookup, RegisterEHFrames, DeregisterEHFrames); + + while (1) { + MyServerT::JITFuncId Id = MyServerT::InvalidId; + ExitOnErr(Server.startReceivingFunction(TCPChannel, (uint32_t&)Id)); + switch (Id) { + case MyServerT::TerminateSessionId: + ExitOnErr(Server.handleTerminateSession()); + return 0; + default: + ExitOnErr(Server.handleKnownFunction(Id)); + break; + } + } + + llvm_unreachable("Fell through server command loop."); +} diff --git a/examples/Kaleidoscope/BuildingAJIT/Chapter5/toy.cpp b/examples/Kaleidoscope/BuildingAJIT/Chapter5/toy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c21098971a68185a7cdc75ccce0b4fbf2c4cbb9 --- /dev/null +++ b/examples/Kaleidoscope/BuildingAJIT/Chapter5/toy.cpp @@ -0,0 +1,1294 @@ +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/GVN.h" +#include "KaleidoscopeJIT.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::orc; + +// Command line argument for TCP hostname. +cl::opt HostName("hostname", + cl::desc("TCP hostname to connect to"), + cl::init("localhost")); + +// Command line argument for TCP port. +cl::opt Port("port", + cl::desc("TCP port to connect to"), + cl::init(20000)); + +//===----------------------------------------------------------------------===// +// Lexer +//===----------------------------------------------------------------------===// + +// The lexer returns tokens [0-255] if it is an unknown character, otherwise one +// of these for known things. +enum Token { + tok_eof = -1, + + // commands + tok_def = -2, + tok_extern = -3, + + // primary + tok_identifier = -4, + tok_number = -5, + + // control + tok_if = -6, + tok_then = -7, + tok_else = -8, + tok_for = -9, + tok_in = -10, + + // operators + tok_binary = -11, + tok_unary = -12, + + // var definition + tok_var = -13 +}; + +static std::string IdentifierStr; // Filled in if tok_identifier +static double NumVal; // Filled in if tok_number + +/// gettok - Return the next token from standard input. +static int gettok() { + static int LastChar = ' '; + + // Skip any whitespace. + while (isspace(LastChar)) + LastChar = getchar(); + + if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* + IdentifierStr = LastChar; + while (isalnum((LastChar = getchar()))) + IdentifierStr += LastChar; + + if (IdentifierStr == "def") + return tok_def; + if (IdentifierStr == "extern") + return tok_extern; + if (IdentifierStr == "if") + return tok_if; + if (IdentifierStr == "then") + return tok_then; + if (IdentifierStr == "else") + return tok_else; + if (IdentifierStr == "for") + return tok_for; + if (IdentifierStr == "in") + return tok_in; + if (IdentifierStr == "binary") + return tok_binary; + if (IdentifierStr == "unary") + return tok_unary; + if (IdentifierStr == "var") + return tok_var; + return tok_identifier; + } + + if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ + std::string NumStr; + do { + NumStr += LastChar; + LastChar = getchar(); + } while (isdigit(LastChar) || LastChar == '.'); + + NumVal = strtod(NumStr.c_str(), nullptr); + return tok_number; + } + + if (LastChar == '#') { + // Comment until end of line. + do + LastChar = getchar(); + while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); + + if (LastChar != EOF) + return gettok(); + } + + // Check for end of file. Don't eat the EOF. + if (LastChar == EOF) + return tok_eof; + + // Otherwise, just return the character as its ascii value. + int ThisChar = LastChar; + LastChar = getchar(); + return ThisChar; +} + +//===----------------------------------------------------------------------===// +// Abstract Syntax Tree (aka Parse Tree) +//===----------------------------------------------------------------------===// + +/// ExprAST - Base class for all expression nodes. +class ExprAST { +public: + virtual ~ExprAST() {} + virtual Value *codegen() = 0; +}; + +/// NumberExprAST - Expression class for numeric literals like "1.0". +class NumberExprAST : public ExprAST { + double Val; + +public: + NumberExprAST(double Val) : Val(Val) {} + Value *codegen() override; +}; + +/// VariableExprAST - Expression class for referencing a variable, like "a". +class VariableExprAST : public ExprAST { + std::string Name; + +public: + VariableExprAST(const std::string &Name) : Name(Name) {} + const std::string &getName() const { return Name; } + Value *codegen() override; +}; + +/// UnaryExprAST - Expression class for a unary operator. +class UnaryExprAST : public ExprAST { + char Opcode; + std::unique_ptr Operand; + +public: + UnaryExprAST(char Opcode, std::unique_ptr Operand) + : Opcode(Opcode), Operand(std::move(Operand)) {} + Value *codegen() override; +}; + +/// BinaryExprAST - Expression class for a binary operator. +class BinaryExprAST : public ExprAST { + char Op; + std::unique_ptr LHS, RHS; + +public: + BinaryExprAST(char Op, std::unique_ptr LHS, + std::unique_ptr RHS) + : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} + Value *codegen() override; +}; + +/// CallExprAST - Expression class for function calls. +class CallExprAST : public ExprAST { + std::string Callee; + std::vector> Args; + +public: + CallExprAST(const std::string &Callee, + std::vector> Args) + : Callee(Callee), Args(std::move(Args)) {} + Value *codegen() override; +}; + +/// IfExprAST - Expression class for if/then/else. +class IfExprAST : public ExprAST { + std::unique_ptr Cond, Then, Else; + +public: + IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, + std::unique_ptr Else) + : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} + Value *codegen() override; +}; + +/// ForExprAST - Expression class for for/in. +class ForExprAST : public ExprAST { + std::string VarName; + std::unique_ptr Start, End, Step, Body; + +public: + ForExprAST(const std::string &VarName, std::unique_ptr Start, + std::unique_ptr End, std::unique_ptr Step, + std::unique_ptr Body) + : VarName(VarName), Start(std::move(Start)), End(std::move(End)), + Step(std::move(Step)), Body(std::move(Body)) {} + Value *codegen() override; +}; + +/// VarExprAST - Expression class for var/in +class VarExprAST : public ExprAST { + std::vector>> VarNames; + std::unique_ptr Body; + +public: + VarExprAST( + std::vector>> VarNames, + std::unique_ptr Body) + : VarNames(std::move(VarNames)), Body(std::move(Body)) {} + Value *codegen() override; +}; + +/// PrototypeAST - This class represents the "prototype" for a function, +/// which captures its name, and its argument names (thus implicitly the number +/// of arguments the function takes), as well as if it is an operator. +class PrototypeAST { + std::string Name; + std::vector Args; + bool IsOperator; + unsigned Precedence; // Precedence if a binary op. + +public: + PrototypeAST(const std::string &Name, std::vector Args, + bool IsOperator = false, unsigned Prec = 0) + : Name(Name), Args(std::move(Args)), IsOperator(IsOperator), + Precedence(Prec) {} + Function *codegen(); + const std::string &getName() const { return Name; } + + bool isUnaryOp() const { return IsOperator && Args.size() == 1; } + bool isBinaryOp() const { return IsOperator && Args.size() == 2; } + + char getOperatorName() const { + assert(isUnaryOp() || isBinaryOp()); + return Name[Name.size() - 1]; + } + + unsigned getBinaryPrecedence() const { return Precedence; } +}; + +//===----------------------------------------------------------------------===// +// Parser +//===----------------------------------------------------------------------===// + +/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current +/// token the parser is looking at. getNextToken reads another token from the +/// lexer and updates CurTok with its results. +static int CurTok; +static int getNextToken() { return CurTok = gettok(); } + +/// BinopPrecedence - This holds the precedence for each binary operator that is +/// defined. +static std::map BinopPrecedence; + +/// GetTokPrecedence - Get the precedence of the pending binary operator token. +static int GetTokPrecedence() { + if (!isascii(CurTok)) + return -1; + + // Make sure it's a declared binop. + int TokPrec = BinopPrecedence[CurTok]; + if (TokPrec <= 0) + return -1; + return TokPrec; +} + +/// LogError* - These are little helper functions for error handling. +std::unique_ptr LogError(const char *Str) { + fprintf(stderr, "Error: %s\n", Str); + return nullptr; +} + +std::unique_ptr LogErrorP(const char *Str) { + LogError(Str); + return nullptr; +} + +static std::unique_ptr ParseExpression(); + +/// numberexpr ::= number +static std::unique_ptr ParseNumberExpr() { + auto Result = llvm::make_unique(NumVal); + getNextToken(); // consume the number + return std::move(Result); +} + +/// parenexpr ::= '(' expression ')' +static std::unique_ptr ParseParenExpr() { + getNextToken(); // eat (. + auto V = ParseExpression(); + if (!V) + return nullptr; + + if (CurTok != ')') + return LogError("expected ')'"); + getNextToken(); // eat ). + return V; +} + +/// identifierexpr +/// ::= identifier +/// ::= identifier '(' expression* ')' +static std::unique_ptr ParseIdentifierExpr() { + std::string IdName = IdentifierStr; + + getNextToken(); // eat identifier. + + if (CurTok != '(') // Simple variable ref. + return llvm::make_unique(IdName); + + // Call. + getNextToken(); // eat ( + std::vector> Args; + if (CurTok != ')') { + while (true) { + if (auto Arg = ParseExpression()) + Args.push_back(std::move(Arg)); + else + return nullptr; + + if (CurTok == ')') + break; + + if (CurTok != ',') + return LogError("Expected ')' or ',' in argument list"); + getNextToken(); + } + } + + // Eat the ')'. + getNextToken(); + + return llvm::make_unique(IdName, std::move(Args)); +} + +/// ifexpr ::= 'if' expression 'then' expression 'else' expression +static std::unique_ptr ParseIfExpr() { + getNextToken(); // eat the if. + + // condition. + auto Cond = ParseExpression(); + if (!Cond) + return nullptr; + + if (CurTok != tok_then) + return LogError("expected then"); + getNextToken(); // eat the then + + auto Then = ParseExpression(); + if (!Then) + return nullptr; + + if (CurTok != tok_else) + return LogError("expected else"); + + getNextToken(); + + auto Else = ParseExpression(); + if (!Else) + return nullptr; + + return llvm::make_unique(std::move(Cond), std::move(Then), + std::move(Else)); +} + +/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression +static std::unique_ptr ParseForExpr() { + getNextToken(); // eat the for. + + if (CurTok != tok_identifier) + return LogError("expected identifier after for"); + + std::string IdName = IdentifierStr; + getNextToken(); // eat identifier. + + if (CurTok != '=') + return LogError("expected '=' after for"); + getNextToken(); // eat '='. + + auto Start = ParseExpression(); + if (!Start) + return nullptr; + if (CurTok != ',') + return LogError("expected ',' after for start value"); + getNextToken(); + + auto End = ParseExpression(); + if (!End) + return nullptr; + + // The step value is optional. + std::unique_ptr Step; + if (CurTok == ',') { + getNextToken(); + Step = ParseExpression(); + if (!Step) + return nullptr; + } + + if (CurTok != tok_in) + return LogError("expected 'in' after for"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(IdName, std::move(Start), std::move(End), + std::move(Step), std::move(Body)); +} + +/// varexpr ::= 'var' identifier ('=' expression)? +// (',' identifier ('=' expression)?)* 'in' expression +static std::unique_ptr ParseVarExpr() { + getNextToken(); // eat the var. + + std::vector>> VarNames; + + // At least one variable name is required. + if (CurTok != tok_identifier) + return LogError("expected identifier after var"); + + while (true) { + std::string Name = IdentifierStr; + getNextToken(); // eat identifier. + + // Read the optional initializer. + std::unique_ptr Init = nullptr; + if (CurTok == '=') { + getNextToken(); // eat the '='. + + Init = ParseExpression(); + if (!Init) + return nullptr; + } + + VarNames.push_back(std::make_pair(Name, std::move(Init))); + + // End of var list, exit loop. + if (CurTok != ',') + break; + getNextToken(); // eat the ','. + + if (CurTok != tok_identifier) + return LogError("expected identifier list after var"); + } + + // At this point, we have to have 'in'. + if (CurTok != tok_in) + return LogError("expected 'in' keyword after 'var'"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(std::move(VarNames), std::move(Body)); +} + +/// primary +/// ::= identifierexpr +/// ::= numberexpr +/// ::= parenexpr +/// ::= ifexpr +/// ::= forexpr +/// ::= varexpr +static std::unique_ptr ParsePrimary() { + switch (CurTok) { + default: + return LogError("unknown token when expecting an expression"); + case tok_identifier: + return ParseIdentifierExpr(); + case tok_number: + return ParseNumberExpr(); + case '(': + return ParseParenExpr(); + case tok_if: + return ParseIfExpr(); + case tok_for: + return ParseForExpr(); + case tok_var: + return ParseVarExpr(); + } +} + +/// unary +/// ::= primary +/// ::= '!' unary +static std::unique_ptr ParseUnary() { + // If the current token is not an operator, it must be a primary expr. + if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') + return ParsePrimary(); + + // If this is a unary operator, read it. + int Opc = CurTok; + getNextToken(); + if (auto Operand = ParseUnary()) + return llvm::make_unique(Opc, std::move(Operand)); + return nullptr; +} + +/// binoprhs +/// ::= ('+' unary)* +static std::unique_ptr ParseBinOpRHS(int ExprPrec, + std::unique_ptr LHS) { + // If this is a binop, find its precedence. + while (true) { + int TokPrec = GetTokPrecedence(); + + // If this is a binop that binds at least as tightly as the current binop, + // consume it, otherwise we are done. + if (TokPrec < ExprPrec) + return LHS; + + // Okay, we know this is a binop. + int BinOp = CurTok; + getNextToken(); // eat binop + + // Parse the unary expression after the binary operator. + auto RHS = ParseUnary(); + if (!RHS) + return nullptr; + + // If BinOp binds less tightly with RHS than the operator after RHS, let + // the pending operator take RHS as its LHS. + int NextPrec = GetTokPrecedence(); + if (TokPrec < NextPrec) { + RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); + if (!RHS) + return nullptr; + } + + // Merge LHS/RHS. + LHS = + llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); + } +} + +/// expression +/// ::= unary binoprhs +/// +static std::unique_ptr ParseExpression() { + auto LHS = ParseUnary(); + if (!LHS) + return nullptr; + + return ParseBinOpRHS(0, std::move(LHS)); +} + +/// prototype +/// ::= id '(' id* ')' +/// ::= binary LETTER number? (id, id) +/// ::= unary LETTER (id) +static std::unique_ptr ParsePrototype() { + std::string FnName; + + unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. + unsigned BinaryPrecedence = 30; + + switch (CurTok) { + default: + return LogErrorP("Expected function name in prototype"); + case tok_identifier: + FnName = IdentifierStr; + Kind = 0; + getNextToken(); + break; + case tok_unary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected unary operator"); + FnName = "unary"; + FnName += (char)CurTok; + Kind = 1; + getNextToken(); + break; + case tok_binary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected binary operator"); + FnName = "binary"; + FnName += (char)CurTok; + Kind = 2; + getNextToken(); + + // Read the precedence if present. + if (CurTok == tok_number) { + if (NumVal < 1 || NumVal > 100) + return LogErrorP("Invalid precedecnce: must be 1..100"); + BinaryPrecedence = (unsigned)NumVal; + getNextToken(); + } + break; + } + + if (CurTok != '(') + return LogErrorP("Expected '(' in prototype"); + + std::vector ArgNames; + while (getNextToken() == tok_identifier) + ArgNames.push_back(IdentifierStr); + if (CurTok != ')') + return LogErrorP("Expected ')' in prototype"); + + // success. + getNextToken(); // eat ')'. + + // Verify right number of names for operator. + if (Kind && ArgNames.size() != Kind) + return LogErrorP("Invalid number of operands for operator"); + + return llvm::make_unique(FnName, ArgNames, Kind != 0, + BinaryPrecedence); +} + +/// definition ::= 'def' prototype expression +static std::unique_ptr ParseDefinition() { + getNextToken(); // eat def. + auto Proto = ParsePrototype(); + if (!Proto) + return nullptr; + + if (auto E = ParseExpression()) + return llvm::make_unique(std::move(Proto), std::move(E)); + return nullptr; +} + +/// toplevelexpr ::= expression +static std::unique_ptr ParseTopLevelExpr() { + if (auto E = ParseExpression()) { + + auto PEArgs = std::vector>(); + PEArgs.push_back(std::move(E)); + auto PrintExpr = + llvm::make_unique("printExprResult", std::move(PEArgs)); + + // Make an anonymous proto. + auto Proto = llvm::make_unique("__anon_expr", + std::vector()); + return llvm::make_unique(std::move(Proto), + std::move(PrintExpr)); + } + return nullptr; +} + +/// external ::= 'extern' prototype +static std::unique_ptr ParseExtern() { + getNextToken(); // eat extern. + return ParsePrototype(); +} + +//===----------------------------------------------------------------------===// +// Code Generation +//===----------------------------------------------------------------------===// + +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); +static std::unique_ptr TheModule; +static std::map NamedValues; +static std::unique_ptr TheJIT; +static std::map> FunctionProtos; +static ExitOnError ExitOnErr; + +Value *LogErrorV(const char *Str) { + LogError(Str); + return nullptr; +} + +Function *getFunction(std::string Name) { + // First, see if the function has already been added to the current module. + if (auto *F = TheModule->getFunction(Name)) + return F; + + // If not, check whether we can codegen the declaration from some existing + // prototype. + auto FI = FunctionProtos.find(Name); + if (FI != FunctionProtos.end()) + return FI->second->codegen(); + + // If no existing prototype exists, return null. + return nullptr; +} + +/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of +/// the function. This is used for mutable variables etc. +static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, + const std::string &VarName) { + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), + TheFunction->getEntryBlock().begin()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); +} + +Value *NumberExprAST::codegen() { + return ConstantFP::get(TheContext, APFloat(Val)); +} + +Value *VariableExprAST::codegen() { + // Look this variable up in the function. + Value *V = NamedValues[Name]; + if (!V) + return LogErrorV("Unknown variable name"); + + // Load the value. + return Builder.CreateLoad(V, Name.c_str()); +} + +Value *UnaryExprAST::codegen() { + Value *OperandV = Operand->codegen(); + if (!OperandV) + return nullptr; + + Function *F = getFunction(std::string("unary") + Opcode); + if (!F) + return LogErrorV("Unknown unary operator"); + + return Builder.CreateCall(F, OperandV, "unop"); +} + +Value *BinaryExprAST::codegen() { + // Special case '=' because we don't want to emit the LHS as an expression. + if (Op == '=') { + // Assignment requires the LHS to be an identifier. + // This assume we're building without RTTI because LLVM builds that way by + // default. If you build LLVM with RTTI this can be changed to a + // dynamic_cast for automatic error checking. + VariableExprAST *LHSE = static_cast(LHS.get()); + if (!LHSE) + return LogErrorV("destination of '=' must be a variable"); + // Codegen the RHS. + Value *Val = RHS->codegen(); + if (!Val) + return nullptr; + + // Look up the name. + Value *Variable = NamedValues[LHSE->getName()]; + if (!Variable) + return LogErrorV("Unknown variable name"); + + Builder.CreateStore(Val, Variable); + return Val; + } + + Value *L = LHS->codegen(); + Value *R = RHS->codegen(); + if (!L || !R) + return nullptr; + + switch (Op) { + case '+': + return Builder.CreateFAdd(L, R, "addtmp"); + case '-': + return Builder.CreateFSub(L, R, "subtmp"); + case '*': + return Builder.CreateFMul(L, R, "multmp"); + case '<': + L = Builder.CreateFCmpULT(L, R, "cmptmp"); + // Convert bool 0/1 to double 0.0 or 1.0 + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + default: + break; + } + + // If it wasn't a builtin binary operator, it must be a user defined one. Emit + // a call to it. + Function *F = getFunction(std::string("binary") + Op); + assert(F && "binary operator not found!"); + + Value *Ops[] = {L, R}; + return Builder.CreateCall(F, Ops, "binop"); +} + +Value *CallExprAST::codegen() { + // Look up the name in the global module table. + Function *CalleeF = getFunction(Callee); + if (!CalleeF) + return LogErrorV("Unknown function referenced"); + + // If argument mismatch error. + if (CalleeF->arg_size() != Args.size()) + return LogErrorV("Incorrect # arguments passed"); + + std::vector ArgsV; + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + ArgsV.push_back(Args[i]->codegen()); + if (!ArgsV.back()) + return nullptr; + } + + return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); +} + +Value *IfExprAST::codegen() { + Value *CondV = Cond->codegen(); + if (!CondV) + return nullptr; + + // Convert condition to a bool by comparing equal to 0.0. + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create blocks for the then and else cases. Insert the 'then' block at the + // end of the function. + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + + Builder.CreateCondBr(CondV, ThenBB, ElseBB); + + // Emit then value. + Builder.SetInsertPoint(ThenBB); + + Value *ThenV = Then->codegen(); + if (!ThenV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Then' can change the current block, update ThenBB for the PHI. + ThenBB = Builder.GetInsertBlock(); + + // Emit else block. + TheFunction->getBasicBlockList().push_back(ElseBB); + Builder.SetInsertPoint(ElseBB); + + Value *ElseV = Else->codegen(); + if (!ElseV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Else' can change the current block, update ElseBB for the PHI. + ElseBB = Builder.GetInsertBlock(); + + // Emit merge block. + TheFunction->getBasicBlockList().push_back(MergeBB); + Builder.SetInsertPoint(MergeBB); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + + PN->addIncoming(ThenV, ThenBB); + PN->addIncoming(ElseV, ElseBB); + return PN; +} + +// Output for-loop as: +// var = alloca double +// ... +// start = startexpr +// store start -> var +// goto loop +// loop: +// ... +// bodyexpr +// ... +// loopend: +// step = stepexpr +// endcond = endexpr +// +// curvar = load var +// nextvar = curvar + step +// store nextvar -> var +// br endcond, loop, endloop +// outloop: +Value *ForExprAST::codegen() { + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create an alloca for the variable in the entry block. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + + // Emit the start code first, without 'variable' in scope. + Value *StartVal = Start->codegen(); + if (!StartVal) + return nullptr; + + // Store the value into the alloca. + Builder.CreateStore(StartVal, Alloca); + + // Make the new basic block for the loop header, inserting after current + // block. + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + + // Insert an explicit fall through from the current block to the LoopBB. + Builder.CreateBr(LoopBB); + + // Start insertion in LoopBB. + Builder.SetInsertPoint(LoopBB); + + // Within the loop, the variable is defined equal to the PHI node. If it + // shadows an existing variable, we have to restore it, so save it now. + AllocaInst *OldVal = NamedValues[VarName]; + NamedValues[VarName] = Alloca; + + // Emit the body of the loop. This, like any other expr, can change the + // current BB. Note that we ignore the value computed by the body, but don't + // allow an error. + if (!Body->codegen()) + return nullptr; + + // Emit the step value. + Value *StepVal = nullptr; + if (Step) { + StepVal = Step->codegen(); + if (!StepVal) + return nullptr; + } else { + // If not specified, use 1.0. + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + } + + // Compute the end condition. + Value *EndCond = End->codegen(); + if (!EndCond) + return nullptr; + + // Reload, increment, and restore the alloca. This handles the case where + // the body of the loop mutates the variable. + Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); + Builder.CreateStore(NextVar, Alloca); + + // Convert condition to a bool by comparing equal to 0.0. + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + + // Create the "after loop" block and insert it. + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); + + // Insert the conditional branch into the end of LoopEndBB. + Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + + // Any new code will be inserted in AfterBB. + Builder.SetInsertPoint(AfterBB); + + // Restore the unshadowed variable. + if (OldVal) + NamedValues[VarName] = OldVal; + else + NamedValues.erase(VarName); + + // for expr always returns 0.0. + return Constant::getNullValue(Type::getDoubleTy(TheContext)); +} + +Value *VarExprAST::codegen() { + std::vector OldBindings; + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Register all variables and emit their initializer. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { + const std::string &VarName = VarNames[i].first; + ExprAST *Init = VarNames[i].second.get(); + + // Emit the initializer before adding the variable to scope, this prevents + // the initializer from referencing the variable itself, and permits stuff + // like this: + // var a = 1 in + // var a = a in ... # refers to outer 'a'. + Value *InitVal; + if (Init) { + InitVal = Init->codegen(); + if (!InitVal) + return nullptr; + } else { // If not specified, use 0.0. + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + } + + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + Builder.CreateStore(InitVal, Alloca); + + // Remember the old variable binding so that we can restore the binding when + // we unrecurse. + OldBindings.push_back(NamedValues[VarName]); + + // Remember this binding. + NamedValues[VarName] = Alloca; + } + + // Codegen the body, now that all vars are in scope. + Value *BodyVal = Body->codegen(); + if (!BodyVal) + return nullptr; + + // Pop all our variables from scope. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) + NamedValues[VarNames[i].first] = OldBindings[i]; + + // Return the body computation. + return BodyVal; +} + +Function *PrototypeAST::codegen() { + // Make the function type: double(double,double) etc. + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + + Function *F = + Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); + + // Set names for all arguments. + unsigned Idx = 0; + for (auto &Arg : F->args()) + Arg.setName(Args[Idx++]); + + return F; +} + +const PrototypeAST& FunctionAST::getProto() const { + return *Proto; +} + +const std::string& FunctionAST::getName() const { + return Proto->getName(); +} + +Function *FunctionAST::codegen() { + // Transfer ownership of the prototype to the FunctionProtos map, but keep a + // reference to it for use below. + auto &P = *Proto; + Function *TheFunction = getFunction(P.getName()); + if (!TheFunction) + return nullptr; + + // If this is an operator, install it. + if (P.isBinaryOp()) + BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); + + // Create a new basic block to start insertion into. + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); + Builder.SetInsertPoint(BB); + + // Record the function arguments in the NamedValues map. + NamedValues.clear(); + for (auto &Arg : TheFunction->args()) { + // Create an alloca for this variable. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); + + // Store the initial value into the alloca. + Builder.CreateStore(&Arg, Alloca); + + // Add arguments to variable symbol table. + NamedValues[Arg.getName()] = Alloca; + } + + if (Value *RetVal = Body->codegen()) { + // Finish off the function. + Builder.CreateRet(RetVal); + + // Validate the generated code, checking for consistency. + verifyFunction(*TheFunction); + + return TheFunction; + } + + // Error reading body, remove function. + TheFunction->eraseFromParent(); + + if (P.isBinaryOp()) + BinopPrecedence.erase(Proto->getOperatorName()); + return nullptr; +} + +//===----------------------------------------------------------------------===// +// Top-Level parsing and JIT Driver +//===----------------------------------------------------------------------===// + +static void InitializeModule() { + // Open a new module. + TheModule = llvm::make_unique("my cool jit", TheContext); + TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); +} + +std::unique_ptr +irgenAndTakeOwnership(FunctionAST &FnAST, const std::string &Suffix) { + if (auto *F = FnAST.codegen()) { + F->setName(F->getName() + Suffix); + auto M = std::move(TheModule); + // Start a new module. + InitializeModule(); + return M; + } else + report_fatal_error("Couldn't compile lazily JIT'd function"); +} + +static void HandleDefinition() { + if (auto FnAST = ParseDefinition()) { + FunctionProtos[FnAST->getProto().getName()] = + llvm::make_unique(FnAST->getProto()); + ExitOnErr(TheJIT->addFunctionAST(std::move(FnAST))); + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleExtern() { + if (auto ProtoAST = ParseExtern()) { + if (auto *FnIR = ProtoAST->codegen()) { + fprintf(stderr, "Read extern: "); + FnIR->dump(); + FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleTopLevelExpression() { + // Evaluate a top-level expression into an anonymous function. + if (auto FnAST = ParseTopLevelExpr()) { + FunctionProtos[FnAST->getName()] = + llvm::make_unique(FnAST->getProto()); + if (FnAST->codegen()) { + // JIT the module containing the anonymous expression, keeping a handle so + // we can free it later. + auto H = TheJIT->addModule(std::move(TheModule)); + InitializeModule(); + + // Search the JIT for the __anon_expr symbol. + auto ExprSymbol = TheJIT->findSymbol("__anon_expr"); + assert(ExprSymbol && "Function not found"); + + // Get the symbol's address and cast it to the right type (takes no + // arguments, returns a double) so we can call it as a native function. + ExitOnErr(TheJIT->executeRemoteExpr(ExprSymbol.getAddress())); + + // Delete the anonymous expression module from the JIT. + TheJIT->removeModule(H); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +/// top ::= definition | external | expression | ';' +static void MainLoop() { + while (true) { + fprintf(stderr, "ready> "); + switch (CurTok) { + case tok_eof: + return; + case ';': // ignore top-level semicolons. + getNextToken(); + break; + case tok_def: + HandleDefinition(); + break; + case tok_extern: + HandleExtern(); + break; + default: + HandleTopLevelExpression(); + break; + } + } +} + +//===----------------------------------------------------------------------===// +// "Library" functions that can be "extern'd" from user code. +//===----------------------------------------------------------------------===// + +/// putchard - putchar that takes a double and returns 0. +extern "C" double putchard(double X) { + fputc((char)X, stderr); + return 0; +} + +/// printd - printf that takes a double prints it as "%f\n", returning 0. +extern "C" double printd(double X) { + fprintf(stderr, "%f\n", X); + return 0; +} + +//===----------------------------------------------------------------------===// +// TCP / Connection setup code. +//===----------------------------------------------------------------------===// + +std::unique_ptr connect() { + int sockfd = socket(PF_INET, SOCK_STREAM, 0); + hostent *server = gethostbyname(HostName.c_str()); + + if (!server) { + errs() << "Could not find host " << HostName << "\n"; + exit(1); + } + + sockaddr_in servAddr; + bzero(&servAddr, sizeof(servAddr)); + servAddr.sin_family = PF_INET; + bcopy(server->h_addr, &servAddr.sin_addr.s_addr, server->h_length); + servAddr.sin_port = htons(Port); + if (connect(sockfd, reinterpret_cast(&servAddr), + sizeof(servAddr)) < 0) { + errs() << "Failure to connect.\n"; + exit(1); + } + + return llvm::make_unique(sockfd, sockfd); +} + +//===----------------------------------------------------------------------===// +// Main driver code. +//===----------------------------------------------------------------------===// + +int main(int argc, char *argv[]) { + // Parse the command line options. + cl::ParseCommandLineOptions(argc, argv, "Building A JIT - Client.\n"); + + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetAsmParser(); + + ExitOnErr.setBanner("Kaleidoscope: "); + + // Install standard binary operators. + // 1 is lowest precedence. + BinopPrecedence['='] = 2; + BinopPrecedence['<'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; // highest. + + auto TCPChannel = connect(); + MyRemote Remote = ExitOnErr(MyRemote::Create(*TCPChannel)); + TheJIT = llvm::make_unique(Remote); + + // Automatically inject a definition for 'printExprResult'. + FunctionProtos["printExprResult"] = + llvm::make_unique("printExprResult", + std::vector({"Val"})); + + // Prime the first token. + fprintf(stderr, "ready> "); + getNextToken(); + + InitializeModule(); + + // Run the main "interpreter loop" now. + MainLoop(); + + // Delete the JIT before the Remote and Channel go out of scope, otherwise + // we'll crash in the JIT destructor when it tries to release remote + // resources over a channel that no longer exists. + TheJIT = nullptr; + + // Send a terminate message to the remote to tell it to exit cleanly. + ExitOnErr(Remote.terminateSession()); + + return 0; +} diff --git a/examples/Kaleidoscope/CMakeLists.txt b/examples/Kaleidoscope/CMakeLists.txt index 32664aa2a22721dc35d5e56095273ebe804e8d99..543b9f73b4fe257e6764141e15e6a9f44fc04fa2 100644 --- a/examples/Kaleidoscope/CMakeLists.txt +++ b/examples/Kaleidoscope/CMakeLists.txt @@ -6,6 +6,7 @@ macro(add_kaleidoscope_chapter name) add_llvm_example(${name} ${ARGN}) endmacro(add_kaleidoscope_chapter name) +add_subdirectory(BuildingAJIT) add_subdirectory(Chapter2) add_subdirectory(Chapter3) add_subdirectory(Chapter4) @@ -13,4 +14,3 @@ add_subdirectory(Chapter5) add_subdirectory(Chapter6) add_subdirectory(Chapter7) add_subdirectory(Chapter8) -add_subdirectory(Orc) diff --git a/examples/Kaleidoscope/Chapter2/toy.cpp b/examples/Kaleidoscope/Chapter2/toy.cpp index 24cb424c98560b5d9726d8f9b6190ec7171400f5..31a998faadc748796174f39b55929f6f02924e77 100644 --- a/examples/Kaleidoscope/Chapter2/toy.cpp +++ b/examples/Kaleidoscope/Chapter2/toy.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -15,7 +16,7 @@ static make_unique(Args &&... args) { return std::unique_ptr(new T(std::forward(args)...)); } -} +} // end namespace helper //===----------------------------------------------------------------------===// // Lexer @@ -234,7 +235,7 @@ static std::unique_ptr ParseIdentifierExpr() { getNextToken(); // eat ( std::vector> Args; if (CurTok != ')') { - while (1) { + while (true) { if (auto Arg = ParseExpression()) Args.push_back(std::move(Arg)); else @@ -277,7 +278,7 @@ static std::unique_ptr ParsePrimary() { static std::unique_ptr ParseBinOpRHS(int ExprPrec, std::unique_ptr LHS) { // If this is a binop, find its precedence. - while (1) { + while (true) { int TokPrec = GetTokPrecedence(); // If this is a binop that binds at least as tightly as the current binop, @@ -407,7 +408,7 @@ static void HandleTopLevelExpression() { /// top ::= definition | external | expression | ';' static void MainLoop() { - while (1) { + while (true) { fprintf(stderr, "ready> "); switch (CurTok) { case tok_eof: diff --git a/examples/Kaleidoscope/Chapter3/toy.cpp b/examples/Kaleidoscope/Chapter3/toy.cpp index 8c5252312a7e9e9367ecf19f3177d8bf96af0fea..cdf0d6c8cdb2b4e8daa1fd7e253109b3e5ae7b5a 100644 --- a/examples/Kaleidoscope/Chapter3/toy.cpp +++ b/examples/Kaleidoscope/Chapter3/toy.cpp @@ -1,11 +1,19 @@ +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" #include "llvm/IR/Verifier.h" #include #include +#include #include +#include #include #include @@ -237,7 +245,7 @@ static std::unique_ptr ParseIdentifierExpr() { getNextToken(); // eat ( std::vector> Args; if (CurTok != ')') { - while (1) { + while (true) { if (auto Arg = ParseExpression()) Args.push_back(std::move(Arg)); else @@ -280,7 +288,7 @@ static std::unique_ptr ParsePrimary() { static std::unique_ptr ParseBinOpRHS(int ExprPrec, std::unique_ptr LHS) { // If this is a binop, find its precedence. - while (1) { + while (true) { int TokPrec = GetTokPrecedence(); // If this is a binop that binds at least as tightly as the current binop, @@ -380,8 +388,9 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::unique_ptr TheModule; -static IRBuilder<> Builder(getGlobalContext()); static std::map NamedValues; Value *LogErrorV(const char *Str) { @@ -390,7 +399,7 @@ Value *LogErrorV(const char *Str) { } Value *NumberExprAST::codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -417,8 +426,7 @@ Value *BinaryExprAST::codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: return LogErrorV("invalid binary operator"); } @@ -446,10 +454,9 @@ Value *CallExprAST::codegen() { Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles, false); + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -473,7 +480,7 @@ Function *FunctionAST::codegen() { return nullptr; // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Record the function arguments in the NamedValues map. @@ -539,7 +546,7 @@ static void HandleTopLevelExpression() { /// top ::= definition | external | expression | ';' static void MainLoop() { - while (1) { + while (true) { fprintf(stderr, "ready> "); switch (CurTok) { case tok_eof: @@ -577,7 +584,7 @@ int main() { getNextToken(); // Make the module, which holds all the code. - TheModule = llvm::make_unique("my cool jit", getGlobalContext()); + TheModule = llvm::make_unique("my cool jit", TheContext); // Run the main "interpreter loop" now. MainLoop(); diff --git a/examples/Kaleidoscope/Chapter4/toy.cpp b/examples/Kaleidoscope/Chapter4/toy.cpp index 4b5b1585a3d4ca2662b4073658143987ae17e235..836a2053cbe9f5831d2ef7f474b3be7154cfe8cf 100644 --- a/examples/Kaleidoscope/Chapter4/toy.cpp +++ b/examples/Kaleidoscope/Chapter4/toy.cpp @@ -1,19 +1,29 @@ +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Analysis/Passes.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/GVN.h" +#include "../include/KaleidoscopeJIT.h" +#include #include +#include #include +#include #include +#include #include #include -#include "../include/KaleidoscopeJIT.h" using namespace llvm; using namespace llvm::orc; @@ -244,7 +254,7 @@ static std::unique_ptr ParseIdentifierExpr() { getNextToken(); // eat ( std::vector> Args; if (CurTok != ')') { - while (1) { + while (true) { if (auto Arg = ParseExpression()) Args.push_back(std::move(Arg)); else @@ -287,7 +297,7 @@ static std::unique_ptr ParsePrimary() { static std::unique_ptr ParseBinOpRHS(int ExprPrec, std::unique_ptr LHS) { // If this is a binop, find its precedence. - while (1) { + while (true) { int TokPrec = GetTokPrecedence(); // If this is a binop that binds at least as tightly as the current binop, @@ -387,8 +397,9 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::unique_ptr TheModule; -static IRBuilder<> Builder(getGlobalContext()); static std::map NamedValues; static std::unique_ptr TheFPM; static std::unique_ptr TheJIT; @@ -415,7 +426,7 @@ Function *getFunction(std::string Name) { } Value *NumberExprAST::codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -442,8 +453,7 @@ Value *BinaryExprAST::codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: return LogErrorV("invalid binary operator"); } @@ -471,10 +481,9 @@ Value *CallExprAST::codegen() { Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles, false); + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -497,7 +506,7 @@ Function *FunctionAST::codegen() { return nullptr; // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Record the function arguments in the NamedValues map. @@ -529,7 +538,7 @@ Function *FunctionAST::codegen() { static void InitializeModuleAndPassManager() { // Open a new module. - TheModule = llvm::make_unique("my cool jit", getGlobalContext()); + TheModule = llvm::make_unique("my cool jit", TheContext); TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); // Create a new pass manager attached to it. @@ -578,7 +587,6 @@ static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so // we can free it later. auto H = TheJIT->addModule(std::move(TheModule)); @@ -604,7 +612,7 @@ static void HandleTopLevelExpression() { /// top ::= definition | external | expression | ';' static void MainLoop() { - while (1) { + while (true) { fprintf(stderr, "ready> "); switch (CurTok) { case tok_eof: diff --git a/examples/Kaleidoscope/Chapter5/toy.cpp b/examples/Kaleidoscope/Chapter5/toy.cpp index d54c66962665b355f93a7d94976ebe0008bafa06..a080bd00cb5806e6e6bafb0ea4d1161052408bbe 100644 --- a/examples/Kaleidoscope/Chapter5/toy.cpp +++ b/examples/Kaleidoscope/Chapter5/toy.cpp @@ -1,19 +1,30 @@ +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Analysis/Passes.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/GVN.h" +#include "../include/KaleidoscopeJIT.h" +#include #include +#include #include +#include #include +#include #include #include -#include "../include/KaleidoscopeJIT.h" using namespace llvm; using namespace llvm::orc; @@ -286,7 +297,7 @@ static std::unique_ptr ParseIdentifierExpr() { getNextToken(); // eat ( std::vector> Args; if (CurTok != ')') { - while (1) { + while (true) { if (auto Arg = ParseExpression()) Args.push_back(std::move(Arg)); else @@ -411,7 +422,7 @@ static std::unique_ptr ParsePrimary() { static std::unique_ptr ParseBinOpRHS(int ExprPrec, std::unique_ptr LHS) { // If this is a binop, find its precedence. - while (1) { + while (true) { int TokPrec = GetTokPrecedence(); // If this is a binop that binds at least as tightly as the current binop, @@ -511,8 +522,9 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::unique_ptr TheModule; -static IRBuilder<> Builder(getGlobalContext()); static std::map NamedValues; static std::unique_ptr TheFPM; static std::unique_ptr TheJIT; @@ -539,7 +551,7 @@ Function *getFunction(std::string Name) { } Value *NumberExprAST::codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -566,8 +578,7 @@ Value *BinaryExprAST::codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: return LogErrorV("invalid binary operator"); } @@ -600,16 +611,15 @@ Value *IfExprAST::codegen() { // Convert condition to a bool by comparing equal to 0.0. CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "ifcond"); + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = - BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); @@ -639,8 +649,7 @@ Value *IfExprAST::codegen() { // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); - PHINode *PN = - Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, "iftmp"); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -672,8 +681,7 @@ Value *ForExprAST::codegen() { // block. Function *TheFunction = Builder.GetInsertBlock()->getParent(); BasicBlock *PreheaderBB = Builder.GetInsertBlock(); - BasicBlock *LoopBB = - BasicBlock::Create(getGlobalContext(), "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -682,8 +690,8 @@ Value *ForExprAST::codegen() { Builder.SetInsertPoint(LoopBB); // Start the PHI node with an entry for Start. - PHINode *Variable = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), - 2, VarName.c_str()); + PHINode *Variable = + Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, VarName); Variable->addIncoming(StartVal, PreheaderBB); // Within the loop, the variable is defined equal to the PHI node. If it @@ -705,7 +713,7 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } Value *NextVar = Builder.CreateFAdd(Variable, StepVal, "nextvar"); @@ -717,12 +725,12 @@ Value *ForExprAST::codegen() { // Convert condition to a bool by comparing equal to 0.0. EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "loopcond"); + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. BasicBlock *LoopEndBB = Builder.GetInsertBlock(); BasicBlock *AfterBB = - BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); + BasicBlock::Create(TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -740,15 +748,14 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles, false); + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -771,7 +778,7 @@ Function *FunctionAST::codegen() { return nullptr; // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Record the function arguments in the NamedValues map. @@ -803,7 +810,7 @@ Function *FunctionAST::codegen() { static void InitializeModuleAndPassManager() { // Open a new module. - TheModule = llvm::make_unique("my cool jit", getGlobalContext()); + TheModule = llvm::make_unique("my cool jit", TheContext); TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); // Create a new pass manager attached to it. @@ -852,7 +859,6 @@ static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so // we can free it later. auto H = TheJIT->addModule(std::move(TheModule)); @@ -878,7 +884,7 @@ static void HandleTopLevelExpression() { /// top ::= definition | external | expression | ';' static void MainLoop() { - while (1) { + while (true) { fprintf(stderr, "ready> "); switch (CurTok) { case tok_eof: diff --git a/examples/Kaleidoscope/Chapter6/toy.cpp b/examples/Kaleidoscope/Chapter6/toy.cpp index 532a59a0c918fa6d77b4d3da1b22d830ac409488..85d953b0c75640b38c9a8a93ad28c43e4e79066c 100644 --- a/examples/Kaleidoscope/Chapter6/toy.cpp +++ b/examples/Kaleidoscope/Chapter6/toy.cpp @@ -1,19 +1,30 @@ +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Analysis/Passes.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/GVN.h" +#include "../include/KaleidoscopeJIT.h" +#include #include +#include #include +#include #include +#include #include #include -#include "../include/KaleidoscopeJIT.h" using namespace llvm; using namespace llvm::orc; @@ -319,7 +330,7 @@ static std::unique_ptr ParseIdentifierExpr() { getNextToken(); // eat ( std::vector> Args; if (CurTok != ')') { - while (1) { + while (true) { if (auto Arg = ParseExpression()) Args.push_back(std::move(Arg)); else @@ -460,7 +471,7 @@ static std::unique_ptr ParseUnary() { static std::unique_ptr ParseBinOpRHS(int ExprPrec, std::unique_ptr LHS) { // If this is a binop, find its precedence. - while (1) { + while (true) { int TokPrec = GetTokPrecedence(); // If this is a binop that binds at least as tightly as the current binop, @@ -602,8 +613,9 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::unique_ptr TheModule; -static IRBuilder<> Builder(getGlobalContext()); static std::map NamedValues; static std::unique_ptr TheFPM; static std::unique_ptr TheJIT; @@ -630,7 +642,7 @@ Function *getFunction(std::string Name) { } Value *NumberExprAST::codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -669,8 +681,7 @@ Value *BinaryExprAST::codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: break; } @@ -711,16 +722,15 @@ Value *IfExprAST::codegen() { // Convert condition to a bool by comparing equal to 0.0. CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "ifcond"); + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = - BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); @@ -750,8 +760,7 @@ Value *IfExprAST::codegen() { // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); - PHINode *PN = - Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, "iftmp"); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -783,8 +792,7 @@ Value *ForExprAST::codegen() { // block. Function *TheFunction = Builder.GetInsertBlock()->getParent(); BasicBlock *PreheaderBB = Builder.GetInsertBlock(); - BasicBlock *LoopBB = - BasicBlock::Create(getGlobalContext(), "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -793,8 +801,8 @@ Value *ForExprAST::codegen() { Builder.SetInsertPoint(LoopBB); // Start the PHI node with an entry for Start. - PHINode *Variable = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), - 2, VarName.c_str()); + PHINode *Variable = + Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, VarName); Variable->addIncoming(StartVal, PreheaderBB); // Within the loop, the variable is defined equal to the PHI node. If it @@ -816,7 +824,7 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } Value *NextVar = Builder.CreateFAdd(Variable, StepVal, "nextvar"); @@ -828,12 +836,12 @@ Value *ForExprAST::codegen() { // Convert condition to a bool by comparing equal to 0.0. EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "loopcond"); + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. BasicBlock *LoopEndBB = Builder.GetInsertBlock(); BasicBlock *AfterBB = - BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); + BasicBlock::Create(TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -851,15 +859,14 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles, false); + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -886,7 +893,7 @@ Function *FunctionAST::codegen() { BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Record the function arguments in the NamedValues map. @@ -921,7 +928,7 @@ Function *FunctionAST::codegen() { static void InitializeModuleAndPassManager() { // Open a new module. - TheModule = llvm::make_unique("my cool jit", getGlobalContext()); + TheModule = llvm::make_unique("my cool jit", TheContext); TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); // Create a new pass manager attached to it. @@ -970,7 +977,6 @@ static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so // we can free it later. auto H = TheJIT->addModule(std::move(TheModule)); @@ -996,7 +1002,7 @@ static void HandleTopLevelExpression() { /// top ::= definition | external | expression | ';' static void MainLoop() { - while (1) { + while (true) { fprintf(stderr, "ready> "); switch (CurTok) { case tok_eof: diff --git a/examples/Kaleidoscope/Chapter7/toy.cpp b/examples/Kaleidoscope/Chapter7/toy.cpp index 5cd062a1b5b124e9ac72fd8e4e3c47eb0d694610..3206ca8c5d7be3e7bc6c616538a38a489fd0cd0f 100644 --- a/examples/Kaleidoscope/Chapter7/toy.cpp +++ b/examples/Kaleidoscope/Chapter7/toy.cpp @@ -1,19 +1,31 @@ +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Analysis/Passes.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/GVN.h" +#include "../include/KaleidoscopeJIT.h" +#include #include +#include #include +#include #include +#include #include +#include #include -#include "../include/KaleidoscopeJIT.h" using namespace llvm; using namespace llvm::orc; @@ -338,7 +350,7 @@ static std::unique_ptr ParseIdentifierExpr() { getNextToken(); // eat ( std::vector> Args; if (CurTok != ')') { - while (1) { + while (true) { if (auto Arg = ParseExpression()) Args.push_back(std::move(Arg)); else @@ -446,7 +458,7 @@ static std::unique_ptr ParseVarExpr() { if (CurTok != tok_identifier) return LogError("expected identifier after var"); - while (1) { + while (true) { std::string Name = IdentifierStr; getNextToken(); // eat identifier. @@ -530,7 +542,7 @@ static std::unique_ptr ParseUnary() { static std::unique_ptr ParseBinOpRHS(int ExprPrec, std::unique_ptr LHS) { // If this is a binop, find its precedence. - while (1) { + while (true) { int TokPrec = GetTokPrecedence(); // If this is a binop that binds at least as tightly as the current binop, @@ -672,8 +684,9 @@ static std::unique_ptr ParseExtern() { // Code Generation //===----------------------------------------------------------------------===// +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::unique_ptr TheModule; -static IRBuilder<> Builder(getGlobalContext()); static std::map NamedValues; static std::unique_ptr TheFPM; static std::unique_ptr TheJIT; @@ -705,12 +718,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), nullptr, - VarName.c_str()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); } Value *NumberExprAST::codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -774,8 +786,7 @@ Value *BinaryExprAST::codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: break; } @@ -816,16 +827,15 @@ Value *IfExprAST::codegen() { // Convert condition to a bool by comparing equal to 0.0. CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "ifcond"); + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = - BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); @@ -855,8 +865,7 @@ Value *IfExprAST::codegen() { // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); - PHINode *PN = - Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, "iftmp"); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -898,8 +907,7 @@ Value *ForExprAST::codegen() { // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = - BasicBlock::Create(getGlobalContext(), "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -926,7 +934,7 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } // Compute the end condition. @@ -942,11 +950,11 @@ Value *ForExprAST::codegen() { // Convert condition to a bool by comparing equal to 0.0. EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "loopcond"); + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. BasicBlock *AfterBB = - BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); + BasicBlock::Create(TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -961,7 +969,7 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } Value *VarExprAST::codegen() { @@ -985,7 +993,7 @@ Value *VarExprAST::codegen() { if (!InitVal) return nullptr; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -1014,10 +1022,9 @@ Value *VarExprAST::codegen() { Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles, false); + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -1044,7 +1051,7 @@ Function *FunctionAST::codegen() { BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Record the function arguments in the NamedValues map. @@ -1087,7 +1094,7 @@ Function *FunctionAST::codegen() { static void InitializeModuleAndPassManager() { // Open a new module. - TheModule = llvm::make_unique("my cool jit", getGlobalContext()); + TheModule = llvm::make_unique("my cool jit", TheContext); TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); // Create a new pass manager attached to it. @@ -1136,7 +1143,6 @@ static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { if (FnAST->codegen()) { - // JIT the module containing the anonymous expression, keeping a handle so // we can free it later. auto H = TheJIT->addModule(std::move(TheModule)); @@ -1162,7 +1168,7 @@ static void HandleTopLevelExpression() { /// top ::= definition | external | expression | ';' static void MainLoop() { - while (1) { + while (true) { fprintf(stderr, "ready> "); switch (CurTok) { case tok_eof: diff --git a/examples/Kaleidoscope/Chapter8/CMakeLists.txt b/examples/Kaleidoscope/Chapter8/CMakeLists.txt index d9b5cc421be397e6a7df382b4901505caec67f6d..1bb1cd25af72d836db0f8670d13fcda00b059af1 100644 --- a/examples/Kaleidoscope/Chapter8/CMakeLists.txt +++ b/examples/Kaleidoscope/Chapter8/CMakeLists.txt @@ -1,9 +1,5 @@ set(LLVM_LINK_COMPONENTS - Core - ExecutionEngine - Object - Support - native + all ) add_kaleidoscope_chapter(Kaleidoscope-Ch8 diff --git a/examples/Kaleidoscope/Chapter8/toy.cpp b/examples/Kaleidoscope/Chapter8/toy.cpp index 31a83861a10df713f60ad8e7f748f0dd5e3facdc..f880bb8ea0f0eeadbc1ddc7990741c0e19f74879 100644 --- a/examples/Kaleidoscope/Chapter8/toy.cpp +++ b/examples/Kaleidoscope/Chapter8/toy.cpp @@ -1,23 +1,31 @@ +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/Passes.h" -#include "llvm/IR/DIBuilder.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" #include "llvm/IR/Verifier.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" #include "llvm/Transforms/Scalar.h" #include #include +#include #include +#include #include +#include #include -#include "../include/KaleidoscopeJIT.h" using namespace llvm; -using namespace llvm::orc; +using namespace llvm::sys; //===----------------------------------------------------------------------===// // Lexer @@ -51,70 +59,6 @@ enum Token { tok_var = -13 }; -std::string getTokName(int Tok) { - switch (Tok) { - case tok_eof: - return "eof"; - case tok_def: - return "def"; - case tok_extern: - return "extern"; - case tok_identifier: - return "identifier"; - case tok_number: - return "number"; - case tok_if: - return "if"; - case tok_then: - return "then"; - case tok_else: - return "else"; - case tok_for: - return "for"; - case tok_in: - return "in"; - case tok_binary: - return "binary"; - case tok_unary: - return "unary"; - case tok_var: - return "var"; - } - return std::string(1, (char)Tok); -} - -namespace { -class PrototypeAST; -class ExprAST; -} -static IRBuilder<> Builder(getGlobalContext()); -struct DebugInfo { - DICompileUnit *TheCU; - DIType *DblTy; - std::vector LexicalBlocks; - - void emitLocation(ExprAST *AST); - DIType *getDoubleTy(); -} KSDbgInfo; - -struct SourceLocation { - int Line; - int Col; -}; -static SourceLocation CurLoc; -static SourceLocation LexLoc = {1, 0}; - -static int advance() { - int LastChar = getchar(); - - if (LastChar == '\n' || LastChar == '\r') { - LexLoc.Line++; - LexLoc.Col = 0; - } else - LexLoc.Col++; - return LastChar; -} - static std::string IdentifierStr; // Filled in if tok_identifier static double NumVal; // Filled in if tok_number @@ -124,13 +68,11 @@ static int gettok() { // Skip any whitespace. while (isspace(LastChar)) - LastChar = advance(); - - CurLoc = LexLoc; + LastChar = getchar(); if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* IdentifierStr = LastChar; - while (isalnum((LastChar = advance()))) + while (isalnum((LastChar = getchar()))) IdentifierStr += LastChar; if (IdentifierStr == "def") @@ -160,7 +102,7 @@ static int gettok() { std::string NumStr; do { NumStr += LastChar; - LastChar = advance(); + LastChar = getchar(); } while (isdigit(LastChar) || LastChar == '.'); NumVal = strtod(NumStr.c_str(), nullptr); @@ -170,7 +112,7 @@ static int gettok() { if (LastChar == '#') { // Comment until end of line. do - LastChar = advance(); + LastChar = getchar(); while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); if (LastChar != EOF) @@ -183,7 +125,7 @@ static int gettok() { // Otherwise, just return the character as its ascii value. int ThisChar = LastChar; - LastChar = advance(); + LastChar = getchar(); return ThisChar; } @@ -191,24 +133,11 @@ static int gettok() { // Abstract Syntax Tree (aka Parse Tree) //===----------------------------------------------------------------------===// namespace { - -raw_ostream &indent(raw_ostream &O, int size) { - return O << std::string(size, ' '); -} - /// ExprAST - Base class for all expression nodes. class ExprAST { - SourceLocation Loc; - public: - ExprAST(SourceLocation Loc = CurLoc) : Loc(Loc) {} virtual ~ExprAST() {} virtual Value *codegen() = 0; - int getLine() const { return Loc.Line; } - int getCol() const { return Loc.Col; } - virtual raw_ostream &dump(raw_ostream &out, int ind) { - return out << ':' << getLine() << ':' << getCol() << '\n'; - } }; /// NumberExprAST - Expression class for numeric literals like "1.0". @@ -217,9 +146,6 @@ class NumberExprAST : public ExprAST { public: NumberExprAST(double Val) : Val(Val) {} - raw_ostream &dump(raw_ostream &out, int ind) override { - return ExprAST::dump(out << Val, ind); - } Value *codegen() override; }; @@ -228,13 +154,9 @@ class VariableExprAST : public ExprAST { std::string Name; public: - VariableExprAST(SourceLocation Loc, const std::string &Name) - : ExprAST(Loc), Name(Name) {} + VariableExprAST(const std::string &Name) : Name(Name) {} const std::string &getName() const { return Name; } Value *codegen() override; - raw_ostream &dump(raw_ostream &out, int ind) override { - return ExprAST::dump(out << Name, ind); - } }; /// UnaryExprAST - Expression class for a unary operator. @@ -246,11 +168,6 @@ public: UnaryExprAST(char Opcode, std::unique_ptr Operand) : Opcode(Opcode), Operand(std::move(Operand)) {} Value *codegen() override; - raw_ostream &dump(raw_ostream &out, int ind) override { - ExprAST::dump(out << "unary" << Opcode, ind); - Operand->dump(out, ind + 1); - return out; - } }; /// BinaryExprAST - Expression class for a binary operator. @@ -259,16 +176,10 @@ class BinaryExprAST : public ExprAST { std::unique_ptr LHS, RHS; public: - BinaryExprAST(SourceLocation Loc, char Op, std::unique_ptr LHS, + BinaryExprAST(char Op, std::unique_ptr LHS, std::unique_ptr RHS) - : ExprAST(Loc), Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} + : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} Value *codegen() override; - raw_ostream &dump(raw_ostream &out, int ind) override { - ExprAST::dump(out << "binary" << Op, ind); - LHS->dump(indent(out, ind) << "LHS:", ind + 1); - RHS->dump(indent(out, ind) << "RHS:", ind + 1); - return out; - } }; /// CallExprAST - Expression class for function calls. @@ -277,16 +188,10 @@ class CallExprAST : public ExprAST { std::vector> Args; public: - CallExprAST(SourceLocation Loc, const std::string &Callee, + CallExprAST(const std::string &Callee, std::vector> Args) - : ExprAST(Loc), Callee(Callee), Args(std::move(Args)) {} + : Callee(Callee), Args(std::move(Args)) {} Value *codegen() override; - raw_ostream &dump(raw_ostream &out, int ind) override { - ExprAST::dump(out << "call " << Callee, ind); - for (const auto &Arg : Args) - Arg->dump(indent(out, ind + 1), ind + 1); - return out; - } }; /// IfExprAST - Expression class for if/then/else. @@ -294,18 +199,10 @@ class IfExprAST : public ExprAST { std::unique_ptr Cond, Then, Else; public: - IfExprAST(SourceLocation Loc, std::unique_ptr Cond, - std::unique_ptr Then, std::unique_ptr Else) - : ExprAST(Loc), Cond(std::move(Cond)), Then(std::move(Then)), - Else(std::move(Else)) {} + IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, + std::unique_ptr Else) + : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} Value *codegen() override; - raw_ostream &dump(raw_ostream &out, int ind) override { - ExprAST::dump(out << "if", ind); - Cond->dump(indent(out, ind) << "Cond:", ind + 1); - Then->dump(indent(out, ind) << "Then:", ind + 1); - Else->dump(indent(out, ind) << "Else:", ind + 1); - return out; - } }; /// ForExprAST - Expression class for for/in. @@ -320,14 +217,6 @@ public: : VarName(VarName), Start(std::move(Start)), End(std::move(End)), Step(std::move(Step)), Body(std::move(Body)) {} Value *codegen() override; - raw_ostream &dump(raw_ostream &out, int ind) override { - ExprAST::dump(out << "for", ind); - Start->dump(indent(out, ind) << "Cond:", ind + 1); - End->dump(indent(out, ind) << "End:", ind + 1); - Step->dump(indent(out, ind) << "Step:", ind + 1); - Body->dump(indent(out, ind) << "Body:", ind + 1); - return out; - } }; /// VarExprAST - Expression class for var/in @@ -341,13 +230,6 @@ public: std::unique_ptr Body) : VarNames(std::move(VarNames)), Body(std::move(Body)) {} Value *codegen() override; - raw_ostream &dump(raw_ostream &out, int ind) override { - ExprAST::dump(out << "var", ind); - for (const auto &NamedVar : VarNames) - NamedVar.second->dump(indent(out, ind) << NamedVar.first << ':', ind + 1); - Body->dump(indent(out, ind) << "Body:", ind + 1); - return out; - } }; /// PrototypeAST - This class represents the "prototype" for a function, @@ -358,14 +240,12 @@ class PrototypeAST { std::vector Args; bool IsOperator; unsigned Precedence; // Precedence if a binary op. - int Line; public: - PrototypeAST(SourceLocation Loc, const std::string &Name, - std::vector Args, bool IsOperator = false, - unsigned Prec = 0) + PrototypeAST(const std::string &Name, std::vector Args, + bool IsOperator = false, unsigned Prec = 0) : Name(Name), Args(std::move(Args)), IsOperator(IsOperator), - Precedence(Prec), Line(Loc.Line) {} + Precedence(Prec) {} Function *codegen(); const std::string &getName() const { return Name; } @@ -378,7 +258,6 @@ public: } unsigned getBinaryPrecedence() const { return Precedence; } - int getLine() const { return Line; } }; /// FunctionAST - This class represents a function definition itself. @@ -391,12 +270,6 @@ public: std::unique_ptr Body) : Proto(std::move(Proto)), Body(std::move(Body)) {} Function *codegen(); - raw_ostream &dump(raw_ostream &out, int ind) { - indent(out, ind) << "FunctionAST\n"; - ++ind; - indent(out, ind) << "Body:"; - return Body ? Body->dump(out, ind) : out << "null\n"; - } }; } // end anonymous namespace @@ -465,18 +338,16 @@ static std::unique_ptr ParseParenExpr() { static std::unique_ptr ParseIdentifierExpr() { std::string IdName = IdentifierStr; - SourceLocation LitLoc = CurLoc; - getNextToken(); // eat identifier. if (CurTok != '(') // Simple variable ref. - return llvm::make_unique(LitLoc, IdName); + return llvm::make_unique(IdName); // Call. getNextToken(); // eat ( std::vector> Args; if (CurTok != ')') { - while (1) { + while (true) { if (auto Arg = ParseExpression()) Args.push_back(std::move(Arg)); else @@ -494,13 +365,11 @@ static std::unique_ptr ParseIdentifierExpr() { // Eat the ')'. getNextToken(); - return llvm::make_unique(LitLoc, IdName, std::move(Args)); + return llvm::make_unique(IdName, std::move(Args)); } /// ifexpr ::= 'if' expression 'then' expression 'else' expression static std::unique_ptr ParseIfExpr() { - SourceLocation IfLoc = CurLoc; - getNextToken(); // eat the if. // condition. @@ -525,7 +394,7 @@ static std::unique_ptr ParseIfExpr() { if (!Else) return nullptr; - return llvm::make_unique(IfLoc, std::move(Cond), std::move(Then), + return llvm::make_unique(std::move(Cond), std::move(Then), std::move(Else)); } @@ -586,7 +455,7 @@ static std::unique_ptr ParseVarExpr() { if (CurTok != tok_identifier) return LogError("expected identifier after var"); - while (1) { + while (true) { std::string Name = IdentifierStr; getNextToken(); // eat identifier. @@ -670,7 +539,7 @@ static std::unique_ptr ParseUnary() { static std::unique_ptr ParseBinOpRHS(int ExprPrec, std::unique_ptr LHS) { // If this is a binop, find its precedence. - while (1) { + while (true) { int TokPrec = GetTokPrecedence(); // If this is a binop that binds at least as tightly as the current binop, @@ -680,7 +549,6 @@ static std::unique_ptr ParseBinOpRHS(int ExprPrec, // Okay, we know this is a binop. int BinOp = CurTok; - SourceLocation BinLoc = CurLoc; getNextToken(); // eat binop // Parse the unary expression after the binary operator. @@ -698,8 +566,8 @@ static std::unique_ptr ParseBinOpRHS(int ExprPrec, } // Merge LHS/RHS. - LHS = llvm::make_unique(BinLoc, BinOp, std::move(LHS), - std::move(RHS)); + LHS = + llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); } } @@ -721,8 +589,6 @@ static std::unique_ptr ParseExpression() { static std::unique_ptr ParsePrototype() { std::string FnName; - SourceLocation FnLoc = CurLoc; - unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. unsigned BinaryPrecedence = 30; @@ -778,7 +644,7 @@ static std::unique_ptr ParsePrototype() { if (Kind && ArgNames.size() != Kind) return LogErrorP("Invalid number of operands for operator"); - return llvm::make_unique(FnLoc, FnName, ArgNames, Kind != 0, + return llvm::make_unique(FnName, ArgNames, Kind != 0, BinaryPrecedence); } @@ -796,10 +662,9 @@ static std::unique_ptr ParseDefinition() { /// toplevelexpr ::= expression static std::unique_ptr ParseTopLevelExpr() { - SourceLocation FnLoc = CurLoc; if (auto E = ParseExpression()) { // Make an anonymous proto. - auto Proto = llvm::make_unique(FnLoc, "__anon_expr", + auto Proto = llvm::make_unique("__anon_expr", std::vector()); return llvm::make_unique(std::move(Proto), std::move(E)); } @@ -812,52 +677,14 @@ static std::unique_ptr ParseExtern() { return ParsePrototype(); } -//===----------------------------------------------------------------------===// -// Debug Info Support -//===----------------------------------------------------------------------===// - -static std::unique_ptr DBuilder; - -DIType *DebugInfo::getDoubleTy() { - if (DblTy) - return DblTy; - - DblTy = DBuilder->createBasicType("double", 64, 64, dwarf::DW_ATE_float); - return DblTy; -} - -void DebugInfo::emitLocation(ExprAST *AST) { - if (!AST) - return Builder.SetCurrentDebugLocation(DebugLoc()); - DIScope *Scope; - if (LexicalBlocks.empty()) - Scope = TheCU; - else - Scope = LexicalBlocks.back(); - Builder.SetCurrentDebugLocation( - DebugLoc::get(AST->getLine(), AST->getCol(), Scope)); -} - -static DISubroutineType *CreateFunctionType(unsigned NumArgs, DIFile *Unit) { - SmallVector EltTys; - DIType *DblTy = KSDbgInfo.getDoubleTy(); - - // Add the result type. - EltTys.push_back(DblTy); - - for (unsigned i = 0, e = NumArgs; i != e; ++i) - EltTys.push_back(DblTy); - - return DBuilder->createSubroutineType(DBuilder->getOrCreateTypeArray(EltTys)); -} - //===----------------------------------------------------------------------===// // Code Generation //===----------------------------------------------------------------------===// +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::unique_ptr TheModule; static std::map NamedValues; -static std::unique_ptr TheJIT; static std::map> FunctionProtos; Value *LogErrorV(const char *Str) { @@ -886,13 +713,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), nullptr, - VarName.c_str()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, VarName); } Value *NumberExprAST::codegen() { - KSDbgInfo.emitLocation(this); - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::codegen() { @@ -901,7 +726,6 @@ Value *VariableExprAST::codegen() { if (!V) return LogErrorV("Unknown variable name"); - KSDbgInfo.emitLocation(this); // Load the value. return Builder.CreateLoad(V, Name.c_str()); } @@ -915,13 +739,10 @@ Value *UnaryExprAST::codegen() { if (!F) return LogErrorV("Unknown unary operator"); - KSDbgInfo.emitLocation(this); return Builder.CreateCall(F, OperandV, "unop"); } Value *BinaryExprAST::codegen() { - KSDbgInfo.emitLocation(this); - // Special case '=' because we don't want to emit the LHS as an expression. if (Op == '=') { // Assignment requires the LHS to be an identifier. @@ -960,8 +781,7 @@ Value *BinaryExprAST::codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: break; } @@ -976,8 +796,6 @@ Value *BinaryExprAST::codegen() { } Value *CallExprAST::codegen() { - KSDbgInfo.emitLocation(this); - // Look up the name in the global module table. Function *CalleeF = getFunction(Callee); if (!CalleeF) @@ -998,24 +816,21 @@ Value *CallExprAST::codegen() { } Value *IfExprAST::codegen() { - KSDbgInfo.emitLocation(this); - Value *CondV = Cond->codegen(); if (!CondV) return nullptr; // Convert condition to a bool by comparing equal to 0.0. CondV = Builder.CreateFCmpONE( - CondV, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "ifcond"); + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = - BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); @@ -1045,8 +860,7 @@ Value *IfExprAST::codegen() { // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); - PHINode *PN = - Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, "iftmp"); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -1078,8 +892,6 @@ Value *ForExprAST::codegen() { // Create an alloca for the variable in the entry block. AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - KSDbgInfo.emitLocation(this); - // Emit the start code first, without 'variable' in scope. Value *StartVal = Start->codegen(); if (!StartVal) @@ -1090,8 +902,7 @@ Value *ForExprAST::codegen() { // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = - BasicBlock::Create(getGlobalContext(), "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -1118,7 +929,7 @@ Value *ForExprAST::codegen() { return nullptr; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } // Compute the end condition. @@ -1134,11 +945,11 @@ Value *ForExprAST::codegen() { // Convert condition to a bool by comparing equal to 0.0. EndCond = Builder.CreateFCmpONE( - EndCond, ConstantFP::get(getGlobalContext(), APFloat(0.0)), "loopcond"); + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. BasicBlock *AfterBB = - BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); + BasicBlock::Create(TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -1153,7 +964,7 @@ Value *ForExprAST::codegen() { NamedValues.erase(VarName); // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } Value *VarExprAST::codegen() { @@ -1177,7 +988,7 @@ Value *VarExprAST::codegen() { if (!InitVal) return nullptr; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -1191,8 +1002,6 @@ Value *VarExprAST::codegen() { NamedValues[VarName] = Alloca; } - KSDbgInfo.emitLocation(this); - // Codegen the body, now that all vars are in scope. Value *BodyVal = Body->codegen(); if (!BodyVal) @@ -1208,10 +1017,9 @@ Value *VarExprAST::codegen() { Function *PrototypeAST::codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); FunctionType *FT = - FunctionType::get(Type::getDoubleTy(getGlobalContext()), Doubles, false); + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); @@ -1238,46 +1046,15 @@ Function *FunctionAST::codegen() { BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); - // Create a subprogram DIE for this function. - DIFile *Unit = DBuilder->createFile(KSDbgInfo.TheCU->getFilename(), - KSDbgInfo.TheCU->getDirectory()); - DIScope *FContext = Unit; - unsigned LineNo = P.getLine(); - unsigned ScopeLine = LineNo; - DISubprogram *SP = DBuilder->createFunction( - FContext, P.getName(), StringRef(), Unit, LineNo, - CreateFunctionType(TheFunction->arg_size(), Unit), - false /* internal linkage */, true /* definition */, ScopeLine, - DINode::FlagPrototyped, false); - TheFunction->setSubprogram(SP); - - // Push the current scope. - KSDbgInfo.LexicalBlocks.push_back(SP); - - // Unset the location for the prologue emission (leading instructions with no - // location in a function are considered part of the prologue and the debugger - // will run past them when breaking on a function) - KSDbgInfo.emitLocation(nullptr); - // Record the function arguments in the NamedValues map. NamedValues.clear(); - unsigned ArgIdx = 0; for (auto &Arg : TheFunction->args()) { // Create an alloca for this variable. AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); - // Create a debug descriptor for the variable. - DILocalVariable *D = DBuilder->createParameterVariable( - SP, Arg.getName(), ++ArgIdx, Unit, LineNo, KSDbgInfo.getDoubleTy(), - true); - - DBuilder->insertDeclare(Alloca, D, DBuilder->createExpression(), - DebugLoc::get(LineNo, 0, SP), - Builder.GetInsertBlock()); - // Store the initial value into the alloca. Builder.CreateStore(&Arg, Alloca); @@ -1285,15 +1062,10 @@ Function *FunctionAST::codegen() { NamedValues[Arg.getName()] = Alloca; } - KSDbgInfo.emitLocation(Body.get()); - if (Value *RetVal = Body->codegen()) { // Finish off the function. Builder.CreateRet(RetVal); - // Pop off the lexical block for the function. - KSDbgInfo.LexicalBlocks.pop_back(); - // Validate the generated code, checking for consistency. verifyFunction(*TheFunction); @@ -1305,11 +1077,6 @@ Function *FunctionAST::codegen() { if (P.isBinaryOp()) BinopPrecedence.erase(Proto->getOperatorName()); - - // Pop off the lexical block for the function since we added it - // unconditionally. - KSDbgInfo.LexicalBlocks.pop_back(); - return nullptr; } @@ -1317,16 +1084,17 @@ Function *FunctionAST::codegen() { // Top-Level parsing and JIT Driver //===----------------------------------------------------------------------===// -static void InitializeModule() { +static void InitializeModuleAndPassManager() { // Open a new module. - TheModule = llvm::make_unique("my cool jit", getGlobalContext()); - TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); + TheModule = llvm::make_unique("my cool jit", TheContext); } static void HandleDefinition() { if (auto FnAST = ParseDefinition()) { - if (!FnAST->codegen()) - fprintf(stderr, "Error reading function definition:"); + if (auto *FnIR = FnAST->codegen()) { + fprintf(stderr, "Read function definition:"); + FnIR->dump(); + } } else { // Skip token for error recovery. getNextToken(); @@ -1335,10 +1103,11 @@ static void HandleDefinition() { static void HandleExtern() { if (auto ProtoAST = ParseExtern()) { - if (!ProtoAST->codegen()) - fprintf(stderr, "Error reading extern"); - else + if (auto *FnIR = ProtoAST->codegen()) { + fprintf(stderr, "Read extern: "); + FnIR->dump(); FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); + } } else { // Skip token for error recovery. getNextToken(); @@ -1348,9 +1117,7 @@ static void HandleExtern() { static void HandleTopLevelExpression() { // Evaluate a top-level expression into an anonymous function. if (auto FnAST = ParseTopLevelExpr()) { - if (!FnAST->codegen()) { - fprintf(stderr, "Error generating code for top level expr"); - } + FnAST->codegen(); } else { // Skip token for error recovery. getNextToken(); @@ -1359,7 +1126,7 @@ static void HandleTopLevelExpression() { /// top ::= definition | external | expression | ';' static void MainLoop() { - while (1) { + while (true) { switch (CurTok) { case tok_eof: return; @@ -1400,50 +1167,74 @@ extern "C" double printd(double X) { //===----------------------------------------------------------------------===// int main() { - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetAsmParser(); - // Install standard binary operators. // 1 is lowest precedence. - BinopPrecedence['='] = 2; BinopPrecedence['<'] = 10; BinopPrecedence['+'] = 20; BinopPrecedence['-'] = 20; BinopPrecedence['*'] = 40; // highest. // Prime the first token. + fprintf(stderr, "ready> "); getNextToken(); - TheJIT = llvm::make_unique(); + InitializeModuleAndPassManager(); + + // Run the main "interpreter loop" now. + MainLoop(); - InitializeModule(); + // Initialize the target registry etc. + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmParsers(); + InitializeAllAsmPrinters(); + + auto TargetTriple = sys::getDefaultTargetTriple(); + TheModule->setTargetTriple(TargetTriple); + + std::string Error; + auto Target = TargetRegistry::lookupTarget(TargetTriple, Error); + + // Print an error and exit if we couldn't find the requested target. + // This generally occurs if we've forgotten to initialise the + // TargetRegistry or we have a bogus target triple. + if (!Target) { + errs() << Error; + return 1; + } - // Add the current debug info version into the module. - TheModule->addModuleFlag(Module::Warning, "Debug Info Version", - DEBUG_METADATA_VERSION); + auto CPU = "generic"; + auto Features = ""; - // Darwin only supports dwarf2. - if (Triple(sys::getProcessTriple()).isOSDarwin()) - TheModule->addModuleFlag(llvm::Module::Warning, "Dwarf Version", 2); + TargetOptions opt; + auto RM = Optional(); + auto TheTargetMachine = + Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM); - // Construct the DIBuilder, we do this here because we need the module. - DBuilder = llvm::make_unique(*TheModule); + TheModule->setDataLayout(TheTargetMachine->createDataLayout()); - // Create the compile unit for the module. - // Currently down as "fib.ks" as a filename since we're redirecting stdin - // but we'd like actual source locations. - KSDbgInfo.TheCU = DBuilder->createCompileUnit( - dwarf::DW_LANG_C, "fib.ks", ".", "Kaleidoscope Compiler", 0, "", 0); + auto Filename = "output.o"; + std::error_code EC; + raw_fd_ostream dest(Filename, EC, sys::fs::F_None); - // Run the main "interpreter loop" now. - MainLoop(); + if (EC) { + errs() << "Could not open file: " << EC.message(); + return 1; + } + + legacy::PassManager pass; + auto FileType = TargetMachine::CGFT_ObjectFile; + + if (TheTargetMachine->addPassesToEmitFile(pass, dest, FileType)) { + errs() << "TheTargetMachine can't emit a file of this type"; + return 1; + } - // Finalize the debug info. - DBuilder->finalize(); + pass.run(*TheModule); + dest.flush(); - // Print out all of the generated code. - TheModule->dump(); + outs() << "Wrote " << Filename << "\n"; return 0; } diff --git a/examples/Kaleidoscope/Orc/lazy_irgen/CMakeLists.txt b/examples/Kaleidoscope/Chapter9/CMakeLists.txt similarity index 52% rename from examples/Kaleidoscope/Orc/lazy_irgen/CMakeLists.txt rename to examples/Kaleidoscope/Chapter9/CMakeLists.txt index 44886818e0f0a37fbc4538fca171f91bb7571ee1..a85b2c5e8b318de8c01083422893ec5cefb0382d 100644 --- a/examples/Kaleidoscope/Orc/lazy_irgen/CMakeLists.txt +++ b/examples/Kaleidoscope/Chapter9/CMakeLists.txt @@ -2,11 +2,12 @@ set(LLVM_LINK_COMPONENTS Core ExecutionEngine Object - RuntimeDyld Support native ) -add_kaleidoscope_chapter(Kaleidoscope-Orc-lazy_irgen +add_kaleidoscope_chapter(Kaleidoscope-Ch9 toy.cpp ) + +export_executable_symbols(Kaleidoscope-Ch9) diff --git a/examples/Kaleidoscope/Chapter9/toy.cpp b/examples/Kaleidoscope/Chapter9/toy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a482ccd735256b420b8c5e815b938cf58541c86c --- /dev/null +++ b/examples/Kaleidoscope/Chapter9/toy.cpp @@ -0,0 +1,1445 @@ +#include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Transforms/Scalar.h" +#include +#include +#include +#include +#include +#include "../include/KaleidoscopeJIT.h" + +using namespace llvm; +using namespace llvm::orc; + +//===----------------------------------------------------------------------===// +// Lexer +//===----------------------------------------------------------------------===// + +// The lexer returns tokens [0-255] if it is an unknown character, otherwise one +// of these for known things. +enum Token { + tok_eof = -1, + + // commands + tok_def = -2, + tok_extern = -3, + + // primary + tok_identifier = -4, + tok_number = -5, + + // control + tok_if = -6, + tok_then = -7, + tok_else = -8, + tok_for = -9, + tok_in = -10, + + // operators + tok_binary = -11, + tok_unary = -12, + + // var definition + tok_var = -13 +}; + +std::string getTokName(int Tok) { + switch (Tok) { + case tok_eof: + return "eof"; + case tok_def: + return "def"; + case tok_extern: + return "extern"; + case tok_identifier: + return "identifier"; + case tok_number: + return "number"; + case tok_if: + return "if"; + case tok_then: + return "then"; + case tok_else: + return "else"; + case tok_for: + return "for"; + case tok_in: + return "in"; + case tok_binary: + return "binary"; + case tok_unary: + return "unary"; + case tok_var: + return "var"; + } + return std::string(1, (char)Tok); +} + +namespace { +class PrototypeAST; +class ExprAST; +} +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); +struct DebugInfo { + DICompileUnit *TheCU; + DIType *DblTy; + std::vector LexicalBlocks; + + void emitLocation(ExprAST *AST); + DIType *getDoubleTy(); +} KSDbgInfo; + +struct SourceLocation { + int Line; + int Col; +}; +static SourceLocation CurLoc; +static SourceLocation LexLoc = {1, 0}; + +static int advance() { + int LastChar = getchar(); + + if (LastChar == '\n' || LastChar == '\r') { + LexLoc.Line++; + LexLoc.Col = 0; + } else + LexLoc.Col++; + return LastChar; +} + +static std::string IdentifierStr; // Filled in if tok_identifier +static double NumVal; // Filled in if tok_number + +/// gettok - Return the next token from standard input. +static int gettok() { + static int LastChar = ' '; + + // Skip any whitespace. + while (isspace(LastChar)) + LastChar = advance(); + + CurLoc = LexLoc; + + if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* + IdentifierStr = LastChar; + while (isalnum((LastChar = advance()))) + IdentifierStr += LastChar; + + if (IdentifierStr == "def") + return tok_def; + if (IdentifierStr == "extern") + return tok_extern; + if (IdentifierStr == "if") + return tok_if; + if (IdentifierStr == "then") + return tok_then; + if (IdentifierStr == "else") + return tok_else; + if (IdentifierStr == "for") + return tok_for; + if (IdentifierStr == "in") + return tok_in; + if (IdentifierStr == "binary") + return tok_binary; + if (IdentifierStr == "unary") + return tok_unary; + if (IdentifierStr == "var") + return tok_var; + return tok_identifier; + } + + if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ + std::string NumStr; + do { + NumStr += LastChar; + LastChar = advance(); + } while (isdigit(LastChar) || LastChar == '.'); + + NumVal = strtod(NumStr.c_str(), nullptr); + return tok_number; + } + + if (LastChar == '#') { + // Comment until end of line. + do + LastChar = advance(); + while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); + + if (LastChar != EOF) + return gettok(); + } + + // Check for end of file. Don't eat the EOF. + if (LastChar == EOF) + return tok_eof; + + // Otherwise, just return the character as its ascii value. + int ThisChar = LastChar; + LastChar = advance(); + return ThisChar; +} + +//===----------------------------------------------------------------------===// +// Abstract Syntax Tree (aka Parse Tree) +//===----------------------------------------------------------------------===// +namespace { + +raw_ostream &indent(raw_ostream &O, int size) { + return O << std::string(size, ' '); +} + +/// ExprAST - Base class for all expression nodes. +class ExprAST { + SourceLocation Loc; + +public: + ExprAST(SourceLocation Loc = CurLoc) : Loc(Loc) {} + virtual ~ExprAST() {} + virtual Value *codegen() = 0; + int getLine() const { return Loc.Line; } + int getCol() const { return Loc.Col; } + virtual raw_ostream &dump(raw_ostream &out, int ind) { + return out << ':' << getLine() << ':' << getCol() << '\n'; + } +}; + +/// NumberExprAST - Expression class for numeric literals like "1.0". +class NumberExprAST : public ExprAST { + double Val; + +public: + NumberExprAST(double Val) : Val(Val) {} + raw_ostream &dump(raw_ostream &out, int ind) override { + return ExprAST::dump(out << Val, ind); + } + Value *codegen() override; +}; + +/// VariableExprAST - Expression class for referencing a variable, like "a". +class VariableExprAST : public ExprAST { + std::string Name; + +public: + VariableExprAST(SourceLocation Loc, const std::string &Name) + : ExprAST(Loc), Name(Name) {} + const std::string &getName() const { return Name; } + Value *codegen() override; + raw_ostream &dump(raw_ostream &out, int ind) override { + return ExprAST::dump(out << Name, ind); + } +}; + +/// UnaryExprAST - Expression class for a unary operator. +class UnaryExprAST : public ExprAST { + char Opcode; + std::unique_ptr Operand; + +public: + UnaryExprAST(char Opcode, std::unique_ptr Operand) + : Opcode(Opcode), Operand(std::move(Operand)) {} + Value *codegen() override; + raw_ostream &dump(raw_ostream &out, int ind) override { + ExprAST::dump(out << "unary" << Opcode, ind); + Operand->dump(out, ind + 1); + return out; + } +}; + +/// BinaryExprAST - Expression class for a binary operator. +class BinaryExprAST : public ExprAST { + char Op; + std::unique_ptr LHS, RHS; + +public: + BinaryExprAST(SourceLocation Loc, char Op, std::unique_ptr LHS, + std::unique_ptr RHS) + : ExprAST(Loc), Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} + Value *codegen() override; + raw_ostream &dump(raw_ostream &out, int ind) override { + ExprAST::dump(out << "binary" << Op, ind); + LHS->dump(indent(out, ind) << "LHS:", ind + 1); + RHS->dump(indent(out, ind) << "RHS:", ind + 1); + return out; + } +}; + +/// CallExprAST - Expression class for function calls. +class CallExprAST : public ExprAST { + std::string Callee; + std::vector> Args; + +public: + CallExprAST(SourceLocation Loc, const std::string &Callee, + std::vector> Args) + : ExprAST(Loc), Callee(Callee), Args(std::move(Args)) {} + Value *codegen() override; + raw_ostream &dump(raw_ostream &out, int ind) override { + ExprAST::dump(out << "call " << Callee, ind); + for (const auto &Arg : Args) + Arg->dump(indent(out, ind + 1), ind + 1); + return out; + } +}; + +/// IfExprAST - Expression class for if/then/else. +class IfExprAST : public ExprAST { + std::unique_ptr Cond, Then, Else; + +public: + IfExprAST(SourceLocation Loc, std::unique_ptr Cond, + std::unique_ptr Then, std::unique_ptr Else) + : ExprAST(Loc), Cond(std::move(Cond)), Then(std::move(Then)), + Else(std::move(Else)) {} + Value *codegen() override; + raw_ostream &dump(raw_ostream &out, int ind) override { + ExprAST::dump(out << "if", ind); + Cond->dump(indent(out, ind) << "Cond:", ind + 1); + Then->dump(indent(out, ind) << "Then:", ind + 1); + Else->dump(indent(out, ind) << "Else:", ind + 1); + return out; + } +}; + +/// ForExprAST - Expression class for for/in. +class ForExprAST : public ExprAST { + std::string VarName; + std::unique_ptr Start, End, Step, Body; + +public: + ForExprAST(const std::string &VarName, std::unique_ptr Start, + std::unique_ptr End, std::unique_ptr Step, + std::unique_ptr Body) + : VarName(VarName), Start(std::move(Start)), End(std::move(End)), + Step(std::move(Step)), Body(std::move(Body)) {} + Value *codegen() override; + raw_ostream &dump(raw_ostream &out, int ind) override { + ExprAST::dump(out << "for", ind); + Start->dump(indent(out, ind) << "Cond:", ind + 1); + End->dump(indent(out, ind) << "End:", ind + 1); + Step->dump(indent(out, ind) << "Step:", ind + 1); + Body->dump(indent(out, ind) << "Body:", ind + 1); + return out; + } +}; + +/// VarExprAST - Expression class for var/in +class VarExprAST : public ExprAST { + std::vector>> VarNames; + std::unique_ptr Body; + +public: + VarExprAST( + std::vector>> VarNames, + std::unique_ptr Body) + : VarNames(std::move(VarNames)), Body(std::move(Body)) {} + Value *codegen() override; + raw_ostream &dump(raw_ostream &out, int ind) override { + ExprAST::dump(out << "var", ind); + for (const auto &NamedVar : VarNames) + NamedVar.second->dump(indent(out, ind) << NamedVar.first << ':', ind + 1); + Body->dump(indent(out, ind) << "Body:", ind + 1); + return out; + } +}; + +/// PrototypeAST - This class represents the "prototype" for a function, +/// which captures its name, and its argument names (thus implicitly the number +/// of arguments the function takes), as well as if it is an operator. +class PrototypeAST { + std::string Name; + std::vector Args; + bool IsOperator; + unsigned Precedence; // Precedence if a binary op. + int Line; + +public: + PrototypeAST(SourceLocation Loc, const std::string &Name, + std::vector Args, bool IsOperator = false, + unsigned Prec = 0) + : Name(Name), Args(std::move(Args)), IsOperator(IsOperator), + Precedence(Prec), Line(Loc.Line) {} + Function *codegen(); + const std::string &getName() const { return Name; } + + bool isUnaryOp() const { return IsOperator && Args.size() == 1; } + bool isBinaryOp() const { return IsOperator && Args.size() == 2; } + + char getOperatorName() const { + assert(isUnaryOp() || isBinaryOp()); + return Name[Name.size() - 1]; + } + + unsigned getBinaryPrecedence() const { return Precedence; } + int getLine() const { return Line; } +}; + +/// FunctionAST - This class represents a function definition itself. +class FunctionAST { + std::unique_ptr Proto; + std::unique_ptr Body; + +public: + FunctionAST(std::unique_ptr Proto, + std::unique_ptr Body) + : Proto(std::move(Proto)), Body(std::move(Body)) {} + Function *codegen(); + raw_ostream &dump(raw_ostream &out, int ind) { + indent(out, ind) << "FunctionAST\n"; + ++ind; + indent(out, ind) << "Body:"; + return Body ? Body->dump(out, ind) : out << "null\n"; + } +}; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Parser +//===----------------------------------------------------------------------===// + +/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current +/// token the parser is looking at. getNextToken reads another token from the +/// lexer and updates CurTok with its results. +static int CurTok; +static int getNextToken() { return CurTok = gettok(); } + +/// BinopPrecedence - This holds the precedence for each binary operator that is +/// defined. +static std::map BinopPrecedence; + +/// GetTokPrecedence - Get the precedence of the pending binary operator token. +static int GetTokPrecedence() { + if (!isascii(CurTok)) + return -1; + + // Make sure it's a declared binop. + int TokPrec = BinopPrecedence[CurTok]; + if (TokPrec <= 0) + return -1; + return TokPrec; +} + +/// LogError* - These are little helper functions for error handling. +std::unique_ptr LogError(const char *Str) { + fprintf(stderr, "Error: %s\n", Str); + return nullptr; +} + +std::unique_ptr LogErrorP(const char *Str) { + LogError(Str); + return nullptr; +} + +static std::unique_ptr ParseExpression(); + +/// numberexpr ::= number +static std::unique_ptr ParseNumberExpr() { + auto Result = llvm::make_unique(NumVal); + getNextToken(); // consume the number + return std::move(Result); +} + +/// parenexpr ::= '(' expression ')' +static std::unique_ptr ParseParenExpr() { + getNextToken(); // eat (. + auto V = ParseExpression(); + if (!V) + return nullptr; + + if (CurTok != ')') + return LogError("expected ')'"); + getNextToken(); // eat ). + return V; +} + +/// identifierexpr +/// ::= identifier +/// ::= identifier '(' expression* ')' +static std::unique_ptr ParseIdentifierExpr() { + std::string IdName = IdentifierStr; + + SourceLocation LitLoc = CurLoc; + + getNextToken(); // eat identifier. + + if (CurTok != '(') // Simple variable ref. + return llvm::make_unique(LitLoc, IdName); + + // Call. + getNextToken(); // eat ( + std::vector> Args; + if (CurTok != ')') { + while (1) { + if (auto Arg = ParseExpression()) + Args.push_back(std::move(Arg)); + else + return nullptr; + + if (CurTok == ')') + break; + + if (CurTok != ',') + return LogError("Expected ')' or ',' in argument list"); + getNextToken(); + } + } + + // Eat the ')'. + getNextToken(); + + return llvm::make_unique(LitLoc, IdName, std::move(Args)); +} + +/// ifexpr ::= 'if' expression 'then' expression 'else' expression +static std::unique_ptr ParseIfExpr() { + SourceLocation IfLoc = CurLoc; + + getNextToken(); // eat the if. + + // condition. + auto Cond = ParseExpression(); + if (!Cond) + return nullptr; + + if (CurTok != tok_then) + return LogError("expected then"); + getNextToken(); // eat the then + + auto Then = ParseExpression(); + if (!Then) + return nullptr; + + if (CurTok != tok_else) + return LogError("expected else"); + + getNextToken(); + + auto Else = ParseExpression(); + if (!Else) + return nullptr; + + return llvm::make_unique(IfLoc, std::move(Cond), std::move(Then), + std::move(Else)); +} + +/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression +static std::unique_ptr ParseForExpr() { + getNextToken(); // eat the for. + + if (CurTok != tok_identifier) + return LogError("expected identifier after for"); + + std::string IdName = IdentifierStr; + getNextToken(); // eat identifier. + + if (CurTok != '=') + return LogError("expected '=' after for"); + getNextToken(); // eat '='. + + auto Start = ParseExpression(); + if (!Start) + return nullptr; + if (CurTok != ',') + return LogError("expected ',' after for start value"); + getNextToken(); + + auto End = ParseExpression(); + if (!End) + return nullptr; + + // The step value is optional. + std::unique_ptr Step; + if (CurTok == ',') { + getNextToken(); + Step = ParseExpression(); + if (!Step) + return nullptr; + } + + if (CurTok != tok_in) + return LogError("expected 'in' after for"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(IdName, std::move(Start), std::move(End), + std::move(Step), std::move(Body)); +} + +/// varexpr ::= 'var' identifier ('=' expression)? +// (',' identifier ('=' expression)?)* 'in' expression +static std::unique_ptr ParseVarExpr() { + getNextToken(); // eat the var. + + std::vector>> VarNames; + + // At least one variable name is required. + if (CurTok != tok_identifier) + return LogError("expected identifier after var"); + + while (1) { + std::string Name = IdentifierStr; + getNextToken(); // eat identifier. + + // Read the optional initializer. + std::unique_ptr Init = nullptr; + if (CurTok == '=') { + getNextToken(); // eat the '='. + + Init = ParseExpression(); + if (!Init) + return nullptr; + } + + VarNames.push_back(std::make_pair(Name, std::move(Init))); + + // End of var list, exit loop. + if (CurTok != ',') + break; + getNextToken(); // eat the ','. + + if (CurTok != tok_identifier) + return LogError("expected identifier list after var"); + } + + // At this point, we have to have 'in'. + if (CurTok != tok_in) + return LogError("expected 'in' keyword after 'var'"); + getNextToken(); // eat 'in'. + + auto Body = ParseExpression(); + if (!Body) + return nullptr; + + return llvm::make_unique(std::move(VarNames), std::move(Body)); +} + +/// primary +/// ::= identifierexpr +/// ::= numberexpr +/// ::= parenexpr +/// ::= ifexpr +/// ::= forexpr +/// ::= varexpr +static std::unique_ptr ParsePrimary() { + switch (CurTok) { + default: + return LogError("unknown token when expecting an expression"); + case tok_identifier: + return ParseIdentifierExpr(); + case tok_number: + return ParseNumberExpr(); + case '(': + return ParseParenExpr(); + case tok_if: + return ParseIfExpr(); + case tok_for: + return ParseForExpr(); + case tok_var: + return ParseVarExpr(); + } +} + +/// unary +/// ::= primary +/// ::= '!' unary +static std::unique_ptr ParseUnary() { + // If the current token is not an operator, it must be a primary expr. + if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') + return ParsePrimary(); + + // If this is a unary operator, read it. + int Opc = CurTok; + getNextToken(); + if (auto Operand = ParseUnary()) + return llvm::make_unique(Opc, std::move(Operand)); + return nullptr; +} + +/// binoprhs +/// ::= ('+' unary)* +static std::unique_ptr ParseBinOpRHS(int ExprPrec, + std::unique_ptr LHS) { + // If this is a binop, find its precedence. + while (1) { + int TokPrec = GetTokPrecedence(); + + // If this is a binop that binds at least as tightly as the current binop, + // consume it, otherwise we are done. + if (TokPrec < ExprPrec) + return LHS; + + // Okay, we know this is a binop. + int BinOp = CurTok; + SourceLocation BinLoc = CurLoc; + getNextToken(); // eat binop + + // Parse the unary expression after the binary operator. + auto RHS = ParseUnary(); + if (!RHS) + return nullptr; + + // If BinOp binds less tightly with RHS than the operator after RHS, let + // the pending operator take RHS as its LHS. + int NextPrec = GetTokPrecedence(); + if (TokPrec < NextPrec) { + RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); + if (!RHS) + return nullptr; + } + + // Merge LHS/RHS. + LHS = llvm::make_unique(BinLoc, BinOp, std::move(LHS), + std::move(RHS)); + } +} + +/// expression +/// ::= unary binoprhs +/// +static std::unique_ptr ParseExpression() { + auto LHS = ParseUnary(); + if (!LHS) + return nullptr; + + return ParseBinOpRHS(0, std::move(LHS)); +} + +/// prototype +/// ::= id '(' id* ')' +/// ::= binary LETTER number? (id, id) +/// ::= unary LETTER (id) +static std::unique_ptr ParsePrototype() { + std::string FnName; + + SourceLocation FnLoc = CurLoc; + + unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. + unsigned BinaryPrecedence = 30; + + switch (CurTok) { + default: + return LogErrorP("Expected function name in prototype"); + case tok_identifier: + FnName = IdentifierStr; + Kind = 0; + getNextToken(); + break; + case tok_unary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected unary operator"); + FnName = "unary"; + FnName += (char)CurTok; + Kind = 1; + getNextToken(); + break; + case tok_binary: + getNextToken(); + if (!isascii(CurTok)) + return LogErrorP("Expected binary operator"); + FnName = "binary"; + FnName += (char)CurTok; + Kind = 2; + getNextToken(); + + // Read the precedence if present. + if (CurTok == tok_number) { + if (NumVal < 1 || NumVal > 100) + return LogErrorP("Invalid precedecnce: must be 1..100"); + BinaryPrecedence = (unsigned)NumVal; + getNextToken(); + } + break; + } + + if (CurTok != '(') + return LogErrorP("Expected '(' in prototype"); + + std::vector ArgNames; + while (getNextToken() == tok_identifier) + ArgNames.push_back(IdentifierStr); + if (CurTok != ')') + return LogErrorP("Expected ')' in prototype"); + + // success. + getNextToken(); // eat ')'. + + // Verify right number of names for operator. + if (Kind && ArgNames.size() != Kind) + return LogErrorP("Invalid number of operands for operator"); + + return llvm::make_unique(FnLoc, FnName, ArgNames, Kind != 0, + BinaryPrecedence); +} + +/// definition ::= 'def' prototype expression +static std::unique_ptr ParseDefinition() { + getNextToken(); // eat def. + auto Proto = ParsePrototype(); + if (!Proto) + return nullptr; + + if (auto E = ParseExpression()) + return llvm::make_unique(std::move(Proto), std::move(E)); + return nullptr; +} + +/// toplevelexpr ::= expression +static std::unique_ptr ParseTopLevelExpr() { + SourceLocation FnLoc = CurLoc; + if (auto E = ParseExpression()) { + // Make an anonymous proto. + auto Proto = llvm::make_unique(FnLoc, "__anon_expr", + std::vector()); + return llvm::make_unique(std::move(Proto), std::move(E)); + } + return nullptr; +} + +/// external ::= 'extern' prototype +static std::unique_ptr ParseExtern() { + getNextToken(); // eat extern. + return ParsePrototype(); +} + +//===----------------------------------------------------------------------===// +// Debug Info Support +//===----------------------------------------------------------------------===// + +static std::unique_ptr DBuilder; + +DIType *DebugInfo::getDoubleTy() { + if (DblTy) + return DblTy; + + DblTy = DBuilder->createBasicType("double", 64, 64, dwarf::DW_ATE_float); + return DblTy; +} + +void DebugInfo::emitLocation(ExprAST *AST) { + if (!AST) + return Builder.SetCurrentDebugLocation(DebugLoc()); + DIScope *Scope; + if (LexicalBlocks.empty()) + Scope = TheCU; + else + Scope = LexicalBlocks.back(); + Builder.SetCurrentDebugLocation( + DebugLoc::get(AST->getLine(), AST->getCol(), Scope)); +} + +static DISubroutineType *CreateFunctionType(unsigned NumArgs, DIFile *Unit) { + SmallVector EltTys; + DIType *DblTy = KSDbgInfo.getDoubleTy(); + + // Add the result type. + EltTys.push_back(DblTy); + + for (unsigned i = 0, e = NumArgs; i != e; ++i) + EltTys.push_back(DblTy); + + return DBuilder->createSubroutineType(DBuilder->getOrCreateTypeArray(EltTys)); +} + +//===----------------------------------------------------------------------===// +// Code Generation +//===----------------------------------------------------------------------===// + +static std::unique_ptr TheModule; +static std::map NamedValues; +static std::unique_ptr TheJIT; +static std::map> FunctionProtos; + +Value *LogErrorV(const char *Str) { + LogError(Str); + return nullptr; +} + +Function *getFunction(std::string Name) { + // First, see if the function has already been added to the current module. + if (auto *F = TheModule->getFunction(Name)) + return F; + + // If not, check whether we can codegen the declaration from some existing + // prototype. + auto FI = FunctionProtos.find(Name); + if (FI != FunctionProtos.end()) + return FI->second->codegen(); + + // If no existing prototype exists, return null. + return nullptr; +} + +/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of +/// the function. This is used for mutable variables etc. +static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, + const std::string &VarName) { + IRBuilder<> TmpB(&TheFunction->getEntryBlock(), + TheFunction->getEntryBlock().begin()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), nullptr, + VarName.c_str()); +} + +Value *NumberExprAST::codegen() { + KSDbgInfo.emitLocation(this); + return ConstantFP::get(TheContext, APFloat(Val)); +} + +Value *VariableExprAST::codegen() { + // Look this variable up in the function. + Value *V = NamedValues[Name]; + if (!V) + return LogErrorV("Unknown variable name"); + + KSDbgInfo.emitLocation(this); + // Load the value. + return Builder.CreateLoad(V, Name.c_str()); +} + +Value *UnaryExprAST::codegen() { + Value *OperandV = Operand->codegen(); + if (!OperandV) + return nullptr; + + Function *F = getFunction(std::string("unary") + Opcode); + if (!F) + return LogErrorV("Unknown unary operator"); + + KSDbgInfo.emitLocation(this); + return Builder.CreateCall(F, OperandV, "unop"); +} + +Value *BinaryExprAST::codegen() { + KSDbgInfo.emitLocation(this); + + // Special case '=' because we don't want to emit the LHS as an expression. + if (Op == '=') { + // Assignment requires the LHS to be an identifier. + // This assume we're building without RTTI because LLVM builds that way by + // default. If you build LLVM with RTTI this can be changed to a + // dynamic_cast for automatic error checking. + VariableExprAST *LHSE = static_cast(LHS.get()); + if (!LHSE) + return LogErrorV("destination of '=' must be a variable"); + // Codegen the RHS. + Value *Val = RHS->codegen(); + if (!Val) + return nullptr; + + // Look up the name. + Value *Variable = NamedValues[LHSE->getName()]; + if (!Variable) + return LogErrorV("Unknown variable name"); + + Builder.CreateStore(Val, Variable); + return Val; + } + + Value *L = LHS->codegen(); + Value *R = RHS->codegen(); + if (!L || !R) + return nullptr; + + switch (Op) { + case '+': + return Builder.CreateFAdd(L, R, "addtmp"); + case '-': + return Builder.CreateFSub(L, R, "subtmp"); + case '*': + return Builder.CreateFMul(L, R, "multmp"); + case '<': + L = Builder.CreateFCmpULT(L, R, "cmptmp"); + // Convert bool 0/1 to double 0.0 or 1.0 + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + default: + break; + } + + // If it wasn't a builtin binary operator, it must be a user defined one. Emit + // a call to it. + Function *F = getFunction(std::string("binary") + Op); + assert(F && "binary operator not found!"); + + Value *Ops[] = {L, R}; + return Builder.CreateCall(F, Ops, "binop"); +} + +Value *CallExprAST::codegen() { + KSDbgInfo.emitLocation(this); + + // Look up the name in the global module table. + Function *CalleeF = getFunction(Callee); + if (!CalleeF) + return LogErrorV("Unknown function referenced"); + + // If argument mismatch error. + if (CalleeF->arg_size() != Args.size()) + return LogErrorV("Incorrect # arguments passed"); + + std::vector ArgsV; + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + ArgsV.push_back(Args[i]->codegen()); + if (!ArgsV.back()) + return nullptr; + } + + return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); +} + +Value *IfExprAST::codegen() { + KSDbgInfo.emitLocation(this); + + Value *CondV = Cond->codegen(); + if (!CondV) + return nullptr; + + // Convert condition to a bool by comparing equal to 0.0. + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create blocks for the then and else cases. Insert the 'then' block at the + // end of the function. + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + + Builder.CreateCondBr(CondV, ThenBB, ElseBB); + + // Emit then value. + Builder.SetInsertPoint(ThenBB); + + Value *ThenV = Then->codegen(); + if (!ThenV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Then' can change the current block, update ThenBB for the PHI. + ThenBB = Builder.GetInsertBlock(); + + // Emit else block. + TheFunction->getBasicBlockList().push_back(ElseBB); + Builder.SetInsertPoint(ElseBB); + + Value *ElseV = Else->codegen(); + if (!ElseV) + return nullptr; + + Builder.CreateBr(MergeBB); + // Codegen of 'Else' can change the current block, update ElseBB for the PHI. + ElseBB = Builder.GetInsertBlock(); + + // Emit merge block. + TheFunction->getBasicBlockList().push_back(MergeBB); + Builder.SetInsertPoint(MergeBB); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + + PN->addIncoming(ThenV, ThenBB); + PN->addIncoming(ElseV, ElseBB); + return PN; +} + +// Output for-loop as: +// var = alloca double +// ... +// start = startexpr +// store start -> var +// goto loop +// loop: +// ... +// bodyexpr +// ... +// loopend: +// step = stepexpr +// endcond = endexpr +// +// curvar = load var +// nextvar = curvar + step +// store nextvar -> var +// br endcond, loop, endloop +// outloop: +Value *ForExprAST::codegen() { + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Create an alloca for the variable in the entry block. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + + KSDbgInfo.emitLocation(this); + + // Emit the start code first, without 'variable' in scope. + Value *StartVal = Start->codegen(); + if (!StartVal) + return nullptr; + + // Store the value into the alloca. + Builder.CreateStore(StartVal, Alloca); + + // Make the new basic block for the loop header, inserting after current + // block. + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + + // Insert an explicit fall through from the current block to the LoopBB. + Builder.CreateBr(LoopBB); + + // Start insertion in LoopBB. + Builder.SetInsertPoint(LoopBB); + + // Within the loop, the variable is defined equal to the PHI node. If it + // shadows an existing variable, we have to restore it, so save it now. + AllocaInst *OldVal = NamedValues[VarName]; + NamedValues[VarName] = Alloca; + + // Emit the body of the loop. This, like any other expr, can change the + // current BB. Note that we ignore the value computed by the body, but don't + // allow an error. + if (!Body->codegen()) + return nullptr; + + // Emit the step value. + Value *StepVal = nullptr; + if (Step) { + StepVal = Step->codegen(); + if (!StepVal) + return nullptr; + } else { + // If not specified, use 1.0. + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); + } + + // Compute the end condition. + Value *EndCond = End->codegen(); + if (!EndCond) + return nullptr; + + // Reload, increment, and restore the alloca. This handles the case where + // the body of the loop mutates the variable. + Value *CurVar = Builder.CreateLoad(Alloca, VarName.c_str()); + Value *NextVar = Builder.CreateFAdd(CurVar, StepVal, "nextvar"); + Builder.CreateStore(NextVar, Alloca); + + // Convert condition to a bool by comparing equal to 0.0. + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + + // Create the "after loop" block and insert it. + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); + + // Insert the conditional branch into the end of LoopEndBB. + Builder.CreateCondBr(EndCond, LoopBB, AfterBB); + + // Any new code will be inserted in AfterBB. + Builder.SetInsertPoint(AfterBB); + + // Restore the unshadowed variable. + if (OldVal) + NamedValues[VarName] = OldVal; + else + NamedValues.erase(VarName); + + // for expr always returns 0.0. + return Constant::getNullValue(Type::getDoubleTy(TheContext)); +} + +Value *VarExprAST::codegen() { + std::vector OldBindings; + + Function *TheFunction = Builder.GetInsertBlock()->getParent(); + + // Register all variables and emit their initializer. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) { + const std::string &VarName = VarNames[i].first; + ExprAST *Init = VarNames[i].second.get(); + + // Emit the initializer before adding the variable to scope, this prevents + // the initializer from referencing the variable itself, and permits stuff + // like this: + // var a = 1 in + // var a = a in ... # refers to outer 'a'. + Value *InitVal; + if (Init) { + InitVal = Init->codegen(); + if (!InitVal) + return nullptr; + } else { // If not specified, use 0.0. + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); + } + + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); + Builder.CreateStore(InitVal, Alloca); + + // Remember the old variable binding so that we can restore the binding when + // we unrecurse. + OldBindings.push_back(NamedValues[VarName]); + + // Remember this binding. + NamedValues[VarName] = Alloca; + } + + KSDbgInfo.emitLocation(this); + + // Codegen the body, now that all vars are in scope. + Value *BodyVal = Body->codegen(); + if (!BodyVal) + return nullptr; + + // Pop all our variables from scope. + for (unsigned i = 0, e = VarNames.size(); i != e; ++i) + NamedValues[VarNames[i].first] = OldBindings[i]; + + // Return the body computation. + return BodyVal; +} + +Function *PrototypeAST::codegen() { + // Make the function type: double(double,double) etc. + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + + Function *F = + Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); + + // Set names for all arguments. + unsigned Idx = 0; + for (auto &Arg : F->args()) + Arg.setName(Args[Idx++]); + + return F; +} + +Function *FunctionAST::codegen() { + // Transfer ownership of the prototype to the FunctionProtos map, but keep a + // reference to it for use below. + auto &P = *Proto; + FunctionProtos[Proto->getName()] = std::move(Proto); + Function *TheFunction = getFunction(P.getName()); + if (!TheFunction) + return nullptr; + + // If this is an operator, install it. + if (P.isBinaryOp()) + BinopPrecedence[P.getOperatorName()] = P.getBinaryPrecedence(); + + // Create a new basic block to start insertion into. + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); + Builder.SetInsertPoint(BB); + + // Create a subprogram DIE for this function. + DIFile *Unit = DBuilder->createFile(KSDbgInfo.TheCU->getFilename(), + KSDbgInfo.TheCU->getDirectory()); + DIScope *FContext = Unit; + unsigned LineNo = P.getLine(); + unsigned ScopeLine = LineNo; + DISubprogram *SP = DBuilder->createFunction( + FContext, P.getName(), StringRef(), Unit, LineNo, + CreateFunctionType(TheFunction->arg_size(), Unit), + false /* internal linkage */, true /* definition */, ScopeLine, + DINode::FlagPrototyped, false); + TheFunction->setSubprogram(SP); + + // Push the current scope. + KSDbgInfo.LexicalBlocks.push_back(SP); + + // Unset the location for the prologue emission (leading instructions with no + // location in a function are considered part of the prologue and the debugger + // will run past them when breaking on a function) + KSDbgInfo.emitLocation(nullptr); + + // Record the function arguments in the NamedValues map. + NamedValues.clear(); + unsigned ArgIdx = 0; + for (auto &Arg : TheFunction->args()) { + // Create an alloca for this variable. + AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Arg.getName()); + + // Create a debug descriptor for the variable. + DILocalVariable *D = DBuilder->createParameterVariable( + SP, Arg.getName(), ++ArgIdx, Unit, LineNo, KSDbgInfo.getDoubleTy(), + true); + + DBuilder->insertDeclare(Alloca, D, DBuilder->createExpression(), + DebugLoc::get(LineNo, 0, SP), + Builder.GetInsertBlock()); + + // Store the initial value into the alloca. + Builder.CreateStore(&Arg, Alloca); + + // Add arguments to variable symbol table. + NamedValues[Arg.getName()] = Alloca; + } + + KSDbgInfo.emitLocation(Body.get()); + + if (Value *RetVal = Body->codegen()) { + // Finish off the function. + Builder.CreateRet(RetVal); + + // Pop off the lexical block for the function. + KSDbgInfo.LexicalBlocks.pop_back(); + + // Validate the generated code, checking for consistency. + verifyFunction(*TheFunction); + + return TheFunction; + } + + // Error reading body, remove function. + TheFunction->eraseFromParent(); + + if (P.isBinaryOp()) + BinopPrecedence.erase(Proto->getOperatorName()); + + // Pop off the lexical block for the function since we added it + // unconditionally. + KSDbgInfo.LexicalBlocks.pop_back(); + + return nullptr; +} + +//===----------------------------------------------------------------------===// +// Top-Level parsing and JIT Driver +//===----------------------------------------------------------------------===// + +static void InitializeModule() { + // Open a new module. + TheModule = llvm::make_unique("my cool jit", TheContext); + TheModule->setDataLayout(TheJIT->getTargetMachine().createDataLayout()); +} + +static void HandleDefinition() { + if (auto FnAST = ParseDefinition()) { + if (!FnAST->codegen()) + fprintf(stderr, "Error reading function definition:"); + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleExtern() { + if (auto ProtoAST = ParseExtern()) { + if (!ProtoAST->codegen()) + fprintf(stderr, "Error reading extern"); + else + FunctionProtos[ProtoAST->getName()] = std::move(ProtoAST); + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleTopLevelExpression() { + // Evaluate a top-level expression into an anonymous function. + if (auto FnAST = ParseTopLevelExpr()) { + if (!FnAST->codegen()) { + fprintf(stderr, "Error generating code for top level expr"); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +/// top ::= definition | external | expression | ';' +static void MainLoop() { + while (1) { + switch (CurTok) { + case tok_eof: + return; + case ';': // ignore top-level semicolons. + getNextToken(); + break; + case tok_def: + HandleDefinition(); + break; + case tok_extern: + HandleExtern(); + break; + default: + HandleTopLevelExpression(); + break; + } + } +} + +//===----------------------------------------------------------------------===// +// "Library" functions that can be "extern'd" from user code. +//===----------------------------------------------------------------------===// + +/// putchard - putchar that takes a double and returns 0. +extern "C" double putchard(double X) { + fputc((char)X, stderr); + return 0; +} + +/// printd - printf that takes a double prints it as "%f\n", returning 0. +extern "C" double printd(double X) { + fprintf(stderr, "%f\n", X); + return 0; +} + +//===----------------------------------------------------------------------===// +// Main driver code. +//===----------------------------------------------------------------------===// + +int main() { + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetAsmParser(); + + // Install standard binary operators. + // 1 is lowest precedence. + BinopPrecedence['='] = 2; + BinopPrecedence['<'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; // highest. + + // Prime the first token. + getNextToken(); + + TheJIT = llvm::make_unique(); + + InitializeModule(); + + // Add the current debug info version into the module. + TheModule->addModuleFlag(Module::Warning, "Debug Info Version", + DEBUG_METADATA_VERSION); + + // Darwin only supports dwarf2. + if (Triple(sys::getProcessTriple()).isOSDarwin()) + TheModule->addModuleFlag(llvm::Module::Warning, "Dwarf Version", 2); + + // Construct the DIBuilder, we do this here because we need the module. + DBuilder = llvm::make_unique(*TheModule); + + // Create the compile unit for the module. + // Currently down as "fib.ks" as a filename since we're redirecting stdin + // but we'd like actual source locations. + KSDbgInfo.TheCU = DBuilder->createCompileUnit( + dwarf::DW_LANG_C, "fib.ks", ".", "Kaleidoscope Compiler", 0, "", 0); + + // Run the main "interpreter loop" now. + MainLoop(); + + // Finalize the debug info. + DBuilder->finalize(); + + // Print out all of the generated code. + TheModule->dump(); + + return 0; +} diff --git a/examples/Kaleidoscope/MCJIT/cached/toy-jit.cpp b/examples/Kaleidoscope/MCJIT/cached/toy-jit.cpp index 77b7f001095af3088ffb085211deb0f3b4722828..3f3b133703b1934e3a54faf125047d84425800e8 100644 --- a/examples/Kaleidoscope/MCJIT/cached/toy-jit.cpp +++ b/examples/Kaleidoscope/MCJIT/cached/toy-jit.cpp @@ -623,7 +623,8 @@ static PrototypeAST *ParseExtern() { static Module *TheModule; static FunctionPassManager *TheFPM; -static IRBuilder<> Builder(getGlobalContext()); +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::map NamedValues; Value *ErrorV(const char *Str) { Error(Str); return 0; } @@ -634,12 +635,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), 0, - VarName.c_str()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), 0, VarName.c_str()); } Value *NumberExprAST::Codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::Codegen() { @@ -699,8 +699,7 @@ Value *BinaryExprAST::Codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: break; } @@ -740,18 +739,17 @@ Value *IfExprAST::Codegen() { if (CondV == 0) return 0; // Convert condition to a bool by comparing equal to 0.0. - CondV = Builder.CreateFCmpONE(CondV, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "ifcond"); - + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); - + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + Builder.CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. @@ -778,9 +776,8 @@ Value *IfExprAST::Codegen() { // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, - "iftmp"); - + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); return PN; @@ -821,8 +818,8 @@ Value *ForExprAST::Codegen() { // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); - + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -847,7 +844,7 @@ Value *ForExprAST::Codegen() { if (StepVal == 0) return 0; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } // Compute the end condition. @@ -861,13 +858,13 @@ Value *ForExprAST::Codegen() { Builder.CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing equal to 0.0. - EndCond = Builder.CreateFCmpONE(EndCond, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "loopcond"); - + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + // Create the "after loop" block and insert it. - BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); - + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); + // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -882,7 +879,7 @@ Value *ForExprAST::Codegen() { // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } Value *VarExprAST::Codegen() { @@ -905,7 +902,7 @@ Value *VarExprAST::Codegen() { InitVal = Init->Codegen(); if (InitVal == 0) return 0; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -933,10 +930,9 @@ Value *VarExprAST::Codegen() { Function *PrototypeAST::Codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); - FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), - Doubles, false); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule); // If F conflicted, there was already something named 'Name'. If it has a @@ -994,7 +990,7 @@ Function *FunctionAST::Codegen() { BinopPrecedence[Proto->getOperatorName()] = Proto->getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Add all arguments to the symbol table and create their allocas. @@ -1122,7 +1118,7 @@ double printlf() { Module* parseInputIR(std::string InputFile) { SMDiagnostic Err; - Module *M = ParseIRFile(InputFile, Err, getGlobalContext()); + Module *M = ParseIRFile(InputFile, Err, TheContext); if (!M) { Err.print("IR parsing failed: ", errs()); return NULL; @@ -1137,7 +1133,7 @@ Module* parseInputIR(std::string InputFile) { int main(int argc, char **argv) { InitializeNativeTarget(); - LLVMContext &Context = getGlobalContext(); + LLVMContext &Context = TheContext; cl::ParseCommandLineOptions(argc, argv, "Kaleidoscope example program\n"); diff --git a/examples/Kaleidoscope/MCJIT/cached/toy.cpp b/examples/Kaleidoscope/MCJIT/cached/toy.cpp index cc12abcc43169e503b5bfc39b14223e475aa3196..2b9c3da92188145cceec5b5a52a61d5522e18650 100644 --- a/examples/Kaleidoscope/MCJIT/cached/toy.cpp +++ b/examples/Kaleidoscope/MCJIT/cached/toy.cpp @@ -994,7 +994,8 @@ void MCJITHelper::dump() //===----------------------------------------------------------------------===// static MCJITHelper *TheHelper; -static IRBuilder<> Builder(getGlobalContext()); +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::map NamedValues; Value *ErrorV(const char *Str) { Error(Str); return 0; } @@ -1005,12 +1006,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), 0, - VarName.c_str()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), 0, VarName.c_str()); } Value *NumberExprAST::Codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::Codegen() { @@ -1066,8 +1066,7 @@ Value *BinaryExprAST::Codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: break; } @@ -1104,17 +1103,16 @@ Value *IfExprAST::Codegen() { if (CondV == 0) return 0; // Convert condition to a bool by comparing equal to 0.0. - CondV = Builder.CreateFCmpONE(CondV, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "ifcond"); + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); @@ -1142,8 +1140,7 @@ Value *IfExprAST::Codegen() { // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, - "iftmp"); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -1185,7 +1182,7 @@ Value *ForExprAST::Codegen() { // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -1211,7 +1208,7 @@ Value *ForExprAST::Codegen() { if (StepVal == 0) return 0; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } // Compute the end condition. @@ -1225,12 +1222,12 @@ Value *ForExprAST::Codegen() { Builder.CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing equal to 0.0. - EndCond = Builder.CreateFCmpONE(EndCond, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "loopcond"); + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. - BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -1246,7 +1243,7 @@ Value *ForExprAST::Codegen() { // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } Value *VarExprAST::Codegen() { @@ -1269,7 +1266,7 @@ Value *VarExprAST::Codegen() { InitVal = Init->Codegen(); if (InitVal == 0) return 0; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -1297,10 +1294,9 @@ Value *VarExprAST::Codegen() { Function *PrototypeAST::Codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); - FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), - Doubles, false); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); std::string FnName = MakeLegalFunctionName(Name); @@ -1365,7 +1361,7 @@ Function *FunctionAST::Codegen() { BinopPrecedence[Proto->getOperatorName()] = Proto->getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Add all arguments to the symbol table and create their allocas. @@ -1490,7 +1486,7 @@ double printlf() { Module* parseInputIR(std::string InputFile) { SMDiagnostic Err; - Module *M = ParseIRFile(InputFile, Err, getGlobalContext()); + Module *M = ParseIRFile(InputFile, Err, TheContext); if (!M) { Err.print("IR parsing failed: ", errs()); return NULL; @@ -1512,7 +1508,7 @@ int main(int argc, char **argv) { InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); InitializeNativeTargetAsmParser(); - LLVMContext &Context = getGlobalContext(); + LLVMContext &Context = TheContext; cl::ParseCommandLineOptions(argc, argv, "Kaleidoscope example program\n"); diff --git a/examples/Kaleidoscope/MCJIT/complete/toy.cpp b/examples/Kaleidoscope/MCJIT/complete/toy.cpp index c78ec35fa0b3d1823054e9fc2c511460a1afbc46..40a00693e8cb0ba34c04e0c05270ea037938aae2 100644 --- a/examples/Kaleidoscope/MCJIT/complete/toy.cpp +++ b/examples/Kaleidoscope/MCJIT/complete/toy.cpp @@ -1066,7 +1066,8 @@ void MCJITHelper::dump() //===----------------------------------------------------------------------===// static BaseHelper *TheHelper; -static IRBuilder<> Builder(getGlobalContext()); +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::map NamedValues; Value *ErrorV(const char *Str) { Error(Str); return 0; } @@ -1077,12 +1078,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), 0, - VarName.c_str()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), 0, VarName.c_str()); } Value *NumberExprAST::Codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::Codegen() { @@ -1140,8 +1140,7 @@ Value *BinaryExprAST::Codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: break; } @@ -1182,17 +1181,16 @@ Value *IfExprAST::Codegen() { if (CondV == 0) return 0; // Convert condition to a bool by comparing equal to 0.0. - CondV = Builder.CreateFCmpONE(CondV, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "ifcond"); + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); @@ -1220,8 +1218,7 @@ Value *IfExprAST::Codegen() { // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, - "iftmp"); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -1263,7 +1260,7 @@ Value *ForExprAST::Codegen() { // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -1289,7 +1286,7 @@ Value *ForExprAST::Codegen() { if (StepVal == 0) return 0; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } // Compute the end condition. @@ -1303,12 +1300,12 @@ Value *ForExprAST::Codegen() { Builder.CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing equal to 0.0. - EndCond = Builder.CreateFCmpONE(EndCond, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "loopcond"); + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. - BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -1324,7 +1321,7 @@ Value *ForExprAST::Codegen() { // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } Value *VarExprAST::Codegen() { @@ -1347,7 +1344,7 @@ Value *VarExprAST::Codegen() { InitVal = Init->Codegen(); if (InitVal == 0) return 0; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -1375,10 +1372,9 @@ Value *VarExprAST::Codegen() { Function *PrototypeAST::Codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); - FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), - Doubles, false); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); std::string FnName; FnName = MakeLegalFunctionName(Name); @@ -1443,7 +1439,7 @@ Function *FunctionAST::Codegen() { BinopPrecedence[Proto->getOperatorName()] = Proto->getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Add all arguments to the symbol table and create their allocas. @@ -1565,7 +1561,7 @@ int main(int argc, char **argv) { InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); InitializeNativeTargetAsmParser(); - LLVMContext &Context = getGlobalContext(); + LLVMContext &Context = TheContext; cl::ParseCommandLineOptions(argc, argv, "Kaleidoscope example program\n"); diff --git a/examples/Kaleidoscope/MCJIT/initial/toy.cpp b/examples/Kaleidoscope/MCJIT/initial/toy.cpp index 9455946087d139e74f46e1255958da187c92cf63..1e476aef7862fc3a9f491a510019ead73650cfaf 100644 --- a/examples/Kaleidoscope/MCJIT/initial/toy.cpp +++ b/examples/Kaleidoscope/MCJIT/initial/toy.cpp @@ -852,7 +852,8 @@ void MCJITHelper::dump() //===----------------------------------------------------------------------===// static MCJITHelper *TheHelper; -static IRBuilder<> Builder(getGlobalContext()); +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::map NamedValues; Value *ErrorV(const char *Str) { Error(Str); return 0; } @@ -863,12 +864,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), 0, - VarName.c_str()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), 0, VarName.c_str()); } Value *NumberExprAST::Codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::Codegen() { @@ -924,8 +924,7 @@ Value *BinaryExprAST::Codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: break; } @@ -962,17 +961,16 @@ Value *IfExprAST::Codegen() { if (CondV == 0) return 0; // Convert condition to a bool by comparing equal to 0.0. - CondV = Builder.CreateFCmpONE(CondV, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "ifcond"); + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); @@ -1000,8 +998,7 @@ Value *IfExprAST::Codegen() { // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, - "iftmp"); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -1043,7 +1040,7 @@ Value *ForExprAST::Codegen() { // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -1069,7 +1066,7 @@ Value *ForExprAST::Codegen() { if (StepVal == 0) return 0; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } // Compute the end condition. @@ -1083,12 +1080,12 @@ Value *ForExprAST::Codegen() { Builder.CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing equal to 0.0. - EndCond = Builder.CreateFCmpONE(EndCond, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "loopcond"); + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. - BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -1104,7 +1101,7 @@ Value *ForExprAST::Codegen() { // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } Value *VarExprAST::Codegen() { @@ -1127,7 +1124,7 @@ Value *VarExprAST::Codegen() { InitVal = Init->Codegen(); if (InitVal == 0) return 0; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -1155,10 +1152,9 @@ Value *VarExprAST::Codegen() { Function *PrototypeAST::Codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); - FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), - Doubles, false); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); std::string FnName = MakeLegalFunctionName(Name); @@ -1223,7 +1219,7 @@ Function *FunctionAST::Codegen() { BinopPrecedence[Proto->getOperatorName()] = Proto->getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Add all arguments to the symbol table and create their allocas. @@ -1349,7 +1345,7 @@ int main() { InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); InitializeNativeTargetAsmParser(); - LLVMContext &Context = getGlobalContext(); + LLVMContext &Context = TheContext; // Install standard binary operators. // 1 is lowest precedence. diff --git a/examples/Kaleidoscope/MCJIT/lazy/toy-jit.cpp b/examples/Kaleidoscope/MCJIT/lazy/toy-jit.cpp index 07adbd45014e8ad0d1d35d8834a9bf8471e54cbf..f0c5ad5a46d7fc7efd632938abd505625f4106aa 100644 --- a/examples/Kaleidoscope/MCJIT/lazy/toy-jit.cpp +++ b/examples/Kaleidoscope/MCJIT/lazy/toy-jit.cpp @@ -608,7 +608,8 @@ static PrototypeAST *ParseExtern() { static Module *TheModule; static FunctionPassManager *TheFPM; -static IRBuilder<> Builder(getGlobalContext()); +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::map NamedValues; Value *ErrorV(const char *Str) { Error(Str); return 0; } @@ -619,12 +620,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), 0, - VarName.c_str()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), 0, VarName.c_str()); } Value *NumberExprAST::Codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::Codegen() { @@ -681,8 +681,7 @@ Value *BinaryExprAST::Codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: break; } @@ -722,18 +721,17 @@ Value *IfExprAST::Codegen() { if (CondV == 0) return 0; // Convert condition to a bool by comparing equal to 0.0. - CondV = Builder.CreateFCmpONE(CondV, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "ifcond"); - + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); + Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); - + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); + Builder.CreateCondBr(CondV, ThenBB, ElseBB); // Emit then value. @@ -760,9 +758,8 @@ Value *IfExprAST::Codegen() { // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, - "iftmp"); - + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); + PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); return PN; @@ -803,8 +800,8 @@ Value *ForExprAST::Codegen() { // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); - + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); + // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -829,7 +826,7 @@ Value *ForExprAST::Codegen() { if (StepVal == 0) return 0; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } // Compute the end condition. @@ -843,13 +840,13 @@ Value *ForExprAST::Codegen() { Builder.CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing equal to 0.0. - EndCond = Builder.CreateFCmpONE(EndCond, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "loopcond"); - + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); + // Create the "after loop" block and insert it. - BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); - + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); + // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -864,7 +861,7 @@ Value *ForExprAST::Codegen() { // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } Value *VarExprAST::Codegen() { @@ -887,7 +884,7 @@ Value *VarExprAST::Codegen() { InitVal = Init->Codegen(); if (InitVal == 0) return 0; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -915,10 +912,9 @@ Value *VarExprAST::Codegen() { Function *PrototypeAST::Codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); - FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), - Doubles, false); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); Function *F = Function::Create(FT, Function::ExternalLinkage, Name, TheModule); // If F conflicted, there was already something named 'Name'. If it has a @@ -976,7 +972,7 @@ Function *FunctionAST::Codegen() { BinopPrecedence[Proto->getOperatorName()] = Proto->getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Add all arguments to the symbol table and create their allocas. @@ -1104,7 +1100,7 @@ double printlf() { int main(int argc, char **argv) { InitializeNativeTarget(); - LLVMContext &Context = getGlobalContext(); + LLVMContext &Context = TheContext; // Install standard binary operators. // 1 is lowest precedence. diff --git a/examples/Kaleidoscope/MCJIT/lazy/toy.cpp b/examples/Kaleidoscope/MCJIT/lazy/toy.cpp index 14d758cfa79090c1c42fca909cb5c8ed661e8c3b..37339b60b44831fbe6333b135b97b9f299e37639 100644 --- a/examples/Kaleidoscope/MCJIT/lazy/toy.cpp +++ b/examples/Kaleidoscope/MCJIT/lazy/toy.cpp @@ -892,7 +892,8 @@ void MCJITHelper::dump() //===----------------------------------------------------------------------===// static MCJITHelper *TheHelper; -static IRBuilder<> Builder(getGlobalContext()); +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); static std::map NamedValues; Value *ErrorV(const char *Str) { Error(Str); return 0; } @@ -903,12 +904,11 @@ static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) { IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), 0, - VarName.c_str()); + return TmpB.CreateAlloca(Type::getDoubleTy(TheContext), 0, VarName.c_str()); } Value *NumberExprAST::Codegen() { - return ConstantFP::get(getGlobalContext(), APFloat(Val)); + return ConstantFP::get(TheContext, APFloat(Val)); } Value *VariableExprAST::Codegen() { @@ -964,8 +964,7 @@ Value *BinaryExprAST::Codegen() { case '<': L = Builder.CreateFCmpULT(L, R, "cmptmp"); // Convert bool 0/1 to double 0.0 or 1.0 - return Builder.CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); default: break; } @@ -1002,17 +1001,16 @@ Value *IfExprAST::Codegen() { if (CondV == 0) return 0; // Convert condition to a bool by comparing equal to 0.0. - CondV = Builder.CreateFCmpONE(CondV, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "ifcond"); + CondV = Builder.CreateFCmpONE( + CondV, ConstantFP::get(TheContext, APFloat(0.0)), "ifcond"); Function *TheFunction = Builder.GetInsertBlock()->getParent(); // Create blocks for the then and else cases. Insert the 'then' block at the // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(getGlobalContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(getGlobalContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); + BasicBlock *ThenBB = BasicBlock::Create(TheContext, "then", TheFunction); + BasicBlock *ElseBB = BasicBlock::Create(TheContext, "else"); + BasicBlock *MergeBB = BasicBlock::Create(TheContext, "ifcont"); Builder.CreateCondBr(CondV, ThenBB, ElseBB); @@ -1040,8 +1038,7 @@ Value *IfExprAST::Codegen() { // Emit merge block. TheFunction->getBasicBlockList().push_back(MergeBB); Builder.SetInsertPoint(MergeBB); - PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, - "iftmp"); + PHINode *PN = Builder.CreatePHI(Type::getDoubleTy(TheContext), 2, "iftmp"); PN->addIncoming(ThenV, ThenBB); PN->addIncoming(ElseV, ElseBB); @@ -1083,7 +1080,7 @@ Value *ForExprAST::Codegen() { // Make the new basic block for the loop header, inserting after current // block. - BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); + BasicBlock *LoopBB = BasicBlock::Create(TheContext, "loop", TheFunction); // Insert an explicit fall through from the current block to the LoopBB. Builder.CreateBr(LoopBB); @@ -1109,7 +1106,7 @@ Value *ForExprAST::Codegen() { if (StepVal == 0) return 0; } else { // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); + StepVal = ConstantFP::get(TheContext, APFloat(1.0)); } // Compute the end condition. @@ -1123,12 +1120,12 @@ Value *ForExprAST::Codegen() { Builder.CreateStore(NextVar, Alloca); // Convert condition to a bool by comparing equal to 0.0. - EndCond = Builder.CreateFCmpONE(EndCond, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "loopcond"); + EndCond = Builder.CreateFCmpONE( + EndCond, ConstantFP::get(TheContext, APFloat(0.0)), "loopcond"); // Create the "after loop" block and insert it. - BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); + BasicBlock *AfterBB = + BasicBlock::Create(TheContext, "afterloop", TheFunction); // Insert the conditional branch into the end of LoopEndBB. Builder.CreateCondBr(EndCond, LoopBB, AfterBB); @@ -1144,7 +1141,7 @@ Value *ForExprAST::Codegen() { // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); + return Constant::getNullValue(Type::getDoubleTy(TheContext)); } Value *VarExprAST::Codegen() { @@ -1167,7 +1164,7 @@ Value *VarExprAST::Codegen() { InitVal = Init->Codegen(); if (InitVal == 0) return 0; } else { // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); + InitVal = ConstantFP::get(TheContext, APFloat(0.0)); } AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); @@ -1195,10 +1192,9 @@ Value *VarExprAST::Codegen() { Function *PrototypeAST::Codegen() { // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); - FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), - Doubles, false); + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); std::string FnName = MakeLegalFunctionName(Name); @@ -1263,7 +1259,7 @@ Function *FunctionAST::Codegen() { BinopPrecedence[Proto->getOperatorName()] = Proto->getBinaryPrecedence(); // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); + BasicBlock *BB = BasicBlock::Create(TheContext, "entry", TheFunction); Builder.SetInsertPoint(BB); // Add all arguments to the symbol table and create their allocas. @@ -1390,7 +1386,7 @@ int main() { InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); InitializeNativeTargetAsmParser(); - LLVMContext &Context = getGlobalContext(); + LLVMContext &Context = TheContext; // Install standard binary operators. // 1 is lowest precedence. diff --git a/examples/Kaleidoscope/Orc/CMakeLists.txt b/examples/Kaleidoscope/Orc/CMakeLists.txt deleted file mode 100644 index 5aa04543dc68757bf2d31a94fbdf228d6ffe2388..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_subdirectory(initial) -add_subdirectory(lazy_codegen) -add_subdirectory(lazy_irgen) -add_subdirectory(fully_lazy) diff --git a/examples/Kaleidoscope/Orc/fully_lazy/CMakeLists.txt b/examples/Kaleidoscope/Orc/fully_lazy/CMakeLists.txt deleted file mode 100644 index abb0428a152ea81fc13fd6e825ec10dd21457b29..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/fully_lazy/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Core - ExecutionEngine - Object - OrcJIT - RuntimeDyld - Support - native - ) - -add_kaleidoscope_chapter(Kaleidoscope-Orc-fully_lazy - toy.cpp - ) diff --git a/examples/Kaleidoscope/Orc/fully_lazy/README.txt b/examples/Kaleidoscope/Orc/fully_lazy/README.txt deleted file mode 100644 index c0189319f2c55792841d7d15e9b3806acf442f40..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/fully_lazy/README.txt +++ /dev/null @@ -1,21 +0,0 @@ -//===----------------------------------------------------------------------===/ -// Kaleidoscope with Orc - Lazy IRGen Version -//===----------------------------------------------------------------------===// - -This version of Kaleidoscope with Orc demonstrates fully lazy IR-generation. -Building on the lazy-irgen version of the tutorial, this version injects JIT -callbacks to defer the bulk of IR-generation and code-generation of functions until -they are first called. - -When a function definition is entered, a JIT callback is created and a stub -function is built that will call the body of the function indirectly. The body of -the function is *not* IRGen'd at this point. Instead, the function pointer for -the indirect call is initialized to point at the JIT callback, and the compile -action for the callback is initialized with a lambda that IRGens the body of the -function and adds it to the JIT. The function pointer is updated by the JIT -callback's update action to point at the newly emitted function body, so future -calls to the stub will go straight to the body, not through the JIT. - -This directory contains a Makefile that allows the code to be built in a -standalone manner, independent of the larger LLVM build infrastructure. To build -the program you will need to have 'clang++' and 'llvm-config' in your path. diff --git a/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp b/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp deleted file mode 100644 index 0371a3f76f69ca839f82988b2580956c40886883..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/fully_lazy/toy.cpp +++ /dev/null @@ -1,1440 +0,0 @@ -#include "llvm/Analysis/Passes.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" -#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" -#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Transforms/Scalar.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace llvm; -using namespace llvm::orc; - -//===----------------------------------------------------------------------===// -// Lexer -//===----------------------------------------------------------------------===// - -// The lexer returns tokens [0-255] if it is an unknown character, otherwise one -// of these for known things. -enum Token { - tok_eof = -1, - - // commands - tok_def = -2, tok_extern = -3, - - // primary - tok_identifier = -4, tok_number = -5, - - // control - tok_if = -6, tok_then = -7, tok_else = -8, - tok_for = -9, tok_in = -10, - - // operators - tok_binary = -11, tok_unary = -12, - - // var definition - tok_var = -13 -}; - -static std::string IdentifierStr; // Filled in if tok_identifier -static double NumVal; // Filled in if tok_number - -/// gettok - Return the next token from standard input. -static int gettok() { - static int LastChar = ' '; - - // Skip any whitespace. - while (isspace(LastChar)) - LastChar = getchar(); - - if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* - IdentifierStr = LastChar; - while (isalnum((LastChar = getchar()))) - IdentifierStr += LastChar; - - if (IdentifierStr == "def") return tok_def; - if (IdentifierStr == "extern") return tok_extern; - if (IdentifierStr == "if") return tok_if; - if (IdentifierStr == "then") return tok_then; - if (IdentifierStr == "else") return tok_else; - if (IdentifierStr == "for") return tok_for; - if (IdentifierStr == "in") return tok_in; - if (IdentifierStr == "binary") return tok_binary; - if (IdentifierStr == "unary") return tok_unary; - if (IdentifierStr == "var") return tok_var; - return tok_identifier; - } - - if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ - std::string NumStr; - do { - NumStr += LastChar; - LastChar = getchar(); - } while (isdigit(LastChar) || LastChar == '.'); - - NumVal = strtod(NumStr.c_str(), nullptr); - return tok_number; - } - - if (LastChar == '#') { - // Comment until end of line. - do LastChar = getchar(); - while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); - - if (LastChar != EOF) - return gettok(); - } - - // Check for end of file. Don't eat the EOF. - if (LastChar == EOF) - return tok_eof; - - // Otherwise, just return the character as its ascii value. - int ThisChar = LastChar; - LastChar = getchar(); - return ThisChar; -} - -//===----------------------------------------------------------------------===// -// Abstract Syntax Tree (aka Parse Tree) -//===----------------------------------------------------------------------===// - -class IRGenContext; - -/// ExprAST - Base class for all expression nodes. -struct ExprAST { - virtual ~ExprAST() {} - virtual Value *IRGen(IRGenContext &C) const = 0; -}; - -/// NumberExprAST - Expression class for numeric literals like "1.0". -struct NumberExprAST : public ExprAST { - NumberExprAST(double Val) : Val(Val) {} - Value *IRGen(IRGenContext &C) const override; - - double Val; -}; - -/// VariableExprAST - Expression class for referencing a variable, like "a". -struct VariableExprAST : public ExprAST { - VariableExprAST(std::string Name) : Name(std::move(Name)) {} - Value *IRGen(IRGenContext &C) const override; - - std::string Name; -}; - -/// UnaryExprAST - Expression class for a unary operator. -struct UnaryExprAST : public ExprAST { - UnaryExprAST(char Opcode, std::unique_ptr Operand) - : Opcode(std::move(Opcode)), Operand(std::move(Operand)) {} - - Value *IRGen(IRGenContext &C) const override; - - char Opcode; - std::unique_ptr Operand; -}; - -/// BinaryExprAST - Expression class for a binary operator. -struct BinaryExprAST : public ExprAST { - BinaryExprAST(char Op, std::unique_ptr LHS, - std::unique_ptr RHS) - : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} - - Value *IRGen(IRGenContext &C) const override; - - char Op; - std::unique_ptr LHS, RHS; -}; - -/// CallExprAST - Expression class for function calls. -struct CallExprAST : public ExprAST { - CallExprAST(std::string CalleeName, - std::vector> Args) - : CalleeName(std::move(CalleeName)), Args(std::move(Args)) {} - - Value *IRGen(IRGenContext &C) const override; - - std::string CalleeName; - std::vector> Args; -}; - -/// IfExprAST - Expression class for if/then/else. -struct IfExprAST : public ExprAST { - IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, - std::unique_ptr Else) - : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} - Value *IRGen(IRGenContext &C) const override; - - std::unique_ptr Cond, Then, Else; -}; - -/// ForExprAST - Expression class for for/in. -struct ForExprAST : public ExprAST { - ForExprAST(std::string VarName, std::unique_ptr Start, - std::unique_ptr End, std::unique_ptr Step, - std::unique_ptr Body) - : VarName(std::move(VarName)), Start(std::move(Start)), End(std::move(End)), - Step(std::move(Step)), Body(std::move(Body)) {} - - Value *IRGen(IRGenContext &C) const override; - - std::string VarName; - std::unique_ptr Start, End, Step, Body; -}; - -/// VarExprAST - Expression class for var/in -struct VarExprAST : public ExprAST { - typedef std::pair> Binding; - typedef std::vector BindingList; - - VarExprAST(BindingList VarBindings, std::unique_ptr Body) - : VarBindings(std::move(VarBindings)), Body(std::move(Body)) {} - - Value *IRGen(IRGenContext &C) const override; - - BindingList VarBindings; - std::unique_ptr Body; -}; - -/// PrototypeAST - This class represents the "prototype" for a function, -/// which captures its argument names as well as if it is an operator. -struct PrototypeAST { - PrototypeAST(std::string Name, std::vector Args, - bool IsOperator = false, unsigned Precedence = 0) - : Name(std::move(Name)), Args(std::move(Args)), IsOperator(IsOperator), - Precedence(Precedence) {} - - Function *IRGen(IRGenContext &C) const; - void CreateArgumentAllocas(Function *F, IRGenContext &C); - - bool isUnaryOp() const { return IsOperator && Args.size() == 1; } - bool isBinaryOp() const { return IsOperator && Args.size() == 2; } - - char getOperatorName() const { - assert(isUnaryOp() || isBinaryOp()); - return Name[Name.size()-1]; - } - - std::string Name; - std::vector Args; - bool IsOperator; - unsigned Precedence; // Precedence if a binary op. -}; - -/// FunctionAST - This class represents a function definition itself. -struct FunctionAST { - FunctionAST(std::unique_ptr Proto, - std::unique_ptr Body) - : Proto(std::move(Proto)), Body(std::move(Body)) {} - - Function *IRGen(IRGenContext &C) const; - - std::unique_ptr Proto; - std::unique_ptr Body; -}; - -//===----------------------------------------------------------------------===// -// Parser -//===----------------------------------------------------------------------===// - -/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current -/// token the parser is looking at. getNextToken reads another token from the -/// lexer and updates CurTok with its results. -static int CurTok; -static int getNextToken() { - return CurTok = gettok(); -} - -/// BinopPrecedence - This holds the precedence for each binary operator that is -/// defined. -static std::map BinopPrecedence; - -/// GetTokPrecedence - Get the precedence of the pending binary operator token. -static int GetTokPrecedence() { - if (!isascii(CurTok)) - return -1; - - // Make sure it's a declared binop. - int TokPrec = BinopPrecedence[CurTok]; - if (TokPrec <= 0) return -1; - return TokPrec; -} - -template -std::unique_ptr ErrorU(const std::string &Str) { - std::cerr << "Error: " << Str << "\n"; - return nullptr; -} - -template -T* ErrorP(const std::string &Str) { - std::cerr << "Error: " << Str << "\n"; - return nullptr; -} - -static std::unique_ptr ParseExpression(); - -/// identifierexpr -/// ::= identifier -/// ::= identifier '(' expression* ')' -static std::unique_ptr ParseIdentifierExpr() { - std::string IdName = IdentifierStr; - - getNextToken(); // eat identifier. - - if (CurTok != '(') // Simple variable ref. - return llvm::make_unique(IdName); - - // Call. - getNextToken(); // eat ( - std::vector> Args; - if (CurTok != ')') { - while (1) { - auto Arg = ParseExpression(); - if (!Arg) return nullptr; - Args.push_back(std::move(Arg)); - - if (CurTok == ')') break; - - if (CurTok != ',') - return ErrorU("Expected ')' or ',' in argument list"); - getNextToken(); - } - } - - // Eat the ')'. - getNextToken(); - - return llvm::make_unique(IdName, std::move(Args)); -} - -/// numberexpr ::= number -static std::unique_ptr ParseNumberExpr() { - auto Result = llvm::make_unique(NumVal); - getNextToken(); // consume the number - return Result; -} - -/// parenexpr ::= '(' expression ')' -static std::unique_ptr ParseParenExpr() { - getNextToken(); // eat (. - auto V = ParseExpression(); - if (!V) - return nullptr; - - if (CurTok != ')') - return ErrorU("expected ')'"); - getNextToken(); // eat ). - return V; -} - -/// ifexpr ::= 'if' expression 'then' expression 'else' expression -static std::unique_ptr ParseIfExpr() { - getNextToken(); // eat the if. - - // condition. - auto Cond = ParseExpression(); - if (!Cond) - return nullptr; - - if (CurTok != tok_then) - return ErrorU("expected then"); - getNextToken(); // eat the then - - auto Then = ParseExpression(); - if (!Then) - return nullptr; - - if (CurTok != tok_else) - return ErrorU("expected else"); - - getNextToken(); - - auto Else = ParseExpression(); - if (!Else) - return nullptr; - - return llvm::make_unique(std::move(Cond), std::move(Then), - std::move(Else)); -} - -/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression -static std::unique_ptr ParseForExpr() { - getNextToken(); // eat the for. - - if (CurTok != tok_identifier) - return ErrorU("expected identifier after for"); - - std::string IdName = IdentifierStr; - getNextToken(); // eat identifier. - - if (CurTok != '=') - return ErrorU("expected '=' after for"); - getNextToken(); // eat '='. - - auto Start = ParseExpression(); - if (!Start) - return nullptr; - if (CurTok != ',') - return ErrorU("expected ',' after for start value"); - getNextToken(); - - auto End = ParseExpression(); - if (!End) - return nullptr; - - // The step value is optional. - std::unique_ptr Step; - if (CurTok == ',') { - getNextToken(); - Step = ParseExpression(); - if (!Step) - return nullptr; - } - - if (CurTok != tok_in) - return ErrorU("expected 'in' after for"); - getNextToken(); // eat 'in'. - - auto Body = ParseExpression(); - if (Body) - return nullptr; - - return llvm::make_unique(IdName, std::move(Start), std::move(End), - std::move(Step), std::move(Body)); -} - -/// varexpr ::= 'var' identifier ('=' expression)? -// (',' identifier ('=' expression)?)* 'in' expression -static std::unique_ptr ParseVarExpr() { - getNextToken(); // eat the var. - - VarExprAST::BindingList VarBindings; - - // At least one variable name is required. - if (CurTok != tok_identifier) - return ErrorU("expected identifier after var"); - - while (1) { - std::string Name = IdentifierStr; - getNextToken(); // eat identifier. - - // Read the optional initializer. - std::unique_ptr Init; - if (CurTok == '=') { - getNextToken(); // eat the '='. - - Init = ParseExpression(); - if (!Init) - return nullptr; - } - - VarBindings.push_back(VarExprAST::Binding(Name, std::move(Init))); - - // End of var list, exit loop. - if (CurTok != ',') break; - getNextToken(); // eat the ','. - - if (CurTok != tok_identifier) - return ErrorU("expected identifier list after var"); - } - - // At this point, we have to have 'in'. - if (CurTok != tok_in) - return ErrorU("expected 'in' keyword after 'var'"); - getNextToken(); // eat 'in'. - - auto Body = ParseExpression(); - if (!Body) - return nullptr; - - return llvm::make_unique(std::move(VarBindings), std::move(Body)); -} - -/// primary -/// ::= identifierexpr -/// ::= numberexpr -/// ::= parenexpr -/// ::= ifexpr -/// ::= forexpr -/// ::= varexpr -static std::unique_ptr ParsePrimary() { - switch (CurTok) { - default: return ErrorU("unknown token when expecting an expression"); - case tok_identifier: return ParseIdentifierExpr(); - case tok_number: return ParseNumberExpr(); - case '(': return ParseParenExpr(); - case tok_if: return ParseIfExpr(); - case tok_for: return ParseForExpr(); - case tok_var: return ParseVarExpr(); - } -} - -/// unary -/// ::= primary -/// ::= '!' unary -static std::unique_ptr ParseUnary() { - // If the current token is not an operator, it must be a primary expr. - if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') - return ParsePrimary(); - - // If this is a unary operator, read it. - int Opc = CurTok; - getNextToken(); - if (auto Operand = ParseUnary()) - return llvm::make_unique(Opc, std::move(Operand)); - return nullptr; -} - -/// binoprhs -/// ::= ('+' unary)* -static std::unique_ptr ParseBinOpRHS(int ExprPrec, - std::unique_ptr LHS) { - // If this is a binop, find its precedence. - while (1) { - int TokPrec = GetTokPrecedence(); - - // If this is a binop that binds at least as tightly as the current binop, - // consume it, otherwise we are done. - if (TokPrec < ExprPrec) - return LHS; - - // Okay, we know this is a binop. - int BinOp = CurTok; - getNextToken(); // eat binop - - // Parse the unary expression after the binary operator. - auto RHS = ParseUnary(); - if (!RHS) - return nullptr; - - // If BinOp binds less tightly with RHS than the operator after RHS, let - // the pending operator take RHS as its LHS. - int NextPrec = GetTokPrecedence(); - if (TokPrec < NextPrec) { - RHS = ParseBinOpRHS(TokPrec+1, std::move(RHS)); - if (!RHS) - return nullptr; - } - - // Merge LHS/RHS. - LHS = llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); - } -} - -/// expression -/// ::= unary binoprhs -/// -static std::unique_ptr ParseExpression() { - auto LHS = ParseUnary(); - if (!LHS) - return nullptr; - - return ParseBinOpRHS(0, std::move(LHS)); -} - -/// prototype -/// ::= id '(' id* ')' -/// ::= binary LETTER number? (id, id) -/// ::= unary LETTER (id) -static std::unique_ptr ParsePrototype() { - std::string FnName; - - unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. - unsigned BinaryPrecedence = 30; - - switch (CurTok) { - default: - return ErrorU("Expected function name in prototype"); - case tok_identifier: - FnName = IdentifierStr; - Kind = 0; - getNextToken(); - break; - case tok_unary: - getNextToken(); - if (!isascii(CurTok)) - return ErrorU("Expected unary operator"); - FnName = "unary"; - FnName += (char)CurTok; - Kind = 1; - getNextToken(); - break; - case tok_binary: - getNextToken(); - if (!isascii(CurTok)) - return ErrorU("Expected binary operator"); - FnName = "binary"; - FnName += (char)CurTok; - Kind = 2; - getNextToken(); - - // Read the precedence if present. - if (CurTok == tok_number) { - if (NumVal < 1 || NumVal > 100) - return ErrorU("Invalid precedecnce: must be 1..100"); - BinaryPrecedence = (unsigned)NumVal; - getNextToken(); - } - break; - } - - if (CurTok != '(') - return ErrorU("Expected '(' in prototype"); - - std::vector ArgNames; - while (getNextToken() == tok_identifier) - ArgNames.push_back(IdentifierStr); - if (CurTok != ')') - return ErrorU("Expected ')' in prototype"); - - // success. - getNextToken(); // eat ')'. - - // Verify right number of names for operator. - if (Kind && ArgNames.size() != Kind) - return ErrorU("Invalid number of operands for operator"); - - return llvm::make_unique(FnName, std::move(ArgNames), Kind != 0, - BinaryPrecedence); -} - -/// definition ::= 'def' prototype expression -static std::unique_ptr ParseDefinition() { - getNextToken(); // eat def. - auto Proto = ParsePrototype(); - if (!Proto) - return nullptr; - - if (auto Body = ParseExpression()) - return llvm::make_unique(std::move(Proto), std::move(Body)); - return nullptr; -} - -/// toplevelexpr ::= expression -static std::unique_ptr ParseTopLevelExpr() { - if (auto E = ParseExpression()) { - // Make an anonymous proto. - auto Proto = - llvm::make_unique("__anon_expr", std::vector()); - return llvm::make_unique(std::move(Proto), std::move(E)); - } - return nullptr; -} - -/// external ::= 'extern' prototype -static std::unique_ptr ParseExtern() { - getNextToken(); // eat extern. - return ParsePrototype(); -} - -//===----------------------------------------------------------------------===// -// Code Generation -//===----------------------------------------------------------------------===// - -// FIXME: Obviously we can do better than this -std::string GenerateUniqueName(const std::string &Root) { - static int i = 0; - std::ostringstream NameStream; - NameStream << Root << ++i; - return NameStream.str(); -} - -std::string MakeLegalFunctionName(std::string Name) -{ - std::string NewName; - assert(!Name.empty() && "Base name must not be empty"); - - // Start with what we have - NewName = Name; - - // Look for a numberic first character - if (NewName.find_first_of("0123456789") == 0) { - NewName.insert(0, 1, 'n'); - } - - // Replace illegal characters with their ASCII equivalent - std::string legal_elements = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - size_t pos; - while ((pos = NewName.find_first_not_of(legal_elements)) != std::string::npos) { - std::ostringstream NumStream; - NumStream << (int)NewName.at(pos); - NewName = NewName.replace(pos, 1, NumStream.str()); - } - - return NewName; -} - -class SessionContext { -public: - SessionContext(LLVMContext &C) - : Context(C), TM(EngineBuilder().selectTarget()) {} - LLVMContext& getLLVMContext() const { return Context; } - TargetMachine& getTarget() { return *TM; } - void addPrototypeAST(std::unique_ptr P); - PrototypeAST* getPrototypeAST(const std::string &Name); -private: - typedef std::map> PrototypeMap; - - LLVMContext &Context; - std::unique_ptr TM; - - PrototypeMap Prototypes; -}; - -void SessionContext::addPrototypeAST(std::unique_ptr P) { - Prototypes[P->Name] = std::move(P); -} - -PrototypeAST* SessionContext::getPrototypeAST(const std::string &Name) { - PrototypeMap::iterator I = Prototypes.find(Name); - if (I != Prototypes.end()) - return I->second.get(); - return nullptr; -} - -class IRGenContext { -public: - - IRGenContext(SessionContext &S) - : Session(S), - M(new Module(GenerateUniqueName("jit_module_"), - Session.getLLVMContext())), - Builder(Session.getLLVMContext()) { - M->setDataLayout(Session.getTarget().createDataLayout()); - } - - SessionContext& getSession() { return Session; } - Module& getM() const { return *M; } - std::unique_ptr takeM() { return std::move(M); } - IRBuilder<>& getBuilder() { return Builder; } - LLVMContext& getLLVMContext() { return Session.getLLVMContext(); } - Function* getPrototype(const std::string &Name); - - std::map NamedValues; -private: - SessionContext &Session; - std::unique_ptr M; - IRBuilder<> Builder; -}; - -Function* IRGenContext::getPrototype(const std::string &Name) { - if (Function *ExistingProto = M->getFunction(Name)) - return ExistingProto; - if (PrototypeAST *ProtoAST = Session.getPrototypeAST(Name)) - return ProtoAST->IRGen(*this); - return nullptr; -} - -/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of -/// the function. This is used for mutable variables etc. -static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, - const std::string &VarName) { - IRBuilder<> TmpB(&TheFunction->getEntryBlock(), - TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), nullptr, - VarName.c_str()); -} - -Value *NumberExprAST::IRGen(IRGenContext &C) const { - return ConstantFP::get(C.getLLVMContext(), APFloat(Val)); -} - -Value *VariableExprAST::IRGen(IRGenContext &C) const { - // Look this variable up in the function. - Value *V = C.NamedValues[Name]; - - if (!V) - return ErrorP("Unknown variable name '" + Name + "'"); - - // Load the value. - return C.getBuilder().CreateLoad(V, Name.c_str()); -} - -Value *UnaryExprAST::IRGen(IRGenContext &C) const { - if (Value *OperandV = Operand->IRGen(C)) { - std::string FnName = MakeLegalFunctionName(std::string("unary")+Opcode); - if (Function *F = C.getPrototype(FnName)) - return C.getBuilder().CreateCall(F, OperandV, "unop"); - return ErrorP("Unknown unary operator"); - } - - // Could not codegen operand - return null. - return nullptr; -} - -Value *BinaryExprAST::IRGen(IRGenContext &C) const { - // Special case '=' because we don't want to emit the LHS as an expression. - if (Op == '=') { - // Assignment requires the LHS to be an identifier. - auto &LHSVar = static_cast(*LHS); - // Codegen the RHS. - Value *Val = RHS->IRGen(C); - if (!Val) return nullptr; - - // Look up the name. - if (auto Variable = C.NamedValues[LHSVar.Name]) { - C.getBuilder().CreateStore(Val, Variable); - return Val; - } - return ErrorP("Unknown variable name"); - } - - Value *L = LHS->IRGen(C); - Value *R = RHS->IRGen(C); - if (!L || !R) return nullptr; - - switch (Op) { - case '+': return C.getBuilder().CreateFAdd(L, R, "addtmp"); - case '-': return C.getBuilder().CreateFSub(L, R, "subtmp"); - case '*': return C.getBuilder().CreateFMul(L, R, "multmp"); - case '/': return C.getBuilder().CreateFDiv(L, R, "divtmp"); - case '<': - L = C.getBuilder().CreateFCmpULT(L, R, "cmptmp"); - // Convert bool 0/1 to double 0.0 or 1.0 - return C.getBuilder().CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); - default: break; - } - - // If it wasn't a builtin binary operator, it must be a user defined one. Emit - // a call to it. - std::string FnName = MakeLegalFunctionName(std::string("binary")+Op); - if (Function *F = C.getPrototype(FnName)) { - Value *Ops[] = { L, R }; - return C.getBuilder().CreateCall(F, Ops, "binop"); - } - - return ErrorP("Unknown binary operator"); -} - -Value *CallExprAST::IRGen(IRGenContext &C) const { - // Look up the name in the global module table. - if (auto CalleeF = C.getPrototype(CalleeName)) { - // If argument mismatch error. - if (CalleeF->arg_size() != Args.size()) - return ErrorP("Incorrect # arguments passed"); - - std::vector ArgsV; - for (unsigned i = 0, e = Args.size(); i != e; ++i) { - ArgsV.push_back(Args[i]->IRGen(C)); - if (!ArgsV.back()) return nullptr; - } - - return C.getBuilder().CreateCall(CalleeF, ArgsV, "calltmp"); - } - - return ErrorP("Unknown function referenced"); -} - -Value *IfExprAST::IRGen(IRGenContext &C) const { - Value *CondV = Cond->IRGen(C); - if (!CondV) return nullptr; - - // Convert condition to a bool by comparing equal to 0.0. - ConstantFP *FPZero = - ConstantFP::get(C.getLLVMContext(), APFloat(0.0)); - CondV = C.getBuilder().CreateFCmpONE(CondV, FPZero, "ifcond"); - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Create blocks for the then and else cases. Insert the 'then' block at the - // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(C.getLLVMContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(C.getLLVMContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(C.getLLVMContext(), "ifcont"); - - C.getBuilder().CreateCondBr(CondV, ThenBB, ElseBB); - - // Emit then value. - C.getBuilder().SetInsertPoint(ThenBB); - - Value *ThenV = Then->IRGen(C); - if (!ThenV) return nullptr; - - C.getBuilder().CreateBr(MergeBB); - // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = C.getBuilder().GetInsertBlock(); - - // Emit else block. - TheFunction->getBasicBlockList().push_back(ElseBB); - C.getBuilder().SetInsertPoint(ElseBB); - - Value *ElseV = Else->IRGen(C); - if (!ElseV) return nullptr; - - C.getBuilder().CreateBr(MergeBB); - // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = C.getBuilder().GetInsertBlock(); - - // Emit merge block. - TheFunction->getBasicBlockList().push_back(MergeBB); - C.getBuilder().SetInsertPoint(MergeBB); - PHINode *PN = C.getBuilder().CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, - "iftmp"); - - PN->addIncoming(ThenV, ThenBB); - PN->addIncoming(ElseV, ElseBB); - return PN; -} - -Value *ForExprAST::IRGen(IRGenContext &C) const { - // Output this as: - // var = alloca double - // ... - // start = startexpr - // store start -> var - // goto loop - // loop: - // ... - // bodyexpr - // ... - // loopend: - // step = stepexpr - // endcond = endexpr - // - // curvar = load var - // nextvar = curvar + step - // store nextvar -> var - // br endcond, loop, endloop - // outloop: - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Create an alloca for the variable in the entry block. - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - - // Emit the start code first, without 'variable' in scope. - Value *StartVal = Start->IRGen(C); - if (!StartVal) return nullptr; - - // Store the value into the alloca. - C.getBuilder().CreateStore(StartVal, Alloca); - - // Make the new basic block for the loop header, inserting after current - // block. - BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); - - // Insert an explicit fall through from the current block to the LoopBB. - C.getBuilder().CreateBr(LoopBB); - - // Start insertion in LoopBB. - C.getBuilder().SetInsertPoint(LoopBB); - - // Within the loop, the variable is defined equal to the PHI node. If it - // shadows an existing variable, we have to restore it, so save it now. - AllocaInst *OldVal = C.NamedValues[VarName]; - C.NamedValues[VarName] = Alloca; - - // Emit the body of the loop. This, like any other expr, can change the - // current BB. Note that we ignore the value computed by the body, but don't - // allow an error. - if (!Body->IRGen(C)) - return nullptr; - - // Emit the step value. - Value *StepVal; - if (Step) { - StepVal = Step->IRGen(C); - if (!StepVal) return nullptr; - } else { - // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); - } - - // Compute the end condition. - Value *EndCond = End->IRGen(C); - if (!EndCond) return nullptr; - - // Reload, increment, and restore the alloca. This handles the case where - // the body of the loop mutates the variable. - Value *CurVar = C.getBuilder().CreateLoad(Alloca, VarName.c_str()); - Value *NextVar = C.getBuilder().CreateFAdd(CurVar, StepVal, "nextvar"); - C.getBuilder().CreateStore(NextVar, Alloca); - - // Convert condition to a bool by comparing equal to 0.0. - EndCond = C.getBuilder().CreateFCmpONE(EndCond, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "loopcond"); - - // Create the "after loop" block and insert it. - BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); - - // Insert the conditional branch into the end of LoopEndBB. - C.getBuilder().CreateCondBr(EndCond, LoopBB, AfterBB); - - // Any new code will be inserted in AfterBB. - C.getBuilder().SetInsertPoint(AfterBB); - - // Restore the unshadowed variable. - if (OldVal) - C.NamedValues[VarName] = OldVal; - else - C.NamedValues.erase(VarName); - - // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); -} - -Value *VarExprAST::IRGen(IRGenContext &C) const { - std::vector OldBindings; - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Register all variables and emit their initializer. - for (unsigned i = 0, e = VarBindings.size(); i != e; ++i) { - auto &VarName = VarBindings[i].first; - auto &Init = VarBindings[i].second; - - // Emit the initializer before adding the variable to scope, this prevents - // the initializer from referencing the variable itself, and permits stuff - // like this: - // var a = 1 in - // var a = a in ... # refers to outer 'a'. - Value *InitVal; - if (Init) { - InitVal = Init->IRGen(C); - if (!InitVal) return nullptr; - } else // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); - - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - C.getBuilder().CreateStore(InitVal, Alloca); - - // Remember the old variable binding so that we can restore the binding when - // we unrecurse. - OldBindings.push_back(C.NamedValues[VarName]); - - // Remember this binding. - C.NamedValues[VarName] = Alloca; - } - - // Codegen the body, now that all vars are in scope. - Value *BodyVal = Body->IRGen(C); - if (!BodyVal) return nullptr; - - // Pop all our variables from scope. - for (unsigned i = 0, e = VarBindings.size(); i != e; ++i) - C.NamedValues[VarBindings[i].first] = OldBindings[i]; - - // Return the body computation. - return BodyVal; -} - -Function *PrototypeAST::IRGen(IRGenContext &C) const { - std::string FnName = MakeLegalFunctionName(Name); - - // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); - FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), - Doubles, false); - Function *F = Function::Create(FT, Function::ExternalLinkage, FnName, - &C.getM()); - - // If F conflicted, there was already something named 'FnName'. If it has a - // body, don't allow redefinition or reextern. - if (F->getName() != FnName) { - // Delete the one we just made and get the existing one. - F->eraseFromParent(); - F = C.getM().getFunction(Name); - - // If F already has a body, reject this. - if (!F->empty()) { - ErrorP("redefinition of function"); - return nullptr; - } - - // If F took a different number of args, reject. - if (F->arg_size() != Args.size()) { - ErrorP("redefinition of function with different # args"); - return nullptr; - } - } - - // Set names for all arguments. - unsigned Idx = 0; - for (Function::arg_iterator AI = F->arg_begin(); Idx != Args.size(); - ++AI, ++Idx) - AI->setName(Args[Idx]); - - return F; -} - -/// CreateArgumentAllocas - Create an alloca for each argument and register the -/// argument in the symbol table so that references to it will succeed. -void PrototypeAST::CreateArgumentAllocas(Function *F, IRGenContext &C) { - Function::arg_iterator AI = F->arg_begin(); - for (unsigned Idx = 0, e = Args.size(); Idx != e; ++Idx, ++AI) { - // Create an alloca for this variable. - AllocaInst *Alloca = CreateEntryBlockAlloca(F, Args[Idx]); - - // Store the initial value into the alloca. - C.getBuilder().CreateStore(&*AI, Alloca); - - // Add arguments to variable symbol table. - C.NamedValues[Args[Idx]] = Alloca; - } -} - -Function *FunctionAST::IRGen(IRGenContext &C) const { - C.NamedValues.clear(); - - Function *TheFunction = Proto->IRGen(C); - if (!TheFunction) - return nullptr; - - // If this is an operator, install it. - if (Proto->isBinaryOp()) - BinopPrecedence[Proto->getOperatorName()] = Proto->Precedence; - - // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); - C.getBuilder().SetInsertPoint(BB); - - // Add all arguments to the symbol table and create their allocas. - Proto->CreateArgumentAllocas(TheFunction, C); - - if (Value *RetVal = Body->IRGen(C)) { - // Finish off the function. - C.getBuilder().CreateRet(RetVal); - - // Validate the generated code, checking for consistency. - verifyFunction(*TheFunction); - - return TheFunction; - } - - // Error reading body, remove function. - TheFunction->eraseFromParent(); - - if (Proto->isBinaryOp()) - BinopPrecedence.erase(Proto->getOperatorName()); - return nullptr; -} - -//===----------------------------------------------------------------------===// -// Top-Level parsing and JIT Driver -//===----------------------------------------------------------------------===// - -static std::unique_ptr IRGen(SessionContext &S, - const FunctionAST &F) { - IRGenContext C(S); - auto LF = F.IRGen(C); - if (!LF) - return nullptr; -#ifndef MINIMAL_STDERR_OUTPUT - fprintf(stderr, "Read function definition:"); - LF->dump(); -#endif - return C.takeM(); -} - -template -static std::vector singletonSet(T t) { - std::vector Vec; - Vec.push_back(std::move(t)); - return Vec; -} - -static void EarthShatteringKaboom() { - fprintf(stderr, "Earth shattering kaboom."); - exit(1); -} - -class KaleidoscopeJIT { -public: - typedef ObjectLinkingLayer<> ObjLayerT; - typedef IRCompileLayer CompileLayerT; - typedef LazyEmittingLayer LazyEmitLayerT; - typedef LazyEmitLayerT::ModuleSetHandleT ModuleHandleT; - - KaleidoscopeJIT(SessionContext &Session) - : Session(Session), - CompileLayer(ObjectLayer, SimpleCompiler(Session.getTarget())), - LazyEmitLayer(CompileLayer), - CompileCallbacks(reinterpret_cast(EarthShatteringKaboom)) {} - - std::string mangle(const std::string &Name) { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, - Session.getTarget().createDataLayout()); - } - return MangledName; - } - - void addFunctionAST(std::unique_ptr FnAST) { - std::cerr << "Adding AST: " << FnAST->Proto->Name << "\n"; - FunctionDefs[mangle(FnAST->Proto->Name)] = std::move(FnAST); - } - - ModuleHandleT addModule(std::unique_ptr M) { - // We need a memory manager to allocate memory and resolve symbols for this - // new module. Create one that resolves symbols by looking back into the - // JIT. - auto Resolver = createLambdaResolver( - [&](const std::string &Name) { - // First try to find 'Name' within the JIT. - if (auto Symbol = findSymbol(Name)) - return RuntimeDyld::SymbolInfo(Symbol.getAddress(), - Symbol.getFlags()); - - // If we don't already have a definition of 'Name' then search - // the ASTs. - return searchFunctionASTs(Name); - }, - [](const std::string &S) { return nullptr; } ); - - return LazyEmitLayer.addModuleSet(singletonSet(std::move(M)), - make_unique(), - std::move(Resolver)); - } - - void removeModule(ModuleHandleT H) { LazyEmitLayer.removeModuleSet(H); } - - JITSymbol findSymbol(const std::string &Name) { - return LazyEmitLayer.findSymbol(Name, false); - } - - JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name) { - return LazyEmitLayer.findSymbolIn(H, Name, false); - } - - JITSymbol findUnmangledSymbol(const std::string &Name) { - return findSymbol(mangle(Name)); - } - - JITSymbol findUnmangledSymbolIn(ModuleHandleT H, const std::string &Name) { - return findSymbolIn(H, mangle(Name)); - } - -private: - - // This method searches the FunctionDefs map for a definition of 'Name'. If it - // finds one it generates a stub for it and returns the address of the stub. - RuntimeDyld::SymbolInfo searchFunctionASTs(const std::string &Name) { - auto DefI = FunctionDefs.find(Name); - if (DefI == FunctionDefs.end()) - return nullptr; - - // Return the address of the stub. - // Take the FunctionAST out of the map. - auto FnAST = std::move(DefI->second); - FunctionDefs.erase(DefI); - - // IRGen the AST, add it to the JIT, and return the address for it. - auto H = irGenStub(std::move(FnAST)); - auto Sym = findSymbolIn(H, Name); - return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); - } - - // This method will take the AST for a function definition and IR-gen a stub - // for that function that will, on first call, IR-gen the actual body of the - // function. - ModuleHandleT irGenStub(std::unique_ptr FnAST) { - // Step 1) IRGen a prototype for the stub. This will have the same type as - // the function. - IRGenContext C(Session); - Function *F = FnAST->Proto->IRGen(C); - - // Step 2) Get a compile callback that can be used to compile the body of - // the function. The resulting CallbackInfo type will let us set the - // compile and update actions for the callback, and get a pointer to - // the jit trampoline that we need to call to trigger those actions. - auto CallbackInfo = CompileCallbacks.getCompileCallback(); - - // Step 3) Create a stub that will indirectly call the body of this - // function once it is compiled. Initially, set the function - // pointer for the indirection to point at the trampoline. - std::string BodyPtrName = (F->getName() + "$address").str(); - GlobalVariable *FunctionBodyPointer = - createImplPointer(*F->getType(), *F->getParent(), BodyPtrName, - createIRTypedAddress(*F->getFunctionType(), - CallbackInfo.getAddress())); - makeStub(*F, *FunctionBodyPointer); - - // Step 4) Add the module containing the stub to the JIT. - auto StubH = addModule(C.takeM()); - - // Step 5) Set the compile and update actions. - // - // The compile action will IRGen the function and add it to the JIT, then - // request its address, which will trigger codegen. Since we don't need the - // AST after this, we pass ownership of the AST into the compile action: - // compile actions (and update actions) are deleted after they're run, so - // this will free the AST for us. - // - // The update action will update FunctionBodyPointer to point at the newly - // compiled function. - std::shared_ptr Fn = std::move(FnAST); - CallbackInfo.setCompileAction([this, Fn, BodyPtrName, StubH]() { - auto H = addModule(IRGen(Session, *Fn)); - auto BodySym = findUnmangledSymbolIn(H, Fn->Proto->Name); - auto BodyPtrSym = findUnmangledSymbolIn(StubH, BodyPtrName); - assert(BodySym && "Missing function body."); - assert(BodyPtrSym && "Missing function pointer."); - auto BodyAddr = BodySym.getAddress(); - auto BodyPtr = reinterpret_cast( - static_cast(BodyPtrSym.getAddress())); - memcpy(BodyPtr, &BodyAddr, sizeof(uintptr_t)); - return BodyAddr; - }); - - return StubH; - } - - SessionContext &Session; - SectionMemoryManager CCMgrMemMgr; - ObjLayerT ObjectLayer; - CompileLayerT CompileLayer; - LazyEmitLayerT LazyEmitLayer; - - std::map> FunctionDefs; - - LocalJITCompileCallbackManager CompileCallbacks; -}; - -static void HandleDefinition(SessionContext &S, KaleidoscopeJIT &J) { - if (auto F = ParseDefinition()) { - S.addPrototypeAST(llvm::make_unique(*F->Proto)); - J.addFunctionAST(std::move(F)); - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -static void HandleExtern(SessionContext &S) { - if (auto P = ParseExtern()) - S.addPrototypeAST(std::move(P)); - else { - // Skip token for error recovery. - getNextToken(); - } -} - -static void HandleTopLevelExpression(SessionContext &S, KaleidoscopeJIT &J) { - // Evaluate a top-level expression into an anonymous function. - if (auto F = ParseTopLevelExpr()) { - IRGenContext C(S); - if (auto ExprFunc = F->IRGen(C)) { -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "Expression function:\n"; - ExprFunc->dump(); -#endif - // Add the CodeGen'd module to the JIT. Keep a handle to it: We can remove - // this module as soon as we've executed Function ExprFunc. - auto H = J.addModule(C.takeM()); - - // Get the address of the JIT'd function in memory. - auto ExprSymbol = J.findUnmangledSymbol("__anon_expr"); - - // Cast it to the right type (takes no arguments, returns a double) so we - // can call it as a native function. - double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); -#ifdef MINIMAL_STDERR_OUTPUT - FP(); -#else - std::cerr << "Evaluated to " << FP() << "\n"; -#endif - - // Remove the function. - J.removeModule(H); - } - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -/// top ::= definition | external | expression | ';' -static void MainLoop() { - SessionContext S(getGlobalContext()); - KaleidoscopeJIT J(S); - - while (1) { - switch (CurTok) { - case tok_eof: return; - case ';': getNextToken(); continue; // ignore top-level semicolons. - case tok_def: HandleDefinition(S, J); break; - case tok_extern: HandleExtern(S); break; - default: HandleTopLevelExpression(S, J); break; - } -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "ready> "; -#endif - } -} - -//===----------------------------------------------------------------------===// -// "Library" functions that can be "extern'd" from user code. -//===----------------------------------------------------------------------===// - -/// putchard - putchar that takes a double and returns 0. -extern "C" -double putchard(double X) { - putchar((char)X); - return 0; -} - -/// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" -double printd(double X) { - printf("%f", X); - return 0; -} - -extern "C" -double printlf() { - printf("\n"); - return 0; -} - -//===----------------------------------------------------------------------===// -// Main driver code. -//===----------------------------------------------------------------------===// - -int main() { - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetAsmParser(); - - // Install standard binary operators. - // 1 is lowest precedence. - BinopPrecedence['='] = 2; - BinopPrecedence['<'] = 10; - BinopPrecedence['+'] = 20; - BinopPrecedence['-'] = 20; - BinopPrecedence['/'] = 40; - BinopPrecedence['*'] = 40; // highest. - - // Prime the first token. -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "ready> "; -#endif - getNextToken(); - - std::cerr << std::fixed; - - // Run the main "interpreter loop" now. - MainLoop(); - - return 0; -} diff --git a/examples/Kaleidoscope/Orc/initial/CMakeLists.txt b/examples/Kaleidoscope/Orc/initial/CMakeLists.txt deleted file mode 100644 index 4f21e1c622186461f67955474987dcecaeca13fd..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/initial/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Core - ExecutionEngine - Object - RuntimeDyld - Support - native - ) - -add_kaleidoscope_chapter(Kaleidoscope-Orc-initial - toy.cpp - ) diff --git a/examples/Kaleidoscope/Orc/initial/README.txt b/examples/Kaleidoscope/Orc/initial/README.txt deleted file mode 100644 index 5f4cbbfe3d2c880672699f7c34d25a8b910586ed..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/initial/README.txt +++ /dev/null @@ -1,13 +0,0 @@ -//===----------------------------------------------------------------------===/ -// Kaleidoscope with Orc - Initial Version -//===----------------------------------------------------------------------===// - -This version of Kaleidoscope with Orc demonstrates fully eager compilation. When -a function definition or top-level expression is entered it is immediately -translated (IRGen'd) to LLVM IR and added to the JIT, where it is code-gen'd to -native code and either stored (for function definitions) or executed (for -top-level expressions). - -This directory contain a Makefile that allow the code to be built in a -standalone manner, independent of the larger LLVM build infrastructure. To build -the program you will need to have 'clang++' and 'llvm-config' in your path. diff --git a/examples/Kaleidoscope/Orc/initial/toy.cpp b/examples/Kaleidoscope/Orc/initial/toy.cpp deleted file mode 100644 index 2a6bb92246d04a5a090ed2c4dd673d4a43e6d900..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/initial/toy.cpp +++ /dev/null @@ -1,1335 +0,0 @@ -#include "llvm/Analysis/Passes.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" -#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" -#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Transforms/Scalar.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace llvm; -using namespace llvm::orc; - -//===----------------------------------------------------------------------===// -// Lexer -//===----------------------------------------------------------------------===// - -// The lexer returns tokens [0-255] if it is an unknown character, otherwise one -// of these for known things. -enum Token { - tok_eof = -1, - - // commands - tok_def = -2, tok_extern = -3, - - // primary - tok_identifier = -4, tok_number = -5, - - // control - tok_if = -6, tok_then = -7, tok_else = -8, - tok_for = -9, tok_in = -10, - - // operators - tok_binary = -11, tok_unary = -12, - - // var definition - tok_var = -13 -}; - -static std::string IdentifierStr; // Filled in if tok_identifier -static double NumVal; // Filled in if tok_number - -/// gettok - Return the next token from standard input. -static int gettok() { - static int LastChar = ' '; - - // Skip any whitespace. - while (isspace(LastChar)) - LastChar = getchar(); - - if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* - IdentifierStr = LastChar; - while (isalnum((LastChar = getchar()))) - IdentifierStr += LastChar; - - if (IdentifierStr == "def") return tok_def; - if (IdentifierStr == "extern") return tok_extern; - if (IdentifierStr == "if") return tok_if; - if (IdentifierStr == "then") return tok_then; - if (IdentifierStr == "else") return tok_else; - if (IdentifierStr == "for") return tok_for; - if (IdentifierStr == "in") return tok_in; - if (IdentifierStr == "binary") return tok_binary; - if (IdentifierStr == "unary") return tok_unary; - if (IdentifierStr == "var") return tok_var; - return tok_identifier; - } - - if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ - std::string NumStr; - do { - NumStr += LastChar; - LastChar = getchar(); - } while (isdigit(LastChar) || LastChar == '.'); - - NumVal = strtod(NumStr.c_str(), nullptr); - return tok_number; - } - - if (LastChar == '#') { - // Comment until end of line. - do LastChar = getchar(); - while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); - - if (LastChar != EOF) - return gettok(); - } - - // Check for end of file. Don't eat the EOF. - if (LastChar == EOF) - return tok_eof; - - // Otherwise, just return the character as its ascii value. - int ThisChar = LastChar; - LastChar = getchar(); - return ThisChar; -} - -//===----------------------------------------------------------------------===// -// Abstract Syntax Tree (aka Parse Tree) -//===----------------------------------------------------------------------===// - -class IRGenContext; - -/// ExprAST - Base class for all expression nodes. -struct ExprAST { - virtual ~ExprAST() {} - virtual Value *IRGen(IRGenContext &C) const = 0; -}; - -/// NumberExprAST - Expression class for numeric literals like "1.0". -struct NumberExprAST : public ExprAST { - NumberExprAST(double Val) : Val(Val) {} - Value *IRGen(IRGenContext &C) const override; - - double Val; -}; - -/// VariableExprAST - Expression class for referencing a variable, like "a". -struct VariableExprAST : public ExprAST { - VariableExprAST(std::string Name) : Name(std::move(Name)) {} - Value *IRGen(IRGenContext &C) const override; - - std::string Name; -}; - -/// UnaryExprAST - Expression class for a unary operator. -struct UnaryExprAST : public ExprAST { - UnaryExprAST(char Opcode, std::unique_ptr Operand) - : Opcode(std::move(Opcode)), Operand(std::move(Operand)) {} - - Value *IRGen(IRGenContext &C) const override; - - char Opcode; - std::unique_ptr Operand; -}; - -/// BinaryExprAST - Expression class for a binary operator. -struct BinaryExprAST : public ExprAST { - BinaryExprAST(char Op, std::unique_ptr LHS, - std::unique_ptr RHS) - : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} - - Value *IRGen(IRGenContext &C) const override; - - char Op; - std::unique_ptr LHS, RHS; -}; - -/// CallExprAST - Expression class for function calls. -struct CallExprAST : public ExprAST { - CallExprAST(std::string CalleeName, - std::vector> Args) - : CalleeName(std::move(CalleeName)), Args(std::move(Args)) {} - - Value *IRGen(IRGenContext &C) const override; - - std::string CalleeName; - std::vector> Args; -}; - -/// IfExprAST - Expression class for if/then/else. -struct IfExprAST : public ExprAST { - IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, - std::unique_ptr Else) - : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} - Value *IRGen(IRGenContext &C) const override; - - std::unique_ptr Cond, Then, Else; -}; - -/// ForExprAST - Expression class for for/in. -struct ForExprAST : public ExprAST { - ForExprAST(std::string VarName, std::unique_ptr Start, - std::unique_ptr End, std::unique_ptr Step, - std::unique_ptr Body) - : VarName(std::move(VarName)), Start(std::move(Start)), End(std::move(End)), - Step(std::move(Step)), Body(std::move(Body)) {} - - Value *IRGen(IRGenContext &C) const override; - - std::string VarName; - std::unique_ptr Start, End, Step, Body; -}; - -/// VarExprAST - Expression class for var/in -struct VarExprAST : public ExprAST { - typedef std::pair> Binding; - typedef std::vector BindingList; - - VarExprAST(BindingList VarBindings, std::unique_ptr Body) - : VarBindings(std::move(VarBindings)), Body(std::move(Body)) {} - - Value *IRGen(IRGenContext &C) const override; - - BindingList VarBindings; - std::unique_ptr Body; -}; - -/// PrototypeAST - This class represents the "prototype" for a function, -/// which captures its argument names as well as if it is an operator. -struct PrototypeAST { - PrototypeAST(std::string Name, std::vector Args, - bool IsOperator = false, unsigned Precedence = 0) - : Name(std::move(Name)), Args(std::move(Args)), IsOperator(IsOperator), - Precedence(Precedence) {} - - Function *IRGen(IRGenContext &C) const; - void CreateArgumentAllocas(Function *F, IRGenContext &C); - - bool isUnaryOp() const { return IsOperator && Args.size() == 1; } - bool isBinaryOp() const { return IsOperator && Args.size() == 2; } - - char getOperatorName() const { - assert(isUnaryOp() || isBinaryOp()); - return Name[Name.size()-1]; - } - - std::string Name; - std::vector Args; - bool IsOperator; - unsigned Precedence; // Precedence if a binary op. -}; - -/// FunctionAST - This class represents a function definition itself. -struct FunctionAST { - FunctionAST(std::unique_ptr Proto, - std::unique_ptr Body) - : Proto(std::move(Proto)), Body(std::move(Body)) {} - - Function *IRGen(IRGenContext &C) const; - - std::unique_ptr Proto; - std::unique_ptr Body; -}; - -//===----------------------------------------------------------------------===// -// Parser -//===----------------------------------------------------------------------===// - -/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current -/// token the parser is looking at. getNextToken reads another token from the -/// lexer and updates CurTok with its results. -static int CurTok; -static int getNextToken() { - return CurTok = gettok(); -} - -/// BinopPrecedence - This holds the precedence for each binary operator that is -/// defined. -static std::map BinopPrecedence; - -/// GetTokPrecedence - Get the precedence of the pending binary operator token. -static int GetTokPrecedence() { - if (!isascii(CurTok)) - return -1; - - // Make sure it's a declared binop. - int TokPrec = BinopPrecedence[CurTok]; - if (TokPrec <= 0) return -1; - return TokPrec; -} - -template -std::unique_ptr ErrorU(const std::string &Str) { - std::cerr << "Error: " << Str << "\n"; - return nullptr; -} - -template -T* ErrorP(const std::string &Str) { - std::cerr << "Error: " << Str << "\n"; - return nullptr; -} - -static std::unique_ptr ParseExpression(); - -/// identifierexpr -/// ::= identifier -/// ::= identifier '(' expression* ')' -static std::unique_ptr ParseIdentifierExpr() { - std::string IdName = IdentifierStr; - - getNextToken(); // eat identifier. - - if (CurTok != '(') // Simple variable ref. - return llvm::make_unique(IdName); - - // Call. - getNextToken(); // eat ( - std::vector> Args; - if (CurTok != ')') { - while (1) { - auto Arg = ParseExpression(); - if (!Arg) return nullptr; - Args.push_back(std::move(Arg)); - - if (CurTok == ')') break; - - if (CurTok != ',') - return ErrorU("Expected ')' or ',' in argument list"); - getNextToken(); - } - } - - // Eat the ')'. - getNextToken(); - - return llvm::make_unique(IdName, std::move(Args)); -} - -/// numberexpr ::= number -static std::unique_ptr ParseNumberExpr() { - auto Result = llvm::make_unique(NumVal); - getNextToken(); // consume the number - return Result; -} - -/// parenexpr ::= '(' expression ')' -static std::unique_ptr ParseParenExpr() { - getNextToken(); // eat (. - auto V = ParseExpression(); - if (!V) - return nullptr; - - if (CurTok != ')') - return ErrorU("expected ')'"); - getNextToken(); // eat ). - return V; -} - -/// ifexpr ::= 'if' expression 'then' expression 'else' expression -static std::unique_ptr ParseIfExpr() { - getNextToken(); // eat the if. - - // condition. - auto Cond = ParseExpression(); - if (!Cond) - return nullptr; - - if (CurTok != tok_then) - return ErrorU("expected then"); - getNextToken(); // eat the then - - auto Then = ParseExpression(); - if (!Then) - return nullptr; - - if (CurTok != tok_else) - return ErrorU("expected else"); - - getNextToken(); - - auto Else = ParseExpression(); - if (!Else) - return nullptr; - - return llvm::make_unique(std::move(Cond), std::move(Then), - std::move(Else)); -} - -/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression -static std::unique_ptr ParseForExpr() { - getNextToken(); // eat the for. - - if (CurTok != tok_identifier) - return ErrorU("expected identifier after for"); - - std::string IdName = IdentifierStr; - getNextToken(); // eat identifier. - - if (CurTok != '=') - return ErrorU("expected '=' after for"); - getNextToken(); // eat '='. - - auto Start = ParseExpression(); - if (!Start) - return nullptr; - if (CurTok != ',') - return ErrorU("expected ',' after for start value"); - getNextToken(); - - auto End = ParseExpression(); - if (!End) - return nullptr; - - // The step value is optional. - std::unique_ptr Step; - if (CurTok == ',') { - getNextToken(); - Step = ParseExpression(); - if (!Step) - return nullptr; - } - - if (CurTok != tok_in) - return ErrorU("expected 'in' after for"); - getNextToken(); // eat 'in'. - - auto Body = ParseExpression(); - if (Body) - return nullptr; - - return llvm::make_unique(IdName, std::move(Start), std::move(End), - std::move(Step), std::move(Body)); -} - -/// varexpr ::= 'var' identifier ('=' expression)? -// (',' identifier ('=' expression)?)* 'in' expression -static std::unique_ptr ParseVarExpr() { - getNextToken(); // eat the var. - - VarExprAST::BindingList VarBindings; - - // At least one variable name is required. - if (CurTok != tok_identifier) - return ErrorU("expected identifier after var"); - - while (1) { - std::string Name = IdentifierStr; - getNextToken(); // eat identifier. - - // Read the optional initializer. - std::unique_ptr Init; - if (CurTok == '=') { - getNextToken(); // eat the '='. - - Init = ParseExpression(); - if (!Init) - return nullptr; - } - - VarBindings.push_back(VarExprAST::Binding(Name, std::move(Init))); - - // End of var list, exit loop. - if (CurTok != ',') break; - getNextToken(); // eat the ','. - - if (CurTok != tok_identifier) - return ErrorU("expected identifier list after var"); - } - - // At this point, we have to have 'in'. - if (CurTok != tok_in) - return ErrorU("expected 'in' keyword after 'var'"); - getNextToken(); // eat 'in'. - - auto Body = ParseExpression(); - if (!Body) - return nullptr; - - return llvm::make_unique(std::move(VarBindings), std::move(Body)); -} - -/// primary -/// ::= identifierexpr -/// ::= numberexpr -/// ::= parenexpr -/// ::= ifexpr -/// ::= forexpr -/// ::= varexpr -static std::unique_ptr ParsePrimary() { - switch (CurTok) { - default: return ErrorU("unknown token when expecting an expression"); - case tok_identifier: return ParseIdentifierExpr(); - case tok_number: return ParseNumberExpr(); - case '(': return ParseParenExpr(); - case tok_if: return ParseIfExpr(); - case tok_for: return ParseForExpr(); - case tok_var: return ParseVarExpr(); - } -} - -/// unary -/// ::= primary -/// ::= '!' unary -static std::unique_ptr ParseUnary() { - // If the current token is not an operator, it must be a primary expr. - if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') - return ParsePrimary(); - - // If this is a unary operator, read it. - int Opc = CurTok; - getNextToken(); - if (auto Operand = ParseUnary()) - return llvm::make_unique(Opc, std::move(Operand)); - return nullptr; -} - -/// binoprhs -/// ::= ('+' unary)* -static std::unique_ptr ParseBinOpRHS(int ExprPrec, - std::unique_ptr LHS) { - // If this is a binop, find its precedence. - while (1) { - int TokPrec = GetTokPrecedence(); - - // If this is a binop that binds at least as tightly as the current binop, - // consume it, otherwise we are done. - if (TokPrec < ExprPrec) - return LHS; - - // Okay, we know this is a binop. - int BinOp = CurTok; - getNextToken(); // eat binop - - // Parse the unary expression after the binary operator. - auto RHS = ParseUnary(); - if (!RHS) - return nullptr; - - // If BinOp binds less tightly with RHS than the operator after RHS, let - // the pending operator take RHS as its LHS. - int NextPrec = GetTokPrecedence(); - if (TokPrec < NextPrec) { - RHS = ParseBinOpRHS(TokPrec+1, std::move(RHS)); - if (!RHS) - return nullptr; - } - - // Merge LHS/RHS. - LHS = llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); - } -} - -/// expression -/// ::= unary binoprhs -/// -static std::unique_ptr ParseExpression() { - auto LHS = ParseUnary(); - if (!LHS) - return nullptr; - - return ParseBinOpRHS(0, std::move(LHS)); -} - -/// prototype -/// ::= id '(' id* ')' -/// ::= binary LETTER number? (id, id) -/// ::= unary LETTER (id) -static std::unique_ptr ParsePrototype() { - std::string FnName; - - unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. - unsigned BinaryPrecedence = 30; - - switch (CurTok) { - default: - return ErrorU("Expected function name in prototype"); - case tok_identifier: - FnName = IdentifierStr; - Kind = 0; - getNextToken(); - break; - case tok_unary: - getNextToken(); - if (!isascii(CurTok)) - return ErrorU("Expected unary operator"); - FnName = "unary"; - FnName += (char)CurTok; - Kind = 1; - getNextToken(); - break; - case tok_binary: - getNextToken(); - if (!isascii(CurTok)) - return ErrorU("Expected binary operator"); - FnName = "binary"; - FnName += (char)CurTok; - Kind = 2; - getNextToken(); - - // Read the precedence if present. - if (CurTok == tok_number) { - if (NumVal < 1 || NumVal > 100) - return ErrorU("Invalid precedecnce: must be 1..100"); - BinaryPrecedence = (unsigned)NumVal; - getNextToken(); - } - break; - } - - if (CurTok != '(') - return ErrorU("Expected '(' in prototype"); - - std::vector ArgNames; - while (getNextToken() == tok_identifier) - ArgNames.push_back(IdentifierStr); - if (CurTok != ')') - return ErrorU("Expected ')' in prototype"); - - // success. - getNextToken(); // eat ')'. - - // Verify right number of names for operator. - if (Kind && ArgNames.size() != Kind) - return ErrorU("Invalid number of operands for operator"); - - return llvm::make_unique(FnName, std::move(ArgNames), Kind != 0, - BinaryPrecedence); -} - -/// definition ::= 'def' prototype expression -static std::unique_ptr ParseDefinition() { - getNextToken(); // eat def. - auto Proto = ParsePrototype(); - if (!Proto) - return nullptr; - - if (auto Body = ParseExpression()) - return llvm::make_unique(std::move(Proto), std::move(Body)); - return nullptr; -} - -/// toplevelexpr ::= expression -static std::unique_ptr ParseTopLevelExpr() { - if (auto E = ParseExpression()) { - // Make an anonymous proto. - auto Proto = - llvm::make_unique("__anon_expr", std::vector()); - return llvm::make_unique(std::move(Proto), std::move(E)); - } - return nullptr; -} - -/// external ::= 'extern' prototype -static std::unique_ptr ParseExtern() { - getNextToken(); // eat extern. - return ParsePrototype(); -} - -//===----------------------------------------------------------------------===// -// Code Generation -//===----------------------------------------------------------------------===// - -// FIXME: Obviously we can do better than this -std::string GenerateUniqueName(const std::string &Root) { - static int i = 0; - std::ostringstream NameStream; - NameStream << Root << ++i; - return NameStream.str(); -} - -std::string MakeLegalFunctionName(std::string Name) -{ - std::string NewName; - assert(!Name.empty() && "Base name must not be empty"); - - // Start with what we have - NewName = Name; - - // Look for a numberic first character - if (NewName.find_first_of("0123456789") == 0) { - NewName.insert(0, 1, 'n'); - } - - // Replace illegal characters with their ASCII equivalent - std::string legal_elements = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - size_t pos; - while ((pos = NewName.find_first_not_of(legal_elements)) != std::string::npos) { - std::ostringstream NumStream; - NumStream << (int)NewName.at(pos); - NewName = NewName.replace(pos, 1, NumStream.str()); - } - - return NewName; -} - -class SessionContext { -public: - SessionContext(LLVMContext &C) - : Context(C), TM(EngineBuilder().selectTarget()) {} - LLVMContext& getLLVMContext() const { return Context; } - TargetMachine& getTarget() { return *TM; } - void addPrototypeAST(std::unique_ptr P); - PrototypeAST* getPrototypeAST(const std::string &Name); -private: - typedef std::map> PrototypeMap; - - LLVMContext &Context; - std::unique_ptr TM; - - PrototypeMap Prototypes; -}; - -void SessionContext::addPrototypeAST(std::unique_ptr P) { - Prototypes[P->Name] = std::move(P); -} - -PrototypeAST* SessionContext::getPrototypeAST(const std::string &Name) { - PrototypeMap::iterator I = Prototypes.find(Name); - if (I != Prototypes.end()) - return I->second.get(); - return nullptr; -} - -class IRGenContext { -public: - - IRGenContext(SessionContext &S) - : Session(S), - M(new Module(GenerateUniqueName("jit_module_"), - Session.getLLVMContext())), - Builder(Session.getLLVMContext()) { - M->setDataLayout(Session.getTarget().createDataLayout()); - } - - SessionContext& getSession() { return Session; } - Module& getM() const { return *M; } - std::unique_ptr takeM() { return std::move(M); } - IRBuilder<>& getBuilder() { return Builder; } - LLVMContext& getLLVMContext() { return Session.getLLVMContext(); } - Function* getPrototype(const std::string &Name); - - std::map NamedValues; -private: - SessionContext &Session; - std::unique_ptr M; - IRBuilder<> Builder; -}; - -Function* IRGenContext::getPrototype(const std::string &Name) { - if (Function *ExistingProto = M->getFunction(Name)) - return ExistingProto; - if (PrototypeAST *ProtoAST = Session.getPrototypeAST(Name)) - return ProtoAST->IRGen(*this); - return nullptr; -} - -/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of -/// the function. This is used for mutable variables etc. -static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, - const std::string &VarName) { - IRBuilder<> TmpB(&TheFunction->getEntryBlock(), - TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), nullptr, - VarName.c_str()); -} - -Value *NumberExprAST::IRGen(IRGenContext &C) const { - return ConstantFP::get(C.getLLVMContext(), APFloat(Val)); -} - -Value *VariableExprAST::IRGen(IRGenContext &C) const { - // Look this variable up in the function. - Value *V = C.NamedValues[Name]; - - if (!V) - return ErrorP("Unknown variable name '" + Name + "'"); - - // Load the value. - return C.getBuilder().CreateLoad(V, Name.c_str()); -} - -Value *UnaryExprAST::IRGen(IRGenContext &C) const { - if (Value *OperandV = Operand->IRGen(C)) { - std::string FnName = MakeLegalFunctionName(std::string("unary")+Opcode); - if (Function *F = C.getPrototype(FnName)) - return C.getBuilder().CreateCall(F, OperandV, "unop"); - return ErrorP("Unknown unary operator"); - } - - // Could not codegen operand - return null. - return nullptr; -} - -Value *BinaryExprAST::IRGen(IRGenContext &C) const { - // Special case '=' because we don't want to emit the LHS as an expression. - if (Op == '=') { - // Assignment requires the LHS to be an identifier. - auto &LHSVar = static_cast(*LHS); - // Codegen the RHS. - Value *Val = RHS->IRGen(C); - if (!Val) return nullptr; - - // Look up the name. - if (auto Variable = C.NamedValues[LHSVar.Name]) { - C.getBuilder().CreateStore(Val, Variable); - return Val; - } - return ErrorP("Unknown variable name"); - } - - Value *L = LHS->IRGen(C); - Value *R = RHS->IRGen(C); - if (!L || !R) return nullptr; - - switch (Op) { - case '+': return C.getBuilder().CreateFAdd(L, R, "addtmp"); - case '-': return C.getBuilder().CreateFSub(L, R, "subtmp"); - case '*': return C.getBuilder().CreateFMul(L, R, "multmp"); - case '/': return C.getBuilder().CreateFDiv(L, R, "divtmp"); - case '<': - L = C.getBuilder().CreateFCmpULT(L, R, "cmptmp"); - // Convert bool 0/1 to double 0.0 or 1.0 - return C.getBuilder().CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); - default: break; - } - - // If it wasn't a builtin binary operator, it must be a user defined one. Emit - // a call to it. - std::string FnName = MakeLegalFunctionName(std::string("binary")+Op); - if (Function *F = C.getPrototype(FnName)) { - Value *Ops[] = { L, R }; - return C.getBuilder().CreateCall(F, Ops, "binop"); - } - - return ErrorP("Unknown binary operator"); -} - -Value *CallExprAST::IRGen(IRGenContext &C) const { - // Look up the name in the global module table. - if (auto CalleeF = C.getPrototype(CalleeName)) { - // If argument mismatch error. - if (CalleeF->arg_size() != Args.size()) - return ErrorP("Incorrect # arguments passed"); - - std::vector ArgsV; - for (unsigned i = 0, e = Args.size(); i != e; ++i) { - ArgsV.push_back(Args[i]->IRGen(C)); - if (!ArgsV.back()) return nullptr; - } - - return C.getBuilder().CreateCall(CalleeF, ArgsV, "calltmp"); - } - - return ErrorP("Unknown function referenced"); -} - -Value *IfExprAST::IRGen(IRGenContext &C) const { - Value *CondV = Cond->IRGen(C); - if (!CondV) return nullptr; - - // Convert condition to a bool by comparing equal to 0.0. - ConstantFP *FPZero = - ConstantFP::get(C.getLLVMContext(), APFloat(0.0)); - CondV = C.getBuilder().CreateFCmpONE(CondV, FPZero, "ifcond"); - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Create blocks for the then and else cases. Insert the 'then' block at the - // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(C.getLLVMContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(C.getLLVMContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(C.getLLVMContext(), "ifcont"); - - C.getBuilder().CreateCondBr(CondV, ThenBB, ElseBB); - - // Emit then value. - C.getBuilder().SetInsertPoint(ThenBB); - - Value *ThenV = Then->IRGen(C); - if (!ThenV) return nullptr; - - C.getBuilder().CreateBr(MergeBB); - // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = C.getBuilder().GetInsertBlock(); - - // Emit else block. - TheFunction->getBasicBlockList().push_back(ElseBB); - C.getBuilder().SetInsertPoint(ElseBB); - - Value *ElseV = Else->IRGen(C); - if (!ElseV) return nullptr; - - C.getBuilder().CreateBr(MergeBB); - // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = C.getBuilder().GetInsertBlock(); - - // Emit merge block. - TheFunction->getBasicBlockList().push_back(MergeBB); - C.getBuilder().SetInsertPoint(MergeBB); - PHINode *PN = C.getBuilder().CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, - "iftmp"); - - PN->addIncoming(ThenV, ThenBB); - PN->addIncoming(ElseV, ElseBB); - return PN; -} - -Value *ForExprAST::IRGen(IRGenContext &C) const { - // Output this as: - // var = alloca double - // ... - // start = startexpr - // store start -> var - // goto loop - // loop: - // ... - // bodyexpr - // ... - // loopend: - // step = stepexpr - // endcond = endexpr - // - // curvar = load var - // nextvar = curvar + step - // store nextvar -> var - // br endcond, loop, endloop - // outloop: - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Create an alloca for the variable in the entry block. - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - - // Emit the start code first, without 'variable' in scope. - Value *StartVal = Start->IRGen(C); - if (!StartVal) return nullptr; - - // Store the value into the alloca. - C.getBuilder().CreateStore(StartVal, Alloca); - - // Make the new basic block for the loop header, inserting after current - // block. - BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); - - // Insert an explicit fall through from the current block to the LoopBB. - C.getBuilder().CreateBr(LoopBB); - - // Start insertion in LoopBB. - C.getBuilder().SetInsertPoint(LoopBB); - - // Within the loop, the variable is defined equal to the PHI node. If it - // shadows an existing variable, we have to restore it, so save it now. - AllocaInst *OldVal = C.NamedValues[VarName]; - C.NamedValues[VarName] = Alloca; - - // Emit the body of the loop. This, like any other expr, can change the - // current BB. Note that we ignore the value computed by the body, but don't - // allow an error. - if (!Body->IRGen(C)) - return nullptr; - - // Emit the step value. - Value *StepVal; - if (Step) { - StepVal = Step->IRGen(C); - if (!StepVal) return nullptr; - } else { - // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); - } - - // Compute the end condition. - Value *EndCond = End->IRGen(C); - if (!EndCond) return nullptr; - - // Reload, increment, and restore the alloca. This handles the case where - // the body of the loop mutates the variable. - Value *CurVar = C.getBuilder().CreateLoad(Alloca, VarName.c_str()); - Value *NextVar = C.getBuilder().CreateFAdd(CurVar, StepVal, "nextvar"); - C.getBuilder().CreateStore(NextVar, Alloca); - - // Convert condition to a bool by comparing equal to 0.0. - EndCond = C.getBuilder().CreateFCmpONE(EndCond, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "loopcond"); - - // Create the "after loop" block and insert it. - BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); - - // Insert the conditional branch into the end of LoopEndBB. - C.getBuilder().CreateCondBr(EndCond, LoopBB, AfterBB); - - // Any new code will be inserted in AfterBB. - C.getBuilder().SetInsertPoint(AfterBB); - - // Restore the unshadowed variable. - if (OldVal) - C.NamedValues[VarName] = OldVal; - else - C.NamedValues.erase(VarName); - - // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); -} - -Value *VarExprAST::IRGen(IRGenContext &C) const { - std::vector OldBindings; - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Register all variables and emit their initializer. - for (unsigned i = 0, e = VarBindings.size(); i != e; ++i) { - auto &VarName = VarBindings[i].first; - auto &Init = VarBindings[i].second; - - // Emit the initializer before adding the variable to scope, this prevents - // the initializer from referencing the variable itself, and permits stuff - // like this: - // var a = 1 in - // var a = a in ... # refers to outer 'a'. - Value *InitVal; - if (Init) { - InitVal = Init->IRGen(C); - if (!InitVal) return nullptr; - } else // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); - - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - C.getBuilder().CreateStore(InitVal, Alloca); - - // Remember the old variable binding so that we can restore the binding when - // we unrecurse. - OldBindings.push_back(C.NamedValues[VarName]); - - // Remember this binding. - C.NamedValues[VarName] = Alloca; - } - - // Codegen the body, now that all vars are in scope. - Value *BodyVal = Body->IRGen(C); - if (!BodyVal) return nullptr; - - // Pop all our variables from scope. - for (unsigned i = 0, e = VarBindings.size(); i != e; ++i) - C.NamedValues[VarBindings[i].first] = OldBindings[i]; - - // Return the body computation. - return BodyVal; -} - -Function *PrototypeAST::IRGen(IRGenContext &C) const { - std::string FnName = MakeLegalFunctionName(Name); - - // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); - FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), - Doubles, false); - Function *F = Function::Create(FT, Function::ExternalLinkage, FnName, - &C.getM()); - - // If F conflicted, there was already something named 'FnName'. If it has a - // body, don't allow redefinition or reextern. - if (F->getName() != FnName) { - // Delete the one we just made and get the existing one. - F->eraseFromParent(); - F = C.getM().getFunction(Name); - - // If F already has a body, reject this. - if (!F->empty()) { - ErrorP("redefinition of function"); - return nullptr; - } - - // If F took a different number of args, reject. - if (F->arg_size() != Args.size()) { - ErrorP("redefinition of function with different # args"); - return nullptr; - } - } - - // Set names for all arguments. - unsigned Idx = 0; - for (Function::arg_iterator AI = F->arg_begin(); Idx != Args.size(); - ++AI, ++Idx) - AI->setName(Args[Idx]); - - return F; -} - -/// CreateArgumentAllocas - Create an alloca for each argument and register the -/// argument in the symbol table so that references to it will succeed. -void PrototypeAST::CreateArgumentAllocas(Function *F, IRGenContext &C) { - Function::arg_iterator AI = F->arg_begin(); - for (unsigned Idx = 0, e = Args.size(); Idx != e; ++Idx, ++AI) { - // Create an alloca for this variable. - AllocaInst *Alloca = CreateEntryBlockAlloca(F, Args[Idx]); - - // Store the initial value into the alloca. - C.getBuilder().CreateStore(&*AI, Alloca); - - // Add arguments to variable symbol table. - C.NamedValues[Args[Idx]] = Alloca; - } -} - -Function *FunctionAST::IRGen(IRGenContext &C) const { - C.NamedValues.clear(); - - Function *TheFunction = Proto->IRGen(C); - if (!TheFunction) - return nullptr; - - // If this is an operator, install it. - if (Proto->isBinaryOp()) - BinopPrecedence[Proto->getOperatorName()] = Proto->Precedence; - - // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); - C.getBuilder().SetInsertPoint(BB); - - // Add all arguments to the symbol table and create their allocas. - Proto->CreateArgumentAllocas(TheFunction, C); - - if (Value *RetVal = Body->IRGen(C)) { - // Finish off the function. - C.getBuilder().CreateRet(RetVal); - - // Validate the generated code, checking for consistency. - verifyFunction(*TheFunction); - - return TheFunction; - } - - // Error reading body, remove function. - TheFunction->eraseFromParent(); - - if (Proto->isBinaryOp()) - BinopPrecedence.erase(Proto->getOperatorName()); - return nullptr; -} - -//===----------------------------------------------------------------------===// -// Top-Level parsing and JIT Driver -//===----------------------------------------------------------------------===// - -static std::unique_ptr IRGen(SessionContext &S, - const FunctionAST &F) { - IRGenContext C(S); - auto LF = F.IRGen(C); - if (!LF) - return nullptr; -#ifndef MINIMAL_STDERR_OUTPUT - fprintf(stderr, "Read function definition:"); - LF->dump(); -#endif - return C.takeM(); -} - -template -static std::vector singletonSet(T t) { - std::vector Vec; - Vec.push_back(std::move(t)); - return Vec; -} - -class KaleidoscopeJIT { -public: - typedef ObjectLinkingLayer<> ObjLayerT; - typedef IRCompileLayer CompileLayerT; - typedef CompileLayerT::ModuleSetHandleT ModuleHandleT; - - KaleidoscopeJIT(SessionContext &Session) - : DL(Session.getTarget().createDataLayout()), - CompileLayer(ObjectLayer, SimpleCompiler(Session.getTarget())) {} - - std::string mangle(const std::string &Name) { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - } - return MangledName; - } - - ModuleHandleT addModule(std::unique_ptr M) { - // We need a memory manager to allocate memory and resolve symbols for this - // new module. Create one that resolves symbols by looking back into the - // JIT. - auto Resolver = createLambdaResolver( - [&](const std::string &Name) { - if (auto Sym = findSymbol(Name)) - return RuntimeDyld::SymbolInfo(Sym.getAddress(), - Sym.getFlags()); - return RuntimeDyld::SymbolInfo(nullptr); - }, - [](const std::string &S) { return nullptr; } - ); - return CompileLayer.addModuleSet(singletonSet(std::move(M)), - make_unique(), - std::move(Resolver)); - } - - void removeModule(ModuleHandleT H) { CompileLayer.removeModuleSet(H); } - - JITSymbol findSymbol(const std::string &Name) { - return CompileLayer.findSymbol(Name, true); - } - - JITSymbol findUnmangledSymbol(const std::string Name) { - return findSymbol(mangle(Name)); - } - -private: - const DataLayout DL; - ObjLayerT ObjectLayer; - CompileLayerT CompileLayer; -}; - -static void HandleDefinition(SessionContext &S, KaleidoscopeJIT &J) { - if (auto F = ParseDefinition()) { - if (auto M = IRGen(S, *F)) { - S.addPrototypeAST(llvm::make_unique(*F->Proto)); - J.addModule(std::move(M)); - } - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -static void HandleExtern(SessionContext &S) { - if (auto P = ParseExtern()) - S.addPrototypeAST(std::move(P)); - else { - // Skip token for error recovery. - getNextToken(); - } -} - -static void HandleTopLevelExpression(SessionContext &S, KaleidoscopeJIT &J) { - // Evaluate a top-level expression into an anonymous function. - if (auto F = ParseTopLevelExpr()) { - IRGenContext C(S); - if (auto ExprFunc = F->IRGen(C)) { -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "Expression function:\n"; - ExprFunc->dump(); -#endif - // Add the CodeGen'd module to the JIT. Keep a handle to it: We can remove - // this module as soon as we've executed Function ExprFunc. - auto H = J.addModule(C.takeM()); - - // Get the address of the JIT'd function in memory. - auto ExprSymbol = J.findUnmangledSymbol("__anon_expr"); - - // Cast it to the right type (takes no arguments, returns a double) so we - // can call it as a native function. - double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); -#ifdef MINIMAL_STDERR_OUTPUT - FP(); -#else - std::cerr << "Evaluated to " << FP() << "\n"; -#endif - - // Remove the function. - J.removeModule(H); - } - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -/// top ::= definition | external | expression | ';' -static void MainLoop() { - SessionContext S(getGlobalContext()); - KaleidoscopeJIT J(S); - - while (1) { - switch (CurTok) { - case tok_eof: return; - case ';': getNextToken(); continue; // ignore top-level semicolons. - case tok_def: HandleDefinition(S, J); break; - case tok_extern: HandleExtern(S); break; - default: HandleTopLevelExpression(S, J); break; - } -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "ready> "; -#endif - } -} - -//===----------------------------------------------------------------------===// -// "Library" functions that can be "extern'd" from user code. -//===----------------------------------------------------------------------===// - -/// putchard - putchar that takes a double and returns 0. -extern "C" -double putchard(double X) { - putchar((char)X); - return 0; -} - -/// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" -double printd(double X) { - printf("%f", X); - return 0; -} - -extern "C" -double printlf() { - printf("\n"); - return 0; -} - -//===----------------------------------------------------------------------===// -// Main driver code. -//===----------------------------------------------------------------------===// - -int main() { - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetAsmParser(); - - // Install standard binary operators. - // 1 is lowest precedence. - BinopPrecedence['='] = 2; - BinopPrecedence['<'] = 10; - BinopPrecedence['+'] = 20; - BinopPrecedence['-'] = 20; - BinopPrecedence['/'] = 40; - BinopPrecedence['*'] = 40; // highest. - - // Prime the first token. -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "ready> "; -#endif - getNextToken(); - - std::cerr << std::fixed; - - // Run the main "interpreter loop" now. - MainLoop(); - - return 0; -} diff --git a/examples/Kaleidoscope/Orc/lazy_codegen/CMakeLists.txt b/examples/Kaleidoscope/Orc/lazy_codegen/CMakeLists.txt deleted file mode 100644 index faad3420c6a023d6d96c2ee822f1cf859e1ec2e7..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/lazy_codegen/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Core - ExecutionEngine - Object - RuntimeDyld - Support - native - ) - -add_kaleidoscope_chapter(Kaleidoscope-Orc-lazy_codegen - toy.cpp - ) diff --git a/examples/Kaleidoscope/Orc/lazy_codegen/README.txt b/examples/Kaleidoscope/Orc/lazy_codegen/README.txt deleted file mode 100644 index 9d62a9143279787f40c8e7242ff8d37d410cdf73..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/lazy_codegen/README.txt +++ /dev/null @@ -1,13 +0,0 @@ -//===----------------------------------------------------------------------===/ -// Kaleidoscope with Orc - Initial Version -//===----------------------------------------------------------------------===// - -This version of Kaleidoscope with Orc demonstrates lazy code-generation. -Unlike the first Kaleidoscope-Orc tutorial, where code-gen was performed as soon -as modules were added to the JIT, this tutorial adds a LazyEmittingLayer to defer -code-generation until modules are actually referenced. All IR-generation is still -performed up-front. - -This directory contain a Makefile that allow the code to be built in a -standalone manner, independent of the larger LLVM build infrastructure. To build -the program you will need to have 'clang++' and 'llvm-config' in your path. diff --git a/examples/Kaleidoscope/Orc/lazy_codegen/toy.cpp b/examples/Kaleidoscope/Orc/lazy_codegen/toy.cpp deleted file mode 100644 index 5205b406ed71811fce4d5b53aeaa84d26d2c9959..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/lazy_codegen/toy.cpp +++ /dev/null @@ -1,1339 +0,0 @@ -#include "llvm/Analysis/Passes.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" -#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" -#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Transforms/Scalar.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace llvm; -using namespace llvm::orc; - -//===----------------------------------------------------------------------===// -// Lexer -//===----------------------------------------------------------------------===// - -// The lexer returns tokens [0-255] if it is an unknown character, otherwise one -// of these for known things. -enum Token { - tok_eof = -1, - - // commands - tok_def = -2, tok_extern = -3, - - // primary - tok_identifier = -4, tok_number = -5, - - // control - tok_if = -6, tok_then = -7, tok_else = -8, - tok_for = -9, tok_in = -10, - - // operators - tok_binary = -11, tok_unary = -12, - - // var definition - tok_var = -13 -}; - -static std::string IdentifierStr; // Filled in if tok_identifier -static double NumVal; // Filled in if tok_number - -/// gettok - Return the next token from standard input. -static int gettok() { - static int LastChar = ' '; - - // Skip any whitespace. - while (isspace(LastChar)) - LastChar = getchar(); - - if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* - IdentifierStr = LastChar; - while (isalnum((LastChar = getchar()))) - IdentifierStr += LastChar; - - if (IdentifierStr == "def") return tok_def; - if (IdentifierStr == "extern") return tok_extern; - if (IdentifierStr == "if") return tok_if; - if (IdentifierStr == "then") return tok_then; - if (IdentifierStr == "else") return tok_else; - if (IdentifierStr == "for") return tok_for; - if (IdentifierStr == "in") return tok_in; - if (IdentifierStr == "binary") return tok_binary; - if (IdentifierStr == "unary") return tok_unary; - if (IdentifierStr == "var") return tok_var; - return tok_identifier; - } - - if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ - std::string NumStr; - do { - NumStr += LastChar; - LastChar = getchar(); - } while (isdigit(LastChar) || LastChar == '.'); - - NumVal = strtod(NumStr.c_str(), nullptr); - return tok_number; - } - - if (LastChar == '#') { - // Comment until end of line. - do LastChar = getchar(); - while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); - - if (LastChar != EOF) - return gettok(); - } - - // Check for end of file. Don't eat the EOF. - if (LastChar == EOF) - return tok_eof; - - // Otherwise, just return the character as its ascii value. - int ThisChar = LastChar; - LastChar = getchar(); - return ThisChar; -} - -//===----------------------------------------------------------------------===// -// Abstract Syntax Tree (aka Parse Tree) -//===----------------------------------------------------------------------===// - -class IRGenContext; - -/// ExprAST - Base class for all expression nodes. -struct ExprAST { - virtual ~ExprAST() {} - virtual Value *IRGen(IRGenContext &C) const = 0; -}; - -/// NumberExprAST - Expression class for numeric literals like "1.0". -struct NumberExprAST : public ExprAST { - NumberExprAST(double Val) : Val(Val) {} - Value *IRGen(IRGenContext &C) const override; - - double Val; -}; - -/// VariableExprAST - Expression class for referencing a variable, like "a". -struct VariableExprAST : public ExprAST { - VariableExprAST(std::string Name) : Name(std::move(Name)) {} - Value *IRGen(IRGenContext &C) const override; - - std::string Name; -}; - -/// UnaryExprAST - Expression class for a unary operator. -struct UnaryExprAST : public ExprAST { - UnaryExprAST(char Opcode, std::unique_ptr Operand) - : Opcode(std::move(Opcode)), Operand(std::move(Operand)) {} - - Value *IRGen(IRGenContext &C) const override; - - char Opcode; - std::unique_ptr Operand; -}; - -/// BinaryExprAST - Expression class for a binary operator. -struct BinaryExprAST : public ExprAST { - BinaryExprAST(char Op, std::unique_ptr LHS, - std::unique_ptr RHS) - : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} - - Value *IRGen(IRGenContext &C) const override; - - char Op; - std::unique_ptr LHS, RHS; -}; - -/// CallExprAST - Expression class for function calls. -struct CallExprAST : public ExprAST { - CallExprAST(std::string CalleeName, - std::vector> Args) - : CalleeName(std::move(CalleeName)), Args(std::move(Args)) {} - - Value *IRGen(IRGenContext &C) const override; - - std::string CalleeName; - std::vector> Args; -}; - -/// IfExprAST - Expression class for if/then/else. -struct IfExprAST : public ExprAST { - IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, - std::unique_ptr Else) - : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} - Value *IRGen(IRGenContext &C) const override; - - std::unique_ptr Cond, Then, Else; -}; - -/// ForExprAST - Expression class for for/in. -struct ForExprAST : public ExprAST { - ForExprAST(std::string VarName, std::unique_ptr Start, - std::unique_ptr End, std::unique_ptr Step, - std::unique_ptr Body) - : VarName(std::move(VarName)), Start(std::move(Start)), End(std::move(End)), - Step(std::move(Step)), Body(std::move(Body)) {} - - Value *IRGen(IRGenContext &C) const override; - - std::string VarName; - std::unique_ptr Start, End, Step, Body; -}; - -/// VarExprAST - Expression class for var/in -struct VarExprAST : public ExprAST { - typedef std::pair> Binding; - typedef std::vector BindingList; - - VarExprAST(BindingList VarBindings, std::unique_ptr Body) - : VarBindings(std::move(VarBindings)), Body(std::move(Body)) {} - - Value *IRGen(IRGenContext &C) const override; - - BindingList VarBindings; - std::unique_ptr Body; -}; - -/// PrototypeAST - This class represents the "prototype" for a function, -/// which captures its argument names as well as if it is an operator. -struct PrototypeAST { - PrototypeAST(std::string Name, std::vector Args, - bool IsOperator = false, unsigned Precedence = 0) - : Name(std::move(Name)), Args(std::move(Args)), IsOperator(IsOperator), - Precedence(Precedence) {} - - Function *IRGen(IRGenContext &C) const; - void CreateArgumentAllocas(Function *F, IRGenContext &C); - - bool isUnaryOp() const { return IsOperator && Args.size() == 1; } - bool isBinaryOp() const { return IsOperator && Args.size() == 2; } - - char getOperatorName() const { - assert(isUnaryOp() || isBinaryOp()); - return Name[Name.size()-1]; - } - - std::string Name; - std::vector Args; - bool IsOperator; - unsigned Precedence; // Precedence if a binary op. -}; - -/// FunctionAST - This class represents a function definition itself. -struct FunctionAST { - FunctionAST(std::unique_ptr Proto, - std::unique_ptr Body) - : Proto(std::move(Proto)), Body(std::move(Body)) {} - - Function *IRGen(IRGenContext &C) const; - - std::unique_ptr Proto; - std::unique_ptr Body; -}; - -//===----------------------------------------------------------------------===// -// Parser -//===----------------------------------------------------------------------===// - -/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current -/// token the parser is looking at. getNextToken reads another token from the -/// lexer and updates CurTok with its results. -static int CurTok; -static int getNextToken() { - return CurTok = gettok(); -} - -/// BinopPrecedence - This holds the precedence for each binary operator that is -/// defined. -static std::map BinopPrecedence; - -/// GetTokPrecedence - Get the precedence of the pending binary operator token. -static int GetTokPrecedence() { - if (!isascii(CurTok)) - return -1; - - // Make sure it's a declared binop. - int TokPrec = BinopPrecedence[CurTok]; - if (TokPrec <= 0) return -1; - return TokPrec; -} - -template -std::unique_ptr ErrorU(const std::string &Str) { - std::cerr << "Error: " << Str << "\n"; - return nullptr; -} - -template -T* ErrorP(const std::string &Str) { - std::cerr << "Error: " << Str << "\n"; - return nullptr; -} - -static std::unique_ptr ParseExpression(); - -/// identifierexpr -/// ::= identifier -/// ::= identifier '(' expression* ')' -static std::unique_ptr ParseIdentifierExpr() { - std::string IdName = IdentifierStr; - - getNextToken(); // eat identifier. - - if (CurTok != '(') // Simple variable ref. - return llvm::make_unique(IdName); - - // Call. - getNextToken(); // eat ( - std::vector> Args; - if (CurTok != ')') { - while (1) { - auto Arg = ParseExpression(); - if (!Arg) return nullptr; - Args.push_back(std::move(Arg)); - - if (CurTok == ')') break; - - if (CurTok != ',') - return ErrorU("Expected ')' or ',' in argument list"); - getNextToken(); - } - } - - // Eat the ')'. - getNextToken(); - - return llvm::make_unique(IdName, std::move(Args)); -} - -/// numberexpr ::= number -static std::unique_ptr ParseNumberExpr() { - auto Result = llvm::make_unique(NumVal); - getNextToken(); // consume the number - return Result; -} - -/// parenexpr ::= '(' expression ')' -static std::unique_ptr ParseParenExpr() { - getNextToken(); // eat (. - auto V = ParseExpression(); - if (!V) - return nullptr; - - if (CurTok != ')') - return ErrorU("expected ')'"); - getNextToken(); // eat ). - return V; -} - -/// ifexpr ::= 'if' expression 'then' expression 'else' expression -static std::unique_ptr ParseIfExpr() { - getNextToken(); // eat the if. - - // condition. - auto Cond = ParseExpression(); - if (!Cond) - return nullptr; - - if (CurTok != tok_then) - return ErrorU("expected then"); - getNextToken(); // eat the then - - auto Then = ParseExpression(); - if (!Then) - return nullptr; - - if (CurTok != tok_else) - return ErrorU("expected else"); - - getNextToken(); - - auto Else = ParseExpression(); - if (!Else) - return nullptr; - - return llvm::make_unique(std::move(Cond), std::move(Then), - std::move(Else)); -} - -/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression -static std::unique_ptr ParseForExpr() { - getNextToken(); // eat the for. - - if (CurTok != tok_identifier) - return ErrorU("expected identifier after for"); - - std::string IdName = IdentifierStr; - getNextToken(); // eat identifier. - - if (CurTok != '=') - return ErrorU("expected '=' after for"); - getNextToken(); // eat '='. - - auto Start = ParseExpression(); - if (!Start) - return nullptr; - if (CurTok != ',') - return ErrorU("expected ',' after for start value"); - getNextToken(); - - auto End = ParseExpression(); - if (!End) - return nullptr; - - // The step value is optional. - std::unique_ptr Step; - if (CurTok == ',') { - getNextToken(); - Step = ParseExpression(); - if (!Step) - return nullptr; - } - - if (CurTok != tok_in) - return ErrorU("expected 'in' after for"); - getNextToken(); // eat 'in'. - - auto Body = ParseExpression(); - if (Body) - return nullptr; - - return llvm::make_unique(IdName, std::move(Start), std::move(End), - std::move(Step), std::move(Body)); -} - -/// varexpr ::= 'var' identifier ('=' expression)? -// (',' identifier ('=' expression)?)* 'in' expression -static std::unique_ptr ParseVarExpr() { - getNextToken(); // eat the var. - - VarExprAST::BindingList VarBindings; - - // At least one variable name is required. - if (CurTok != tok_identifier) - return ErrorU("expected identifier after var"); - - while (1) { - std::string Name = IdentifierStr; - getNextToken(); // eat identifier. - - // Read the optional initializer. - std::unique_ptr Init; - if (CurTok == '=') { - getNextToken(); // eat the '='. - - Init = ParseExpression(); - if (!Init) - return nullptr; - } - - VarBindings.push_back(VarExprAST::Binding(Name, std::move(Init))); - - // End of var list, exit loop. - if (CurTok != ',') break; - getNextToken(); // eat the ','. - - if (CurTok != tok_identifier) - return ErrorU("expected identifier list after var"); - } - - // At this point, we have to have 'in'. - if (CurTok != tok_in) - return ErrorU("expected 'in' keyword after 'var'"); - getNextToken(); // eat 'in'. - - auto Body = ParseExpression(); - if (!Body) - return nullptr; - - return llvm::make_unique(std::move(VarBindings), std::move(Body)); -} - -/// primary -/// ::= identifierexpr -/// ::= numberexpr -/// ::= parenexpr -/// ::= ifexpr -/// ::= forexpr -/// ::= varexpr -static std::unique_ptr ParsePrimary() { - switch (CurTok) { - default: return ErrorU("unknown token when expecting an expression"); - case tok_identifier: return ParseIdentifierExpr(); - case tok_number: return ParseNumberExpr(); - case '(': return ParseParenExpr(); - case tok_if: return ParseIfExpr(); - case tok_for: return ParseForExpr(); - case tok_var: return ParseVarExpr(); - } -} - -/// unary -/// ::= primary -/// ::= '!' unary -static std::unique_ptr ParseUnary() { - // If the current token is not an operator, it must be a primary expr. - if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') - return ParsePrimary(); - - // If this is a unary operator, read it. - int Opc = CurTok; - getNextToken(); - if (auto Operand = ParseUnary()) - return llvm::make_unique(Opc, std::move(Operand)); - return nullptr; -} - -/// binoprhs -/// ::= ('+' unary)* -static std::unique_ptr ParseBinOpRHS(int ExprPrec, - std::unique_ptr LHS) { - // If this is a binop, find its precedence. - while (1) { - int TokPrec = GetTokPrecedence(); - - // If this is a binop that binds at least as tightly as the current binop, - // consume it, otherwise we are done. - if (TokPrec < ExprPrec) - return LHS; - - // Okay, we know this is a binop. - int BinOp = CurTok; - getNextToken(); // eat binop - - // Parse the unary expression after the binary operator. - auto RHS = ParseUnary(); - if (!RHS) - return nullptr; - - // If BinOp binds less tightly with RHS than the operator after RHS, let - // the pending operator take RHS as its LHS. - int NextPrec = GetTokPrecedence(); - if (TokPrec < NextPrec) { - RHS = ParseBinOpRHS(TokPrec+1, std::move(RHS)); - if (!RHS) - return nullptr; - } - - // Merge LHS/RHS. - LHS = llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); - } -} - -/// expression -/// ::= unary binoprhs -/// -static std::unique_ptr ParseExpression() { - auto LHS = ParseUnary(); - if (!LHS) - return nullptr; - - return ParseBinOpRHS(0, std::move(LHS)); -} - -/// prototype -/// ::= id '(' id* ')' -/// ::= binary LETTER number? (id, id) -/// ::= unary LETTER (id) -static std::unique_ptr ParsePrototype() { - std::string FnName; - - unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. - unsigned BinaryPrecedence = 30; - - switch (CurTok) { - default: - return ErrorU("Expected function name in prototype"); - case tok_identifier: - FnName = IdentifierStr; - Kind = 0; - getNextToken(); - break; - case tok_unary: - getNextToken(); - if (!isascii(CurTok)) - return ErrorU("Expected unary operator"); - FnName = "unary"; - FnName += (char)CurTok; - Kind = 1; - getNextToken(); - break; - case tok_binary: - getNextToken(); - if (!isascii(CurTok)) - return ErrorU("Expected binary operator"); - FnName = "binary"; - FnName += (char)CurTok; - Kind = 2; - getNextToken(); - - // Read the precedence if present. - if (CurTok == tok_number) { - if (NumVal < 1 || NumVal > 100) - return ErrorU("Invalid precedecnce: must be 1..100"); - BinaryPrecedence = (unsigned)NumVal; - getNextToken(); - } - break; - } - - if (CurTok != '(') - return ErrorU("Expected '(' in prototype"); - - std::vector ArgNames; - while (getNextToken() == tok_identifier) - ArgNames.push_back(IdentifierStr); - if (CurTok != ')') - return ErrorU("Expected ')' in prototype"); - - // success. - getNextToken(); // eat ')'. - - // Verify right number of names for operator. - if (Kind && ArgNames.size() != Kind) - return ErrorU("Invalid number of operands for operator"); - - return llvm::make_unique(FnName, std::move(ArgNames), Kind != 0, - BinaryPrecedence); -} - -/// definition ::= 'def' prototype expression -static std::unique_ptr ParseDefinition() { - getNextToken(); // eat def. - auto Proto = ParsePrototype(); - if (!Proto) - return nullptr; - - if (auto Body = ParseExpression()) - return llvm::make_unique(std::move(Proto), std::move(Body)); - return nullptr; -} - -/// toplevelexpr ::= expression -static std::unique_ptr ParseTopLevelExpr() { - if (auto E = ParseExpression()) { - // Make an anonymous proto. - auto Proto = - llvm::make_unique("__anon_expr", std::vector()); - return llvm::make_unique(std::move(Proto), std::move(E)); - } - return nullptr; -} - -/// external ::= 'extern' prototype -static std::unique_ptr ParseExtern() { - getNextToken(); // eat extern. - return ParsePrototype(); -} - -//===----------------------------------------------------------------------===// -// Code Generation -//===----------------------------------------------------------------------===// - -// FIXME: Obviously we can do better than this -std::string GenerateUniqueName(const std::string &Root) { - static int i = 0; - std::ostringstream NameStream; - NameStream << Root << ++i; - return NameStream.str(); -} - -std::string MakeLegalFunctionName(std::string Name) -{ - std::string NewName; - assert(!Name.empty() && "Base name must not be empty"); - - // Start with what we have - NewName = Name; - - // Look for a numberic first character - if (NewName.find_first_of("0123456789") == 0) { - NewName.insert(0, 1, 'n'); - } - - // Replace illegal characters with their ASCII equivalent - std::string legal_elements = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - size_t pos; - while ((pos = NewName.find_first_not_of(legal_elements)) != std::string::npos) { - std::ostringstream NumStream; - NumStream << (int)NewName.at(pos); - NewName = NewName.replace(pos, 1, NumStream.str()); - } - - return NewName; -} - -class SessionContext { -public: - SessionContext(LLVMContext &C) - : Context(C), TM(EngineBuilder().selectTarget()) {} - LLVMContext& getLLVMContext() const { return Context; } - TargetMachine& getTarget() { return *TM; } - void addPrototypeAST(std::unique_ptr P); - PrototypeAST* getPrototypeAST(const std::string &Name); -private: - typedef std::map> PrototypeMap; - - LLVMContext &Context; - std::unique_ptr TM; - - PrototypeMap Prototypes; -}; - -void SessionContext::addPrototypeAST(std::unique_ptr P) { - Prototypes[P->Name] = std::move(P); -} - -PrototypeAST* SessionContext::getPrototypeAST(const std::string &Name) { - PrototypeMap::iterator I = Prototypes.find(Name); - if (I != Prototypes.end()) - return I->second.get(); - return nullptr; -} - -class IRGenContext { -public: - - IRGenContext(SessionContext &S) - : Session(S), - M(new Module(GenerateUniqueName("jit_module_"), - Session.getLLVMContext())), - Builder(Session.getLLVMContext()) { - M->setDataLayout(Session.getTarget().createDataLayout()); - } - - SessionContext& getSession() { return Session; } - Module& getM() const { return *M; } - std::unique_ptr takeM() { return std::move(M); } - IRBuilder<>& getBuilder() { return Builder; } - LLVMContext& getLLVMContext() { return Session.getLLVMContext(); } - Function* getPrototype(const std::string &Name); - - std::map NamedValues; -private: - SessionContext &Session; - std::unique_ptr M; - IRBuilder<> Builder; -}; - -Function* IRGenContext::getPrototype(const std::string &Name) { - if (Function *ExistingProto = M->getFunction(Name)) - return ExistingProto; - if (PrototypeAST *ProtoAST = Session.getPrototypeAST(Name)) - return ProtoAST->IRGen(*this); - return nullptr; -} - -/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of -/// the function. This is used for mutable variables etc. -static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, - const std::string &VarName) { - IRBuilder<> TmpB(&TheFunction->getEntryBlock(), - TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), nullptr, - VarName.c_str()); -} - -Value *NumberExprAST::IRGen(IRGenContext &C) const { - return ConstantFP::get(C.getLLVMContext(), APFloat(Val)); -} - -Value *VariableExprAST::IRGen(IRGenContext &C) const { - // Look this variable up in the function. - Value *V = C.NamedValues[Name]; - - if (!V) - return ErrorP("Unknown variable name '" + Name + "'"); - - // Load the value. - return C.getBuilder().CreateLoad(V, Name.c_str()); -} - -Value *UnaryExprAST::IRGen(IRGenContext &C) const { - if (Value *OperandV = Operand->IRGen(C)) { - std::string FnName = MakeLegalFunctionName(std::string("unary")+Opcode); - if (Function *F = C.getPrototype(FnName)) - return C.getBuilder().CreateCall(F, OperandV, "unop"); - return ErrorP("Unknown unary operator"); - } - - // Could not codegen operand - return null. - return nullptr; -} - -Value *BinaryExprAST::IRGen(IRGenContext &C) const { - // Special case '=' because we don't want to emit the LHS as an expression. - if (Op == '=') { - // Assignment requires the LHS to be an identifier. - auto &LHSVar = static_cast(*LHS); - // Codegen the RHS. - Value *Val = RHS->IRGen(C); - if (!Val) return nullptr; - - // Look up the name. - if (auto Variable = C.NamedValues[LHSVar.Name]) { - C.getBuilder().CreateStore(Val, Variable); - return Val; - } - return ErrorP("Unknown variable name"); - } - - Value *L = LHS->IRGen(C); - Value *R = RHS->IRGen(C); - if (!L || !R) return nullptr; - - switch (Op) { - case '+': return C.getBuilder().CreateFAdd(L, R, "addtmp"); - case '-': return C.getBuilder().CreateFSub(L, R, "subtmp"); - case '*': return C.getBuilder().CreateFMul(L, R, "multmp"); - case '/': return C.getBuilder().CreateFDiv(L, R, "divtmp"); - case '<': - L = C.getBuilder().CreateFCmpULT(L, R, "cmptmp"); - // Convert bool 0/1 to double 0.0 or 1.0 - return C.getBuilder().CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); - default: break; - } - - // If it wasn't a builtin binary operator, it must be a user defined one. Emit - // a call to it. - std::string FnName = MakeLegalFunctionName(std::string("binary")+Op); - if (Function *F = C.getPrototype(FnName)) { - Value *Ops[] = { L, R }; - return C.getBuilder().CreateCall(F, Ops, "binop"); - } - - return ErrorP("Unknown binary operator"); -} - -Value *CallExprAST::IRGen(IRGenContext &C) const { - // Look up the name in the global module table. - if (auto CalleeF = C.getPrototype(CalleeName)) { - // If argument mismatch error. - if (CalleeF->arg_size() != Args.size()) - return ErrorP("Incorrect # arguments passed"); - - std::vector ArgsV; - for (unsigned i = 0, e = Args.size(); i != e; ++i) { - ArgsV.push_back(Args[i]->IRGen(C)); - if (!ArgsV.back()) return nullptr; - } - - return C.getBuilder().CreateCall(CalleeF, ArgsV, "calltmp"); - } - - return ErrorP("Unknown function referenced"); -} - -Value *IfExprAST::IRGen(IRGenContext &C) const { - Value *CondV = Cond->IRGen(C); - if (!CondV) return nullptr; - - // Convert condition to a bool by comparing equal to 0.0. - ConstantFP *FPZero = - ConstantFP::get(C.getLLVMContext(), APFloat(0.0)); - CondV = C.getBuilder().CreateFCmpONE(CondV, FPZero, "ifcond"); - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Create blocks for the then and else cases. Insert the 'then' block at the - // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(C.getLLVMContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(C.getLLVMContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(C.getLLVMContext(), "ifcont"); - - C.getBuilder().CreateCondBr(CondV, ThenBB, ElseBB); - - // Emit then value. - C.getBuilder().SetInsertPoint(ThenBB); - - Value *ThenV = Then->IRGen(C); - if (!ThenV) return nullptr; - - C.getBuilder().CreateBr(MergeBB); - // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = C.getBuilder().GetInsertBlock(); - - // Emit else block. - TheFunction->getBasicBlockList().push_back(ElseBB); - C.getBuilder().SetInsertPoint(ElseBB); - - Value *ElseV = Else->IRGen(C); - if (!ElseV) return nullptr; - - C.getBuilder().CreateBr(MergeBB); - // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = C.getBuilder().GetInsertBlock(); - - // Emit merge block. - TheFunction->getBasicBlockList().push_back(MergeBB); - C.getBuilder().SetInsertPoint(MergeBB); - PHINode *PN = C.getBuilder().CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, - "iftmp"); - - PN->addIncoming(ThenV, ThenBB); - PN->addIncoming(ElseV, ElseBB); - return PN; -} - -Value *ForExprAST::IRGen(IRGenContext &C) const { - // Output this as: - // var = alloca double - // ... - // start = startexpr - // store start -> var - // goto loop - // loop: - // ... - // bodyexpr - // ... - // loopend: - // step = stepexpr - // endcond = endexpr - // - // curvar = load var - // nextvar = curvar + step - // store nextvar -> var - // br endcond, loop, endloop - // outloop: - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Create an alloca for the variable in the entry block. - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - - // Emit the start code first, without 'variable' in scope. - Value *StartVal = Start->IRGen(C); - if (!StartVal) return nullptr; - - // Store the value into the alloca. - C.getBuilder().CreateStore(StartVal, Alloca); - - // Make the new basic block for the loop header, inserting after current - // block. - BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); - - // Insert an explicit fall through from the current block to the LoopBB. - C.getBuilder().CreateBr(LoopBB); - - // Start insertion in LoopBB. - C.getBuilder().SetInsertPoint(LoopBB); - - // Within the loop, the variable is defined equal to the PHI node. If it - // shadows an existing variable, we have to restore it, so save it now. - AllocaInst *OldVal = C.NamedValues[VarName]; - C.NamedValues[VarName] = Alloca; - - // Emit the body of the loop. This, like any other expr, can change the - // current BB. Note that we ignore the value computed by the body, but don't - // allow an error. - if (!Body->IRGen(C)) - return nullptr; - - // Emit the step value. - Value *StepVal; - if (Step) { - StepVal = Step->IRGen(C); - if (!StepVal) return nullptr; - } else { - // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); - } - - // Compute the end condition. - Value *EndCond = End->IRGen(C); - if (!EndCond) return nullptr; - - // Reload, increment, and restore the alloca. This handles the case where - // the body of the loop mutates the variable. - Value *CurVar = C.getBuilder().CreateLoad(Alloca, VarName.c_str()); - Value *NextVar = C.getBuilder().CreateFAdd(CurVar, StepVal, "nextvar"); - C.getBuilder().CreateStore(NextVar, Alloca); - - // Convert condition to a bool by comparing equal to 0.0. - EndCond = C.getBuilder().CreateFCmpONE(EndCond, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "loopcond"); - - // Create the "after loop" block and insert it. - BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); - - // Insert the conditional branch into the end of LoopEndBB. - C.getBuilder().CreateCondBr(EndCond, LoopBB, AfterBB); - - // Any new code will be inserted in AfterBB. - C.getBuilder().SetInsertPoint(AfterBB); - - // Restore the unshadowed variable. - if (OldVal) - C.NamedValues[VarName] = OldVal; - else - C.NamedValues.erase(VarName); - - // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); -} - -Value *VarExprAST::IRGen(IRGenContext &C) const { - std::vector OldBindings; - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Register all variables and emit their initializer. - for (unsigned i = 0, e = VarBindings.size(); i != e; ++i) { - auto &VarName = VarBindings[i].first; - auto &Init = VarBindings[i].second; - - // Emit the initializer before adding the variable to scope, this prevents - // the initializer from referencing the variable itself, and permits stuff - // like this: - // var a = 1 in - // var a = a in ... # refers to outer 'a'. - Value *InitVal; - if (Init) { - InitVal = Init->IRGen(C); - if (!InitVal) return nullptr; - } else // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); - - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - C.getBuilder().CreateStore(InitVal, Alloca); - - // Remember the old variable binding so that we can restore the binding when - // we unrecurse. - OldBindings.push_back(C.NamedValues[VarName]); - - // Remember this binding. - C.NamedValues[VarName] = Alloca; - } - - // Codegen the body, now that all vars are in scope. - Value *BodyVal = Body->IRGen(C); - if (!BodyVal) return nullptr; - - // Pop all our variables from scope. - for (unsigned i = 0, e = VarBindings.size(); i != e; ++i) - C.NamedValues[VarBindings[i].first] = OldBindings[i]; - - // Return the body computation. - return BodyVal; -} - -Function *PrototypeAST::IRGen(IRGenContext &C) const { - std::string FnName = MakeLegalFunctionName(Name); - - // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); - FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), - Doubles, false); - Function *F = Function::Create(FT, Function::ExternalLinkage, FnName, - &C.getM()); - - // If F conflicted, there was already something named 'FnName'. If it has a - // body, don't allow redefinition or reextern. - if (F->getName() != FnName) { - // Delete the one we just made and get the existing one. - F->eraseFromParent(); - F = C.getM().getFunction(Name); - - // If F already has a body, reject this. - if (!F->empty()) { - ErrorP("redefinition of function"); - return nullptr; - } - - // If F took a different number of args, reject. - if (F->arg_size() != Args.size()) { - ErrorP("redefinition of function with different # args"); - return nullptr; - } - } - - // Set names for all arguments. - unsigned Idx = 0; - for (Function::arg_iterator AI = F->arg_begin(); Idx != Args.size(); - ++AI, ++Idx) - AI->setName(Args[Idx]); - - return F; -} - -/// CreateArgumentAllocas - Create an alloca for each argument and register the -/// argument in the symbol table so that references to it will succeed. -void PrototypeAST::CreateArgumentAllocas(Function *F, IRGenContext &C) { - Function::arg_iterator AI = F->arg_begin(); - for (unsigned Idx = 0, e = Args.size(); Idx != e; ++Idx, ++AI) { - // Create an alloca for this variable. - AllocaInst *Alloca = CreateEntryBlockAlloca(F, Args[Idx]); - - // Store the initial value into the alloca. - C.getBuilder().CreateStore(&*AI, Alloca); - - // Add arguments to variable symbol table. - C.NamedValues[Args[Idx]] = Alloca; - } -} - -Function *FunctionAST::IRGen(IRGenContext &C) const { - C.NamedValues.clear(); - - Function *TheFunction = Proto->IRGen(C); - if (!TheFunction) - return nullptr; - - // If this is an operator, install it. - if (Proto->isBinaryOp()) - BinopPrecedence[Proto->getOperatorName()] = Proto->Precedence; - - // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); - C.getBuilder().SetInsertPoint(BB); - - // Add all arguments to the symbol table and create their allocas. - Proto->CreateArgumentAllocas(TheFunction, C); - - if (Value *RetVal = Body->IRGen(C)) { - // Finish off the function. - C.getBuilder().CreateRet(RetVal); - - // Validate the generated code, checking for consistency. - verifyFunction(*TheFunction); - - return TheFunction; - } - - // Error reading body, remove function. - TheFunction->eraseFromParent(); - - if (Proto->isBinaryOp()) - BinopPrecedence.erase(Proto->getOperatorName()); - return nullptr; -} - -//===----------------------------------------------------------------------===// -// Top-Level parsing and JIT Driver -//===----------------------------------------------------------------------===// - -static std::unique_ptr IRGen(SessionContext &S, - const FunctionAST &F) { - IRGenContext C(S); - auto LF = F.IRGen(C); - if (!LF) - return nullptr; -#ifndef MINIMAL_STDERR_OUTPUT - fprintf(stderr, "Read function definition:"); - LF->dump(); -#endif - return C.takeM(); -} - -template -static std::vector singletonSet(T t) { - std::vector Vec; - Vec.push_back(std::move(t)); - return Vec; -} - -class KaleidoscopeJIT { -public: - typedef ObjectLinkingLayer<> ObjLayerT; - typedef IRCompileLayer CompileLayerT; - typedef LazyEmittingLayer LazyEmitLayerT; - - typedef LazyEmitLayerT::ModuleSetHandleT ModuleHandleT; - - KaleidoscopeJIT(SessionContext &Session) - : DL(Session.getTarget().createDataLayout()), - CompileLayer(ObjectLayer, SimpleCompiler(Session.getTarget())), - LazyEmitLayer(CompileLayer) {} - - std::string mangle(const std::string &Name) { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - } - return MangledName; - } - - ModuleHandleT addModule(std::unique_ptr M) { - // We need a memory manager to allocate memory and resolve symbols for this - // new module. Create one that resolves symbols by looking back into the - // JIT. - auto Resolver = createLambdaResolver( - [&](const std::string &Name) { - if (auto Sym = findSymbol(Name)) - return RuntimeDyld::SymbolInfo(Sym.getAddress(), - Sym.getFlags()); - return RuntimeDyld::SymbolInfo(nullptr); - }, - [](const std::string &S) { return nullptr; } ); - - return LazyEmitLayer.addModuleSet(singletonSet(std::move(M)), - make_unique(), - std::move(Resolver)); - } - - void removeModule(ModuleHandleT H) { LazyEmitLayer.removeModuleSet(H); } - - JITSymbol findSymbol(const std::string &Name) { - return LazyEmitLayer.findSymbol(Name, true); - } - - JITSymbol findUnmangledSymbol(const std::string Name) { - return findSymbol(mangle(Name)); - } - -private: - const DataLayout DL; - ObjLayerT ObjectLayer; - CompileLayerT CompileLayer; - LazyEmitLayerT LazyEmitLayer; -}; - -static void HandleDefinition(SessionContext &S, KaleidoscopeJIT &J) { - if (auto F = ParseDefinition()) { - if (auto M = IRGen(S, *F)) { - S.addPrototypeAST(llvm::make_unique(*F->Proto)); - J.addModule(std::move(M)); - } - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -static void HandleExtern(SessionContext &S) { - if (auto P = ParseExtern()) - S.addPrototypeAST(std::move(P)); - else { - // Skip token for error recovery. - getNextToken(); - } -} - -static void HandleTopLevelExpression(SessionContext &S, KaleidoscopeJIT &J) { - // Evaluate a top-level expression into an anonymous function. - if (auto F = ParseTopLevelExpr()) { - IRGenContext C(S); - if (auto ExprFunc = F->IRGen(C)) { -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "Expression function:\n"; - ExprFunc->dump(); -#endif - // Add the CodeGen'd module to the JIT. Keep a handle to it: We can remove - // this module as soon as we've executed Function ExprFunc. - auto H = J.addModule(C.takeM()); - - // Get the address of the JIT'd function in memory. - auto ExprSymbol = J.findUnmangledSymbol("__anon_expr"); - - // Cast it to the right type (takes no arguments, returns a double) so we - // can call it as a native function. - double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); -#ifdef MINIMAL_STDERR_OUTPUT - FP(); -#else - std::cerr << "Evaluated to " << FP() << "\n"; -#endif - - // Remove the function. - J.removeModule(H); - } - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -/// top ::= definition | external | expression | ';' -static void MainLoop() { - SessionContext S(getGlobalContext()); - KaleidoscopeJIT J(S); - - while (1) { - switch (CurTok) { - case tok_eof: return; - case ';': getNextToken(); continue; // ignore top-level semicolons. - case tok_def: HandleDefinition(S, J); break; - case tok_extern: HandleExtern(S); break; - default: HandleTopLevelExpression(S, J); break; - } -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "ready> "; -#endif - } -} - -//===----------------------------------------------------------------------===// -// "Library" functions that can be "extern'd" from user code. -//===----------------------------------------------------------------------===// - -/// putchard - putchar that takes a double and returns 0. -extern "C" -double putchard(double X) { - putchar((char)X); - return 0; -} - -/// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" -double printd(double X) { - printf("%f", X); - return 0; -} - -extern "C" -double printlf() { - printf("\n"); - return 0; -} - -//===----------------------------------------------------------------------===// -// Main driver code. -//===----------------------------------------------------------------------===// - -int main() { - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetAsmParser(); - - // Install standard binary operators. - // 1 is lowest precedence. - BinopPrecedence['='] = 2; - BinopPrecedence['<'] = 10; - BinopPrecedence['+'] = 20; - BinopPrecedence['-'] = 20; - BinopPrecedence['/'] = 40; - BinopPrecedence['*'] = 40; // highest. - - // Prime the first token. -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "ready> "; -#endif - getNextToken(); - - std::cerr << std::fixed; - - // Run the main "interpreter loop" now. - MainLoop(); - - return 0; -} diff --git a/examples/Kaleidoscope/Orc/lazy_irgen/README.txt b/examples/Kaleidoscope/Orc/lazy_irgen/README.txt deleted file mode 100644 index 9aaa431712dc1b8db7cbfd2d5acbfe1f6013e7fc..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/lazy_irgen/README.txt +++ /dev/null @@ -1,16 +0,0 @@ -//===----------------------------------------------------------------------===/ -// Kaleidoscope with Orc - Lazy IRGen Version -//===----------------------------------------------------------------------===// - -This version of Kaleidoscope with Orc demonstrates lazy IR-generation. -Building on the lazy-codegen version of the tutorial, this version reduces the -amount of up-front work that must be done by lazily IRgen'ing ASTs. When a -function definition is entered, its AST is added to a map of available -definitions. No IRGen is performed at this point and nothing is added to the JIT. -When attempting to resolve symbol addresses, the lambda in -KaleidoscopeJIT::getSymbolAddress will scan the AST map and generate IR on the -fly. - -This directory contains a Makefile that allows the code to be built in a -standalone manner, independent of the larger LLVM build infrastructure. To build -the program you will need to have 'clang++' and 'llvm-config' in your path. diff --git a/examples/Kaleidoscope/Orc/lazy_irgen/toy.cpp b/examples/Kaleidoscope/Orc/lazy_irgen/toy.cpp deleted file mode 100644 index ebaff49e89b25712cd11c697c57dcd9560ac5226..0000000000000000000000000000000000000000 --- a/examples/Kaleidoscope/Orc/lazy_irgen/toy.cpp +++ /dev/null @@ -1,1370 +0,0 @@ -#include "llvm/Analysis/Passes.h" -#include "llvm/ExecutionEngine/Orc/CompileUtils.h" -#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" -#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" -#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Transforms/Scalar.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace llvm; -using namespace llvm::orc; - -//===----------------------------------------------------------------------===// -// Lexer -//===----------------------------------------------------------------------===// - -// The lexer returns tokens [0-255] if it is an unknown character, otherwise one -// of these for known things. -enum Token { - tok_eof = -1, - - // commands - tok_def = -2, tok_extern = -3, - - // primary - tok_identifier = -4, tok_number = -5, - - // control - tok_if = -6, tok_then = -7, tok_else = -8, - tok_for = -9, tok_in = -10, - - // operators - tok_binary = -11, tok_unary = -12, - - // var definition - tok_var = -13 -}; - -static std::string IdentifierStr; // Filled in if tok_identifier -static double NumVal; // Filled in if tok_number - -/// gettok - Return the next token from standard input. -static int gettok() { - static int LastChar = ' '; - - // Skip any whitespace. - while (isspace(LastChar)) - LastChar = getchar(); - - if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* - IdentifierStr = LastChar; - while (isalnum((LastChar = getchar()))) - IdentifierStr += LastChar; - - if (IdentifierStr == "def") return tok_def; - if (IdentifierStr == "extern") return tok_extern; - if (IdentifierStr == "if") return tok_if; - if (IdentifierStr == "then") return tok_then; - if (IdentifierStr == "else") return tok_else; - if (IdentifierStr == "for") return tok_for; - if (IdentifierStr == "in") return tok_in; - if (IdentifierStr == "binary") return tok_binary; - if (IdentifierStr == "unary") return tok_unary; - if (IdentifierStr == "var") return tok_var; - return tok_identifier; - } - - if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ - std::string NumStr; - do { - NumStr += LastChar; - LastChar = getchar(); - } while (isdigit(LastChar) || LastChar == '.'); - - NumVal = strtod(NumStr.c_str(), nullptr); - return tok_number; - } - - if (LastChar == '#') { - // Comment until end of line. - do LastChar = getchar(); - while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); - - if (LastChar != EOF) - return gettok(); - } - - // Check for end of file. Don't eat the EOF. - if (LastChar == EOF) - return tok_eof; - - // Otherwise, just return the character as its ascii value. - int ThisChar = LastChar; - LastChar = getchar(); - return ThisChar; -} - -//===----------------------------------------------------------------------===// -// Abstract Syntax Tree (aka Parse Tree) -//===----------------------------------------------------------------------===// - -class IRGenContext; - -/// ExprAST - Base class for all expression nodes. -struct ExprAST { - virtual ~ExprAST() {} - virtual Value *IRGen(IRGenContext &C) const = 0; -}; - -/// NumberExprAST - Expression class for numeric literals like "1.0". -struct NumberExprAST : public ExprAST { - NumberExprAST(double Val) : Val(Val) {} - Value *IRGen(IRGenContext &C) const override; - - double Val; -}; - -/// VariableExprAST - Expression class for referencing a variable, like "a". -struct VariableExprAST : public ExprAST { - VariableExprAST(std::string Name) : Name(std::move(Name)) {} - Value *IRGen(IRGenContext &C) const override; - - std::string Name; -}; - -/// UnaryExprAST - Expression class for a unary operator. -struct UnaryExprAST : public ExprAST { - UnaryExprAST(char Opcode, std::unique_ptr Operand) - : Opcode(std::move(Opcode)), Operand(std::move(Operand)) {} - - Value *IRGen(IRGenContext &C) const override; - - char Opcode; - std::unique_ptr Operand; -}; - -/// BinaryExprAST - Expression class for a binary operator. -struct BinaryExprAST : public ExprAST { - BinaryExprAST(char Op, std::unique_ptr LHS, - std::unique_ptr RHS) - : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} - - Value *IRGen(IRGenContext &C) const override; - - char Op; - std::unique_ptr LHS, RHS; -}; - -/// CallExprAST - Expression class for function calls. -struct CallExprAST : public ExprAST { - CallExprAST(std::string CalleeName, - std::vector> Args) - : CalleeName(std::move(CalleeName)), Args(std::move(Args)) {} - - Value *IRGen(IRGenContext &C) const override; - - std::string CalleeName; - std::vector> Args; -}; - -/// IfExprAST - Expression class for if/then/else. -struct IfExprAST : public ExprAST { - IfExprAST(std::unique_ptr Cond, std::unique_ptr Then, - std::unique_ptr Else) - : Cond(std::move(Cond)), Then(std::move(Then)), Else(std::move(Else)) {} - Value *IRGen(IRGenContext &C) const override; - - std::unique_ptr Cond, Then, Else; -}; - -/// ForExprAST - Expression class for for/in. -struct ForExprAST : public ExprAST { - ForExprAST(std::string VarName, std::unique_ptr Start, - std::unique_ptr End, std::unique_ptr Step, - std::unique_ptr Body) - : VarName(std::move(VarName)), Start(std::move(Start)), End(std::move(End)), - Step(std::move(Step)), Body(std::move(Body)) {} - - Value *IRGen(IRGenContext &C) const override; - - std::string VarName; - std::unique_ptr Start, End, Step, Body; -}; - -/// VarExprAST - Expression class for var/in -struct VarExprAST : public ExprAST { - typedef std::pair> Binding; - typedef std::vector BindingList; - - VarExprAST(BindingList VarBindings, std::unique_ptr Body) - : VarBindings(std::move(VarBindings)), Body(std::move(Body)) {} - - Value *IRGen(IRGenContext &C) const override; - - BindingList VarBindings; - std::unique_ptr Body; -}; - -/// PrototypeAST - This class represents the "prototype" for a function, -/// which captures its argument names as well as if it is an operator. -struct PrototypeAST { - PrototypeAST(std::string Name, std::vector Args, - bool IsOperator = false, unsigned Precedence = 0) - : Name(std::move(Name)), Args(std::move(Args)), IsOperator(IsOperator), - Precedence(Precedence) {} - - Function *IRGen(IRGenContext &C) const; - void CreateArgumentAllocas(Function *F, IRGenContext &C); - - bool isUnaryOp() const { return IsOperator && Args.size() == 1; } - bool isBinaryOp() const { return IsOperator && Args.size() == 2; } - - char getOperatorName() const { - assert(isUnaryOp() || isBinaryOp()); - return Name[Name.size()-1]; - } - - std::string Name; - std::vector Args; - bool IsOperator; - unsigned Precedence; // Precedence if a binary op. -}; - -/// FunctionAST - This class represents a function definition itself. -struct FunctionAST { - FunctionAST(std::unique_ptr Proto, - std::unique_ptr Body) - : Proto(std::move(Proto)), Body(std::move(Body)) {} - - Function *IRGen(IRGenContext &C) const; - - std::unique_ptr Proto; - std::unique_ptr Body; -}; - -//===----------------------------------------------------------------------===// -// Parser -//===----------------------------------------------------------------------===// - -/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current -/// token the parser is looking at. getNextToken reads another token from the -/// lexer and updates CurTok with its results. -static int CurTok; -static int getNextToken() { - return CurTok = gettok(); -} - -/// BinopPrecedence - This holds the precedence for each binary operator that is -/// defined. -static std::map BinopPrecedence; - -/// GetTokPrecedence - Get the precedence of the pending binary operator token. -static int GetTokPrecedence() { - if (!isascii(CurTok)) - return -1; - - // Make sure it's a declared binop. - int TokPrec = BinopPrecedence[CurTok]; - if (TokPrec <= 0) return -1; - return TokPrec; -} - -template -std::unique_ptr ErrorU(const std::string &Str) { - std::cerr << "Error: " << Str << "\n"; - return nullptr; -} - -template -T* ErrorP(const std::string &Str) { - std::cerr << "Error: " << Str << "\n"; - return nullptr; -} - -static std::unique_ptr ParseExpression(); - -/// identifierexpr -/// ::= identifier -/// ::= identifier '(' expression* ')' -static std::unique_ptr ParseIdentifierExpr() { - std::string IdName = IdentifierStr; - - getNextToken(); // eat identifier. - - if (CurTok != '(') // Simple variable ref. - return llvm::make_unique(IdName); - - // Call. - getNextToken(); // eat ( - std::vector> Args; - if (CurTok != ')') { - while (1) { - auto Arg = ParseExpression(); - if (!Arg) return nullptr; - Args.push_back(std::move(Arg)); - - if (CurTok == ')') break; - - if (CurTok != ',') - return ErrorU("Expected ')' or ',' in argument list"); - getNextToken(); - } - } - - // Eat the ')'. - getNextToken(); - - return llvm::make_unique(IdName, std::move(Args)); -} - -/// numberexpr ::= number -static std::unique_ptr ParseNumberExpr() { - auto Result = llvm::make_unique(NumVal); - getNextToken(); // consume the number - return Result; -} - -/// parenexpr ::= '(' expression ')' -static std::unique_ptr ParseParenExpr() { - getNextToken(); // eat (. - auto V = ParseExpression(); - if (!V) - return nullptr; - - if (CurTok != ')') - return ErrorU("expected ')'"); - getNextToken(); // eat ). - return V; -} - -/// ifexpr ::= 'if' expression 'then' expression 'else' expression -static std::unique_ptr ParseIfExpr() { - getNextToken(); // eat the if. - - // condition. - auto Cond = ParseExpression(); - if (!Cond) - return nullptr; - - if (CurTok != tok_then) - return ErrorU("expected then"); - getNextToken(); // eat the then - - auto Then = ParseExpression(); - if (!Then) - return nullptr; - - if (CurTok != tok_else) - return ErrorU("expected else"); - - getNextToken(); - - auto Else = ParseExpression(); - if (!Else) - return nullptr; - - return llvm::make_unique(std::move(Cond), std::move(Then), - std::move(Else)); -} - -/// forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression -static std::unique_ptr ParseForExpr() { - getNextToken(); // eat the for. - - if (CurTok != tok_identifier) - return ErrorU("expected identifier after for"); - - std::string IdName = IdentifierStr; - getNextToken(); // eat identifier. - - if (CurTok != '=') - return ErrorU("expected '=' after for"); - getNextToken(); // eat '='. - - auto Start = ParseExpression(); - if (!Start) - return nullptr; - if (CurTok != ',') - return ErrorU("expected ',' after for start value"); - getNextToken(); - - auto End = ParseExpression(); - if (!End) - return nullptr; - - // The step value is optional. - std::unique_ptr Step; - if (CurTok == ',') { - getNextToken(); - Step = ParseExpression(); - if (!Step) - return nullptr; - } - - if (CurTok != tok_in) - return ErrorU("expected 'in' after for"); - getNextToken(); // eat 'in'. - - auto Body = ParseExpression(); - if (Body) - return nullptr; - - return llvm::make_unique(IdName, std::move(Start), std::move(End), - std::move(Step), std::move(Body)); -} - -/// varexpr ::= 'var' identifier ('=' expression)? -// (',' identifier ('=' expression)?)* 'in' expression -static std::unique_ptr ParseVarExpr() { - getNextToken(); // eat the var. - - VarExprAST::BindingList VarBindings; - - // At least one variable name is required. - if (CurTok != tok_identifier) - return ErrorU("expected identifier after var"); - - while (1) { - std::string Name = IdentifierStr; - getNextToken(); // eat identifier. - - // Read the optional initializer. - std::unique_ptr Init; - if (CurTok == '=') { - getNextToken(); // eat the '='. - - Init = ParseExpression(); - if (!Init) - return nullptr; - } - - VarBindings.push_back(VarExprAST::Binding(Name, std::move(Init))); - - // End of var list, exit loop. - if (CurTok != ',') break; - getNextToken(); // eat the ','. - - if (CurTok != tok_identifier) - return ErrorU("expected identifier list after var"); - } - - // At this point, we have to have 'in'. - if (CurTok != tok_in) - return ErrorU("expected 'in' keyword after 'var'"); - getNextToken(); // eat 'in'. - - auto Body = ParseExpression(); - if (!Body) - return nullptr; - - return llvm::make_unique(std::move(VarBindings), std::move(Body)); -} - -/// primary -/// ::= identifierexpr -/// ::= numberexpr -/// ::= parenexpr -/// ::= ifexpr -/// ::= forexpr -/// ::= varexpr -static std::unique_ptr ParsePrimary() { - switch (CurTok) { - default: return ErrorU("unknown token when expecting an expression"); - case tok_identifier: return ParseIdentifierExpr(); - case tok_number: return ParseNumberExpr(); - case '(': return ParseParenExpr(); - case tok_if: return ParseIfExpr(); - case tok_for: return ParseForExpr(); - case tok_var: return ParseVarExpr(); - } -} - -/// unary -/// ::= primary -/// ::= '!' unary -static std::unique_ptr ParseUnary() { - // If the current token is not an operator, it must be a primary expr. - if (!isascii(CurTok) || CurTok == '(' || CurTok == ',') - return ParsePrimary(); - - // If this is a unary operator, read it. - int Opc = CurTok; - getNextToken(); - if (auto Operand = ParseUnary()) - return llvm::make_unique(Opc, std::move(Operand)); - return nullptr; -} - -/// binoprhs -/// ::= ('+' unary)* -static std::unique_ptr ParseBinOpRHS(int ExprPrec, - std::unique_ptr LHS) { - // If this is a binop, find its precedence. - while (1) { - int TokPrec = GetTokPrecedence(); - - // If this is a binop that binds at least as tightly as the current binop, - // consume it, otherwise we are done. - if (TokPrec < ExprPrec) - return LHS; - - // Okay, we know this is a binop. - int BinOp = CurTok; - getNextToken(); // eat binop - - // Parse the unary expression after the binary operator. - auto RHS = ParseUnary(); - if (!RHS) - return nullptr; - - // If BinOp binds less tightly with RHS than the operator after RHS, let - // the pending operator take RHS as its LHS. - int NextPrec = GetTokPrecedence(); - if (TokPrec < NextPrec) { - RHS = ParseBinOpRHS(TokPrec+1, std::move(RHS)); - if (!RHS) - return nullptr; - } - - // Merge LHS/RHS. - LHS = llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); - } -} - -/// expression -/// ::= unary binoprhs -/// -static std::unique_ptr ParseExpression() { - auto LHS = ParseUnary(); - if (!LHS) - return nullptr; - - return ParseBinOpRHS(0, std::move(LHS)); -} - -/// prototype -/// ::= id '(' id* ')' -/// ::= binary LETTER number? (id, id) -/// ::= unary LETTER (id) -static std::unique_ptr ParsePrototype() { - std::string FnName; - - unsigned Kind = 0; // 0 = identifier, 1 = unary, 2 = binary. - unsigned BinaryPrecedence = 30; - - switch (CurTok) { - default: - return ErrorU("Expected function name in prototype"); - case tok_identifier: - FnName = IdentifierStr; - Kind = 0; - getNextToken(); - break; - case tok_unary: - getNextToken(); - if (!isascii(CurTok)) - return ErrorU("Expected unary operator"); - FnName = "unary"; - FnName += (char)CurTok; - Kind = 1; - getNextToken(); - break; - case tok_binary: - getNextToken(); - if (!isascii(CurTok)) - return ErrorU("Expected binary operator"); - FnName = "binary"; - FnName += (char)CurTok; - Kind = 2; - getNextToken(); - - // Read the precedence if present. - if (CurTok == tok_number) { - if (NumVal < 1 || NumVal > 100) - return ErrorU("Invalid precedecnce: must be 1..100"); - BinaryPrecedence = (unsigned)NumVal; - getNextToken(); - } - break; - } - - if (CurTok != '(') - return ErrorU("Expected '(' in prototype"); - - std::vector ArgNames; - while (getNextToken() == tok_identifier) - ArgNames.push_back(IdentifierStr); - if (CurTok != ')') - return ErrorU("Expected ')' in prototype"); - - // success. - getNextToken(); // eat ')'. - - // Verify right number of names for operator. - if (Kind && ArgNames.size() != Kind) - return ErrorU("Invalid number of operands for operator"); - - return llvm::make_unique(FnName, std::move(ArgNames), Kind != 0, - BinaryPrecedence); -} - -/// definition ::= 'def' prototype expression -static std::unique_ptr ParseDefinition() { - getNextToken(); // eat def. - auto Proto = ParsePrototype(); - if (!Proto) - return nullptr; - - if (auto Body = ParseExpression()) - return llvm::make_unique(std::move(Proto), std::move(Body)); - return nullptr; -} - -/// toplevelexpr ::= expression -static std::unique_ptr ParseTopLevelExpr() { - if (auto E = ParseExpression()) { - // Make an anonymous proto. - auto Proto = - llvm::make_unique("__anon_expr", std::vector()); - return llvm::make_unique(std::move(Proto), std::move(E)); - } - return nullptr; -} - -/// external ::= 'extern' prototype -static std::unique_ptr ParseExtern() { - getNextToken(); // eat extern. - return ParsePrototype(); -} - -//===----------------------------------------------------------------------===// -// Code Generation -//===----------------------------------------------------------------------===// - -// FIXME: Obviously we can do better than this -std::string GenerateUniqueName(const std::string &Root) { - static int i = 0; - std::ostringstream NameStream; - NameStream << Root << ++i; - return NameStream.str(); -} - -std::string MakeLegalFunctionName(std::string Name) -{ - std::string NewName; - assert(!Name.empty() && "Base name must not be empty"); - - // Start with what we have - NewName = Name; - - // Look for a numberic first character - if (NewName.find_first_of("0123456789") == 0) { - NewName.insert(0, 1, 'n'); - } - - // Replace illegal characters with their ASCII equivalent - std::string legal_elements = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - size_t pos; - while ((pos = NewName.find_first_not_of(legal_elements)) != std::string::npos) { - std::ostringstream NumStream; - NumStream << (int)NewName.at(pos); - NewName = NewName.replace(pos, 1, NumStream.str()); - } - - return NewName; -} - -class SessionContext { -public: - SessionContext(LLVMContext &C) - : Context(C), TM(EngineBuilder().selectTarget()) {} - LLVMContext& getLLVMContext() const { return Context; } - TargetMachine& getTarget() { return *TM; } - void addPrototypeAST(std::unique_ptr P); - PrototypeAST* getPrototypeAST(const std::string &Name); -private: - typedef std::map> PrototypeMap; - - LLVMContext &Context; - std::unique_ptr TM; - - PrototypeMap Prototypes; -}; - -void SessionContext::addPrototypeAST(std::unique_ptr P) { - Prototypes[P->Name] = std::move(P); -} - -PrototypeAST* SessionContext::getPrototypeAST(const std::string &Name) { - PrototypeMap::iterator I = Prototypes.find(Name); - if (I != Prototypes.end()) - return I->second.get(); - return nullptr; -} - -class IRGenContext { -public: - - IRGenContext(SessionContext &S) - : Session(S), - M(new Module(GenerateUniqueName("jit_module_"), - Session.getLLVMContext())), - Builder(Session.getLLVMContext()) { - M->setDataLayout(Session.getTarget().createDataLayout()); - } - - SessionContext& getSession() { return Session; } - Module& getM() const { return *M; } - std::unique_ptr takeM() { return std::move(M); } - IRBuilder<>& getBuilder() { return Builder; } - LLVMContext& getLLVMContext() { return Session.getLLVMContext(); } - Function* getPrototype(const std::string &Name); - - std::map NamedValues; -private: - SessionContext &Session; - std::unique_ptr M; - IRBuilder<> Builder; -}; - -Function* IRGenContext::getPrototype(const std::string &Name) { - if (Function *ExistingProto = M->getFunction(Name)) - return ExistingProto; - if (PrototypeAST *ProtoAST = Session.getPrototypeAST(Name)) - return ProtoAST->IRGen(*this); - return nullptr; -} - -/// CreateEntryBlockAlloca - Create an alloca instruction in the entry block of -/// the function. This is used for mutable variables etc. -static AllocaInst *CreateEntryBlockAlloca(Function *TheFunction, - const std::string &VarName) { - IRBuilder<> TmpB(&TheFunction->getEntryBlock(), - TheFunction->getEntryBlock().begin()); - return TmpB.CreateAlloca(Type::getDoubleTy(getGlobalContext()), nullptr, - VarName.c_str()); -} - -Value *NumberExprAST::IRGen(IRGenContext &C) const { - return ConstantFP::get(C.getLLVMContext(), APFloat(Val)); -} - -Value *VariableExprAST::IRGen(IRGenContext &C) const { - // Look this variable up in the function. - Value *V = C.NamedValues[Name]; - - if (!V) - return ErrorP("Unknown variable name '" + Name + "'"); - - // Load the value. - return C.getBuilder().CreateLoad(V, Name.c_str()); -} - -Value *UnaryExprAST::IRGen(IRGenContext &C) const { - if (Value *OperandV = Operand->IRGen(C)) { - std::string FnName = MakeLegalFunctionName(std::string("unary")+Opcode); - if (Function *F = C.getPrototype(FnName)) - return C.getBuilder().CreateCall(F, OperandV, "unop"); - return ErrorP("Unknown unary operator"); - } - - // Could not codegen operand - return null. - return nullptr; -} - -Value *BinaryExprAST::IRGen(IRGenContext &C) const { - // Special case '=' because we don't want to emit the LHS as an expression. - if (Op == '=') { - // Assignment requires the LHS to be an identifier. - auto &LHSVar = static_cast(*LHS); - // Codegen the RHS. - Value *Val = RHS->IRGen(C); - if (!Val) return nullptr; - - // Look up the name. - if (auto Variable = C.NamedValues[LHSVar.Name]) { - C.getBuilder().CreateStore(Val, Variable); - return Val; - } - return ErrorP("Unknown variable name"); - } - - Value *L = LHS->IRGen(C); - Value *R = RHS->IRGen(C); - if (!L || !R) return nullptr; - - switch (Op) { - case '+': return C.getBuilder().CreateFAdd(L, R, "addtmp"); - case '-': return C.getBuilder().CreateFSub(L, R, "subtmp"); - case '*': return C.getBuilder().CreateFMul(L, R, "multmp"); - case '/': return C.getBuilder().CreateFDiv(L, R, "divtmp"); - case '<': - L = C.getBuilder().CreateFCmpULT(L, R, "cmptmp"); - // Convert bool 0/1 to double 0.0 or 1.0 - return C.getBuilder().CreateUIToFP(L, Type::getDoubleTy(getGlobalContext()), - "booltmp"); - default: break; - } - - // If it wasn't a builtin binary operator, it must be a user defined one. Emit - // a call to it. - std::string FnName = MakeLegalFunctionName(std::string("binary")+Op); - if (Function *F = C.getPrototype(FnName)) { - Value *Ops[] = { L, R }; - return C.getBuilder().CreateCall(F, Ops, "binop"); - } - - return ErrorP("Unknown binary operator"); -} - -Value *CallExprAST::IRGen(IRGenContext &C) const { - // Look up the name in the global module table. - if (auto CalleeF = C.getPrototype(CalleeName)) { - // If argument mismatch error. - if (CalleeF->arg_size() != Args.size()) - return ErrorP("Incorrect # arguments passed"); - - std::vector ArgsV; - for (unsigned i = 0, e = Args.size(); i != e; ++i) { - ArgsV.push_back(Args[i]->IRGen(C)); - if (!ArgsV.back()) return nullptr; - } - - return C.getBuilder().CreateCall(CalleeF, ArgsV, "calltmp"); - } - - return ErrorP("Unknown function referenced"); -} - -Value *IfExprAST::IRGen(IRGenContext &C) const { - Value *CondV = Cond->IRGen(C); - if (!CondV) return nullptr; - - // Convert condition to a bool by comparing equal to 0.0. - ConstantFP *FPZero = - ConstantFP::get(C.getLLVMContext(), APFloat(0.0)); - CondV = C.getBuilder().CreateFCmpONE(CondV, FPZero, "ifcond"); - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Create blocks for the then and else cases. Insert the 'then' block at the - // end of the function. - BasicBlock *ThenBB = BasicBlock::Create(C.getLLVMContext(), "then", TheFunction); - BasicBlock *ElseBB = BasicBlock::Create(C.getLLVMContext(), "else"); - BasicBlock *MergeBB = BasicBlock::Create(C.getLLVMContext(), "ifcont"); - - C.getBuilder().CreateCondBr(CondV, ThenBB, ElseBB); - - // Emit then value. - C.getBuilder().SetInsertPoint(ThenBB); - - Value *ThenV = Then->IRGen(C); - if (!ThenV) return nullptr; - - C.getBuilder().CreateBr(MergeBB); - // Codegen of 'Then' can change the current block, update ThenBB for the PHI. - ThenBB = C.getBuilder().GetInsertBlock(); - - // Emit else block. - TheFunction->getBasicBlockList().push_back(ElseBB); - C.getBuilder().SetInsertPoint(ElseBB); - - Value *ElseV = Else->IRGen(C); - if (!ElseV) return nullptr; - - C.getBuilder().CreateBr(MergeBB); - // Codegen of 'Else' can change the current block, update ElseBB for the PHI. - ElseBB = C.getBuilder().GetInsertBlock(); - - // Emit merge block. - TheFunction->getBasicBlockList().push_back(MergeBB); - C.getBuilder().SetInsertPoint(MergeBB); - PHINode *PN = C.getBuilder().CreatePHI(Type::getDoubleTy(getGlobalContext()), 2, - "iftmp"); - - PN->addIncoming(ThenV, ThenBB); - PN->addIncoming(ElseV, ElseBB); - return PN; -} - -Value *ForExprAST::IRGen(IRGenContext &C) const { - // Output this as: - // var = alloca double - // ... - // start = startexpr - // store start -> var - // goto loop - // loop: - // ... - // bodyexpr - // ... - // loopend: - // step = stepexpr - // endcond = endexpr - // - // curvar = load var - // nextvar = curvar + step - // store nextvar -> var - // br endcond, loop, endloop - // outloop: - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Create an alloca for the variable in the entry block. - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - - // Emit the start code first, without 'variable' in scope. - Value *StartVal = Start->IRGen(C); - if (!StartVal) return nullptr; - - // Store the value into the alloca. - C.getBuilder().CreateStore(StartVal, Alloca); - - // Make the new basic block for the loop header, inserting after current - // block. - BasicBlock *LoopBB = BasicBlock::Create(getGlobalContext(), "loop", TheFunction); - - // Insert an explicit fall through from the current block to the LoopBB. - C.getBuilder().CreateBr(LoopBB); - - // Start insertion in LoopBB. - C.getBuilder().SetInsertPoint(LoopBB); - - // Within the loop, the variable is defined equal to the PHI node. If it - // shadows an existing variable, we have to restore it, so save it now. - AllocaInst *OldVal = C.NamedValues[VarName]; - C.NamedValues[VarName] = Alloca; - - // Emit the body of the loop. This, like any other expr, can change the - // current BB. Note that we ignore the value computed by the body, but don't - // allow an error. - if (!Body->IRGen(C)) - return nullptr; - - // Emit the step value. - Value *StepVal; - if (Step) { - StepVal = Step->IRGen(C); - if (!StepVal) return nullptr; - } else { - // If not specified, use 1.0. - StepVal = ConstantFP::get(getGlobalContext(), APFloat(1.0)); - } - - // Compute the end condition. - Value *EndCond = End->IRGen(C); - if (!EndCond) return nullptr; - - // Reload, increment, and restore the alloca. This handles the case where - // the body of the loop mutates the variable. - Value *CurVar = C.getBuilder().CreateLoad(Alloca, VarName.c_str()); - Value *NextVar = C.getBuilder().CreateFAdd(CurVar, StepVal, "nextvar"); - C.getBuilder().CreateStore(NextVar, Alloca); - - // Convert condition to a bool by comparing equal to 0.0. - EndCond = C.getBuilder().CreateFCmpONE(EndCond, - ConstantFP::get(getGlobalContext(), APFloat(0.0)), - "loopcond"); - - // Create the "after loop" block and insert it. - BasicBlock *AfterBB = BasicBlock::Create(getGlobalContext(), "afterloop", TheFunction); - - // Insert the conditional branch into the end of LoopEndBB. - C.getBuilder().CreateCondBr(EndCond, LoopBB, AfterBB); - - // Any new code will be inserted in AfterBB. - C.getBuilder().SetInsertPoint(AfterBB); - - // Restore the unshadowed variable. - if (OldVal) - C.NamedValues[VarName] = OldVal; - else - C.NamedValues.erase(VarName); - - // for expr always returns 0.0. - return Constant::getNullValue(Type::getDoubleTy(getGlobalContext())); -} - -Value *VarExprAST::IRGen(IRGenContext &C) const { - std::vector OldBindings; - - Function *TheFunction = C.getBuilder().GetInsertBlock()->getParent(); - - // Register all variables and emit their initializer. - for (unsigned i = 0, e = VarBindings.size(); i != e; ++i) { - auto &VarName = VarBindings[i].first; - auto &Init = VarBindings[i].second; - - // Emit the initializer before adding the variable to scope, this prevents - // the initializer from referencing the variable itself, and permits stuff - // like this: - // var a = 1 in - // var a = a in ... # refers to outer 'a'. - Value *InitVal; - if (Init) { - InitVal = Init->IRGen(C); - if (!InitVal) return nullptr; - } else // If not specified, use 0.0. - InitVal = ConstantFP::get(getGlobalContext(), APFloat(0.0)); - - AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, VarName); - C.getBuilder().CreateStore(InitVal, Alloca); - - // Remember the old variable binding so that we can restore the binding when - // we unrecurse. - OldBindings.push_back(C.NamedValues[VarName]); - - // Remember this binding. - C.NamedValues[VarName] = Alloca; - } - - // Codegen the body, now that all vars are in scope. - Value *BodyVal = Body->IRGen(C); - if (!BodyVal) return nullptr; - - // Pop all our variables from scope. - for (unsigned i = 0, e = VarBindings.size(); i != e; ++i) - C.NamedValues[VarBindings[i].first] = OldBindings[i]; - - // Return the body computation. - return BodyVal; -} - -Function *PrototypeAST::IRGen(IRGenContext &C) const { - std::string FnName = MakeLegalFunctionName(Name); - - // Make the function type: double(double,double) etc. - std::vector Doubles(Args.size(), - Type::getDoubleTy(getGlobalContext())); - FunctionType *FT = FunctionType::get(Type::getDoubleTy(getGlobalContext()), - Doubles, false); - Function *F = Function::Create(FT, Function::ExternalLinkage, FnName, - &C.getM()); - - // If F conflicted, there was already something named 'FnName'. If it has a - // body, don't allow redefinition or reextern. - if (F->getName() != FnName) { - // Delete the one we just made and get the existing one. - F->eraseFromParent(); - F = C.getM().getFunction(Name); - - // If F already has a body, reject this. - if (!F->empty()) { - ErrorP("redefinition of function"); - return nullptr; - } - - // If F took a different number of args, reject. - if (F->arg_size() != Args.size()) { - ErrorP("redefinition of function with different # args"); - return nullptr; - } - } - - // Set names for all arguments. - unsigned Idx = 0; - for (Function::arg_iterator AI = F->arg_begin(); Idx != Args.size(); - ++AI, ++Idx) - AI->setName(Args[Idx]); - - return F; -} - -/// CreateArgumentAllocas - Create an alloca for each argument and register the -/// argument in the symbol table so that references to it will succeed. -void PrototypeAST::CreateArgumentAllocas(Function *F, IRGenContext &C) { - Function::arg_iterator AI = F->arg_begin(); - for (unsigned Idx = 0, e = Args.size(); Idx != e; ++Idx, ++AI) { - // Create an alloca for this variable. - AllocaInst *Alloca = CreateEntryBlockAlloca(F, Args[Idx]); - - // Store the initial value into the alloca. - C.getBuilder().CreateStore(&*AI, Alloca); - - // Add arguments to variable symbol table. - C.NamedValues[Args[Idx]] = Alloca; - } -} - -Function *FunctionAST::IRGen(IRGenContext &C) const { - C.NamedValues.clear(); - - Function *TheFunction = Proto->IRGen(C); - if (!TheFunction) - return nullptr; - - // If this is an operator, install it. - if (Proto->isBinaryOp()) - BinopPrecedence[Proto->getOperatorName()] = Proto->Precedence; - - // Create a new basic block to start insertion into. - BasicBlock *BB = BasicBlock::Create(getGlobalContext(), "entry", TheFunction); - C.getBuilder().SetInsertPoint(BB); - - // Add all arguments to the symbol table and create their allocas. - Proto->CreateArgumentAllocas(TheFunction, C); - - if (Value *RetVal = Body->IRGen(C)) { - // Finish off the function. - C.getBuilder().CreateRet(RetVal); - - // Validate the generated code, checking for consistency. - verifyFunction(*TheFunction); - - return TheFunction; - } - - // Error reading body, remove function. - TheFunction->eraseFromParent(); - - if (Proto->isBinaryOp()) - BinopPrecedence.erase(Proto->getOperatorName()); - return nullptr; -} - -//===----------------------------------------------------------------------===// -// Top-Level parsing and JIT Driver -//===----------------------------------------------------------------------===// - -static std::unique_ptr IRGen(SessionContext &S, - const FunctionAST &F) { - IRGenContext C(S); - auto LF = F.IRGen(C); - if (!LF) - return nullptr; -#ifndef MINIMAL_STDERR_OUTPUT - fprintf(stderr, "Read function definition:"); - LF->dump(); -#endif - return C.takeM(); -} - -template -static std::vector singletonSet(T t) { - std::vector Vec; - Vec.push_back(std::move(t)); - return Vec; -} - -class KaleidoscopeJIT { -public: - typedef ObjectLinkingLayer<> ObjLayerT; - typedef IRCompileLayer CompileLayerT; - typedef LazyEmittingLayer LazyEmitLayerT; - typedef LazyEmitLayerT::ModuleSetHandleT ModuleHandleT; - - KaleidoscopeJIT(SessionContext &Session) - : Session(Session), - CompileLayer(ObjectLayer, SimpleCompiler(Session.getTarget())), - LazyEmitLayer(CompileLayer) {} - - std::string mangle(const std::string &Name) { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, - Session.getTarget().createDataLayout()); - } - return MangledName; - } - - void addFunctionAST(std::unique_ptr FnAST) { - std::cerr << "Adding AST: " << FnAST->Proto->Name << "\n"; - FunctionDefs[mangle(FnAST->Proto->Name)] = std::move(FnAST); - } - - ModuleHandleT addModule(std::unique_ptr M) { - // We need a memory manager to allocate memory and resolve symbols for this - // new module. Create one that resolves symbols by looking back into the - // JIT. - auto Resolver = createLambdaResolver( - [&](const std::string &Name) { - // First try to find 'Name' within the JIT. - if (auto Symbol = findSymbol(Name)) - return RuntimeDyld::SymbolInfo(Symbol.getAddress(), - Symbol.getFlags()); - - // If we don't already have a definition of 'Name' then search - // the ASTs. - return searchFunctionASTs(Name); - }, - [](const std::string &S) { return nullptr; } ); - - return LazyEmitLayer.addModuleSet(singletonSet(std::move(M)), - make_unique(), - std::move(Resolver)); - } - - void removeModule(ModuleHandleT H) { LazyEmitLayer.removeModuleSet(H); } - - JITSymbol findSymbol(const std::string &Name) { - return LazyEmitLayer.findSymbol(Name, true); - } - - JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name) { - return LazyEmitLayer.findSymbolIn(H, Name, true); - } - - JITSymbol findUnmangledSymbol(const std::string &Name) { - return findSymbol(mangle(Name)); - } - -private: - - // This method searches the FunctionDefs map for a definition of 'Name'. If it - // finds one it generates a stub for it and returns the address of the stub. - RuntimeDyld::SymbolInfo searchFunctionASTs(const std::string &Name) { - auto DefI = FunctionDefs.find(Name); - if (DefI == FunctionDefs.end()) - return nullptr; - - // Take the FunctionAST out of the map. - auto FnAST = std::move(DefI->second); - FunctionDefs.erase(DefI); - - // IRGen the AST, add it to the JIT, and return the address for it. - auto H = addModule(IRGen(Session, *FnAST)); - auto Sym = findSymbolIn(H, Name); - return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); - } - - SessionContext &Session; - ObjLayerT ObjectLayer; - CompileLayerT CompileLayer; - LazyEmitLayerT LazyEmitLayer; - - std::map> FunctionDefs; -}; - -static void HandleDefinition(SessionContext &S, KaleidoscopeJIT &J) { - if (auto F = ParseDefinition()) { - S.addPrototypeAST(llvm::make_unique(*F->Proto)); - J.addFunctionAST(std::move(F)); - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -static void HandleExtern(SessionContext &S) { - if (auto P = ParseExtern()) - S.addPrototypeAST(std::move(P)); - else { - // Skip token for error recovery. - getNextToken(); - } -} - -static void HandleTopLevelExpression(SessionContext &S, KaleidoscopeJIT &J) { - // Evaluate a top-level expression into an anonymous function. - if (auto F = ParseTopLevelExpr()) { - IRGenContext C(S); - if (auto ExprFunc = F->IRGen(C)) { -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "Expression function:\n"; - ExprFunc->dump(); -#endif - // Add the CodeGen'd module to the JIT. Keep a handle to it: We can remove - // this module as soon as we've executed Function ExprFunc. - auto H = J.addModule(C.takeM()); - - // Get the address of the JIT'd function in memory. - auto ExprSymbol = J.findUnmangledSymbol("__anon_expr"); - - // Cast it to the right type (takes no arguments, returns a double) so we - // can call it as a native function. - double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress(); -#ifdef MINIMAL_STDERR_OUTPUT - FP(); -#else - std::cerr << "Evaluated to " << FP() << "\n"; -#endif - - // Remove the function. - J.removeModule(H); - } - } else { - // Skip token for error recovery. - getNextToken(); - } -} - -/// top ::= definition | external | expression | ';' -static void MainLoop() { - SessionContext S(getGlobalContext()); - KaleidoscopeJIT J(S); - - while (1) { - switch (CurTok) { - case tok_eof: return; - case ';': getNextToken(); continue; // ignore top-level semicolons. - case tok_def: HandleDefinition(S, J); break; - case tok_extern: HandleExtern(S); break; - default: HandleTopLevelExpression(S, J); break; - } -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "ready> "; -#endif - } -} - -//===----------------------------------------------------------------------===// -// "Library" functions that can be "extern'd" from user code. -//===----------------------------------------------------------------------===// - -/// putchard - putchar that takes a double and returns 0. -extern "C" -double putchard(double X) { - putchar((char)X); - return 0; -} - -/// printd - printf that takes a double prints it as "%f\n", returning 0. -extern "C" -double printd(double X) { - printf("%f", X); - return 0; -} - -extern "C" -double printlf() { - printf("\n"); - return 0; -} - -//===----------------------------------------------------------------------===// -// Main driver code. -//===----------------------------------------------------------------------===// - -int main() { - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetAsmParser(); - - // Install standard binary operators. - // 1 is lowest precedence. - BinopPrecedence['='] = 2; - BinopPrecedence['<'] = 10; - BinopPrecedence['+'] = 20; - BinopPrecedence['-'] = 20; - BinopPrecedence['/'] = 40; - BinopPrecedence['*'] = 40; // highest. - - // Prime the first token. -#ifndef MINIMAL_STDERR_OUTPUT - std::cerr << "ready> "; -#endif - getNextToken(); - - std::cerr << std::fixed; - - // Run the main "interpreter loop" now. - MainLoop(); - - return 0; -} diff --git a/examples/Kaleidoscope/include/KaleidoscopeJIT.h b/examples/Kaleidoscope/include/KaleidoscopeJIT.h index 0c825cc94c0e1a4696f37b9e1b4073bbc2844655..2f492b0e17ffdf89597f2e2fc7fba9783396a163 100644 --- a/examples/Kaleidoscope/include/KaleidoscopeJIT.h +++ b/examples/Kaleidoscope/include/KaleidoscopeJIT.h @@ -14,14 +14,27 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H +#include "llvm/ADT/iterator_range.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/JITSymbolFlags.h" #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/Mangler.h" #include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include +#include +#include +#include namespace llvm { namespace orc { @@ -47,7 +60,7 @@ public: auto Resolver = createLambdaResolver( [&](const std::string &Name) { if (auto Sym = findMangledSymbol(Name)) - return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); + return Sym.toRuntimeDyldSymbol(); return RuntimeDyld::SymbolInfo(nullptr); }, [](const std::string &S) { return nullptr; }); @@ -70,7 +83,6 @@ public: } private: - std::string mangle(const std::string &Name) { std::string MangledName; { @@ -108,7 +120,7 @@ private: std::vector ModuleHandles; }; -} // End namespace orc. -} // End namespace llvm +} // end namespace orc +} // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H diff --git a/examples/ModuleMaker/ModuleMaker.cpp b/examples/ModuleMaker/ModuleMaker.cpp index c931972f5b60d337974b505675296a50b9b4b1af..d6f998b39225c694b8e83391530d747569429d73 100644 --- a/examples/ModuleMaker/ModuleMaker.cpp +++ b/examples/ModuleMaker/ModuleMaker.cpp @@ -14,12 +14,18 @@ //===----------------------------------------------------------------------===// #include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" #include "llvm/Support/raw_ostream.h" + using namespace llvm; int main() { diff --git a/examples/ParallelJIT/ParallelJIT.cpp b/examples/ParallelJIT/ParallelJIT.cpp index 3c485d4c964d1532972d4b57adaeab2686de65aa..6fb8bd61982b5a141d305c2827d6badc88e9fb5a 100644 --- a/examples/ParallelJIT/ParallelJIT.cpp +++ b/examples/ParallelJIT/ParallelJIT.cpp @@ -16,17 +16,33 @@ // wakes them up. This complicated work is performed so that all three threads // call into the JIT at the same time (or the best possible approximation of the // same time). This test had assertion errors until I got the locking right. +// +//===----------------------------------------------------------------------===// +#include "llvm/ADT/APInt.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/Interpreter.h" +#include "llvm/IR/Argument.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/TargetSelect.h" +#include +#include +#include +#include #include +#include +#include #include using namespace llvm; diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h index db7e3b1244f9ed18f9d978344f9447ba594a3750..6bdb96ac433325b6768e71db4532674b64a672ff 100644 --- a/include/llvm-c/Core.h +++ b/include/llvm-c/Core.h @@ -94,6 +94,8 @@ typedef enum { LLVMJumpTableAttribute = 1ULL << 45, LLVMConvergentAttribute = 1ULL << 46, LLVMSafeStackAttribute = 1ULL << 47, + LLVMSwiftSelfAttribute = 1ULL << 48, + LLVMSwiftErrorAttribute = 1ULL << 49, */ } LLVMAttribute; @@ -245,6 +247,38 @@ typedef enum { LLVMX86FastcallCallConv = 65 } LLVMCallConv; +typedef enum { + LLVMArgumentValueKind, + LLVMBasicBlockValueKind, + LLVMMemoryUseValueKind, + LLVMMemoryDefValueKind, + LLVMMemoryPhiValueKind, + + LLVMFunctionValueKind, + LLVMGlobalAliasValueKind, + LLVMGlobalIFuncValueKind, + LLVMGlobalVariableValueKind, + LLVMBlockAddressValueKind, + LLVMConstantExprValueKind, + LLVMConstantArrayValueKind, + LLVMConstantStructValueKind, + LLVMConstantVectorValueKind, + + LLVMUndefValueValueKind, + LLVMConstantAggregateZeroValueKind, + LLVMConstantDataArrayValueKind, + LLVMConstantDataVectorValueKind, + LLVMConstantIntValueKind, + LLVMConstantFPValueKind, + LLVMConstantPointerNullValueKind, + LLVMConstantTokenNoneValueKind, + + LLVMMetadataAsValueValueKind, + LLVMInlineAsmValueKind, + + LLVMInstructionValueKind, +} LLVMValueKind; + typedef enum { LLVMIntEQ = 32, /**< equal */ LLVMIntNE, /**< not equal */ @@ -346,6 +380,20 @@ typedef enum { LLVMDSNote } LLVMDiagnosticSeverity; +/** + * Attribute index are either LLVMAttributeReturnIndex, + * LLVMAttributeFunctionIndex or a parameter number from 1 to N. + */ +enum { + LLVMAttributeReturnIndex = 0U, + // ISO C restricts enumerator values to range of 'int' + // (4294967295 is too large) + // LLVMAttributeFunctionIndex = ~0U, + LLVMAttributeFunctionIndex = -1, +}; + +typedef unsigned LLVMAttributeIndex; + /** * @} */ @@ -397,6 +445,16 @@ void LLVMContextSetDiagnosticHandler(LLVMContextRef C, LLVMDiagnosticHandler Handler, void *DiagnosticContext); +/** + * Get the diagnostic handler of this context. + */ +LLVMDiagnosticHandler LLVMContextGetDiagnosticHandler(LLVMContextRef C); + +/** + * Get the diagnostic context of this context. + */ +void *LLVMContextGetDiagnosticContext(LLVMContextRef C); + /** * Set the yield callback function for this context. * @@ -428,9 +486,63 @@ char *LLVMGetDiagInfoDescription(LLVMDiagnosticInfoRef DI); */ LLVMDiagnosticSeverity LLVMGetDiagInfoSeverity(LLVMDiagnosticInfoRef DI); -unsigned LLVMGetMDKindIDInContext(LLVMContextRef C, const char* Name, +unsigned LLVMGetMDKindIDInContext(LLVMContextRef C, const char *Name, unsigned SLen); -unsigned LLVMGetMDKindID(const char* Name, unsigned SLen); +unsigned LLVMGetMDKindID(const char *Name, unsigned SLen); + +/** + * Return an unique id given the name of a enum attribute, + * or 0 if no attribute by that name exists. + * + * See http://llvm.org/docs/LangRef.html#parameter-attributes + * and http://llvm.org/docs/LangRef.html#function-attributes + * for the list of available attributes. + * + * NB: Attribute names and/or id are subject to change without + * going through the C API deprecation cycle. + */ +unsigned LLVMGetEnumAttributeKindForName(const char *Name, size_t SLen); +unsigned LLVMGetLastEnumAttributeKind(void); + +/** + * Create an enum attribute. + */ +LLVMAttributeRef LLVMCreateEnumAttribute(LLVMContextRef C, unsigned KindID, + uint64_t Val); + +/** + * Get the unique id corresponding to the enum attribute + * passed as argument. + */ +unsigned LLVMGetEnumAttributeKind(LLVMAttributeRef A); + +/** + * Get the enum attribute's value. 0 is returned if none exists. + */ +uint64_t LLVMGetEnumAttributeValue(LLVMAttributeRef A); + +/** + * Create a string attribute. + */ +LLVMAttributeRef LLVMCreateStringAttribute(LLVMContextRef C, + const char *K, unsigned KLength, + const char *V, unsigned VLength); + +/** + * Get the string attribute's kind. + */ +const char *LLVMGetStringAttributeKind(LLVMAttributeRef A, unsigned *Length); + +/** + * Get the string attribute's value. + */ +const char *LLVMGetStringAttributeValue(LLVMAttributeRef A, unsigned *Length); + +/** + * Check for the different types of attributes. + */ +LLVMBool LLVMIsEnumAttribute(LLVMAttributeRef A); +LLVMBool LLVMIsStringAttribute(LLVMAttributeRef A); /** * @} @@ -478,6 +590,26 @@ LLVMModuleRef LLVMCloneModule(LLVMModuleRef M); */ void LLVMDisposeModule(LLVMModuleRef M); +/** + * Obtain the identifier of a module. + * + * @param M Module to obtain identifier of + * @param Len Out parameter which holds the length of the returned string. + * @return The identifier of M. + * @see Module::getModuleIdentifier() + */ +const char *LLVMGetModuleIdentifier(LLVMModuleRef M, size_t *Len); + +/** + * Set the identifier of a module to a string Ident with length Len. + * + * @param M The module to set identifier + * @param Ident The string to set M's identifier to + * @param Len Length of Ident + * @see Module::setModuleIdentifier() + */ +void LLVMSetModuleIdentifier(LLVMModuleRef M, const char *Ident, size_t Len); + /** * Obtain the data layout for a module. * @@ -559,7 +691,7 @@ LLVMTypeRef LLVMGetTypeByName(LLVMModuleRef M, const char *Name); * * @see llvm::Module::getNamedMetadata() */ -unsigned LLVMGetNamedMetadataNumOperands(LLVMModuleRef M, const char* name); +unsigned LLVMGetNamedMetadataNumOperands(LLVMModuleRef M, const char *Name); /** * Obtain the named metadata operands for a module. @@ -572,7 +704,8 @@ unsigned LLVMGetNamedMetadataNumOperands(LLVMModuleRef M, const char* name); * @see llvm::Module::getNamedMetadata() * @see llvm::MDNode::getOperand() */ -void LLVMGetNamedMetadataOperands(LLVMModuleRef M, const char* name, LLVMValueRef *Dest); +void LLVMGetNamedMetadataOperands(LLVMModuleRef M, const char *Name, + LLVMValueRef *Dest); /** * Add an operand to named metadata. @@ -580,7 +713,7 @@ void LLVMGetNamedMetadataOperands(LLVMModuleRef M, const char* name, LLVMValueRe * @see llvm::Module::getNamedMetadata() * @see llvm::MDNode::addOperand() */ -void LLVMAddNamedMetadataOperand(LLVMModuleRef M, const char* name, +void LLVMAddNamedMetadataOperand(LLVMModuleRef M, const char *Name, LLVMValueRef Val); /** @@ -1168,6 +1301,13 @@ LLVMTypeRef LLVMX86MMXType(void); */ LLVMTypeRef LLVMTypeOf(LLVMValueRef Val); +/** + * Obtain the enumerated type of a Value instance. + * + * @see llvm::Value::getValueID() + */ +LLVMValueKind LLVMGetValueKind(LLVMValueRef Val); + /** * Obtain the string name of a value. * @@ -1525,7 +1665,7 @@ LLVMBool LLVMIsConstantString(LLVMValueRef c); * * @see ConstantDataSequential::getAsString() */ -const char *LLVMGetAsString(LLVMValueRef c, size_t* out); +const char *LLVMGetAsString(LLVMValueRef c, size_t *Length); /** * Create an anonymous ConstantStruct with the specified values. @@ -1872,6 +2012,19 @@ void LLVMSetGC(LLVMValueRef Fn, const char *Name); */ void LLVMAddFunctionAttr(LLVMValueRef Fn, LLVMAttribute PA); +void LLVMAddAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, + LLVMAttributeRef A); +LLVMAttributeRef LLVMGetEnumAttributeAtIndex(LLVMValueRef F, + LLVMAttributeIndex Idx, + unsigned KindID); +LLVMAttributeRef LLVMGetStringAttributeAtIndex(LLVMValueRef F, + LLVMAttributeIndex Idx, + const char *K, unsigned KLen); +void LLVMRemoveEnumAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, + unsigned KindID); +void LLVMRemoveStringAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, + const char *K, unsigned KLen); + /** * Add a target-dependent attribute to a function * @see llvm::AttrBuilder::addAttribute() @@ -1997,7 +2150,7 @@ LLVMAttribute LLVMGetAttribute(LLVMValueRef Arg); * @see llvm::Argument::addAttr() * @see llvm::AttrBuilder::addAlignmentAttr() */ -void LLVMSetParamAlignment(LLVMValueRef Arg, unsigned align); +void LLVMSetParamAlignment(LLVMValueRef Arg, unsigned Align); /** * @} @@ -2055,10 +2208,10 @@ LLVMValueRef LLVMMDNode(LLVMValueRef *Vals, unsigned Count); * Obtain the underlying string from a MDString value. * * @param V Instance to obtain string from. - * @param Len Memory address which will hold length of returned string. + * @param Length Memory address which will hold length of returned string. * @return String data in MDString. */ -const char *LLVMGetMDString(LLVMValueRef V, unsigned* Len); +const char *LLVMGetMDString(LLVMValueRef V, unsigned *Length); /** * Obtain the number of operands from an MDNode value. @@ -2439,12 +2592,24 @@ void LLVMSetInstructionCallConv(LLVMValueRef Instr, unsigned CC); */ unsigned LLVMGetInstructionCallConv(LLVMValueRef Instr); - void LLVMAddInstrAttribute(LLVMValueRef Instr, unsigned index, LLVMAttribute); void LLVMRemoveInstrAttribute(LLVMValueRef Instr, unsigned index, LLVMAttribute); void LLVMSetInstrParamAlignment(LLVMValueRef Instr, unsigned index, - unsigned align); + unsigned Align); + +void LLVMAddCallSiteAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, + LLVMAttributeRef A); +LLVMAttributeRef LLVMGetCallSiteEnumAttribute(LLVMValueRef C, + LLVMAttributeIndex Idx, + unsigned KindID); +LLVMAttributeRef LLVMGetCallSiteStringAttribute(LLVMValueRef C, + LLVMAttributeIndex Idx, + const char *K, unsigned KLen); +void LLVMRemoveCallSiteEnumAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, + unsigned KindID); +void LLVMRemoveCallSiteStringAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, + const char *K, unsigned KLen); /** * Obtain the pointer to the function invoked by this instruction. @@ -2620,7 +2785,7 @@ LLVMBool LLVMIsInBounds(LLVMValueRef GEP); /** * Set the given GEP instruction to be inbounds or not. */ -void LLVMSetIsInBounds(LLVMValueRef GEP, LLVMBool b); +void LLVMSetIsInBounds(LLVMValueRef GEP, LLVMBool InBounds); /** * @} diff --git a/include/llvm-c/OrcBindings.h b/include/llvm-c/OrcBindings.h index 92e6ca310b13d35d38dabc7ed566d2e4776ca2b4..de2969ab1c9bbb5baa2986172e8823de27394e80 100644 --- a/include/llvm-c/OrcBindings.h +++ b/include/llvm-c/OrcBindings.h @@ -32,11 +32,12 @@ extern "C" { typedef struct LLVMOrcOpaqueJITStack *LLVMOrcJITStackRef; typedef uint32_t LLVMOrcModuleHandle; typedef uint64_t LLVMOrcTargetAddress; -typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name, - void *LookupCtx); +typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name, void *LookupCtx); typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack, void *CallbackCtx); +typedef enum { LLVMOrcErrSuccess = 0, LLVMOrcErrGeneric } LLVMOrcErrorCode; + /** * Create an ORC JIT stack. * @@ -48,6 +49,14 @@ typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack, */ LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM); +/** + * Get the error message for the most recent error (if any). + * + * This message is owned by the ORC JIT Stack and will be freed when the stack + * is disposed of by LLVMOrcDisposeInstance. + */ +const char *LLVMOrcGetErrorMsg(LLVMOrcJITStackRef JITStack); + /** * Mangle the given symbol. * Memory will be allocated for MangledSymbol to hold the result. The client @@ -58,7 +67,6 @@ void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledSymbol, /** * Dispose of a mangled symbol. */ - void LLVMOrcDisposeMangledSymbol(char *MangledSymbol); /** @@ -72,16 +80,16 @@ LLVMOrcCreateLazyCompileCallback(LLVMOrcJITStackRef JITStack, /** * Create a named indirect call stub. */ -void LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack, - const char *StubName, - LLVMOrcTargetAddress InitAddr); +LLVMOrcErrorCode LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack, + const char *StubName, + LLVMOrcTargetAddress InitAddr); /** * Set the pointer for the given indirect stub. */ -void LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack, - const char *StubName, - LLVMOrcTargetAddress NewAddr); +LLVMOrcErrorCode LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack, + const char *StubName, + LLVMOrcTargetAddress NewAddr); /** * Add module to be eagerly compiled. @@ -102,10 +110,10 @@ LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod, /** * Add an object file. */ -LLVMOrcModuleHandle -LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack, LLVMObjectFileRef Obj, - LLVMOrcSymbolResolverFn SymbolResolver, - void *SymbolResolverCtx); +LLVMOrcModuleHandle LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack, + LLVMObjectFileRef Obj, + LLVMOrcSymbolResolverFn SymbolResolver, + void *SymbolResolverCtx); /** * Remove a module set from the JIT. diff --git a/include/llvm-c/Transforms/Scalar.h b/include/llvm-c/Transforms/Scalar.h index c989ee86b9f7f381fd1f9798498b66ddd8d1827d..b8a09984aa4db643d72be301d27174bd022cfa4a 100644 --- a/include/llvm-c/Transforms/Scalar.h +++ b/include/llvm-c/Transforms/Scalar.h @@ -104,13 +104,13 @@ void LLVMAddReassociatePass(LLVMPassManagerRef PM); /** See llvm::createSCCPPass function. */ void LLVMAddSCCPPass(LLVMPassManagerRef PM); -/** See llvm::createScalarReplAggregatesPass function. */ +/** See llvm::createSROAPass function. */ void LLVMAddScalarReplAggregatesPass(LLVMPassManagerRef PM); -/** See llvm::createScalarReplAggregatesPass function. */ +/** See llvm::createSROAPass function. */ void LLVMAddScalarReplAggregatesPassSSA(LLVMPassManagerRef PM); -/** See llvm::createScalarReplAggregatesPass function. */ +/** See llvm::createSROAPass function. */ void LLVMAddScalarReplAggregatesPassWithThreshold(LLVMPassManagerRef PM, int Threshold); diff --git a/include/llvm-c/Types.h b/include/llvm-c/Types.h index 19029584efcccef1217f32262b095e27c9a4a6f2..3d472a6bf47d0e6dd505b65d02b4bb79bac37416 100644 --- a/include/llvm-c/Types.h +++ b/include/llvm-c/Types.h @@ -108,6 +108,13 @@ typedef struct LLVMOpaquePassRegistry *LLVMPassRegistryRef; * @see llvm::Use */ typedef struct LLVMOpaqueUse *LLVMUseRef; +/** + * Used to represent an attributes. + * + * @see llvm::Attribute + */ +typedef struct LLVMOpaqueAttributeRef *LLVMAttributeRef; + /** * @see llvm::DiagnosticInfo */ diff --git a/include/llvm-c/lto.h b/include/llvm-c/lto.h index 42c280210a2a35c84ec7dd98f7811a41db90378c..b1f5a45d6650e323cc220bfd4edcaa3abc23cf58 100644 --- a/include/llvm-c/lto.h +++ b/include/llvm-c/lto.h @@ -44,7 +44,8 @@ typedef bool lto_bool_t; * @{ */ -#define LTO_API_VERSION 18 +#define LTO_API_VERSION 20 + /** * \since prior to LTO_API_VERSION=3 */ @@ -135,12 +136,21 @@ lto_module_is_object_file_for_target(const char* path, const char* target_triple_prefix); /** - * Checks if a buffer is a loadable object file. + * Return true if \p Buffer contains a bitcode file with ObjC code (category + * or class) in it. * - * \since prior to LTO_API_VERSION=3 + * \since LTO_API_VERSION=20 */ extern lto_bool_t -lto_module_is_object_file_in_memory(const void* mem, size_t length); +lto_module_has_objc_category(const void *mem, size_t length); + +/** +* Checks if a buffer is a loadable object file. +* +* \since prior to LTO_API_VERSION=3 +*/ +extern lto_bool_t lto_module_is_object_file_in_memory(const void *mem, + size_t length); /** * Checks if a buffer is a loadable object compiled for requested target. @@ -658,6 +668,7 @@ extern lto_bool_t thinlto_codegen_set_pic_model(thinlto_code_gen_t cg, /** * Sets the path to a directory to use as a cache storage for incremental build. + * Setting this activates caching. * * \since LTO_API_VERSION=18 */ @@ -666,7 +677,8 @@ extern void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg, /** * Sets the cache pruning interval (in seconds). A negative value disable the - * pruning (default). + * pruning. An unspecified default value will be applied, and a value of 0 will + * be ignored. * * \since LTO_API_VERSION=18 */ @@ -677,7 +689,8 @@ extern void thinlto_codegen_set_cache_pruning_interval(thinlto_code_gen_t cg, * Sets the maximum cache size that can be persistent across build, in terms of * percentage of the available space on the the disk. Set to 100 to indicate * no limit, 50 to indicate that the cache size will not be left over half the - * available space. A value over 100 will be reduced to 100. + * available space. A value over 100 will be reduced to 100, a value of 0 will + * be ignored. An unspecified default value will be applied. * * The formula looks like: * AvailableSpace = FreeSpace + ExistingCacheSize @@ -689,7 +702,8 @@ extern void thinlto_codegen_set_final_cache_size_relative_to_available_space( thinlto_code_gen_t cg, unsigned percentage); /** - * Sets the expiration (in seconds) for an entry in the cache. + * Sets the expiration (in seconds) for an entry in the cache. An unspecified + * default value will be applied. A value of 0 will be ignored. * * \since LTO_API_VERSION=18 */ @@ -717,6 +731,23 @@ extern void thinlto_codegen_set_savetemps_dir(thinlto_code_gen_t cg, */ extern void thinlto_codegen_set_cpu(thinlto_code_gen_t cg, const char *cpu); +/** + * Disable CodeGen, only run the stages till codegen and stop. The output will + * be bitcode. + * + * \since LTO_API_VERSION=19 + */ +extern void thinlto_codegen_disable_codegen(thinlto_code_gen_t cg, + lto_bool_t disable); + +/** + * Perform CodeGen only: disable all other stages. + * + * \since LTO_API_VERSION=19 + */ +extern void thinlto_codegen_set_codegen_only(thinlto_code_gen_t cg, + lto_bool_t codegen_only); + /** * Parse -mllvm style debug options. * diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index 3decdf2eca9e138b9084f64663f82f0a8a4443f8..3f6bd00a779ce74707a453007ea25ed8a35a0710 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -25,6 +25,8 @@ struct fltSemantics; class APSInt; class StringRef; +template class SmallVectorImpl; + /// Enum that represents what fraction of the LSB truncated bits of an fp number /// represent. /// diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h index 1e10253ffe18d0688aba3db2279046e33d0b6e55..d77d1c7ca93f3aac0b9c50b1201c165ace5849d5 100644 --- a/include/llvm/ADT/APInt.h +++ b/include/llvm/ADT/APInt.h @@ -16,7 +16,6 @@ #ifndef LLVM_ADT_APINT_H #define LLVM_ADT_APINT_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" #include @@ -31,6 +30,7 @@ class hash_code; class raw_ostream; template class SmallVectorImpl; +template class ArrayRef; // An unsigned host type used as a single part of a multi-part // bignum. @@ -177,11 +177,11 @@ class APInt { /// provides a more convenient form of divide for internal use since KnuthDiv /// has specific constraints on its inputs. If those constraints are not met /// then it provides a simpler form of divide. - static void divide(const APInt LHS, unsigned lhsWords, const APInt &RHS, + static void divide(const APInt &LHS, unsigned lhsWords, const APInt &RHS, unsigned rhsWords, APInt *Quotient, APInt *Remainder); /// out-of-line slow case for inline constructor - void initSlowCase(unsigned numBits, uint64_t val, bool isSigned); + void initSlowCase(uint64_t val, bool isSigned); /// shared code between two array constructors void initFromArray(ArrayRef array); @@ -239,7 +239,7 @@ public: if (isSingleWord()) VAL = val; else - initSlowCase(numBits, val, isSigned); + initSlowCase(val, isSigned); clearUnusedBits(); } @@ -625,7 +625,12 @@ public: /// Negates *this using two's complement logic. /// /// \returns An APInt value representing the negation of *this. - APInt operator-() const { return APInt(BitWidth, 0) - (*this); } + APInt operator-() const { + APInt Result(*this); + Result.flipAllBits(); + ++Result; + return Result; + } /// \brief Logical negation operator. /// @@ -835,13 +840,13 @@ public: /// /// Adds RHS to this APInt and returns the result. APInt operator+(const APInt &RHS) const; - APInt operator+(uint64_t RHS) const { return (*this) + APInt(BitWidth, RHS); } + APInt operator+(uint64_t RHS) const; /// \brief Subtraction operator. /// /// Subtracts RHS from this APInt and returns the result. APInt operator-(const APInt &RHS) const; - APInt operator-(uint64_t RHS) const { return (*this) - APInt(BitWidth, RHS); } + APInt operator-(uint64_t RHS) const; /// \brief Left logical shift operator. /// @@ -1782,6 +1787,13 @@ inline bool isMask(unsigned numBits, const APInt &APIVal) { APIVal == APInt::getLowBitsSet(APIVal.getBitWidth(), numBits); } +/// \returns true if the argument is a non-empty sequence of ones starting at +/// the least significant bit with the remainder zero (32 bit version). +/// Ex. isMask(0x0000FFFFU) == true. +inline bool isMask(const APInt &Value) { + return (Value != 0) && ((Value + 1) & Value) == 0; +} + /// \brief Return true if the argument APInt value contains a sequence of ones /// with the remainder zero. inline bool isShiftedMask(unsigned numBits, const APInt &APIVal) { diff --git a/include/llvm/ADT/ArrayRef.h b/include/llvm/ADT/ArrayRef.h index a801e985d15ce9daad14b4ffd0b05f675bdf2671..95a1e62ef00576e1132ee974326b2e0a36cce883 100644 --- a/include/llvm/ADT/ArrayRef.h +++ b/include/llvm/ADT/ArrayRef.h @@ -161,20 +161,26 @@ namespace llvm { } /// slice(n) - Chop off the first N elements of the array. - ArrayRef slice(unsigned N) const { + ArrayRef slice(size_t N) const { assert(N <= size() && "Invalid specifier"); return ArrayRef(data()+N, size()-N); } /// slice(n, m) - Chop off the first N elements of the array, and keep M /// elements in the array. - ArrayRef slice(unsigned N, unsigned M) const { + ArrayRef slice(size_t N, size_t M) const { assert(N+M <= size() && "Invalid specifier"); return ArrayRef(data()+N, M); } - // \brief Drop the last \p N elements of the array. - ArrayRef drop_back(unsigned N = 1) const { + /// \brief Drop the first \p N elements of the array. + ArrayRef drop_front(size_t N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return slice(N, size() - N); + } + + /// \brief Drop the last \p N elements of the array. + ArrayRef drop_back(size_t N = 1) const { assert(size() >= N && "Dropping more elements than exist"); return slice(0, size() - N); } @@ -273,19 +279,25 @@ namespace llvm { } /// slice(n) - Chop off the first N elements of the array. - MutableArrayRef slice(unsigned N) const { + MutableArrayRef slice(size_t N) const { assert(N <= this->size() && "Invalid specifier"); return MutableArrayRef(data()+N, this->size()-N); } /// slice(n, m) - Chop off the first N elements of the array, and keep M /// elements in the array. - MutableArrayRef slice(unsigned N, unsigned M) const { + MutableArrayRef slice(size_t N, size_t M) const { assert(N+M <= this->size() && "Invalid specifier"); return MutableArrayRef(data()+N, M); } - MutableArrayRef drop_back(unsigned N) const { + /// \brief Drop the first \p N elements of the array. + MutableArrayRef drop_front(size_t N = 1) const { + assert(this->size() >= N && "Dropping more elements than exist"); + return slice(N, this->size() - N); + } + + MutableArrayRef drop_back(size_t N = 1) const { assert(this->size() >= N && "Dropping more elements than exist"); return slice(0, this->size() - N); } diff --git a/include/llvm/ADT/BitVector.h b/include/llvm/ADT/BitVector.h index 70ed2468f928698552e10b2e135ef4fe504da938..661437126d4885af5f0f7930ac9f11e98f42528a 100644 --- a/include/llvm/ADT/BitVector.h +++ b/include/llvm/ADT/BitVector.h @@ -14,13 +14,13 @@ #ifndef LLVM_ADT_BITVECTOR_H #define LLVM_ADT_BITVECTOR_H -#include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include #include #include +#include #include +#include namespace llvm { @@ -69,7 +69,7 @@ public: } operator bool() const { - return ((*WordRef) & (BitWord(1) << BitPos)) ? true : false; + return ((*WordRef) & (BitWord(1) << BitPos)) != 0; } }; @@ -105,6 +105,7 @@ public: BitVector(BitVector &&RHS) : Bits(RHS.Bits), Size(RHS.Size), Capacity(RHS.Capacity) { RHS.Bits = nullptr; + RHS.Size = RHS.Capacity = 0; } ~BitVector() { @@ -454,6 +455,7 @@ public: Capacity = RHS.Capacity; RHS.Bits = nullptr; + RHS.Size = RHS.Capacity = 0; return *this; } @@ -576,7 +578,7 @@ static inline size_t capacity_in_bytes(const BitVector &X) { return X.getMemorySize(); } -} // End llvm namespace +} // end namespace llvm namespace std { /// Implement std::swap in terms of BitVector swap. @@ -584,6 +586,6 @@ namespace std { swap(llvm::BitVector &LHS, llvm::BitVector &RHS) { LHS.swap(RHS); } -} +} // end namespace std -#endif +#endif // LLVM_ADT_BITVECTOR_H diff --git a/include/llvm/ADT/BitmaskEnum.h b/include/llvm/ADT/BitmaskEnum.h new file mode 100644 index 0000000000000000000000000000000000000000..18c6ba5a3eb8b28d8ed20b0ffbedf4fd1b7c4d8c --- /dev/null +++ b/include/llvm/ADT/BitmaskEnum.h @@ -0,0 +1,153 @@ +//===-- llvm/ADT/BitmaskEnum.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_BITMASKENUM_H +#define LLVM_ADT_BITMASKENUM_H + +#include +#include +#include + +#include "llvm/Support/MathExtras.h" + +/// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can +/// perform bitwise operations on it without putting static_cast everywhere. +/// +/// \code +/// enum MyEnum { +/// E1 = 1, E2 = 2, E3 = 4, E4 = 8, +/// LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4) +/// }; +/// +/// void Foo() { +/// MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast! +/// } +/// \endcode +/// +/// Normally when you do a bitwise operation on an enum value, you get back an +/// instance of the underlying type (e.g. int). But using this macro, bitwise +/// ops on your enum will return you back instances of the enum. This is +/// particularly useful for enums which represent a combination of flags. +/// +/// The parameter to LLVM_MARK_AS_BITMASK_ENUM should be the largest individual +/// value in your enum. +/// +/// All of the enum's values must be non-negative. +#define LLVM_MARK_AS_BITMASK_ENUM(LargestValue) \ + LLVM_BITMASK_LARGEST_ENUMERATOR = LargestValue + +/// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() pulls the operator overloads used +/// by LLVM_MARK_AS_BITMASK_ENUM into the current namespace. +/// +/// Suppose you have an enum foo::bar::MyEnum. Before using +/// LLVM_MARK_AS_BITMASK_ENUM on MyEnum, you must put +/// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() somewhere inside namespace foo or +/// namespace foo::bar. This allows the relevant operator overloads to be found +/// by ADL. +/// +/// You don't need to use this macro in namespace llvm; it's done at the bottom +/// of this file. +#define LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() \ + using ::llvm::BitmaskEnumDetail::operator~; \ + using ::llvm::BitmaskEnumDetail::operator|; \ + using ::llvm::BitmaskEnumDetail::operator&; \ + using ::llvm::BitmaskEnumDetail::operator^; \ + using ::llvm::BitmaskEnumDetail::operator|=; \ + using ::llvm::BitmaskEnumDetail::operator&=; \ + /* Force a semicolon at the end of this macro. */ \ + using ::llvm::BitmaskEnumDetail::operator^= + +namespace llvm { + +/// Traits class to determine whether an enum has a +/// LLVM_BITMASK_LARGEST_ENUMERATOR enumerator. +template +struct is_bitmask_enum : std::false_type {}; + +template +struct is_bitmask_enum< + E, typename std::enable_if= + 0>::type> : std::true_type {}; +namespace BitmaskEnumDetail { + +/// Get a bitmask with 1s in all places up to the high-order bit of E's largest +/// value. +template typename std::underlying_type::type Mask() { + // On overflow, NextPowerOf2 returns zero with the type uint64_t, so + // subtracting 1 gives us the mask with all bits set, like we want. + return NextPowerOf2(static_cast::type>( + E::LLVM_BITMASK_LARGEST_ENUMERATOR)) - + 1; +} + +/// Check that Val is in range for E, and return Val cast to E's underlying +/// type. +template typename std::underlying_type::type Underlying(E Val) { + auto U = static_cast::type>(Val); + assert(U >= 0 && "Negative enum values are not allowed."); + assert(U <= Mask() && "Enum value too large (or largest val too small?)"); + return U; +} + +template ::value>::type> +E operator~(E Val) { + return static_cast(~Underlying(Val) & Mask()); +} + +template ::value>::type> +E operator|(E LHS, E RHS) { + return static_cast(Underlying(LHS) | Underlying(RHS)); +} + +template ::value>::type> +E operator&(E LHS, E RHS) { + return static_cast(Underlying(LHS) & Underlying(RHS)); +} + +template ::value>::type> +E operator^(E LHS, E RHS) { + return static_cast(Underlying(LHS) ^ Underlying(RHS)); +} + +// |=, &=, and ^= return a reference to LHS, to match the behavior of the +// operators on builtin types. + +template ::value>::type> +E &operator|=(E &LHS, E RHS) { + LHS = LHS | RHS; + return LHS; +} + +template ::value>::type> +E &operator&=(E &LHS, E RHS) { + LHS = LHS & RHS; + return LHS; +} + +template ::value>::type> +E &operator^=(E &LHS, E RHS) { + LHS = LHS ^ RHS; + return LHS; +} + +} // namespace BitmaskEnumDetail + +// Enable bitmask enums in namespace ::llvm and all nested namespaces. +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + +} // namespace llvm + +#endif diff --git a/include/llvm/ADT/DenseMapInfo.h b/include/llvm/ADT/DenseMapInfo.h index a844ebcccf5b89306186097295bb4d9b5f4b86a4..18c692e0cbccbf4bef0c683c11dd060a28cf5924 100644 --- a/include/llvm/ADT/DenseMapInfo.h +++ b/include/llvm/ADT/DenseMapInfo.h @@ -30,6 +30,36 @@ struct DenseMapInfo { //static bool isEqual(const T &LHS, const T &RHS); }; +template struct CachedHash { + CachedHash(T Val) : Val(std::move(Val)) { + Hash = DenseMapInfo::getHashValue(Val); + } + CachedHash(T Val, unsigned Hash) : Val(std::move(Val)), Hash(Hash) {} + T Val; + unsigned Hash; +}; + +// Provide DenseMapInfo for all CachedHash. +template struct DenseMapInfo> { + static CachedHash getEmptyKey() { + T N = DenseMapInfo::getEmptyKey(); + return {N, 0}; + } + static CachedHash getTombstoneKey() { + T N = DenseMapInfo::getTombstoneKey(); + return {N, 0}; + } + static unsigned getHashValue(CachedHash Val) { + assert(!isEqual(Val, getEmptyKey()) && "Cannot hash the empty key!"); + assert(!isEqual(Val, getTombstoneKey()) && + "Cannot hash the tombstone key!"); + return Val.Hash; + } + static bool isEqual(CachedHash A, CachedHash B) { + return DenseMapInfo::isEqual(A.Val, B.Val); + } +}; + // Provide DenseMapInfo for all pointers. template struct DenseMapInfo { diff --git a/include/llvm/ADT/DenseSet.h b/include/llvm/ADT/DenseSet.h index ef09dce379801f734a5282b5389a0bb203203094..3724a09623f3eb12f584cd7e186cb663d4e554c9 100644 --- a/include/llvm/ADT/DenseSet.h +++ b/include/llvm/ADT/DenseSet.h @@ -94,6 +94,7 @@ public: ValueT *operator->() { return &I->getFirst(); } Iterator& operator++() { ++I; return *this; } + Iterator operator++(int) { auto T = *this; ++I; return T; } bool operator==(const Iterator& X) const { return I == X.I; } bool operator!=(const Iterator& X) const { return I != X.I; } }; @@ -115,6 +116,7 @@ public: const ValueT *operator->() { return &I->getFirst(); } ConstIterator& operator++() { ++I; return *this; } + ConstIterator operator++(int) { auto T = *this; ++I; return T; } bool operator==(const ConstIterator& X) const { return I == X.I; } bool operator!=(const ConstIterator& X) const { return I != X.I; } }; @@ -152,6 +154,19 @@ public: return TheMap.insert(std::make_pair(V, Empty)); } + /// Alternative version of insert that uses a different (and possibly less + /// expensive) key type. + template + std::pair insert_as(const ValueT &V, + const LookupKeyT &LookupKey) { + return insert_as(ValueT(V), LookupKey); + } + template + std::pair insert_as(ValueT &&V, const LookupKeyT &LookupKey) { + detail::DenseSetEmpty Empty; + return TheMap.insert_as(std::make_pair(std::move(V), Empty), LookupKey); + } + // Range insertion of values. template void insert(InputIt I, InputIt E) { diff --git a/include/llvm/ADT/FoldingSet.h b/include/llvm/ADT/FoldingSet.h index c9205396591b89bd3cc8d3141c20218cc9356c62..f16258af4ae29bb62420b068e07470a4d078c7a3 100644 --- a/include/llvm/ADT/FoldingSet.h +++ b/include/llvm/ADT/FoldingSet.h @@ -17,10 +17,8 @@ #define LLVM_ADT_FOLDINGSET_H #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/DataTypes.h" namespace llvm { /// This folding set used for two purposes: @@ -98,6 +96,7 @@ namespace llvm { /// The result indicates whether the node existed in the folding set. class FoldingSetNodeID; +class StringRef; //===----------------------------------------------------------------------===// /// FoldingSetImpl - Implements the folding set functionality. The main @@ -181,11 +180,26 @@ public: /// empty - Returns true if there are no nodes in the folding set. bool empty() const { return NumNodes == 0; } + /// reserve - Increase the number of buckets such that adding the + /// EltCount-th node won't cause a rebucket operation. reserve is permitted + /// to allocate more space than requested by EltCount. + void reserve(unsigned EltCount); + /// capacity - Returns the number of nodes permitted in the folding set + /// before a rebucket operation is performed. + unsigned capacity() { + // We allow a load factor of up to 2.0, + // so that means our capacity is NumBuckets * 2 + return NumBuckets * 2; + } + private: /// GrowHashTable - Double the size of the hash table and rehash everything. - /// void GrowHashTable(); + /// GrowBucketCount - resize the hash table and rehash everything. + /// NewBucketCount must be a power of two, and must be greater than the old + /// bucket count. + void GrowBucketCount(unsigned NewBucketCount); protected: /// GetNodeProfile - Instantiations of the FoldingSet template implement /// this function to gather data bits for the given node. diff --git a/include/llvm/ADT/Hashing.h b/include/llvm/ADT/Hashing.h index de56f91eddb154cc2c69c5dbae2b795f370aaaaa..c3b574102f69d843542398b2fef8385c1e061cee 100644 --- a/include/llvm/ADT/Hashing.h +++ b/include/llvm/ADT/Hashing.h @@ -52,7 +52,6 @@ #include #include #include -#include #include #include @@ -632,7 +631,8 @@ inline hash_code hash_integer_value(uint64_t value) { template typename std::enable_if::value, hash_code>::type hash_value(T value) { - return ::llvm::hashing::detail::hash_integer_value(value); + return ::llvm::hashing::detail::hash_integer_value( + static_cast(value)); } // Declared and documented above, but defined here so that any of the hashing diff --git a/include/llvm/ADT/PostOrderIterator.h b/include/llvm/ADT/PostOrderIterator.h index ce343a161b7b22ae8009e9e7155d2283bbb92b81..0cc504b5c39e672764ad0a6f19e7cde18cc59deb 100644 --- a/include/llvm/ADT/PostOrderIterator.h +++ b/include/llvm/ADT/PostOrderIterator.h @@ -28,7 +28,7 @@ namespace llvm { // visited nodes during the po_iterator's depth-first traversal. // // The default implementation simply contains a set of visited nodes, while -// the Extended=true version uses a reference to an external set. +// the External=true version uses a reference to an external set. // // It is possible to prune the depth-first traversal in several ways: // diff --git a/include/llvm/ADT/PriorityWorklist.h b/include/llvm/ADT/PriorityWorklist.h new file mode 100644 index 0000000000000000000000000000000000000000..00549b88fd027a3295bc57ba6e55079ee7ae7e03 --- /dev/null +++ b/include/llvm/ADT/PriorityWorklist.h @@ -0,0 +1,224 @@ +//===- PriorityWorklist.h - Worklist with insertion priority ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file provides a priority worklist. See the class comments for details. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_PRIORITYWORKLIST_H +#define LLVM_ADT_PRIORITYWORKLIST_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include +#include +#include +#include + +namespace llvm { + +/// A FILO worklist that prioritizes on re-insertion without duplication. +/// +/// This is very similar to a \c SetVector with the primary difference that +/// while re-insertion does not create a duplicate, it does adjust the +/// visitation order to respect the last insertion point. This can be useful +/// when the visit order needs to be prioritized based on insertion point +/// without actually having duplicate visits. +/// +/// Note that this doesn't prevent re-insertion of elements which have been +/// visited -- if you need to break cycles, a set will still be necessary. +/// +/// The type \c T must be default constructable to a null value that will be +/// ignored. It is an error to insert such a value, and popping elements will +/// never produce such a value. It is expected to be used with common nullable +/// types like pointers or optionals. +/// +/// Internally this uses a vector to store the worklist and a map to identify +/// existing elements in the worklist. Both of these may be customized, but the +/// map must support the basic DenseMap API for mapping from a T to an integer +/// index into the vector. +/// +/// A partial specialization is provided to automatically select a SmallVector +/// and a SmallDenseMap if custom data structures are not provided. +template , + typename MapT = DenseMap> +class PriorityWorklist { +public: + typedef T value_type; + typedef T key_type; + typedef T& reference; + typedef const T& const_reference; + typedef typename MapT::size_type size_type; + + /// Construct an empty PriorityWorklist + PriorityWorklist() {} + + /// Determine if the PriorityWorklist is empty or not. + bool empty() const { + return V.empty(); + } + + /// Returns the number of elements in the worklist. + size_type size() const { + return M.size(); + } + + /// Count the number of elements of a given key in the PriorityWorklist. + /// \returns 0 if the element is not in the PriorityWorklist, 1 if it is. + size_type count(const key_type &key) const { + return M.count(key); + } + + /// Return the last element of the PriorityWorklist. + const T &back() const { + assert(!empty() && "Cannot call back() on empty PriorityWorklist!"); + return V.back(); + } + + /// Insert a new element into the PriorityWorklist. + /// \returns true if the element was inserted into the PriorityWorklist. + bool insert(const T &X) { + assert(X != T() && "Cannot insert a null (default constructed) value!"); + auto InsertResult = M.insert({X, V.size()}); + if (InsertResult.second) { + // Fresh value, just append it to the vector. + V.push_back(X); + return true; + } + + auto &Index = InsertResult.first->second; + assert(V[Index] == X && "Value not actually at index in map!"); + if (Index != (ptrdiff_t)(V.size() - 1)) { + // If the element isn't at the back, null it out and append a fresh one. + V[Index] = T(); + Index = (ptrdiff_t)V.size(); + V.push_back(X); + } + return false; + } + + /// Remove the last element of the PriorityWorklist. + void pop_back() { + assert(!empty() && "Cannot remove an element when empty!"); + assert(back() != T() && "Cannot have a null element at the back!"); + M.erase(back()); + do { + V.pop_back(); + } while (!V.empty() && V.back() == T()); + } + + T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() { + T Ret = back(); + pop_back(); + return Ret; + } + + /// Erase an item from the worklist. + /// + /// Note that this is constant time due to the nature of the worklist implementation. + bool erase(const T& X) { + auto I = M.find(X); + if (I == M.end()) + return false; + + assert(V[I->second] == X && "Value not actually at index in map!"); + if (I->second == (ptrdiff_t)(V.size() - 1)) { + do { + V.pop_back(); + } while (!V.empty() && V.back() == T()); + } else { + V[I->second] = T(); + } + M.erase(I); + return true; + } + + /// Erase items from the set vector based on a predicate function. + /// + /// This is intended to be equivalent to the following code, if we could + /// write it: + /// + /// \code + /// V.erase(std::remove_if(V.begin(), V.end(), P), V.end()); + /// \endcode + /// + /// However, PriorityWorklist doesn't expose non-const iterators, making any + /// algorithm like remove_if impossible to use. + /// + /// \returns true if any element is removed. + template + bool erase_if(UnaryPredicate P) { + typename VectorT::iterator E = std::remove_if( + V.begin(), V.end(), TestAndEraseFromMap(P, M)); + if (E == V.end()) + return false; + for (auto I = V.begin(); I != E; ++I) + if (*I != T()) + M[*I] = I - V.begin(); + V.erase(E, V.end()); + return true; + } + + /// Completely clear the PriorityWorklist + void clear() { + M.clear(); + V.clear(); + } + +private: + /// A wrapper predicate designed for use with std::remove_if. + /// + /// This predicate wraps a predicate suitable for use with std::remove_if to + /// call M.erase(x) on each element which is slated for removal. This just + /// allows the predicate to be move only which we can't do with lambdas + /// today. + template + class TestAndEraseFromMap { + UnaryPredicateT P; + MapT &M; + + public: + TestAndEraseFromMap(UnaryPredicateT P, MapT &M) + : P(std::move(P)), M(M) {} + + bool operator()(const T &Arg) { + if (Arg == T()) + // Skip null values in the PriorityWorklist. + return false; + + if (P(Arg)) { + M.erase(Arg); + return true; + } + return false; + } + }; + + /// The map from value to index in the vector. + MapT M; + + /// The vector of elements in insertion order. + VectorT V; +}; + +/// A version of \c PriorityWorklist that selects small size optimized data +/// structures for the vector and map. +template +class SmallPriorityWorklist + : public PriorityWorklist, + SmallDenseMap> { +public: + SmallPriorityWorklist() {} +}; + +} + +#endif diff --git a/include/llvm/ADT/STLExtras.h b/include/llvm/ADT/STLExtras.h index 06a1756e26fa4f65df41e6649b1229c11994835a..abd39dacc671351d940d3edca4fc680169f63635 100644 --- a/include/llvm/ADT/STLExtras.h +++ b/include/llvm/ADT/STLExtras.h @@ -17,7 +17,6 @@ #ifndef LLVM_ADT_STLEXTRAS_H #define LLVM_ADT_STLEXTRAS_H -#include "llvm/Support/Compiler.h" #include // for std::all_of #include #include // for std::size_t @@ -27,6 +26,9 @@ #include #include // for std::pair +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Compiler.h" + namespace llvm { //===----------------------------------------------------------------------===// @@ -381,6 +383,14 @@ bool any_of(R &&Range, UnaryPredicate &&P) { std::forward(P)); } +/// Provide wrappers to std::none_of which take ranges instead of having to pass +/// begin/end explicitly. +template +bool none_of(R &&Range, UnaryPredicate &&P) { + return std::none_of(Range.begin(), Range.end(), + std::forward(P)); +} + /// Provide wrappers to std::find which take ranges instead of having to pass /// begin/end explicitly. template @@ -402,6 +412,29 @@ auto remove_if(R &&Range, UnaryPredicate &&P) -> decltype(Range.begin()) { return std::remove_if(Range.begin(), Range.end(), P); } +/// Wrapper function around std::find to detect if an element exists +/// in a container. +template +bool is_contained(R &&Range, const E &Element) { + return std::find(Range.begin(), Range.end(), Element) != Range.end(); +} + +/// Wrapper function around std::count_if to count the number of times an +/// element satisfying a given predicate occurs in a range. +template +auto count_if(R &&Range, UnaryPredicate &&P) + -> typename std::iterator_traits::difference_type { + return std::count_if(Range.begin(), Range.end(), P); +} + +/// Wrapper function around std::transform to apply a function to a range and +/// store the result elsewhere. +template +OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate &&P) { + return std::transform(Range.begin(), Range.end(), d_first, + std::forward(P)); +} + //===----------------------------------------------------------------------===// // Extra additions to //===----------------------------------------------------------------------===// diff --git a/include/llvm/ADT/Sequence.h b/include/llvm/ADT/Sequence.h new file mode 100644 index 0000000000000000000000000000000000000000..5d36831cc128ec03a22e820d9af1865a7d07bd8e --- /dev/null +++ b/include/llvm/ADT/Sequence.h @@ -0,0 +1,79 @@ +//===- Sequence.h - Utility for producing sequences of values ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This routine provides some synthesis utilities to produce sequences of +/// values. The names are intentionally kept very short as they tend to occur +/// in common and widely used contexts. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SEQ_H +#define LLVM_ADT_SEQ_H + +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" + +namespace llvm { + +namespace detail { +template +class value_sequence_iterator + : public iterator_facade_base, + std::random_access_iterator_tag, + const ValueT> { + typedef typename value_sequence_iterator::iterator_facade_base BaseT; + + ValueT Value; + +public: + typedef typename BaseT::difference_type difference_type; + typedef typename BaseT::reference reference; + + value_sequence_iterator() = default; + value_sequence_iterator(const value_sequence_iterator &) = default; + value_sequence_iterator(value_sequence_iterator &&Arg) + : Value(std::move(Arg.Value)) {} + + template ()))> + value_sequence_iterator(U &&Value) : Value(std::forward(Value)) {} + + value_sequence_iterator &operator+=(difference_type N) { + Value += N; + return *this; + } + value_sequence_iterator &operator-=(difference_type N) { + Value -= N; + return *this; + } + using BaseT::operator-; + difference_type operator-(const value_sequence_iterator &RHS) const { + return Value - RHS.Value; + } + + bool operator==(const value_sequence_iterator &RHS) const { + return Value == RHS.Value; + } + bool operator<(const value_sequence_iterator &RHS) const { + return Value < RHS.Value; + } + + reference operator*() const { return Value; } +}; +} // End detail namespace. + +template +iterator_range> seq(ValueT Begin, + ValueT End) { + return make_range(detail::value_sequence_iterator(Begin), + detail::value_sequence_iterator(End)); +} + +} + +#endif diff --git a/include/llvm/ADT/SetVector.h b/include/llvm/ADT/SetVector.h index f17c56d81330400ccdfa95fb086f0a113ea94d5a..2bb0fdbd33709642260c18e25377d91c5879a682 100644 --- a/include/llvm/ADT/SetVector.h +++ b/include/llvm/ADT/SetVector.h @@ -24,6 +24,7 @@ #include "llvm/ADT/SmallSet.h" #include #include +#include #include namespace llvm { @@ -123,7 +124,7 @@ public: } /// \brief Insert a new element into the SetVector. - /// \returns true iff the element was inserted into the SetVector. + /// \returns true if the element was inserted into the SetVector. bool insert(const value_type &X) { bool result = set_.insert(X).second; if (result) @@ -225,6 +226,31 @@ public: bool operator!=(const SetVector &that) const { return vector_ != that.vector_; } + + /// \brief Compute This := This u S, return whether 'This' changed. + /// TODO: We should be able to use set_union from SetOperations.h, but + /// SetVector interface is inconsistent with DenseSet. + template + bool set_union(const STy &S) { + bool Changed = false; + + for (typename STy::const_iterator SI = S.begin(), SE = S.end(); SI != SE; + ++SI) + if (insert(*SI)) + Changed = true; + + return Changed; + } + + /// \brief Compute This := This - B + /// TODO: We should be able to use set_subtract from SetOperations.h, but + /// SetVector interface is inconsistent with DenseSet. + template + void set_subtract(const STy &S) { + for (typename STy::const_iterator SI = S.begin(), SE = S.end(); SI != SE; + ++SI) + remove(*SI); + } private: /// \brief A wrapper predicate designed for use with std::remove_if. @@ -237,7 +263,8 @@ private: set_type &set_; public: - TestAndEraseFromSet(UnaryPredicate P, set_type &set_) : P(P), set_(set_) {} + TestAndEraseFromSet(UnaryPredicate P, set_type &set_) + : P(std::move(P)), set_(set_) {} template bool operator()(const ArgumentT &Arg) { diff --git a/include/llvm/ADT/SmallBitVector.h b/include/llvm/ADT/SmallBitVector.h index e94f3967d7198d37b31d9b726a9fe3edab1230dd..bb99e0cf221f78c186a8287ee9ec89edfaab5f1d 100644 --- a/include/llvm/ADT/SmallBitVector.h +++ b/include/llvm/ADT/SmallBitVector.h @@ -15,7 +15,6 @@ #define LLVM_ADT_SMALLBITVECTOR_H #include "llvm/ADT/BitVector.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" #include diff --git a/include/llvm/ADT/SmallVector.h b/include/llvm/ADT/SmallVector.h index aa83e3f0e341a9c408411bd3af1623fafc65a61e..42eedc63e07906b5afac76694c9ed156a1fe57d0 100644 --- a/include/llvm/ADT/SmallVector.h +++ b/include/llvm/ADT/SmallVector.h @@ -184,33 +184,12 @@ protected: } } - /// Use move-assignment to move the range [I, E) onto the - /// objects starting with "Dest". This is just 's - /// std::move, but not all stdlibs actually provide that. - template - static It2 move(It1 I, It1 E, It2 Dest) { - for (; I != E; ++I, ++Dest) - *Dest = ::std::move(*I); - return Dest; - } - - /// Use move-assignment to move the range - /// [I, E) onto the objects ending at "Dest", moving objects - /// in reverse order. This is just 's - /// std::move_backward, but not all stdlibs actually provide that. - template - static It2 move_backward(It1 I, It1 E, It2 Dest) { - while (I != E) - *--Dest = ::std::move(*--E); - return Dest; - } - /// Move the range [I, E) into the uninitialized memory starting with "Dest", /// constructing elements as needed. template static void uninitialized_move(It1 I, It1 E, It2 Dest) { - for (; I != E; ++I, ++Dest) - ::new ((void*) &*Dest) T(::std::move(*I)); + std::uninitialized_copy(std::make_move_iterator(I), + std::make_move_iterator(E), Dest); } /// Copy the range [I, E) onto the uninitialized memory starting with "Dest", @@ -283,20 +262,6 @@ protected: // No need to do a destroy loop for POD's. static void destroy_range(T *, T *) {} - /// Use move-assignment to move the range [I, E) onto the - /// objects starting with "Dest". For PODs, this is just memcpy. - template - static It2 move(It1 I, It1 E, It2 Dest) { - return ::std::copy(I, E, Dest); - } - - /// Use move-assignment to move the range [I, E) onto the objects ending at - /// "Dest", moving objects in reverse order. - template - static It2 move_backward(It1 I, It1 E, It2 Dest) { - return ::std::copy_backward(I, E, Dest); - } - /// Move the range [I, E) onto the uninitialized memory /// starting with "Dest", constructing elements into it as needed. template @@ -469,7 +434,7 @@ public: iterator N = I; // Shift all elts down one. - this->move(I+1, this->end(), I); + std::move(I+1, this->end(), I); // Drop the last elt. this->pop_back(); return(N); @@ -486,7 +451,7 @@ public: iterator N = S; // Shift all elts down. - iterator I = this->move(E, this->end(), S); + iterator I = std::move(E, this->end(), S); // Drop the last elts. this->destroy_range(I, this->end()); this->setEnd(I); @@ -510,7 +475,7 @@ public: ::new ((void*) this->end()) T(::std::move(this->back())); // Push everything else over. - this->move_backward(I, this->end()-1, this->end()); + std::move_backward(I, this->end()-1, this->end()); this->setEnd(this->end()+1); // If we just moved the element we're inserting, be sure to update @@ -539,7 +504,7 @@ public: } ::new ((void*) this->end()) T(std::move(this->back())); // Push everything else over. - this->move_backward(I, this->end()-1, this->end()); + std::move_backward(I, this->end()-1, this->end()); this->setEnd(this->end()+1); // If we just moved the element we're inserting, be sure to update @@ -580,7 +545,7 @@ public: std::move_iterator(this->end())); // Copy the existing elements that get replaced. - this->move_backward(I, OldEnd-NumToInsert, OldEnd); + std::move_backward(I, OldEnd-NumToInsert, OldEnd); std::fill_n(I, NumToInsert, Elt); return I; @@ -634,7 +599,7 @@ public: std::move_iterator(this->end())); // Copy the existing elements that get replaced. - this->move_backward(I, OldEnd-NumToInsert, OldEnd); + std::move_backward(I, OldEnd-NumToInsert, OldEnd); std::copy(From, To, I); return I; @@ -815,7 +780,7 @@ SmallVectorImpl &SmallVectorImpl::operator=(SmallVectorImpl &&RHS) { // Assign common elements. iterator NewEnd = this->begin(); if (RHSSize) - NewEnd = this->move(RHS.begin(), RHS.end(), NewEnd); + NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd); // Destroy excess elements and trim the bounds. this->destroy_range(NewEnd, this->end()); @@ -839,7 +804,7 @@ SmallVectorImpl &SmallVectorImpl::operator=(SmallVectorImpl &&RHS) { this->grow(RHSSize); } else if (CurSize) { // Otherwise, use assignment for the already-constructed elements. - this->move(RHS.begin(), RHS.begin()+CurSize, this->begin()); + std::move(RHS.begin(), RHS.begin()+CurSize, this->begin()); } // Move-construct the new elements in place. diff --git a/include/llvm/ADT/Statistic.h b/include/llvm/ADT/Statistic.h index 57e7253c5c732f0ee53f67a0162586df7a8f33bd..32175fdc7c5ccb40383d906edff8ce4f4b624641 100644 --- a/include/llvm/ADT/Statistic.h +++ b/include/llvm/ADT/Statistic.h @@ -28,6 +28,7 @@ #include "llvm/Support/Atomic.h" #include "llvm/Support/Compiler.h" +#include #include namespace llvm { @@ -36,77 +37,66 @@ class raw_fd_ostream; class Statistic { public: + const char *DebugType; const char *Name; const char *Desc; - volatile llvm::sys::cas_flag Value; + std::atomic Value; bool Initialized; - llvm::sys::cas_flag getValue() const { return Value; } + unsigned getValue() const { return Value.load(std::memory_order_relaxed); } + const char *getDebugType() const { return DebugType; } const char *getName() const { return Name; } const char *getDesc() const { return Desc; } /// construct - This should only be called for non-global statistics. - void construct(const char *name, const char *desc) { - Name = name; Desc = desc; - Value = 0; Initialized = false; + void construct(const char *debugtype, const char *name, const char *desc) { + DebugType = debugtype; + Name = name; + Desc = desc; + Value = 0; + Initialized = false; } // Allow use of this class as the value itself. - operator unsigned() const { return Value; } + operator unsigned() const { return getValue(); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) const Statistic &operator=(unsigned Val) { - Value = Val; + Value.store(Val, std::memory_order_relaxed); return init(); } const Statistic &operator++() { - // FIXME: This function and all those that follow carefully use an - // atomic operation to update the value safely in the presence of - // concurrent accesses, but not to read the return value, so the - // return value is not thread safe. - sys::AtomicIncrement(&Value); + Value.fetch_add(1, std::memory_order_relaxed); return init(); } unsigned operator++(int) { init(); - unsigned OldValue = Value; - sys::AtomicIncrement(&Value); - return OldValue; + return Value.fetch_add(1, std::memory_order_relaxed); } const Statistic &operator--() { - sys::AtomicDecrement(&Value); + Value.fetch_sub(1, std::memory_order_relaxed); return init(); } unsigned operator--(int) { init(); - unsigned OldValue = Value; - sys::AtomicDecrement(&Value); - return OldValue; + return Value.fetch_sub(1, std::memory_order_relaxed); } - const Statistic &operator+=(const unsigned &V) { - if (!V) return *this; - sys::AtomicAdd(&Value, V); - return init(); - } - - const Statistic &operator-=(const unsigned &V) { - if (!V) return *this; - sys::AtomicAdd(&Value, -V); - return init(); - } - - const Statistic &operator*=(const unsigned &V) { - sys::AtomicMul(&Value, V); + const Statistic &operator+=(unsigned V) { + if (V == 0) + return *this; + Value.fetch_add(V, std::memory_order_relaxed); return init(); } - const Statistic &operator/=(const unsigned &V) { - sys::AtomicDiv(&Value, V); + const Statistic &operator-=(unsigned V) { + if (V == 0) + return *this; + Value.fetch_sub(V, std::memory_order_relaxed); return init(); } @@ -140,14 +130,6 @@ public: return *this; } - const Statistic &operator*=(const unsigned &V) { - return *this; - } - - const Statistic &operator/=(const unsigned &V) { - return *this; - } - #endif // !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) protected: @@ -163,8 +145,8 @@ protected: // STATISTIC - A macro to make definition of statistics really simple. This // automatically passes the DEBUG_TYPE of the file into the statistic. -#define STATISTIC(VARNAME, DESC) \ - static llvm::Statistic VARNAME = { DEBUG_TYPE, DESC, 0, 0 } +#define STATISTIC(VARNAME, DESC) \ + static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC, {0}, 0} /// \brief Enable the collection and printing of statistics. void EnableStatistics(); @@ -181,6 +163,9 @@ void PrintStatistics(); /// \brief Print statistics to the given output stream. void PrintStatistics(raw_ostream &OS); +/// Print statistics in JSON format. +void PrintStatisticsJSON(raw_ostream &OS); + } // end llvm namespace #endif // LLVM_ADT_STATISTIC_H diff --git a/include/llvm/ADT/StringExtras.h b/include/llvm/ADT/StringExtras.h index 8de6fb257ce8b97f31740e26298f7045ad2e4c66..bdbb4d3f5932ecae46c26c084f2e158515f65daf 100644 --- a/include/llvm/ADT/StringExtras.h +++ b/include/llvm/ADT/StringExtras.h @@ -59,6 +59,22 @@ static inline std::string utohexstr(uint64_t X, bool LowerCase = false) { return std::string(BufPtr, std::end(Buffer)); } +/// Convert buffer \p Input to its hexadecimal representation. +/// The returned string is double the size of \p Input. +static inline std::string toHex(StringRef Input) { + static const char *const LUT = "0123456789ABCDEF"; + size_t Length = Input.size(); + + std::string Output; + Output.reserve(2 * Length); + for (size_t i = 0; i < Length; ++i) { + const unsigned char c = Input[i]; + Output.push_back(LUT[c >> 4]); + Output.push_back(LUT[c & 15]); + } + return Output; +} + static inline std::string utostr(uint64_t X, bool isNeg = false) { char Buffer[21]; char *BufPtr = std::end(Buffer); diff --git a/include/llvm/ADT/StringMap.h b/include/llvm/ADT/StringMap.h index 3a3ffc2aa32bd86390b2995efd7cd99de3451b27..260275295c993cd2b8aa2f5687fbe1422d00f410 100644 --- a/include/llvm/ADT/StringMap.h +++ b/include/llvm/ADT/StringMap.h @@ -15,8 +15,8 @@ #define LLVM_ADT_STRINGMAP_H #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/PointerLikeTypeTraits.h" #include #include @@ -89,12 +89,15 @@ protected: /// table, returning it. If the key is not in the table, this returns null. StringMapEntryBase *RemoveKey(StringRef Key); -private: + /// Allocate the table with the specified number of buckets and otherwise + /// setup the map as empty. void init(unsigned Size); public: static StringMapEntryBase *getTombstoneVal() { - return (StringMapEntryBase*)-1; + uintptr_t Val = static_cast(-1); + Val <<= PointerLikeTypeTraits::NumLowBitsAvailable; + return reinterpret_cast(Val); } unsigned getNumBuckets() const { return NumBuckets; } @@ -244,7 +247,40 @@ public: return *this; } - // FIXME: Implement copy operations if/when they're needed. + StringMap(const StringMap &RHS) : + StringMapImpl(static_cast(sizeof(MapEntryTy))), + Allocator(RHS.Allocator) { + if (RHS.empty()) + return; + + // Allocate TheTable of the same size as RHS's TheTable, and set the + // sentinel appropriately (and NumBuckets). + init(RHS.NumBuckets); + unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1), + *RHSHashTable = (unsigned *)(RHS.TheTable + NumBuckets + 1); + + NumItems = RHS.NumItems; + NumTombstones = RHS.NumTombstones; + for (unsigned I = 0, E = NumBuckets; I != E; ++I) { + StringMapEntryBase *Bucket = RHS.TheTable[I]; + if (!Bucket || Bucket == getTombstoneVal()) { + TheTable[I] = Bucket; + continue; + } + + TheTable[I] = MapEntryTy::Create( + static_cast(Bucket)->getKey(), Allocator, + static_cast(Bucket)->getValue()); + HashTable[I] = RHSHashTable[I]; + } + + // Note that here we've copied everything from the RHS into this object, + // tombstones included. We could, instead, have re-probed for each key to + // instantiate this new object without any tombstone buckets. The + // assumption here is that items are rarely deleted from most StringMaps, + // and so tombstones are rare, so the cost of re-probing for all inputs is + // not worthwhile. + } AllocatorTy &getAllocator() { return Allocator; } const AllocatorTy &getAllocator() const { return Allocator; } diff --git a/include/llvm/ADT/StringRef.h b/include/llvm/ADT/StringRef.h index f1189690ffb2efc43a36628e0598ef55b07062ec..398ca69202493914e86d83932a8ffdaba255eb01 100644 --- a/include/llvm/ADT/StringRef.h +++ b/include/llvm/ADT/StringRef.h @@ -10,6 +10,7 @@ #ifndef LLVM_ADT_STRINGREF_H #define LLVM_ADT_STRINGREF_H +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" #include #include @@ -101,6 +102,9 @@ namespace llvm { const unsigned char *bytes_end() const { return reinterpret_cast(end()); } + iterator_range bytes() const { + return make_range(bytes_begin(), bytes_end()); + } /// @} /// @name String Operations @@ -446,9 +450,10 @@ namespace llvm { /// empty substring will be returned. /// /// \param End The index following the last character to include in the - /// substring. If this is npos, or less than \p Start, or exceeds the - /// number of characters remaining in the string, the string suffix - /// (starting with \p Start) will be returned. + /// substring. If this is npos or exceeds the number of characters + /// remaining in the string, the string suffix (starting with \p Start) + /// will be returned. If this is less than \p Start, an empty string will + /// be returned. LLVM_ATTRIBUTE_ALWAYS_INLINE StringRef slice(size_t Start, size_t End) const { Start = std::min(Start, Length); diff --git a/include/llvm/ADT/TinyPtrVector.h b/include/llvm/ADT/TinyPtrVector.h index 487aa46cf64205b4b06b7b8b2b0c14fc69d56328..605f0e70a857855bf7debe04b8b9b5719e35d92c 100644 --- a/include/llvm/ADT/TinyPtrVector.h +++ b/include/llvm/ADT/TinyPtrVector.h @@ -104,8 +104,16 @@ public: /// This also is a constructor for individual array elements due to the single /// element constructor for ArrayRef. explicit TinyPtrVector(ArrayRef Elts) - : Val(Elts.size() == 1 ? PtrUnion(Elts[0]) - : PtrUnion(new VecTy(Elts.begin(), Elts.end()))) {} + : Val(Elts.empty() + ? PtrUnion() + : Elts.size() == 1 + ? PtrUnion(Elts[0]) + : PtrUnion(new VecTy(Elts.begin(), Elts.end()))) {} + + TinyPtrVector(size_t Count, EltTy Value) + : Val(Count == 0 ? PtrUnion() + : Count == 1 ? PtrUnion(Value) + : PtrUnion(new VecTy(Count, Value))) {} // implicit conversion operator to ArrayRef. operator ArrayRef() const { @@ -125,6 +133,15 @@ public: return *Val.template get(); } + // Implicit conversion to ArrayRef if EltTy* implicitly converts to U*. + template, ArrayRef>::value, + bool>::type = false> + operator ArrayRef() const { + return operator ArrayRef(); + } + bool empty() const { // This vector can be empty if it contains no element, or if it // contains a pointer to an empty vector. @@ -142,8 +159,10 @@ public: return Val.template get()->size(); } - typedef const EltTy *const_iterator; typedef EltTy *iterator; + typedef const EltTy *const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; iterator begin() { if (Val.template is()) @@ -166,6 +185,15 @@ public: return (const_iterator)const_cast(this)->end(); } + reverse_iterator rbegin() { return reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + EltTy operator[](unsigned i) const { assert(!Val.isNull() && "can't index into an empty vector"); if (EltTy V = Val.template dyn_cast()) { diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index d163ac7bd77e2db8740e9d0d464d480db4b5d52e..47813049d2f2cf8c98a6717302508f05906e2fff 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -46,50 +46,52 @@ public: enum ArchType { UnknownArch, - arm, // ARM (little endian): arm, armv.*, xscale - armeb, // ARM (big endian): armeb - aarch64, // AArch64 (little endian): aarch64 - aarch64_be, // AArch64 (big endian): aarch64_be - avr, // AVR: Atmel AVR microcontroller - bpfel, // eBPF or extended BPF or 64-bit BPF (little endian) - bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) - hexagon, // Hexagon: hexagon - mips, // MIPS: mips, mipsallegrex - mipsel, // MIPSEL: mipsel, mipsallegrexel - mips64, // MIPS64: mips64 - mips64el, // MIPS64EL: mips64el - msp430, // MSP430: msp430 - ppc, // PPC: powerpc - ppc64, // PPC64: powerpc64, ppu - ppc64le, // PPC64LE: powerpc64le - r600, // R600: AMD GPUs HD2XXX - HD6XXX - amdgcn, // AMDGCN: AMD GCN GPUs - sparc, // Sparc: sparc - sparcv9, // Sparcv9: Sparcv9 - sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant - systemz, // SystemZ: s390x - tce, // TCE (http://tce.cs.tut.fi/): tce - thumb, // Thumb (little endian): thumb, thumbv.* - thumbeb, // Thumb (big endian): thumbeb - x86, // X86: i[3-9]86 - x86_64, // X86-64: amd64, x86_64 - xcore, // XCore: xcore - nvptx, // NVPTX: 32-bit - nvptx64, // NVPTX: 64-bit - le32, // le32: generic little-endian 32-bit CPU (PNaCl) - le64, // le64: generic little-endian 64-bit CPU (PNaCl) - amdil, // AMDIL - amdil64, // AMDIL with 64-bit pointers - hsail, // AMD HSAIL - hsail64, // AMD HSAIL with 64-bit pointers - spir, // SPIR: standard portable IR for OpenCL 32-bit version - spir64, // SPIR: standard portable IR for OpenCL 64-bit version - kalimba, // Kalimba: generic kalimba - shave, // SHAVE: Movidius vector VLIW processors - lanai, // Lanai: Lanai 32-bit - wasm32, // WebAssembly with 32-bit pointers - wasm64, // WebAssembly with 64-bit pointers - LastArchType = wasm64 + arm, // ARM (little endian): arm, armv.*, xscale + armeb, // ARM (big endian): armeb + aarch64, // AArch64 (little endian): aarch64 + aarch64_be, // AArch64 (big endian): aarch64_be + avr, // AVR: Atmel AVR microcontroller + bpfel, // eBPF or extended BPF or 64-bit BPF (little endian) + bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) + hexagon, // Hexagon: hexagon + mips, // MIPS: mips, mipsallegrex + mipsel, // MIPSEL: mipsel, mipsallegrexel + mips64, // MIPS64: mips64 + mips64el, // MIPS64EL: mips64el + msp430, // MSP430: msp430 + ppc, // PPC: powerpc + ppc64, // PPC64: powerpc64, ppu + ppc64le, // PPC64LE: powerpc64le + r600, // R600: AMD GPUs HD2XXX - HD6XXX + amdgcn, // AMDGCN: AMD GCN GPUs + sparc, // Sparc: sparc + sparcv9, // Sparcv9: Sparcv9 + sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant + systemz, // SystemZ: s390x + tce, // TCE (http://tce.cs.tut.fi/): tce + thumb, // Thumb (little endian): thumb, thumbv.* + thumbeb, // Thumb (big endian): thumbeb + x86, // X86: i[3-9]86 + x86_64, // X86-64: amd64, x86_64 + xcore, // XCore: xcore + nvptx, // NVPTX: 32-bit + nvptx64, // NVPTX: 64-bit + le32, // le32: generic little-endian 32-bit CPU (PNaCl) + le64, // le64: generic little-endian 64-bit CPU (PNaCl) + amdil, // AMDIL + amdil64, // AMDIL with 64-bit pointers + hsail, // AMD HSAIL + hsail64, // AMD HSAIL with 64-bit pointers + spir, // SPIR: standard portable IR for OpenCL 32-bit version + spir64, // SPIR: standard portable IR for OpenCL 64-bit version + kalimba, // Kalimba: generic kalimba + shave, // SHAVE: Movidius vector VLIW processors + lanai, // Lanai: Lanai 32-bit + wasm32, // WebAssembly with 32-bit pointers + wasm64, // WebAssembly with 64-bit pointers + renderscript32, // 32-bit RenderScript + renderscript64, // 64-bit RenderScript + LastArchType = renderscript64 }; enum SubArchType { NoSubArch, @@ -179,6 +181,9 @@ public: EABI, EABIHF, Android, + Musl, + MuslEABI, + MuslEABIHF, MSVC, Itanium, @@ -469,6 +474,12 @@ public: return getOS() == Triple::ELFIAMCU; } + bool isGNUEnvironment() const { + EnvironmentType Env = getEnvironment(); + return Env == Triple::GNU || Env == Triple::GNUEABI || + Env == Triple::GNUEABIHF || Env == Triple::GNUX32; + } + /// Checks if the environment could be MSVC. bool isWindowsMSVCEnvironment() const { return getOS() == Triple::Win32 && @@ -523,6 +534,16 @@ public: return getOS() == Triple::Linux; } + /// Tests whether the OS is kFreeBSD. + bool isOSKFreeBSD() const { + return getOS() == Triple::KFreeBSD; + } + + /// Tests whether the OS uses glibc. + bool isOSGlibc() const { + return getOS() == Triple::Linux || getOS() == Triple::KFreeBSD; + } + /// Tests whether the OS uses the ELF binary format. bool isOSBinFormatELF() const { return getObjectFormat() == Triple::ELF; @@ -554,11 +575,21 @@ public: /// Tests whether the target is Android bool isAndroid() const { return getEnvironment() == Triple::Android; } + /// Tests whether the environment is musl-libc + bool isMusl() const { + return getEnvironment() == Triple::Musl || + getEnvironment() == Triple::MuslEABI || + getEnvironment() == Triple::MuslEABIHF; + } + /// Tests whether the target is NVPTX (32- or 64-bit). bool isNVPTX() const { return getArch() == Triple::nvptx || getArch() == Triple::nvptx64; } + /// Tests wether the target supports comdat + bool supportsCOMDAT() const { return !isOSBinFormatMachO(); } + /// @} /// @name Mutators /// @{ @@ -647,6 +678,11 @@ public: /// string then the triple's arch name is used. StringRef getARMCPUForArch(StringRef Arch = StringRef()) const; + /// Tests whether the target triple is little endian. + /// + /// \returns true if the triple is little endian, false otherwise. + bool isLittleEndian() const; + /// @} /// @name Static helpers for IDs. /// @{ diff --git a/include/llvm/ADT/iterator.h b/include/llvm/ADT/iterator.h index c3079289270383dea1c10ed20f3b7b22153ab816..2898a677db371544f93a06483e9bcaa977dbdd92 100644 --- a/include/llvm/ADT/iterator.h +++ b/include/llvm/ADT/iterator.h @@ -46,6 +46,22 @@ protected: std::is_base_of::value, }; + /// A proxy object for computing a reference via indirecting a copy of an + /// iterator. This is used in APIs which need to produce a reference via + /// indirection but for which the iterator object might be a temporary. The + /// proxy preserves the iterator internally and exposes the indirected + /// reference via a conversion operator. + class ReferenceProxy { + friend iterator_facade_base; + + DerivedT I; + + ReferenceProxy(DerivedT I) : I(std::move(I)) {} + + public: + operator ReferenceT() const { return *I; } + }; + public: DerivedT operator+(DifferenceTypeT n) const { static_assert( @@ -120,10 +136,10 @@ public: PointerT operator->() const { return &static_cast(this)->operator*(); } - ReferenceT operator[](DifferenceTypeT n) const { + ReferenceProxy operator[](DifferenceTypeT n) const { static_assert(IsRandomAccess, "Subscripting is only defined for random access iterators."); - return *static_cast(this)->operator+(n); + return ReferenceProxy(static_cast(this)->operator+(n)); } }; diff --git a/include/llvm/Analysis/AliasAnalysis.h b/include/llvm/Analysis/AliasAnalysis.h index 2d06965b84e8572f97babb0c803581a87305fa9f..d6308b7073a09c03ad1d1aaec33748d62c9b2a05 100644 --- a/include/llvm/Analysis/AliasAnalysis.h +++ b/include/llvm/Analysis/AliasAnalysis.h @@ -38,7 +38,6 @@ #ifndef LLVM_ANALYSIS_ALIASANALYSIS_H #define LLVM_ANALYSIS_ALIASANALYSIS_H -#include "llvm/ADT/DenseMap.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/PassManager.h" @@ -141,7 +140,7 @@ enum FunctionModRefBehavior { /// non-volatile loads and stores from objects pointed to by its /// pointer-typed arguments, with arbitrary offsets. /// - /// This property corresponds to the IntrReadWriteArgMem LLVM intrinsic flag. + /// This property corresponds to the IntrArgMemOnly LLVM intrinsic flag. FMRB_OnlyAccessesArgumentPointees = FMRL_ArgumentPointees | MRI_ModRef, /// This function does not perform any non-local stores or volatile loads, @@ -152,6 +151,13 @@ enum FunctionModRefBehavior { /// This property corresponds to the IntrReadMem LLVM intrinsic flag. FMRB_OnlyReadsMemory = FMRL_Anywhere | MRI_Ref, + // This function does not read from memory anywhere, but may write to any + // memory location. + // + // This property corresponds to the LLVM IR 'writeonly' attribute. + // This property corresponds to the IntrWriteMem LLVM intrinsic flag. + FMRB_DoesNotReadMemory = FMRL_Anywhere | MRI_Mod, + /// This indicates that the function could not be classified into one of the /// behaviors above. FMRB_UnknownModRefBehavior = FMRL_Anywhere | MRI_ModRef @@ -313,6 +319,12 @@ public: return !(MRB & MRI_Mod); } + /// Checks if functions with the specified behavior are known to only write + /// memory (or not access memory at all). + static bool doesNotReadMemory(FunctionModRefBehavior MRB) { + return !(MRB & MRI_Ref); + } + /// Checks if functions with the specified behavior are known to read and /// write at most from objects pointed to by their pointer-typed arguments /// (with arbitrary offsets). diff --git a/include/llvm/Analysis/AliasAnalysisEvaluator.h b/include/llvm/Analysis/AliasAnalysisEvaluator.h index 3bdd8dbf7269484c43d9d7781878104fb5f7dc99..505ed0d9723a4cbe9be13933663acefa3c5257d8 100644 --- a/include/llvm/Analysis/AliasAnalysisEvaluator.h +++ b/include/llvm/Analysis/AliasAnalysisEvaluator.h @@ -52,8 +52,6 @@ public: } ~AAEvaluator(); - static StringRef name() { return "AAEvaluator"; } - /// \brief Run the pass over the function. PreservedAnalyses run(Function &F, AnalysisManager &AM); diff --git a/include/llvm/Analysis/AliasSetTracker.h b/include/llvm/Analysis/AliasSetTracker.h index 1a71dc501cac4d0b9336a5a228854b5f92c4498f..cec56889c0ae974cfd37653f2f0c99bb8004a678 100644 --- a/include/llvm/Analysis/AliasSetTracker.h +++ b/include/llvm/Analysis/AliasSetTracker.h @@ -59,8 +59,12 @@ class AliasSet : public ilist_node { return &NextInList; } - void updateSizeAndAAInfo(uint64_t NewSize, const AAMDNodes &NewAAInfo) { - if (NewSize > Size) Size = NewSize; + bool updateSizeAndAAInfo(uint64_t NewSize, const AAMDNodes &NewAAInfo) { + bool SizeChanged = false; + if (NewSize > Size) { + Size = NewSize; + SizeChanged = true; + } if (AAInfo == DenseMapInfo::getEmptyKey()) // We don't have a AAInfo yet. Set it to NewAAInfo. @@ -68,6 +72,8 @@ class AliasSet : public ilist_node { else if (AAInfo != NewAAInfo) // NewAAInfo conflicts with AAInfo. AAInfo = DenseMapInfo::getTombstoneKey(); + + return SizeChanged; } uint64_t getSize() const { return Size; } @@ -145,7 +151,7 @@ class AliasSet : public ilist_node { unsigned Alias : 1; /// True if this alias set contains volatile loads or stores. - bool Volatile : 1; + unsigned Volatile : 1; void addRef() { ++RefCount; } void dropRef(AliasSetTracker &AST) { @@ -365,7 +371,7 @@ public: /// otherwise return null. AliasSet *getAliasSetForPointerIfExists(const Value *P, uint64_t Size, const AAMDNodes &AAInfo) { - return findAliasSetForPointer(P, Size, AAInfo); + return mergeAliasSetsForPointer(P, Size, AAInfo); } /// Return true if the specified location is represented by this alias set, @@ -425,8 +431,8 @@ private: AS.Access |= E; return AS; } - AliasSet *findAliasSetForPointer(const Value *Ptr, uint64_t Size, - const AAMDNodes &AAInfo); + AliasSet *mergeAliasSetsForPointer(const Value *Ptr, uint64_t Size, + const AAMDNodes &AAInfo); AliasSet *findAliasSetForUnknownInst(Instruction *Inst); }; diff --git a/include/llvm/Analysis/AssumptionCache.h b/include/llvm/Analysis/AssumptionCache.h index 9e8243492c04df9a3584d6ed8a0ab2005c7dcc0b..06f2a117ac210299c7ea396d6ec54d89c8ea1f57 100644 --- a/include/llvm/Analysis/AssumptionCache.h +++ b/include/llvm/Analysis/AssumptionCache.h @@ -106,7 +106,9 @@ public: AssumptionAnalysis &operator=(const AssumptionAnalysis &RHS) { return *this; } AssumptionAnalysis &operator=(AssumptionAnalysis &&RHS) { return *this; } - AssumptionCache run(Function &F) { return AssumptionCache(F); } + AssumptionCache run(Function &F, FunctionAnalysisManager &) { + return AssumptionCache(F); + } }; /// \brief Printer pass for the \c AssumptionAnalysis results. @@ -116,8 +118,6 @@ class AssumptionPrinterPass : public PassInfoMixin { public: explicit AssumptionPrinterPass(raw_ostream &OS) : OS(OS) {} PreservedAnalyses run(Function &F, AnalysisManager &AM); - - static StringRef name() { return "AssumptionPrinterPass"; } }; /// \brief An immutable pass that tracks lazily created \c AssumptionCache diff --git a/include/llvm/Analysis/BasicAliasAnalysis.h b/include/llvm/Analysis/BasicAliasAnalysis.h index a1ac3ed57bc5793cdc893c769819e5342f6b8f9e..a3195d17b0290808adfd54db0af45d863d1264db 100644 --- a/include/llvm/Analysis/BasicAliasAnalysis.h +++ b/include/llvm/Analysis/BasicAliasAnalysis.h @@ -109,6 +109,20 @@ private: } }; + // Represents the internal structure of a GEP, decomposed into a base pointer, + // constant offsets, and variable scaled indices. + struct DecomposedGEP { + // Base pointer of the GEP + const Value *Base; + // Total constant offset w.r.t the base from indexing into structs + int64_t StructOffset; + // Total constant offset w.r.t the base from indexing through + // pointers/arrays/vectors + int64_t OtherOffset; + // Scaled variable (non-constant) indices. + SmallVector VarIndices; + }; + /// Track alias queries to guard against recursion. typedef std::pair LocPair; typedef SmallDenseMap AliasCacheTy; @@ -139,11 +153,13 @@ private: const DataLayout &DL, unsigned Depth, AssumptionCache *AC, DominatorTree *DT, bool &NSW, bool &NUW); - static const Value * - DecomposeGEPExpression(const Value *V, int64_t &BaseOffs, - SmallVectorImpl &VarIndices, - bool &MaxLookupReached, const DataLayout &DL, - AssumptionCache *AC, DominatorTree *DT); + static bool DecomposeGEPExpression(const Value *V, DecomposedGEP &Decomposed, + const DataLayout &DL, AssumptionCache *AC, DominatorTree *DT); + + static bool isGEPBaseAtNegativeOffset(const GEPOperator *GEPOp, + const DecomposedGEP &DecompGEP, const DecomposedGEP &DecompObject, + uint64_t ObjectAccessSize); + /// \brief A Heuristic for aliasGEP that searches for a constant offset /// between the variables. /// diff --git a/include/llvm/Analysis/BlockFrequencyInfo.h b/include/llvm/Analysis/BlockFrequencyInfo.h index 875775439b1372c723724afbebecc32b8c68eff4..7d48dfc9121ecaf4ff4baf1dc057d6cf57cf56b3 100644 --- a/include/llvm/Analysis/BlockFrequencyInfo.h +++ b/include/llvm/Analysis/BlockFrequencyInfo.h @@ -15,6 +15,7 @@ #define LLVM_ANALYSIS_BLOCKFREQUENCYINFO_H #include "llvm/ADT/Optional.h" +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include "llvm/Support/BlockFrequency.h" #include @@ -31,12 +32,21 @@ class BlockFrequencyInfo { typedef BlockFrequencyInfoImpl ImplType; std::unique_ptr BFI; + void operator=(const BlockFrequencyInfo &) = delete; + BlockFrequencyInfo(const BlockFrequencyInfo &) = delete; + public: BlockFrequencyInfo(); BlockFrequencyInfo(const Function &F, const BranchProbabilityInfo &BPI, const LoopInfo &LI); + BlockFrequencyInfo(BlockFrequencyInfo &&Arg); + + BlockFrequencyInfo &operator=(BlockFrequencyInfo &&RHS); + + ~BlockFrequencyInfo(); const Function *getFunction() const; + const BranchProbabilityInfo *getBPI() const; void view() const; /// getblockFreq - Return block frequency. Return 0 if we don't have the @@ -71,6 +81,30 @@ public: void print(raw_ostream &OS) const; }; +/// \brief Analysis pass which computes \c BlockFrequencyInfo. +class BlockFrequencyAnalysis + : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static char PassID; + +public: + /// \brief Provide the result typedef for this analysis pass. + typedef BlockFrequencyInfo Result; + + /// \brief Run the analysis pass over a function and produce BFI. + Result run(Function &F, AnalysisManager &AM); +}; + +/// \brief Printer pass for the \c BlockFrequencyInfo results. +class BlockFrequencyPrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit BlockFrequencyPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, AnalysisManager &AM); +}; + /// \brief Legacy analysis pass which computes \c BlockFrequencyInfo. class BlockFrequencyInfoWrapperPass : public FunctionPass { BlockFrequencyInfo BFI; diff --git a/include/llvm/Analysis/BlockFrequencyInfoImpl.h b/include/llvm/Analysis/BlockFrequencyInfoImpl.h index 387e9a887d93ceb8c8b11b29ba2fa2eab042e497..7ed06b1bb68f36d3278c0740cae16f6825d1d287 100644 --- a/include/llvm/Analysis/BlockFrequencyInfoImpl.h +++ b/include/llvm/Analysis/BlockFrequencyInfoImpl.h @@ -16,12 +16,16 @@ #define LLVM_ANALYSIS_BLOCKFREQUENCYINFOIMPL_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/BasicBlock.h" #include "llvm/Support/BlockFrequency.h" #include "llvm/Support/BranchProbability.h" +#include "llvm/Support/DOTGraphTraits.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include "llvm/Support/ScaledNumber.h" #include "llvm/Support/raw_ostream.h" #include @@ -476,6 +480,8 @@ public: Scaled64 getFloatingBlockFreq(const BlockNode &Node) const; BlockFrequency getBlockFreq(const BlockNode &Node) const; + Optional getBlockProfileCount(const Function &F, + const BlockNode &Node) const; void setBlockFreq(const BlockNode &Node, uint64_t Freq); @@ -915,11 +921,17 @@ public: BlockFrequency getBlockFreq(const BlockT *BB) const { return BlockFrequencyInfoImplBase::getBlockFreq(getNode(BB)); } + Optional getBlockProfileCount(const Function &F, + const BlockT *BB) const { + return BlockFrequencyInfoImplBase::getBlockProfileCount(F, getNode(BB)); + } void setBlockFreq(const BlockT *BB, uint64_t Freq); Scaled64 getFloatingBlockFreq(const BlockT *BB) const { return BlockFrequencyInfoImplBase::getFloatingBlockFreq(getNode(BB)); } + const BranchProbabilityInfoT &getBPI() const { return *BPI; } + /// \brief Print the frequencies for the current function. /// /// Prints the frequencies for the blocks in the current function. @@ -1173,12 +1185,10 @@ void BlockFrequencyInfoImpl::computeIrreducibleMass( updateLoopWithIrreducible(*OuterLoop); } -namespace { // A helper function that converts a branch probability into weight. inline uint32_t getWeightFromBranchProb(const BranchProbability Prob) { return Prob.getNumerator(); } -} // namespace template bool @@ -1224,6 +1234,115 @@ raw_ostream &BlockFrequencyInfoImpl::print(raw_ostream &OS) const { return OS; } +// Graph trait base class for block frequency information graph +// viewer. + +enum GVDAGType { GVDT_None, GVDT_Fraction, GVDT_Integer, GVDT_Count }; + +template +struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits { + explicit BFIDOTGraphTraitsBase(bool isSimple = false) + : DefaultDOTGraphTraits(isSimple) {} + + typedef GraphTraits GTraits; + typedef typename GTraits::NodeType NodeType; + typedef typename GTraits::ChildIteratorType EdgeIter; + typedef typename GTraits::nodes_iterator NodeIter; + + uint64_t MaxFrequency = 0; + static std::string getGraphName(const BlockFrequencyInfoT *G) { + return G->getFunction()->getName(); + } + + std::string getNodeAttributes(const NodeType *Node, + const BlockFrequencyInfoT *Graph, + unsigned HotPercentThreshold = 0) { + std::string Result; + if (!HotPercentThreshold) + return Result; + + // Compute MaxFrequency on the fly: + if (!MaxFrequency) { + for (NodeIter I = GTraits::nodes_begin(Graph), + E = GTraits::nodes_end(Graph); + I != E; ++I) { + NodeType &N = *I; + MaxFrequency = + std::max(MaxFrequency, Graph->getBlockFreq(&N).getFrequency()); + } + } + BlockFrequency Freq = Graph->getBlockFreq(Node); + BlockFrequency HotFreq = + (BlockFrequency(MaxFrequency) * + BranchProbability::getBranchProbability(HotPercentThreshold, 100)); + + if (Freq < HotFreq) + return Result; + + raw_string_ostream OS(Result); + OS << "color=\"red\""; + OS.flush(); + return Result; + } + + std::string getNodeLabel(const NodeType *Node, + const BlockFrequencyInfoT *Graph, GVDAGType GType) { + std::string Result; + raw_string_ostream OS(Result); + + OS << Node->getName().str() << " : "; + switch (GType) { + case GVDT_Fraction: + Graph->printBlockFreq(OS, Node); + break; + case GVDT_Integer: + OS << Graph->getBlockFreq(Node).getFrequency(); + break; + case GVDT_Count: { + auto Count = Graph->getBlockProfileCount(Node); + if (Count) + OS << Count.getValue(); + else + OS << "Unknown"; + break; + } + case GVDT_None: + llvm_unreachable("If we are not supposed to render a graph we should " + "never reach this point."); + } + return Result; + } + + std::string getEdgeAttributes(const NodeType *Node, EdgeIter EI, + const BlockFrequencyInfoT *BFI, + const BranchProbabilityInfoT *BPI, + unsigned HotPercentThreshold = 0) { + std::string Str; + if (!BPI) + return Str; + + BranchProbability BP = BPI->getEdgeProbability(Node, EI); + uint32_t N = BP.getNumerator(); + uint32_t D = BP.getDenominator(); + double Percent = 100.0 * N / D; + raw_string_ostream OS(Str); + OS << format("label=\"%.1f%%\"", Percent); + + if (HotPercentThreshold) { + BlockFrequency EFreq = BFI->getBlockFreq(Node) * BP; + BlockFrequency HotFreq = BlockFrequency(MaxFrequency) * + BranchProbability(HotPercentThreshold, 100); + + if (EFreq >= HotFreq) { + OS << ",color=\"red\""; + } + } + + OS.flush(); + return Str; + } +}; + } // end namespace llvm #undef DEBUG_TYPE diff --git a/include/llvm/Analysis/BranchProbabilityInfo.h b/include/llvm/Analysis/BranchProbabilityInfo.h index cfdf218491bdbe473904e0a423a47d5f738278af..54514a9f1f39be14fc7a28a1dd6229940f9ed082 100644 --- a/include/llvm/Analysis/BranchProbabilityInfo.h +++ b/include/llvm/Analysis/BranchProbabilityInfo.h @@ -17,6 +17,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/PassManager.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/BranchProbability.h" @@ -40,7 +41,22 @@ class raw_ostream; class BranchProbabilityInfo { public: BranchProbabilityInfo() {} - BranchProbabilityInfo(Function &F, const LoopInfo &LI) { calculate(F, LI); } + BranchProbabilityInfo(const Function &F, const LoopInfo &LI) { + calculate(F, LI); + } + + BranchProbabilityInfo(BranchProbabilityInfo &&Arg) + : Probs(std::move(Arg.Probs)), LastF(Arg.LastF), + PostDominatedByUnreachable(std::move(Arg.PostDominatedByUnreachable)), + PostDominatedByColdCall(std::move(Arg.PostDominatedByColdCall)) {} + + BranchProbabilityInfo &operator=(BranchProbabilityInfo &&RHS) { + releaseMemory(); + Probs = std::move(RHS.Probs); + PostDominatedByColdCall = std::move(RHS.PostDominatedByColdCall); + PostDominatedByUnreachable = std::move(RHS.PostDominatedByUnreachable); + return *this; + } void releaseMemory(); @@ -74,7 +90,7 @@ public: /// /// Given a basic block, look through its successors and if one exists for /// which \see isEdgeHot would return true, return that successor block. - BasicBlock *getHotSucc(BasicBlock *BB) const; + const BasicBlock *getHotSucc(const BasicBlock *BB) const; /// \brief Print an edge's probability. /// @@ -98,9 +114,12 @@ public: return IsLikely ? LikelyProb : LikelyProb.getCompl(); } - void calculate(Function &F, const LoopInfo& LI); + void calculate(const Function &F, const LoopInfo &LI); private: + void operator=(const BranchProbabilityInfo &) = delete; + BranchProbabilityInfo(const BranchProbabilityInfo &) = delete; + // Since we allow duplicate edges from one basic block to another, we use // a pair (PredBlock and an index in the successors) to specify an edge. typedef std::pair Edge; @@ -116,22 +135,46 @@ private: DenseMap Probs; /// \brief Track the last function we run over for printing. - Function *LastF; + const Function *LastF; /// \brief Track the set of blocks directly succeeded by a returning block. - SmallPtrSet PostDominatedByUnreachable; + SmallPtrSet PostDominatedByUnreachable; /// \brief Track the set of blocks that always lead to a cold call. - SmallPtrSet PostDominatedByColdCall; - - bool calcUnreachableHeuristics(BasicBlock *BB); - bool calcMetadataWeights(BasicBlock *BB); - bool calcColdCallHeuristics(BasicBlock *BB); - bool calcPointerHeuristics(BasicBlock *BB); - bool calcLoopBranchHeuristics(BasicBlock *BB, const LoopInfo &LI); - bool calcZeroHeuristics(BasicBlock *BB); - bool calcFloatingPointHeuristics(BasicBlock *BB); - bool calcInvokeHeuristics(BasicBlock *BB); + SmallPtrSet PostDominatedByColdCall; + + bool calcUnreachableHeuristics(const BasicBlock *BB); + bool calcMetadataWeights(const BasicBlock *BB); + bool calcColdCallHeuristics(const BasicBlock *BB); + bool calcPointerHeuristics(const BasicBlock *BB); + bool calcLoopBranchHeuristics(const BasicBlock *BB, const LoopInfo &LI); + bool calcZeroHeuristics(const BasicBlock *BB); + bool calcFloatingPointHeuristics(const BasicBlock *BB); + bool calcInvokeHeuristics(const BasicBlock *BB); +}; + +/// \brief Analysis pass which computes \c BranchProbabilityInfo. +class BranchProbabilityAnalysis + : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static char PassID; + +public: + /// \brief Provide the result typedef for this analysis pass. + typedef BranchProbabilityInfo Result; + + /// \brief Run the analysis pass over a function and produce BPI. + BranchProbabilityInfo run(Function &F, AnalysisManager &AM); +}; + +/// \brief Printer pass for the \c BranchProbabilityAnalysis results. +class BranchProbabilityPrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit BranchProbabilityPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, AnalysisManager &AM); }; /// \brief Legacy analysis pass which computes \c BranchProbabilityInfo. diff --git a/include/llvm/Analysis/CFLAndersAliasAnalysis.h b/include/llvm/Analysis/CFLAndersAliasAnalysis.h new file mode 100644 index 0000000000000000000000000000000000000000..a5bbed9165d5698e2a1316400ab7c25fae31a8bd --- /dev/null +++ b/include/llvm/Analysis/CFLAndersAliasAnalysis.h @@ -0,0 +1,85 @@ +//=- CFLAndersAliasAnalysis.h - Unification-based Alias Analysis ---*- C++-*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This is the interface for LLVM's inclusion-based alias analysis +/// implemented with CFL graph reachability. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H +#define LLVM_ANALYSIS_CFLANDERSALIASANALYSIS_H + +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/IR/Function.h" +#include "llvm/Pass.h" + +namespace llvm { + +namespace cflaa { +struct AliasSummary; +} + +class CFLAndersAAResult : public AAResultBase { + friend AAResultBase; + +public: + explicit CFLAndersAAResult(); + + /// \brief Get the alias summary for the given function + /// Return nullptr if the summary is not found or not available + const cflaa::AliasSummary *getAliasSummary(Function &Fn) { + // Dummy implementation + return nullptr; + } + + AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) { + // Dummy implementation + return AAResultBase::alias(LocA, LocB); + } +}; + +/// Analysis pass providing a never-invalidated alias analysis result. +/// +/// FIXME: We really should refactor CFL to use the analysis more heavily, and +/// in particular to leverage invalidation to trigger re-computation. +class CFLAndersAA : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static char PassID; + +public: + typedef CFLAndersAAResult Result; + + CFLAndersAAResult run(Function &F, AnalysisManager &AM); +}; + +/// Legacy wrapper pass to provide the CFLAndersAAResult object. +class CFLAndersAAWrapperPass : public ImmutablePass { + std::unique_ptr Result; + +public: + static char ID; + + CFLAndersAAWrapperPass(); + + CFLAndersAAResult &getResult() { return *Result; } + const CFLAndersAAResult &getResult() const { return *Result; } + + void initializePass() override; + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +//===--------------------------------------------------------------------===// +// +// createCFLAndersAAWrapperPass - This pass implements a set-based approach to +// alias analysis. +// +ImmutablePass *createCFLAndersAAWrapperPass(); +} + +#endif diff --git a/include/llvm/Analysis/CFLAliasAnalysis.h b/include/llvm/Analysis/CFLSteensAliasAnalysis.h similarity index 58% rename from include/llvm/Analysis/CFLAliasAnalysis.h rename to include/llvm/Analysis/CFLSteensAliasAnalysis.h index 5ee4dddb94e38b0438e0aabc9755e20dee5e8254..80a00d02b81133b486fe42c9264191a4ede7f497 100644 --- a/include/llvm/Analysis/CFLAliasAnalysis.h +++ b/include/llvm/Analysis/CFLSteensAliasAnalysis.h @@ -1,4 +1,4 @@ -//===- CFLAliasAnalysis.h - CFL-Based Alias Analysis Interface ---*- C++ -*-==// +//=- CFLSteensAliasAnalysis.h - Unification-based Alias Analysis ---*- C++-*-=// // // The LLVM Compiler Infrastructure // @@ -7,17 +7,18 @@ // //===----------------------------------------------------------------------===// /// \file -/// This is the interface for LLVM's primary stateless and local alias analysis. +/// This is the interface for LLVM's unification-based alias analysis +/// implemented with CFL graph reachability. /// //===----------------------------------------------------------------------===// -#ifndef LLVM_ANALYSIS_CFLALIASANALYSIS_H -#define LLVM_ANALYSIS_CFLALIASANALYSIS_H +#ifndef LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H +#define LLVM_ANALYSIS_CFLSTEENSALIASANALYSIS_H -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/IR/ValueHandle.h" @@ -26,15 +27,20 @@ namespace llvm { -class CFLAAResult : public AAResultBase { - friend AAResultBase; +class TargetLibraryInfo; - struct FunctionInfo; +namespace cflaa { +struct AliasSummary; +} + +class CFLSteensAAResult : public AAResultBase { + friend AAResultBase; + class FunctionInfo; public: - explicit CFLAAResult(); - CFLAAResult(CFLAAResult &&Arg); - ~CFLAAResult(); + explicit CFLSteensAAResult(const TargetLibraryInfo &); + CFLSteensAAResult(CFLSteensAAResult &&Arg); + ~CFLSteensAAResult(); /// Handle invalidation events from the new pass manager. /// @@ -50,6 +56,10 @@ public: /// Returns the appropriate entry from the cache. const Optional &ensureCached(Function *Fn); + /// \brief Get the alias summary for the given function + /// Return nullptr if the summary is not found or not available + const cflaa::AliasSummary *getAliasSummary(Function &Fn); + AliasResult query(const MemoryLocation &LocA, const MemoryLocation &LocB); AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) { @@ -58,10 +68,9 @@ public: // Comparisons between global variables and other constants should be // handled by BasicAA. - // TODO: ConstantExpr handling -- CFLAA may report NoAlias when comparing - // a GlobalValue and ConstantExpr, but every query needs to have at least - // one Value tied to a Function, and neither GlobalValues nor ConstantExprs - // are. + // CFLSteensAA may report NoAlias when comparing a GlobalValue and + // ConstantExpr, but every query needs to have at least one Value tied to a + // Function, and neither GlobalValues nor ConstantExprs are. if (isa(LocA.Ptr) && isa(LocB.Ptr)) return AAResultBase::alias(LocA, LocB); @@ -72,9 +81,19 @@ public: return QueryResult; } + /// Get the location associated with a pointer argument of a callsite. + ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx); + + /// Returns the behavior when calling the given call site. + FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS); + + /// Returns the behavior when calling the given function. For use when the + /// call site is not known. + FunctionModRefBehavior getModRefBehavior(const Function *F); + private: struct FunctionHandle final : public CallbackVH { - FunctionHandle(Function *Fn, CFLAAResult *Result) + FunctionHandle(Function *Fn, CFLSteensAAResult *Result) : CallbackVH(Fn), Result(Result) { assert(Fn != nullptr); assert(Result != nullptr); @@ -84,7 +103,7 @@ private: void allUsesReplacedWith(Value *) override { removeSelfFromCache(); } private: - CFLAAResult *Result; + CFLSteensAAResult *Result; void removeSelfFromCache() { assert(Result != nullptr); @@ -94,6 +113,8 @@ private: } }; + const TargetLibraryInfo &TLI; + /// \brief Cached mapping of Functions to their StratifiedSets. /// If a function's sets are currently being built, it is marked /// in the cache as an Optional without a value. This way, if we @@ -109,39 +130,38 @@ private: /// /// FIXME: We really should refactor CFL to use the analysis more heavily, and /// in particular to leverage invalidation to trigger re-computation of sets. -class CFLAA : public AnalysisInfoMixin { - friend AnalysisInfoMixin; +class CFLSteensAA : public AnalysisInfoMixin { + friend AnalysisInfoMixin; static char PassID; public: - typedef CFLAAResult Result; + typedef CFLSteensAAResult Result; - CFLAAResult run(Function &F, AnalysisManager &AM); + CFLSteensAAResult run(Function &F, AnalysisManager &AM); }; -/// Legacy wrapper pass to provide the CFLAAResult object. -class CFLAAWrapperPass : public ImmutablePass { - std::unique_ptr Result; +/// Legacy wrapper pass to provide the CFLSteensAAResult object. +class CFLSteensAAWrapperPass : public ImmutablePass { + std::unique_ptr Result; public: static char ID; - CFLAAWrapperPass(); + CFLSteensAAWrapperPass(); - CFLAAResult &getResult() { return *Result; } - const CFLAAResult &getResult() const { return *Result; } + CFLSteensAAResult &getResult() { return *Result; } + const CFLSteensAAResult &getResult() const { return *Result; } - bool doInitialization(Module &M) override; - bool doFinalization(Module &M) override; + void initializePass() override; void getAnalysisUsage(AnalysisUsage &AU) const override; }; //===--------------------------------------------------------------------===// // -// createCFLAAWrapperPass - This pass implements a set-based approach to +// createCFLSteensAAWrapperPass - This pass implements a set-based approach to // alias analysis. // -ImmutablePass *createCFLAAWrapperPass(); +ImmutablePass *createCFLSteensAAWrapperPass(); } #endif diff --git a/include/llvm/Analysis/CGSCCPassManager.h b/include/llvm/Analysis/CGSCCPassManager.h index 989305ebb272b871cc5f38d9c6d6bdc6423b466c..3263ecec4e2659abe196137d3b908066375ada48 100644 --- a/include/llvm/Analysis/CGSCCPassManager.h +++ b/include/llvm/Analysis/CGSCCPassManager.h @@ -67,19 +67,20 @@ template class ModuleToPostOrderCGSCCPassAdaptor : public PassInfoMixin> { public: - explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) - : Pass(std::move(Pass)) {} + explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false) + : Pass(std::move(Pass)), DebugLogging(DebugLogging) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. ModuleToPostOrderCGSCCPassAdaptor( const ModuleToPostOrderCGSCCPassAdaptor &Arg) - : Pass(Arg.Pass) {} + : Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {} ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg) - : Pass(std::move(Arg.Pass)) {} + : Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {} friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS, ModuleToPostOrderCGSCCPassAdaptor &RHS) { using std::swap; swap(LHS.Pass, RHS.Pass); + swap(LHS.DebugLogging, RHS.DebugLogging); } ModuleToPostOrderCGSCCPassAdaptor & operator=(ModuleToPostOrderCGSCCPassAdaptor RHS) { @@ -97,8 +98,11 @@ public: LazyCallGraph &CG = AM.getResult(M); PreservedAnalyses PA = PreservedAnalyses::all(); - for (LazyCallGraph::RefSCC &OuterC : CG.postorder_ref_sccs()) - for (LazyCallGraph::SCC &C : OuterC) { + for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) { + if (DebugLogging) + dbgs() << "Running an SCC pass across the RefSCC: " << RC << "\n"; + + for (LazyCallGraph::SCC &C : RC) { PreservedAnalyses PassPA = Pass.run(C, CGAM); // We know that the CGSCC pass couldn't have invalidated any other @@ -115,6 +119,7 @@ public: // analyses will eventually occur when the module pass completes. PA.intersect(std::move(PassPA)); } + } // By definition we preserve the proxy. This precludes *any* invalidation // of CGSCC analyses by the proxy, but that's OK because we've taken @@ -126,14 +131,15 @@ public: private: CGSCCPassT Pass; + bool DebugLogging; }; /// \brief A function to deduce a function pass type and wrap it in the /// templated adaptor. template ModuleToPostOrderCGSCCPassAdaptor -createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) { - return ModuleToPostOrderCGSCCPassAdaptor(std::move(Pass)); +createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false) { + return ModuleToPostOrderCGSCCPassAdaptor(std::move(Pass), DebugLogging); } extern template class InnerAnalysisManagerProxy class CGSCCToFunctionPassAdaptor : public PassInfoMixin> { public: - explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass) - : Pass(std::move(Pass)) {} + explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false) + : Pass(std::move(Pass)), DebugLogging(DebugLogging) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. CGSCCToFunctionPassAdaptor(const CGSCCToFunctionPassAdaptor &Arg) - : Pass(Arg.Pass) {} + : Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {} CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg) - : Pass(std::move(Arg.Pass)) {} + : Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {} friend void swap(CGSCCToFunctionPassAdaptor &LHS, CGSCCToFunctionPassAdaptor &RHS) { using std::swap; swap(LHS.Pass, RHS.Pass); + swap(LHS.DebugLogging, RHS.DebugLogging); } CGSCCToFunctionPassAdaptor &operator=(CGSCCToFunctionPassAdaptor RHS) { swap(*this, RHS); @@ -183,6 +190,9 @@ public: FunctionAnalysisManager &FAM = AM.getResult(C).getManager(); + if (DebugLogging) + dbgs() << "Running function passes across an SCC: " << C << "\n"; + PreservedAnalyses PA = PreservedAnalyses::all(); for (LazyCallGraph::Node &N : C) { PreservedAnalyses PassPA = Pass.run(N.getFunction(), FAM); @@ -211,14 +221,16 @@ public: private: FunctionPassT Pass; + bool DebugLogging; }; /// \brief A function to deduce a function pass type and wrap it in the /// templated adaptor. template CGSCCToFunctionPassAdaptor -createCGSCCToFunctionPassAdaptor(FunctionPassT Pass) { - return CGSCCToFunctionPassAdaptor(std::move(Pass)); +createCGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false) { + return CGSCCToFunctionPassAdaptor(std::move(Pass), + DebugLogging); } } diff --git a/include/llvm/Analysis/CallGraph.h b/include/llvm/Analysis/CallGraph.h index 565c20569cf74b67dd0ad58b017234a74fed9691..4ecacb0f0be205866d6113a83ffa0c2aed3631fd 100644 --- a/include/llvm/Analysis/CallGraph.h +++ b/include/llvm/Analysis/CallGraph.h @@ -306,7 +306,7 @@ public: /// \brief Compute the \c CallGraph for the module \c M. /// /// The real work here is done in the \c CallGraph constructor. - CallGraph run(Module &M) { return CallGraph(M); } + CallGraph run(Module &M, ModuleAnalysisManager &) { return CallGraph(M); } }; /// \brief Printer pass for the \c CallGraphAnalysis results. diff --git a/include/llvm/Analysis/CallGraphSCCPass.h b/include/llvm/Analysis/CallGraphSCCPass.h index 9c7f7bd34cceb3614c3ca3b865364a195c167ce7..cb35b3292be71e87ab51e9cb08a6b1bb64757198 100644 --- a/include/llvm/Analysis/CallGraphSCCPass.h +++ b/include/llvm/Analysis/CallGraphSCCPass.h @@ -23,6 +23,7 @@ #include "llvm/Analysis/CallGraph.h" #include "llvm/Pass.h" +#include "llvm/PassSupport.h" namespace llvm { @@ -77,15 +78,21 @@ public: /// the call graph. If the derived class implements this method, it should /// always explicitly call the implementation here. void getAnalysisUsage(AnalysisUsage &Info) const override; + +protected: + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when optimization bisect is over the limit. + bool skipSCC(CallGraphSCC &SCC) const; }; /// CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on. class CallGraphSCC { + const CallGraph &CG; // The call graph for this SCC. void *Context; // The CGPassManager object that is vending this. std::vector Nodes; public: - CallGraphSCC(void *context) : Context(context) {} + CallGraphSCC(CallGraph &cg, void *context) : CG(cg), Context(context) {} void initialize(CallGraphNode *const *I, CallGraphNode *const *E) { Nodes.assign(I, E); @@ -101,6 +108,25 @@ public: typedef std::vector::const_iterator iterator; iterator begin() const { return Nodes.begin(); } iterator end() const { return Nodes.end(); } + + const CallGraph &getCallGraph() { return CG; } +}; + +void initializeDummyCGSCCPassPass(PassRegistry &); + +/// This pass is required by interprocedural register allocation. It forces +/// codegen to follow bottom up order on call graph. +class DummyCGSCCPass : public CallGraphSCCPass { +public: + static char ID; + DummyCGSCCPass() : CallGraphSCCPass(ID) { + PassRegistry &Registry = *PassRegistry::getPassRegistry(); + initializeDummyCGSCCPassPass(Registry); + }; + bool runOnSCC(CallGraphSCC &SCC) override { return false; } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } }; } // End llvm namespace diff --git a/include/llvm/Analysis/ConstantFolding.h b/include/llvm/Analysis/ConstantFolding.h index e1102b4d0c7a1a9207e6dc9fc1316ee95e230992..b1504004d83c95e09996559f84b9fd852e21124c 100644 --- a/include/llvm/Analysis/ConstantFolding.h +++ b/include/llvm/Analysis/ConstantFolding.h @@ -21,14 +21,21 @@ #define LLVM_ANALYSIS_CONSTANTFOLDING_H namespace llvm { +class APInt; +template class ArrayRef; class Constant; class ConstantExpr; -class Instruction; class DataLayout; -class TargetLibraryInfo; class Function; +class GlobalValue; +class Instruction; +class TargetLibraryInfo; class Type; -template class ArrayRef; + +/// If this constant is a constant offset from a global, return the global and +/// the constant. Because of constantexprs, this function is recursive. +bool IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, APInt &Offset, + const DataLayout &DL); /// ConstantFoldInstruction - Try to constant fold the specified instruction. /// If successful, the constant result is returned, if not, null is returned. diff --git a/include/llvm/Analysis/DemandedBits.h b/include/llvm/Analysis/DemandedBits.h index ef31d81bfdd7d4c4711d488aa598e86a72212cfc..fafd5d00b4811799db6034745d41fdd5c7a4c5fb 100644 --- a/include/llvm/Analysis/DemandedBits.h +++ b/include/llvm/Analysis/DemandedBits.h @@ -26,6 +26,7 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/IR/PassManager.h" namespace llvm { @@ -35,31 +36,31 @@ class Instruction; class DominatorTree; class AssumptionCache; -struct DemandedBits : public FunctionPass { - static char ID; // Pass identification, replacement for typeid - DemandedBits(); +class DemandedBits { +public: + DemandedBits(Function &F, AssumptionCache &AC, DominatorTree &DT) : + F(F), AC(AC), DT(DT), Analyzed(false) {} - bool runOnFunction(Function& F) override; - void getAnalysisUsage(AnalysisUsage& AU) const override; - void print(raw_ostream &OS, const Module *M) const override; - /// Return the bits demanded from instruction I. APInt getDemandedBits(Instruction *I); /// Return true if, during analysis, I could not be reached. bool isInstructionDead(Instruction *I); + + void print(raw_ostream &OS); private: + Function &F; + AssumptionCache &AC; + DominatorTree &DT; + void performAnalysis(); void determineLiveOperandBits(const Instruction *UserI, - const Instruction *I, unsigned OperandNo, - const APInt &AOut, APInt &AB, - APInt &KnownZero, APInt &KnownOne, - APInt &KnownZero2, APInt &KnownOne2); - - AssumptionCache *AC; - DominatorTree *DT; - Function *F; + const Instruction *I, unsigned OperandNo, + const APInt &AOut, APInt &AB, + APInt &KnownZero, APInt &KnownOne, + APInt &KnownZero2, APInt &KnownOne2); + bool Analyzed; // The set of visited instructions (non-integer-typed only). @@ -67,8 +68,49 @@ private: DenseMap AliveBits; }; +class DemandedBitsWrapperPass : public FunctionPass { +private: + mutable Optional DB; +public: + static char ID; // Pass identification, replacement for typeid + DemandedBitsWrapperPass(); + + bool runOnFunction(Function &F) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; + + /// Clean up memory in between runs + void releaseMemory() override; + + DemandedBits &getDemandedBits() { return *DB; } + + void print(raw_ostream &OS, const Module *M) const override; +}; + +/// An analysis that produces \c DemandedBits for a function. +class DemandedBitsAnalysis : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static char PassID; + +public: + /// \brief Provide the result typedef for this analysis pass. + typedef DemandedBits Result; + + /// \brief Run the analysis pass over a function and produce demanded bits + /// information. + DemandedBits run(Function &F, AnalysisManager &AM); +}; + +/// \brief Printer pass for DemandedBits +class DemandedBitsPrinterPass : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit DemandedBitsPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, AnalysisManager &AM); +}; + /// Create a demanded bits analysis pass. -FunctionPass *createDemandedBitsPass(); +FunctionPass *createDemandedBitsWrapperPass(); } // End llvm namespace diff --git a/include/llvm/Analysis/DependenceAnalysis.h b/include/llvm/Analysis/DependenceAnalysis.h index 5290552b41dc989c720d078a4c6b8a395bbc694a..32dd367a9c0aa48344d6a770ddd187562cbec025 100644 --- a/include/llvm/Analysis/DependenceAnalysis.h +++ b/include/llvm/Analysis/DependenceAnalysis.h @@ -41,12 +41,12 @@ #define LLVM_ANALYSIS_DEPENDENCEANALYSIS_H #include "llvm/ADT/SmallBitVector.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/IR/Instructions.h" #include "llvm/Pass.h" namespace llvm { +template class ArrayRef; class Loop; class LoopInfo; class ScalarEvolution; @@ -206,7 +206,7 @@ namespace llvm { private: Instruction *Src, *Dst; const Dependence *NextPredecessor, *NextSuccessor; - friend class DependenceAnalysis; + friend class DependenceInfo; }; /// FullDependence - This class represents a dependence between two memory @@ -274,16 +274,17 @@ namespace llvm { bool LoopIndependent; bool Consistent; // Init to true, then refine. std::unique_ptr DV; - friend class DependenceAnalysis; + friend class DependenceInfo; }; - /// DependenceAnalysis - This class is the main dependence-analysis driver. + /// DependenceInfo - This class is the main dependence-analysis driver. /// - class DependenceAnalysis : public FunctionPass { - void operator=(const DependenceAnalysis &) = delete; - DependenceAnalysis(const DependenceAnalysis &) = delete; - + class DependenceInfo { public: + DependenceInfo(Function *F, AliasAnalysis *AA, ScalarEvolution *SE, + LoopInfo *LI) + : AA(AA), SE(SE), LI(LI), F(F) {} + /// depends - Tests for a dependence between the Src and Dst instructions. /// Returns NULL if no dependence; otherwise, returns a Dependence (or a /// FullDependence) with as much information as can be gleaned. @@ -336,6 +337,8 @@ namespace llvm { /// both loops. const SCEV *getSplitIteration(const Dependence &Dep, unsigned Level); + Function *getFunction() const { return F; } + private: AliasAnalysis *AA; ScalarEvolution *SE; @@ -919,22 +922,41 @@ namespace llvm { bool tryDelinearize(Instruction *Src, Instruction *Dst, SmallVectorImpl &Pair); + }; // class DependenceInfo + /// \brief AnalysisPass to compute dependence information in a function + class DependenceAnalysis : public AnalysisInfoMixin { + public: + typedef DependenceInfo Result; + Result run(Function &F, FunctionAnalysisManager &FAM); + + private: + static char PassID; + friend struct AnalysisInfoMixin; + }; // class DependenceAnalysis + + /// \brief Legacy pass manager pass to access dependence information + class DependenceAnalysisWrapperPass : public FunctionPass { public: static char ID; // Class identification, replacement for typeinfo - DependenceAnalysis() : FunctionPass(ID) { - initializeDependenceAnalysisPass(*PassRegistry::getPassRegistry()); + DependenceAnalysisWrapperPass() : FunctionPass(ID) { + initializeDependenceAnalysisWrapperPassPass( + *PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override; void releaseMemory() override; void getAnalysisUsage(AnalysisUsage &) const override; void print(raw_ostream &, const Module * = nullptr) const override; - }; // class DependenceAnalysis + DependenceInfo &getDI() const; + + private: + std::unique_ptr info; + }; // class DependenceAnalysisWrapperPass /// createDependenceAnalysisPass - This creates an instance of the - /// DependenceAnalysis pass. - FunctionPass *createDependenceAnalysisPass(); + /// DependenceAnalysis wrapper pass. + FunctionPass *createDependenceAnalysisWrapperPass(); } // namespace llvm diff --git a/include/llvm/Analysis/EHPersonalities.h b/include/llvm/Analysis/EHPersonalities.h index c647a4932b65ef925483fd6457c974c75494a342..a26c575cfe10f8188067f0c548ac1c4e947b1b6f 100644 --- a/include/llvm/Analysis/EHPersonalities.h +++ b/include/llvm/Analysis/EHPersonalities.h @@ -23,7 +23,9 @@ enum class EHPersonality { Unknown, GNU_Ada, GNU_C, + GNU_C_SjLj, GNU_CXX, + GNU_CXX_SjLj, GNU_ObjC, MSVC_X86SEH, MSVC_Win64SEH, diff --git a/include/llvm/Analysis/IndirectCallPromotionAnalysis.h b/include/llvm/Analysis/IndirectCallPromotionAnalysis.h new file mode 100644 index 0000000000000000000000000000000000000000..007e4d8602fae663aeb181872681fa68f941e022 --- /dev/null +++ b/include/llvm/Analysis/IndirectCallPromotionAnalysis.h @@ -0,0 +1,67 @@ +//===- IndirectCallPromotionAnalysis.h - Indirect call analysis -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// Interface to identify indirect call promotion candidates. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_INDIRECTCALLPROMOTIONANALYSIS_H +#define LLVM_ANALYSIS_INDIRECTCALLPROMOTIONANALYSIS_H + +#include "llvm/ProfileData/InstrProf.h" + +namespace llvm { + +class Instruction; + +// Class for identifying profitable indirect call promotion candidates when +// the indirect-call value profile metadata is available. +class ICallPromotionAnalysis { +private: + // Allocate space to read the profile annotation. + std::unique_ptr ValueDataArray; + + // Count is the call count for the direct-call target and + // TotalCount is the call count for the indirect-call callsite. + // Return true we should promote this indirect-call target. + bool isPromotionProfitable(uint64_t Count, uint64_t TotalCount); + + // Returns the number of profitable candidates to promote for the + // current ValueDataArray and the given \p Inst. + uint32_t getProfitablePromotionCandidates(const Instruction *Inst, + uint32_t NumVals, + uint64_t TotalCount); + + // Noncopyable + ICallPromotionAnalysis(const ICallPromotionAnalysis &other) = delete; + ICallPromotionAnalysis & + operator=(const ICallPromotionAnalysis &other) = delete; + +public: + ICallPromotionAnalysis(); + + /// \brief Returns reference to array of InstrProfValueData for the given + /// instruction \p I. + /// + /// The \p NumVals, \p TotalCount and \p NumCandidates + /// are set to the number of values in the array, the total profile count + /// of the indirect call \p I, and the number of profitable candidates + /// in the given array (which is sorted in reverse order of profitability). + /// + /// The returned array space is owned by this class, and overwritten on + /// subsequent calls. + ArrayRef + getPromotionCandidatesForInstruction(const Instruction *I, uint32_t &NumVals, + uint64_t &TotalCount, + uint32_t &NumCandidates); +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/Analysis/IndirectCallSiteVisitor.h b/include/llvm/Analysis/IndirectCallSiteVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..71a8cb886321676b9e2919ca59cdaa8f05b1a4d0 --- /dev/null +++ b/include/llvm/Analysis/IndirectCallSiteVisitor.h @@ -0,0 +1,43 @@ +//===-- IndirectCallSiteVisitor.h - indirect call-sites visitor -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements defines a visitor class and a helper function that find +// all indirect call-sites in a function. + +#include "llvm/IR/InstVisitor.h" +#include + +namespace llvm { +// Visitor class that finds all indirect call sites. +struct PGOIndirectCallSiteVisitor + : public InstVisitor { + std::vector IndirectCallInsts; + PGOIndirectCallSiteVisitor() {} + + void visitCallSite(CallSite CS) { + if (CS.getCalledFunction() || !CS.getCalledValue()) + return; + Instruction *I = CS.getInstruction(); + if (CallInst *CI = dyn_cast(I)) { + if (CI->isInlineAsm()) + return; + } + if (isa(CS.getCalledValue())) + return; + IndirectCallInsts.push_back(I); + } +}; + +// Helper function that finds all indirect call sites. +static inline std::vector findIndirectCallSites(Function &F) { + PGOIndirectCallSiteVisitor ICV; + ICV.visit(F); + return ICV.IndirectCallInsts; +} +} diff --git a/include/llvm/Analysis/InlineCost.h b/include/llvm/Analysis/InlineCost.h index 6f457bc487dccaeb743c91adf9d32babe8507958..2928d2be30e53b43cfe119cffc33706b9e82d695 100644 --- a/include/llvm/Analysis/InlineCost.h +++ b/include/llvm/Analysis/InlineCost.h @@ -23,6 +23,7 @@ class AssumptionCacheTracker; class CallSite; class DataLayout; class Function; +class ProfileSummaryInfo; class TargetTransformInfo; namespace InlineConstants { @@ -111,7 +112,7 @@ public: /// inlining the callsite. It is an expensive, heavyweight call. InlineCost getInlineCost(CallSite CS, int DefaultThreshold, TargetTransformInfo &CalleeTTI, - AssumptionCacheTracker *ACT); + AssumptionCacheTracker *ACT, ProfileSummaryInfo *PSI); /// \brief Get an InlineCost with the callee explicitly specified. /// This allows you to calculate the cost of inlining a function via a @@ -120,7 +121,7 @@ InlineCost getInlineCost(CallSite CS, int DefaultThreshold, // InlineCost getInlineCost(CallSite CS, Function *Callee, int DefaultThreshold, TargetTransformInfo &CalleeTTI, - AssumptionCacheTracker *ACT); + AssumptionCacheTracker *ACT, ProfileSummaryInfo *PSI); int computeThresholdFromOptLevels(unsigned OptLevel, unsigned SizeOptLevel); diff --git a/include/llvm/Analysis/Interval.h b/include/llvm/Analysis/Interval.h index 01eba3f16c014f13e51335cfcfb2c262bfbb9bfe..a904753adaab22557049fe61b50ff3a44af44f18 100644 --- a/include/llvm/Analysis/Interval.h +++ b/include/llvm/Analysis/Interval.h @@ -67,8 +67,9 @@ public: /// contains - Find out if a basic block is in this interval inline bool contains(BasicBlock *BB) const { - for (unsigned i = 0; i < Nodes.size(); ++i) - if (Nodes[i] == BB) return true; + for (BasicBlock *Node : Nodes) + if (Node == BB) + return true; return false; // I don't want the dependency on //return find(Nodes.begin(), Nodes.end(), BB) != Nodes.end(); @@ -76,8 +77,9 @@ public: /// isSuccessor - find out if a basic block is a successor of this Interval inline bool isSuccessor(BasicBlock *BB) const { - for (unsigned i = 0; i < Successors.size(); ++i) - if (Successors[i] == BB) return true; + for (BasicBlock *Successor : Successors) + if (Successor == BB) + return true; return false; // I don't want the dependency on //return find(Successors.begin(), Successors.end(), BB) != Successors.end(); diff --git a/include/llvm/Analysis/IteratedDominanceFrontier.h b/include/llvm/Analysis/IteratedDominanceFrontier.h index 0fbc9d4811f32b33b0446283bc244f174b4e7ae0..37da5617b913a1b6dbab6e865e54a2bf3a6aba91 100644 --- a/include/llvm/Analysis/IteratedDominanceFrontier.h +++ b/include/llvm/Analysis/IteratedDominanceFrontier.h @@ -24,7 +24,6 @@ #ifndef LLVM_ANALYSIS_IDF_H #define LLVM_ANALYSIS_IDF_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -41,6 +40,9 @@ namespace llvm { /// This algorithm is a linear time computation of Iterated Dominance Frontiers, /// pruned using the live-in set. /// By default, liveness is not used to prune the IDF computation. +/// The template parameters should be either BasicBlock* or Inverse, depending on if you want the forward or reverse IDF. +template class IDFCalculator { public: @@ -89,5 +91,7 @@ private: const SmallPtrSetImpl *DefBlocks; SmallVector PHIBlocks; }; +typedef IDFCalculator ForwardIDFCalculator; +typedef IDFCalculator> ReverseIDFCalculator; } #endif diff --git a/include/llvm/Analysis/LazyBlockFrequencyInfo.h b/include/llvm/Analysis/LazyBlockFrequencyInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..a2d24bb9eb889f7b59e638d5df5821fef4ab3485 --- /dev/null +++ b/include/llvm/Analysis/LazyBlockFrequencyInfo.h @@ -0,0 +1,125 @@ +//===- LazyBlockFrequencyInfo.h - Lazy Block Frequency Analysis -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is an alternative analysis pass to BlockFrequencyInfoWrapperPass. The +// difference is that with this pass the block frequencies are not computed when +// the analysis pass is executed but rather when the BFI results is explicitly +// requested by the analysis client. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_LAZYBLOCKFREQUENCYINFO_H +#define LLVM_ANALYSIS_LAZYBLOCKFREQUENCYINFO_H + +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Pass.h" + +namespace llvm { +class AnalysisUsage; +class BranchProbabilityInfo; +class Function; +class LoopInfo; + +/// \brief This is an alternative analysis pass to +/// BlockFrequencyInfoWrapperPass. The difference is that with this pass the +/// block frequencies are not computed when the analysis pass is executed but +/// rather when the BFI results is explicitly requested by the analysis client. +/// +/// There are some additional requirements for any client pass that wants to use +/// the analysis: +/// +/// 1. The pass needs to initialize dependent passes with: +/// +/// INITIALIZE_PASS_DEPENDENCY(LazyBFIPass) +/// +/// 2. Similarly, getAnalysisUsage should call: +/// +/// LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU) +/// +/// 3. The computed BFI should be requested with +/// getAnalysis().getBFI() before either LoopInfo +/// or BPI could be invalidated for example by changing the CFG. +/// +/// Note that it is expected that we wouldn't need this functionality for the +/// new PM since with the new PM, analyses are executed on demand. +class LazyBlockFrequencyInfoPass : public FunctionPass { + + /// Wraps a BFI to allow lazy computation of the block frequencies. + /// + /// A pass that only conditionally uses BFI can uncondtionally require the + /// analysis without paying for the overhead if BFI doesn't end up being used. + class LazyBlockFrequencyInfo { + public: + LazyBlockFrequencyInfo() + : Calculated(false), F(nullptr), BPI(nullptr), LI(nullptr) {} + + /// Set up the per-function input. + void setAnalysis(const Function *F, const BranchProbabilityInfo *BPI, + const LoopInfo *LI) { + this->F = F; + this->BPI = BPI; + this->LI = LI; + } + + /// Retrieve the BFI with the block frequencies computed. + BlockFrequencyInfo &getCalculated() { + if (!Calculated) { + assert(F && BPI && LI && "call setAnalysis"); + BFI.calculate(*F, *BPI, *LI); + Calculated = true; + } + return BFI; + } + + const BlockFrequencyInfo &getCalculated() const { + return const_cast(this)->getCalculated(); + } + + void releaseMemory() { + BFI.releaseMemory(); + Calculated = false; + setAnalysis(nullptr, nullptr, nullptr); + } + + private: + BlockFrequencyInfo BFI; + bool Calculated; + const Function *F; + const BranchProbabilityInfo *BPI; + const LoopInfo *LI; + }; + + LazyBlockFrequencyInfo LBFI; + +public: + static char ID; + + LazyBlockFrequencyInfoPass(); + + /// \brief Compute and return the block frequencies. + BlockFrequencyInfo &getBFI() { return LBFI.getCalculated(); } + + /// \brief Compute and return the block frequencies. + const BlockFrequencyInfo &getBFI() const { return LBFI.getCalculated(); } + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + /// Helper for client passes to set up the analysis usage on behalf of this + /// pass. + static void getLazyBFIAnalysisUsage(AnalysisUsage &AU); + + bool runOnFunction(Function &F) override; + void releaseMemory() override; + void print(raw_ostream &OS, const Module *M) const override; +}; + +/// \brief Helper for client passes to initialize dependent passes for LBFI. +void initializeLazyBFIPassPass(PassRegistry &Registry); +} +#endif diff --git a/include/llvm/Analysis/LazyCallGraph.h b/include/llvm/Analysis/LazyCallGraph.h index 4e72052b9b8b44e12be9f49ec56a71b8ffae83c0..9f62eaa2e9f8443577d62e6363a825b72f78d287 100644 --- a/include/llvm/Analysis/LazyCallGraph.h +++ b/include/llvm/Analysis/LazyCallGraph.h @@ -48,6 +48,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/raw_ostream.h" #include #include @@ -222,6 +223,14 @@ public: /// Internal helper to remove the edge to the given function. void removeEdgeInternal(Function &ChildF); + /// Print the name of this node's function. + friend raw_ostream &operator<<(raw_ostream &OS, const Node &N) { + return OS << N.F.getName(); + } + + /// Dump the name of this node's function to stderr. + void dump() const; + public: LazyCallGraph &getGraph() const { return *G; } @@ -353,6 +362,34 @@ public: Nodes.clear(); } + /// Print a short descrtiption useful for debugging or logging. + /// + /// We print the function names in the SCC wrapped in '()'s and skipping + /// the middle functions if there are a large number. + // + // Note: this is defined inline to dodge issues with GCC's interpretation + // of enclosing namespaces for friend function declarations. + friend raw_ostream &operator<<(raw_ostream &OS, const SCC &C) { + OS << '('; + int i = 0; + for (LazyCallGraph::Node &N : C) { + if (i > 0) + OS << ", "; + // Elide the inner elements if there are too many. + if (i > 8) { + OS << "..., " << *C.Nodes.back(); + break; + } + OS << N; + ++i; + } + OS << ')'; + return OS; + } + + /// Dump a short description of this SCC to stderr. + void dump() const; + #ifndef NDEBUG /// Verify invariants about the SCC. /// @@ -373,11 +410,17 @@ public: RefSCC &getOuterRefSCC() const { return *OuterRefSCC; } - /// Short name useful for debugging or logging. + /// Provide a short name by printing this SCC to a std::string. /// - /// We use the name of the first function in the SCC to name the SCC for - /// the purposes of debugging and logging. - StringRef getName() const { return begin()->getFunction().getName(); } + /// This copes with the fact that we don't have a name per-se for an SCC + /// while still making the use of this in debugging and logging useful. + std::string getName() const { + std::string Name; + raw_string_ostream OS(Name); + OS << *this; + OS.flush(); + return Name; + } }; /// A RefSCC of the call graph. @@ -410,6 +453,34 @@ public: /// formRefSCCFast on the graph itself. RefSCC(LazyCallGraph &G); + /// Print a short description useful for debugging or logging. + /// + /// We print the SCCs wrapped in '[]'s and skipping the middle SCCs if + /// there are a large number. + // + // Note: this is defined inline to dodge issues with GCC's interpretation + // of enclosing namespaces for friend function declarations. + friend raw_ostream &operator<<(raw_ostream &OS, const RefSCC &RC) { + OS << '['; + int i = 0; + for (LazyCallGraph::SCC &C : RC) { + if (i > 0) + OS << ", "; + // Elide the inner elements if there are too many. + if (i > 4) { + OS << "..., " << *RC.SCCs.back(); + break; + } + OS << C; + ++i; + } + OS << ']'; + return OS; + } + + /// Dump a short description of this RefSCC to stderr. + void dump() const; + #ifndef NDEBUG /// Verify invariants about the RefSCC and all its SCCs. /// @@ -461,12 +532,16 @@ public: /// Test if this RefSCC is a descendant of \a C. bool isDescendantOf(const RefSCC &C) const; - /// Short name useful for debugging or logging. + /// Provide a short name by printing this SCC to a std::string. /// - /// We use the name of the first function in the SCC to name the SCC for - /// the purposes of debugging and logging. - StringRef getName() const { - return begin()->begin()->getFunction().getName(); + /// This copes with the fact that we don't have a name per-se for an SCC + /// while still making the use of this in debugging and logging useful. + std::string getName() const { + std::string Name; + raw_string_ostream OS(Name); + OS << *this; + OS.flush(); + return Name; } ///@{ @@ -907,7 +982,9 @@ public: /// /// This just builds the set of entry points to the call graph. The rest is /// built lazily as it is walked. - LazyCallGraph run(Module &M) { return LazyCallGraph(M); } + LazyCallGraph run(Module &M, ModuleAnalysisManager &) { + return LazyCallGraph(M); + } }; /// A pass which prints the call graph to a \c raw_ostream. @@ -923,6 +1000,18 @@ public: PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; +/// A pass which prints the call graph as a DOT file to a \c raw_ostream. +/// +/// This is primarily useful for visualization purposes. +class LazyCallGraphDOTPrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit LazyCallGraphDOTPrinterPass(raw_ostream &OS); + + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; } #endif diff --git a/include/llvm/Analysis/LazyValueInfo.h b/include/llvm/Analysis/LazyValueInfo.h index 42002062dca21b0d9667428a9a5c1458199cc430..c85cf2c5da56123379becc1b13ab2ea5bfbd863a 100644 --- a/include/llvm/Analysis/LazyValueInfo.h +++ b/include/llvm/Analysis/LazyValueInfo.h @@ -15,11 +15,13 @@ #ifndef LLVM_ANALYSIS_LAZYVALUEINFO_H #define LLVM_ANALYSIS_LAZYVALUEINFO_H +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" namespace llvm { class AssumptionCache; class Constant; + class ConstantRange; class DataLayout; class DominatorTree; class Instruction; @@ -27,19 +29,33 @@ namespace llvm { class Value; /// This pass computes, caches, and vends lazy value constraint information. -class LazyValueInfo : public FunctionPass { - AssumptionCache *AC; - class TargetLibraryInfo *TLI; - DominatorTree *DT; - void *PImpl; +class LazyValueInfo { + friend class LazyValueInfoWrapperPass; + AssumptionCache *AC = nullptr; + class TargetLibraryInfo *TLI = nullptr; + DominatorTree *DT = nullptr; + void *PImpl = nullptr; LazyValueInfo(const LazyValueInfo&) = delete; void operator=(const LazyValueInfo&) = delete; public: - static char ID; - LazyValueInfo() : FunctionPass(ID), PImpl(nullptr) { - initializeLazyValueInfoPass(*PassRegistry::getPassRegistry()); + ~LazyValueInfo(); + LazyValueInfo() {} + LazyValueInfo(AssumptionCache *AC_, TargetLibraryInfo *TLI_, + DominatorTree *DT_) + : AC(AC_), TLI(TLI_), DT(DT_) {} + LazyValueInfo(LazyValueInfo &&Arg) + : AC(Arg.AC), TLI(Arg.TLI), DT(Arg.DT), PImpl(Arg.PImpl) { + Arg.PImpl = nullptr; + } + LazyValueInfo &operator=(LazyValueInfo &&Arg) { + releaseMemory(); + AC = Arg.AC; + TLI = Arg.TLI; + DT = Arg.DT; + PImpl = Arg.PImpl; + Arg.PImpl = nullptr; + return *this; } - ~LazyValueInfo() override { assert(!PImpl && "releaseMemory not called"); } /// This is used to return true/false/dunno results. enum Tristate { @@ -65,6 +81,11 @@ public: /// constant at the end of the specified block. Return null if not. Constant *getConstant(Value *V, BasicBlock *BB, Instruction *CxtI = nullptr); + /// Return the ConstantRange constraint that is known to hold for the + /// specified value at the end of the specified block. This may only be called + /// on integer-typed Values. + ConstantRange getConstantRange(Value *V, BasicBlock *BB, Instruction *CxtI = nullptr); + /// Determine whether the specified value is known to be a /// constant on the specified edge. Return null if not. Constant *getConstantOnEdge(Value *V, BasicBlock *FromBB, BasicBlock *ToBB, @@ -77,11 +98,41 @@ public: /// Inform the analysis cache that we have erased a block. void eraseBlock(BasicBlock *BB); - // Implementation boilerplate. + // For old PM pass. Delete once LazyValueInfoWrapperPass is gone. + void releaseMemory(); +}; + +/// \brief Analysis to compute lazy value information. +class LazyValueAnalysis : public AnalysisInfoMixin { +public: + typedef LazyValueInfo Result; + Result run(Function &F, FunctionAnalysisManager &FAM); + +private: + static char PassID; + friend struct AnalysisInfoMixin; +}; + +/// Wrapper around LazyValueInfo. +class LazyValueInfoWrapperPass : public FunctionPass { + LazyValueInfoWrapperPass(const LazyValueInfoWrapperPass&) = delete; + void operator=(const LazyValueInfoWrapperPass&) = delete; +public: + static char ID; + LazyValueInfoWrapperPass() : FunctionPass(ID) { + initializeLazyValueInfoWrapperPassPass(*PassRegistry::getPassRegistry()); + } + ~LazyValueInfoWrapperPass() override { + assert(!Info.PImpl && "releaseMemory not called"); + } + + LazyValueInfo &getLVI(); void getAnalysisUsage(AnalysisUsage &AU) const override; void releaseMemory() override; bool runOnFunction(Function &F) override; +private: + LazyValueInfo Info; }; } // end namespace llvm diff --git a/include/llvm/Analysis/Loads.h b/include/llvm/Analysis/Loads.h index 49d7a222c92ec70684066a5fc76f877768feb85c..39f80f489e122edfd736266a61fa0817bb33a354 100644 --- a/include/llvm/Analysis/Loads.h +++ b/include/llvm/Analysis/Loads.h @@ -29,8 +29,7 @@ class MDNode; /// specified instruction. bool isDereferenceablePointer(const Value *V, const DataLayout &DL, const Instruction *CtxI = nullptr, - const DominatorTree *DT = nullptr, - const TargetLibraryInfo *TLI = nullptr); + const DominatorTree *DT = nullptr); /// Returns true if V is always a dereferenceable pointer with alignment /// greater or equal than requested. If the context instruction is specified @@ -39,48 +38,59 @@ bool isDereferenceablePointer(const Value *V, const DataLayout &DL, bool isDereferenceableAndAlignedPointer(const Value *V, unsigned Align, const DataLayout &DL, const Instruction *CtxI = nullptr, - const DominatorTree *DT = nullptr, - const TargetLibraryInfo *TLI = nullptr); + const DominatorTree *DT = nullptr); /// isSafeToLoadUnconditionally - Return true if we know that executing a load /// from this value cannot trap. /// -/// If DT is specified this method performs context-sensitive analysis. +/// If DT and ScanFrom are specified this method performs context-sensitive +/// analysis and returns true if it is safe to load immediately before ScanFrom. /// /// If it is not obviously safe to load from the specified pointer, we do a /// quick local scan of the basic block containing ScanFrom, to determine if /// the address is already accessed. bool isSafeToLoadUnconditionally(Value *V, unsigned Align, - Instruction *ScanFrom, - const DominatorTree *DT = nullptr, - const TargetLibraryInfo *TLI = nullptr); + const DataLayout &DL, + Instruction *ScanFrom = nullptr, + const DominatorTree *DT = nullptr); /// DefMaxInstsToScan - the default number of maximum instructions /// to scan in the block, used by FindAvailableLoadedValue(). extern cl::opt DefMaxInstsToScan; -/// FindAvailableLoadedValue - Scan the ScanBB block backwards (starting at -/// the instruction before ScanFrom) checking to see if we have the value at -/// the memory address *Ptr locally available within a small number of -/// instructions. If the value is available, return it. +/// \brief Scan backwards to see if we have the value of the given load +/// available locally within a small number of instructions. /// -/// If not, return the iterator for the last validated instruction that the -/// value would be live through. If we scanned the entire block and didn't -/// find something that invalidates *Ptr or provides it, ScanFrom would be -/// left at begin() and this returns null. ScanFrom could also be left +/// You can use this function to scan across multiple blocks: after you call +/// this function, if ScanFrom points at the beginning of the block, it's safe +/// to continue scanning the predecessors. /// -/// MaxInstsToScan specifies the maximum instructions to scan in the block. -/// If it is set to 0, it will scan the whole block. You can also optionally -/// specify an alias analysis implementation, which makes this more precise. +/// Note that performing load CSE requires special care to make sure the +/// metadata is set appropriately. In particular, aliasing metadata needs +/// to be merged. (This doesn't matter for store-to-load forwarding because +/// the only relevant load gets deleted.) /// -/// If AATags is non-null and a load or store is found, the AA tags from the -/// load or store are recorded there. If there are no AA tags or if no access -/// is found, it is left unmodified. -Value *FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB, +/// \param Load The load we want to replace. +/// \param ScanBB The basic block to scan. FIXME: This is redundant. +/// \param [in,out] ScanFrom The location to start scanning from. When this +/// function returns, it points at the last instruction scanned. +/// \param MaxInstsToScan The maximum number of instructions to scan. If this +/// is zero, the whole block will be scanned. +/// \param AA Optional pointer to alias analysis, to make the scan more +/// precise. +/// \param [out] AATags The aliasing metadata for the operation which produced +/// the value. FIXME: This is basically useless. +/// \param [out] IsLoadCSE Whether the returned value is a load from the same +/// location in memory, as opposed to the value operand of a store. +/// +/// \returns The found value, or nullptr if no value is found. +Value *FindAvailableLoadedValue(LoadInst *Load, + BasicBlock *ScanBB, BasicBlock::iterator &ScanFrom, unsigned MaxInstsToScan = DefMaxInstsToScan, AliasAnalysis *AA = nullptr, - AAMDNodes *AATags = nullptr); + AAMDNodes *AATags = nullptr, + bool *IsLoadCSE = nullptr); } diff --git a/include/llvm/Analysis/LoopAccessAnalysis.h b/include/llvm/Analysis/LoopAccessAnalysis.h index bcf4e5d52f77f56c4a744215871dfd85a4001e65..ceee1be5e1e7511c9a48ace8ef289bc31ec0b0e3 100644 --- a/include/llvm/Analysis/LoopAccessAnalysis.h +++ b/include/llvm/Analysis/LoopAccessAnalysis.h @@ -228,7 +228,7 @@ public: /// \brief The maximum number of bytes of a vector register we can vectorize /// the accesses safely with. - unsigned getMaxSafeDepDistBytes() { return MaxSafeDepDistBytes; } + uint64_t getMaxSafeDepDistBytes() { return MaxSafeDepDistBytes; } /// \brief In same cases when the dependency check fails we can still /// vectorize the loop with a dynamic array access check. @@ -284,7 +284,7 @@ private: unsigned AccessIdx; // We can access this many bytes in parallel safely. - unsigned MaxSafeDepDistBytes; + uint64_t MaxSafeDepDistBytes; /// \brief If we see a non-constant dependence distance we can still try to /// vectorize this loop with runtime checks. @@ -321,7 +321,10 @@ private: /// \brief Check whether the data dependence could prevent store-load /// forwarding. - bool couldPreventStoreLoadForward(unsigned Distance, unsigned TypeByteSize); + /// + /// \return false if we shouldn't vectorize at all or avoid larger + /// vectorization factors by limiting MaxSafeDepDistBytes. + bool couldPreventStoreLoadForward(uint64_t Distance, uint64_t TypeByteSize); }; /// \brief Holds information about the memory runtime legality checks to verify @@ -508,23 +511,53 @@ private: /// PSE must be emitted in order for the results of this analysis to be valid. class LoopAccessInfo { public: - LoopAccessInfo(Loop *L, ScalarEvolution *SE, const DataLayout &DL, - const TargetLibraryInfo *TLI, AliasAnalysis *AA, - DominatorTree *DT, LoopInfo *LI, - const ValueToValueMap &Strides); + LoopAccessInfo(Loop *L, ScalarEvolution *SE, const TargetLibraryInfo *TLI, + AliasAnalysis *AA, DominatorTree *DT, LoopInfo *LI); + + // FIXME: + // Hack for MSVC 2013 which sems like it can't synthesize this even + // with default keyword: + // LoopAccessInfo(LoopAccessInfo &&LAI) = default; + LoopAccessInfo(LoopAccessInfo &&LAI) + : PSE(std::move(LAI.PSE)), PtrRtChecking(std::move(LAI.PtrRtChecking)), + DepChecker(std::move(LAI.DepChecker)), TheLoop(LAI.TheLoop), + NumLoads(LAI.NumLoads), NumStores(LAI.NumStores), + MaxSafeDepDistBytes(LAI.MaxSafeDepDistBytes), CanVecMem(LAI.CanVecMem), + StoreToLoopInvariantAddress(LAI.StoreToLoopInvariantAddress), + Report(std::move(LAI.Report)), + SymbolicStrides(std::move(LAI.SymbolicStrides)), + StrideSet(std::move(LAI.StrideSet)) {} + // LoopAccessInfo &operator=(LoopAccessInfo &&LAI) = default; + LoopAccessInfo &operator=(LoopAccessInfo &&LAI) { + assert(this != &LAI); + + PSE = std::move(LAI.PSE); + PtrRtChecking = std::move(LAI.PtrRtChecking); + DepChecker = std::move(LAI.DepChecker); + TheLoop = LAI.TheLoop; + NumLoads = LAI.NumLoads; + NumStores = LAI.NumStores; + MaxSafeDepDistBytes = LAI.MaxSafeDepDistBytes; + CanVecMem = LAI.CanVecMem; + StoreToLoopInvariantAddress = LAI.StoreToLoopInvariantAddress; + Report = std::move(LAI.Report); + SymbolicStrides = std::move(LAI.SymbolicStrides); + StrideSet = std::move(LAI.StrideSet); + return *this; + } /// Return true we can analyze the memory accesses in the loop and there are /// no memory dependence cycles. bool canVectorizeMemory() const { return CanVecMem; } const RuntimePointerChecking *getRuntimePointerChecking() const { - return &PtrRtChecking; + return PtrRtChecking.get(); } /// \brief Number of memchecks required to prove independence of otherwise /// may-alias pointers. unsigned getNumRuntimePointerChecks() const { - return PtrRtChecking.getNumberOfChecks(); + return PtrRtChecking->getNumberOfChecks(); } /// Return true if the block BB needs to be predicated in order for the loop @@ -535,7 +568,7 @@ public: /// Returns true if the value V is uniform within the loop. bool isUniform(Value *V) const; - unsigned getMaxSafeDepDistBytes() const { return MaxSafeDepDistBytes; } + uint64_t getMaxSafeDepDistBytes() const { return MaxSafeDepDistBytes; } unsigned getNumStores() const { return NumStores; } unsigned getNumLoads() const { return NumLoads;} @@ -563,23 +596,25 @@ public: /// \brief the Memory Dependence Checker which can determine the /// loop-independent and loop-carried dependences between memory accesses. - const MemoryDepChecker &getDepChecker() const { return DepChecker; } + const MemoryDepChecker &getDepChecker() const { return *DepChecker; } /// \brief Return the list of instructions that use \p Ptr to read or write /// memory. SmallVector getInstructionsForAccess(Value *Ptr, bool isWrite) const { - return DepChecker.getInstructionsForAccess(Ptr, isWrite); + return DepChecker->getInstructionsForAccess(Ptr, isWrite); } + /// \brief If an access has a symbolic strides, this maps the pointer value to + /// the stride symbol. + const ValueToValueMap &getSymbolicStrides() const { return SymbolicStrides; } + + /// \brief Pointer has a symbolic stride. + bool hasStride(Value *V) const { return StrideSet.count(V); } + /// \brief Print the information about the memory accesses in the loop. void print(raw_ostream &OS, unsigned Depth = 0) const; - /// \brief Used to ensure that if the analysis was run with speculating the - /// value of symbolic strides, the client queries it with the same assumption. - /// Only used in DEBUG build but we don't want NDEBUG-dependent ABI. - unsigned NumSymbolicStrides; - /// \brief Checks existence of store to invariant address inside loop. /// If the loop has any store to invariant address, then it returns true, /// else returns false. @@ -592,11 +627,12 @@ public: /// should be re-written (and therefore simplified) according to PSE. /// A user of LoopAccessAnalysis will need to emit the runtime checks /// associated with this predicate. - PredicatedScalarEvolution PSE; + const PredicatedScalarEvolution &getPSE() const { return *PSE; } private: - /// \brief Analyze the loop. Substitute symbolic strides using Strides. - void analyzeLoop(const ValueToValueMap &Strides); + /// \brief Analyze the loop. + void analyzeLoop(AliasAnalysis *AA, LoopInfo *LI, + const TargetLibraryInfo *TLI, DominatorTree *DT); /// \brief Check if the structure of the loop allows it to be analyzed by this /// pass. @@ -604,25 +640,28 @@ private: void emitAnalysis(LoopAccessReport &Message); + /// \brief Collect memory access with loop invariant strides. + /// + /// Looks for accesses like "a[i * StrideA]" where "StrideA" is loop + /// invariant. + void collectStridedAccess(Value *LoadOrStoreInst); + + std::unique_ptr PSE; + /// We need to check that all of the pointers in this list are disjoint - /// at runtime. - RuntimePointerChecking PtrRtChecking; + /// at runtime. Using std::unique_ptr to make using move ctor simpler. + std::unique_ptr PtrRtChecking; /// \brief the Memory Dependence Checker which can determine the /// loop-independent and loop-carried dependences between memory accesses. - MemoryDepChecker DepChecker; + std::unique_ptr DepChecker; Loop *TheLoop; - const DataLayout &DL; - const TargetLibraryInfo *TLI; - AliasAnalysis *AA; - DominatorTree *DT; - LoopInfo *LI; unsigned NumLoads; unsigned NumStores; - unsigned MaxSafeDepDistBytes; + uint64_t MaxSafeDepDistBytes; /// \brief Cache the result of analyzeLoop. bool CanVecMem; @@ -634,6 +673,13 @@ private: /// \brief The diagnostics report generated for the analysis. E.g. why we /// couldn't analyze the loop. Optional Report; + + /// \brief If an access has a symbolic strides, this maps the pointer value to + /// the stride symbol. + ValueToValueMap SymbolicStrides; + + /// \brief Set of symbolic strides values. + SmallPtrSet StrideSet; }; Value *stripIntegerCast(Value *V); @@ -662,9 +708,9 @@ const SCEV *replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE, /// to \p PtrToStride and therefore add further predicates to \p PSE. /// The \p Assume parameter indicates if we are allowed to make additional /// run-time assumptions. -int isStridedPtr(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp, - const ValueToValueMap &StridesMap = ValueToValueMap(), - bool Assume = false); +int64_t getPtrStride(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp, + const ValueToValueMap &StridesMap = ValueToValueMap(), + bool Assume = false); /// \brief Returns true if the memory operations \p A and \p B are consecutive. /// This is a simple API that does not depend on the analysis pass. @@ -678,12 +724,12 @@ bool isConsecutiveAccess(Value *A, Value *B, const DataLayout &DL, /// querying the loop access info via LAA::getInfo. getInfo return a /// LoopAccessInfo object. See this class for the specifics of what information /// is provided. -class LoopAccessAnalysis : public FunctionPass { +class LoopAccessLegacyAnalysis : public FunctionPass { public: static char ID; - LoopAccessAnalysis() : FunctionPass(ID) { - initializeLoopAccessAnalysisPass(*PassRegistry::getPassRegistry()); + LoopAccessLegacyAnalysis() : FunctionPass(ID) { + initializeLoopAccessLegacyAnalysisPass(*PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override; @@ -692,11 +738,8 @@ public: /// \brief Query the result of the loop access information for the loop \p L. /// - /// If the client speculates (and then issues run-time checks) for the values - /// of symbolic strides, \p Strides provides the mapping (see - /// replaceSymbolicStrideSCEV). If there is no cached result available run - /// the analysis. - const LoopAccessInfo &getInfo(Loop *L, const ValueToValueMap &Strides); + /// If there is no cached result available run the analysis. + const LoopAccessInfo &getInfo(Loop *L); void releaseMemory() override { // Invalidate the cache when the pass is freed. @@ -718,6 +761,34 @@ private: LoopInfo *LI; }; +/// \brief This analysis provides dependence information for the memory +/// accesses of a loop. +/// +/// It runs the analysis for a loop on demand. This can be initiated by +/// querying the loop access info via AM.getResult. +/// getResult return a LoopAccessInfo object. See this class for the +/// specifics of what information is provided. +class LoopAccessAnalysis + : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static char PassID; + +public: + typedef LoopAccessInfo Result; + Result run(Loop &, AnalysisManager &); + static StringRef name() { return "LoopAccessAnalysis"; } +}; + +/// \brief Printer pass for the \c LoopAccessInfo results. +class LoopAccessInfoPrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit LoopAccessInfoPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Loop &L, AnalysisManager &AM); +}; + inline Instruction *MemoryDepChecker::Dependence::getSource( const LoopAccessInfo &LAI) const { return LAI.getDepChecker().getMemoryInstructions()[Source]; diff --git a/include/llvm/Analysis/LoopInfo.h b/include/llvm/Analysis/LoopInfo.h index 934db11abf5976bb8a815bc9ec6c9cd1ca0c697c..35dc6bcb68642e908d76b562575787b42bffcfcb 100644 --- a/include/llvm/Analysis/LoopInfo.h +++ b/include/llvm/Analysis/LoopInfo.h @@ -457,22 +457,7 @@ public: /// location by looking at the preheader and header blocks. If it /// cannot find a terminating instruction with location information, /// it returns an unknown location. - DebugLoc getStartLoc() const { - BasicBlock *HeadBB; - - // Try the pre-header first. - if ((HeadBB = getLoopPreheader()) != nullptr) - if (DebugLoc DL = HeadBB->getTerminator()->getDebugLoc()) - return DL; - - // If we have no pre-header or there are no instructions with debug - // info in it, try the header. - HeadBB = getHeader(); - if (HeadBB) - return HeadBB->getTerminator()->getDebugLoc(); - - return DebugLoc(); - } + DebugLoc getStartLoc() const; StringRef getName() const { if (BasicBlock *Header = getHeader()) @@ -841,7 +826,7 @@ public: PrintLoopPass(); PrintLoopPass(raw_ostream &OS, const std::string &Banner = ""); - PreservedAnalyses run(Loop &L); + PreservedAnalyses run(Loop &L, AnalysisManager &); }; } // End llvm namespace diff --git a/include/llvm/Analysis/LoopPass.h b/include/llvm/Analysis/LoopPass.h index 2cf734e53bb43ecf7dd81c64987fede322a3f53f..89debec04e94d058bbcaa702e5c00b136b4e6ac6 100644 --- a/include/llvm/Analysis/LoopPass.h +++ b/include/llvm/Analysis/LoopPass.h @@ -88,9 +88,10 @@ public: virtual void deleteAnalysisLoop(Loop *L) {} protected: - /// skipOptnoneFunction - Containing function has Attribute::OptimizeNone - /// and most transformation passes should skip it. - bool skipOptnoneFunction(const Loop *L) const; + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when Attribute::OptimizeNone is set or when + /// optimization bisect is over the limit. + bool skipLoop(const Loop *L) const; }; class LPPassManager : public FunctionPass, public PMDataManager { diff --git a/include/llvm/Analysis/LoopPassManager.h b/include/llvm/Analysis/LoopPassManager.h index e7d9578c1f8f426fe9a1cf6395b6e66cf79c8993..a8955185125995360f96791cc7fde8a958da92d5 100644 --- a/include/llvm/Analysis/LoopPassManager.h +++ b/include/llvm/Analysis/LoopPassManager.h @@ -48,6 +48,9 @@ extern template class OuterAnalysisManagerProxy; typedef OuterAnalysisManagerProxy FunctionAnalysisManagerLoopProxy; +/// Returns the minimum set of Analyses that all loop passes must preserve. +PreservedAnalyses getLoopPassPreservedAnalyses(); + /// \brief Adaptor that maps from a function to its loops. /// /// Designed to allow composition of a LoopPass(Manager) and a @@ -101,6 +104,8 @@ public: // post-order. for (auto *L : reverse(Loops)) { PreservedAnalyses PassPA = Pass.run(*L, LAM); + assert(PassPA.preserved(getLoopPassPreservedAnalyses()) && + "Loop passes must preserve all relevant analyses"); // We know that the loop pass couldn't have invalidated any other loop's // analyses (that's the contract of a loop pass), so directly handle the diff --git a/include/llvm/Analysis/LoopUnrollAnalyzer.h b/include/llvm/Analysis/LoopUnrollAnalyzer.h index 7e827e8737b92c8e68e6956fca5ed1081a8b8a11..80f3e5fdcd436871931114745867450009f95ada 100644 --- a/include/llvm/Analysis/LoopUnrollAnalyzer.h +++ b/include/llvm/Analysis/LoopUnrollAnalyzer.h @@ -89,6 +89,7 @@ private: bool visitLoad(LoadInst &I); bool visitCastInst(CastInst &I); bool visitCmpInst(CmpInst &I); + bool visitPHINode(PHINode &PN); }; } #endif diff --git a/include/llvm/Analysis/MemoryBuiltins.h b/include/llvm/Analysis/MemoryBuiltins.h index c31c4df99889d697c281207ba56e269a4afa019d..140b731c59dee78b20bf1e7ef142e89423c55f98 100644 --- a/include/llvm/Analysis/MemoryBuiltins.h +++ b/include/llvm/Analysis/MemoryBuiltins.h @@ -32,6 +32,11 @@ class TargetLibraryInfo; class Type; class Value; +enum class ObjSizeMode { + Exact = 0, + Min = 1, + Max = 2 +}; /// \brief Tests if a value is a call or invoke to a library function that /// allocates or reallocates memory (either malloc, calloc, realloc, or strdup @@ -130,8 +135,11 @@ static inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) { /// underlying object pointed to by Ptr. /// If RoundToAlign is true, then Size is rounded up to the aligment of allocas, /// byval arguments, and global variables. +/// If Mode is Min or Max the size will be evaluated even if it depends on +/// a condition and corresponding value will be returned (min or max). bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, - const TargetLibraryInfo *TLI, bool RoundToAlign = false); + const TargetLibraryInfo *TLI, bool RoundToAlign = false, + ObjSizeMode Mode = ObjSizeMode::Exact); typedef std::pair SizeOffsetType; @@ -143,6 +151,7 @@ class ObjectSizeOffsetVisitor const DataLayout &DL; const TargetLibraryInfo *TLI; bool RoundToAlign; + ObjSizeMode Mode; unsigned IntTyBits; APInt Zero; SmallPtrSet SeenInsts; @@ -155,7 +164,8 @@ class ObjectSizeOffsetVisitor public: ObjectSizeOffsetVisitor(const DataLayout &DL, const TargetLibraryInfo *TLI, - LLVMContext &Context, bool RoundToAlign = false); + LLVMContext &Context, bool RoundToAlign = false, + ObjSizeMode Mode = ObjSizeMode::Exact); SizeOffsetType compute(Value *V); diff --git a/include/llvm/Analysis/MemoryLocation.h b/include/llvm/Analysis/MemoryLocation.h index 426b49a3ecd7c100877811013264ac82bd49efc4..f2cb2a123f2e45de79c2d8ab928bb1a2f936ad62 100644 --- a/include/llvm/Analysis/MemoryLocation.h +++ b/include/llvm/Analysis/MemoryLocation.h @@ -16,7 +16,7 @@ #ifndef LLVM_ANALYSIS_MEMORYLOCATION_H #define LLVM_ANALYSIS_MEMORYLOCATION_H -#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Metadata.h" diff --git a/include/llvm/Analysis/ModuleSummaryAnalysis.h b/include/llvm/Analysis/ModuleSummaryAnalysis.h new file mode 100644 index 0000000000000000000000000000000000000000..9f03610ba5b197455cc8197eb70eb4961f01ca74 --- /dev/null +++ b/include/llvm/Analysis/ModuleSummaryAnalysis.h @@ -0,0 +1,91 @@ +//===- ModuleSummaryAnalysis.h - Module summary index builder ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This is the interface to build a ModuleSummaryIndex for a module. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_MODULESUMMARYANALYSIS_H +#define LLVM_ANALYSIS_MODULESUMMARYANALYSIS_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/ModuleSummaryIndex.h" +#include "llvm/Pass.h" + +namespace llvm { + +class BlockFrequencyInfo; + +/// Class to build a module summary index for the given Module, possibly from +/// a Pass. +class ModuleSummaryIndexBuilder { + /// The index being built + std::unique_ptr Index; + /// The module for which we are building an index + const Module *M; + +public: + /// Default constructor + ModuleSummaryIndexBuilder() = default; + + /// Constructor that builds an index for the given Module. An optional + /// callback can be supplied to obtain the frequency info for a function. + ModuleSummaryIndexBuilder( + const Module *M, + std::function Ftor = nullptr); + + /// Get a reference to the index owned by builder + ModuleSummaryIndex &getIndex() const { return *Index; } + + /// Take ownership of the built index + std::unique_ptr takeIndex() { return std::move(Index); } + +private: + /// Compute summary for given function with optional frequency information + void computeFunctionSummary(const Function &F, + BlockFrequencyInfo *BFI = nullptr); + + /// Compute summary for given variable with optional frequency information + void computeVariableSummary(const GlobalVariable &V); +}; + +/// Legacy wrapper pass to provide the ModuleSummaryIndex object. +class ModuleSummaryIndexWrapperPass : public ModulePass { + std::unique_ptr IndexBuilder; + +public: + static char ID; + + ModuleSummaryIndexWrapperPass(); + + /// Get the index built by pass + ModuleSummaryIndex &getIndex() { return IndexBuilder->getIndex(); } + const ModuleSummaryIndex &getIndex() const { + return IndexBuilder->getIndex(); + } + + bool runOnModule(Module &M) override; + bool doFinalization(Module &M) override; + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +//===--------------------------------------------------------------------===// +// +// createModuleSummaryIndexWrapperPass - This pass builds a ModuleSummaryIndex +// object for the module, to be written to bitcode or LLVM assembly. +// +ModulePass *createModuleSummaryIndexWrapperPass(); + +/// Returns true if \p M is eligible for ThinLTO promotion. +/// +/// Currently we check if it has any any InlineASM that uses an internal symbol. +bool moduleCanBeRenamedForThinLTO(const Module &M); +} + +#endif diff --git a/include/llvm/Analysis/Passes.h b/include/llvm/Analysis/Passes.h index 1e0fe065e3a9694bf7fc51e503fbaac84988ec8f..6d8f14fa32f94fe7c3a36c22dc5ce2cd76a7512a 100644 --- a/include/llvm/Analysis/Passes.h +++ b/include/llvm/Analysis/Passes.h @@ -40,10 +40,10 @@ namespace llvm { //===--------------------------------------------------------------------===// // - // createDependenceAnalysisPass - This creates an instance of the - // DependenceAnalysis pass. + // createDependenceAnalysisWrapperPass - This creates an instance of the + // DependenceAnalysisWrapper pass. // - FunctionPass *createDependenceAnalysisPass(); + FunctionPass *createDependenceAnalysisWrapperPass(); //===--------------------------------------------------------------------===// // diff --git a/include/llvm/Analysis/PostDominators.h b/include/llvm/Analysis/PostDominators.h index 28a1b0d0dc7a69a35fb3255d2edd62785c645acf..99240a40408e3803d1903359ff25fde1168ebfca 100644 --- a/include/llvm/Analysis/PostDominators.h +++ b/include/llvm/Analysis/PostDominators.h @@ -48,7 +48,7 @@ public: /// \brief Run the analysis pass over a function and produce a post dominator /// tree. - PostDominatorTree run(Function &F); + PostDominatorTree run(Function &F, FunctionAnalysisManager &); }; /// \brief Printer pass for the \c PostDominatorTree. diff --git a/include/llvm/Analysis/ProfileSummaryInfo.h b/include/llvm/Analysis/ProfileSummaryInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..cd624c8404da22d0eba1a4efe3233818c5def548 --- /dev/null +++ b/include/llvm/Analysis/ProfileSummaryInfo.h @@ -0,0 +1,113 @@ +//===- llvm/Analysis/ProfileSummaryInfo.h - profile summary ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a pass that provides access to profile summary +// information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_PROFILE_SUMMARY_INFO_H +#define LLVM_ANALYSIS_PROFILE_SUMMARY_INFO_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/ProfileSummary.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Pass.h" +#include + +namespace llvm { +class ProfileSummary; +/// \brief Analysis providing profile information. +/// +/// This is an immutable analysis pass that provides ability to query global +/// (program-level) profile information. The main APIs are isHotCount and +/// isColdCount that tells whether a given profile count is considered hot/cold +/// based on the profile summary. This also provides convenience methods to +/// check whether a function is hot or cold. + +// FIXME: Provide convenience methods to determine hotness/coldness of other IR +// units. This would require making this depend on BFI. +class ProfileSummaryInfo { +private: + Module &M; + std::unique_ptr Summary; + void computeSummary(); + void computeThresholds(); + // Count thresholds to answer isHotCount and isColdCount queries. + Optional HotCountThreshold, ColdCountThreshold; + +public: + ProfileSummaryInfo(Module &M) : M(M) {} + ProfileSummaryInfo(ProfileSummaryInfo &&Arg) + : M(Arg.M), Summary(std::move(Arg.Summary)) {} + /// \brief Returns true if \p F is a hot function. + bool isHotFunction(const Function *F); + /// \brief Returns true if \p F is a cold function. + bool isColdFunction(const Function *F); + /// \brief Returns true if count \p C is considered hot. + bool isHotCount(uint64_t C); + /// \brief Returns true if count \p C is considered cold. + bool isColdCount(uint64_t C); +}; + +/// An analysis pass based on legacy pass manager to deliver ProfileSummaryInfo. +class ProfileSummaryInfoWrapperPass : public ImmutablePass { + std::unique_ptr PSI; + +public: + static char ID; + ProfileSummaryInfoWrapperPass(); + + ProfileSummaryInfo *getPSI(Module &M); + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } +}; + +/// An analysis pass based on the new PM to deliver ProfileSummaryInfo. +class ProfileSummaryAnalysis + : public AnalysisInfoMixin { +public: + typedef ProfileSummaryInfo Result; + + ProfileSummaryAnalysis() {} + ProfileSummaryAnalysis(const ProfileSummaryAnalysis &Arg) {} + ProfileSummaryAnalysis(ProfileSummaryAnalysis &&Arg) {} + ProfileSummaryAnalysis &operator=(const ProfileSummaryAnalysis &RHS) { + return *this; + } + ProfileSummaryAnalysis &operator=(ProfileSummaryAnalysis &&RHS) { + return *this; + } + + Result run(Module &M, ModuleAnalysisManager &); + +private: + friend AnalysisInfoMixin; + static char PassID; +}; + +/// \brief Printer pass that uses \c ProfileSummaryAnalysis. +class ProfileSummaryPrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit ProfileSummaryPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Module &M, AnalysisManager &AM); +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/Analysis/RegionInfoImpl.h b/include/llvm/Analysis/RegionInfoImpl.h index 134cd8f96fbeabc72bc00bbd346d46bc90180c2a..15dd1a2000e68aed76ade169e8fd372eebb450c8 100644 --- a/include/llvm/Analysis/RegionInfoImpl.h +++ b/include/llvm/Analysis/RegionInfoImpl.h @@ -18,7 +18,6 @@ #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/RegionInfo.h" #include "llvm/Analysis/RegionIterator.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include @@ -666,7 +665,7 @@ typename Tr::RegionT *RegionInfoBase::createRegion(BlockT *entry, new RegionT(entry, exit, static_cast(this), DT); BBtoRegion.insert(std::make_pair(entry, region)); -#ifdef XDEBUG +#ifdef EXPENSIVE_CHECKS region->verifyRegion(); #else DEBUG(region->verifyRegion()); @@ -765,7 +764,7 @@ void RegionInfoBase::buildRegionsTree(DomTreeNodeT *N, RegionT *region) { } } -#ifdef XDEBUG +#ifdef EXPENSIVE_CHECKS template bool RegionInfoBase::VerifyRegionInfo = true; #else @@ -799,7 +798,7 @@ void RegionInfoBase::releaseMemory() { template void RegionInfoBase::verifyAnalysis() const { - // Do only verify regions if explicitely activated using XDEBUG or + // Do only verify regions if explicitely activated using EXPENSIVE_CHECKS or // -verify-region-info if (!RegionInfoBase::VerifyRegionInfo) return; diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h index 3a84e77b53a74d56acacd951f0e49c324c36b7e1..535b623d31ac668b20fd0367e5be30b3d4e51d0a 100644 --- a/include/llvm/Analysis/ScalarEvolution.h +++ b/include/llvm/Analysis/ScalarEvolution.h @@ -26,7 +26,6 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/ConstantRange.h" -#include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Operator.h" #include "llvm/IR/PassManager.h" @@ -35,7 +34,6 @@ #include "llvm/Pass.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/DataTypes.h" -#include namespace llvm { class APInt; @@ -55,6 +53,7 @@ namespace llvm { class SCEVExpander; class SCEVPredicate; class SCEVUnknown; + class Function; template <> struct FoldingSetTrait; template <> struct FoldingSetTrait; @@ -170,8 +169,8 @@ namespace llvm { static bool classof(const SCEV *S); }; - /// SCEVPredicate - This class represents an assumption made using SCEV - /// expressions which can be checked at run-time. + /// This class represents an assumption made using SCEV expressions which can + /// be checked at run-time. class SCEVPredicate : public FoldingSetNode { friend struct FoldingSetTrait; @@ -193,23 +192,23 @@ namespace llvm { SCEVPredicateKind getKind() const { return Kind; } - /// \brief Returns the estimated complexity of this predicate. - /// This is roughly measured in the number of run-time checks required. + /// Returns the estimated complexity of this predicate. This is roughly + /// measured in the number of run-time checks required. virtual unsigned getComplexity() const { return 1; } - /// \brief Returns true if the predicate is always true. This means that no + /// Returns true if the predicate is always true. This means that no /// assumptions were made and nothing needs to be checked at run-time. virtual bool isAlwaysTrue() const = 0; - /// \brief Returns true if this predicate implies \p N. + /// Returns true if this predicate implies \p N. virtual bool implies(const SCEVPredicate *N) const = 0; - /// \brief Prints a textual representation of this predicate with an - /// indentation of \p Depth. + /// Prints a textual representation of this predicate with an indentation of + /// \p Depth. virtual void print(raw_ostream &OS, unsigned Depth = 0) const = 0; - /// \brief Returns the SCEV to which this predicate applies, or nullptr - /// if this is a SCEVUnionPredicate. + /// Returns the SCEV to which this predicate applies, or nullptr if this is + /// a SCEVUnionPredicate. virtual const SCEV *getExpr() const = 0; }; @@ -238,10 +237,9 @@ namespace llvm { } }; - /// SCEVEqualPredicate - This class represents an assumption that two SCEV - /// expressions are equal, and this can be checked at run-time. We assume - /// that the left hand side is a SCEVUnknown and the right hand side a - /// constant. + /// This class represents an assumption that two SCEV expressions are equal, + /// and this can be checked at run-time. We assume that the left hand side is + /// a SCEVUnknown and the right hand side a constant. class SCEVEqualPredicate final : public SCEVPredicate { /// We assume that LHS == RHS, where LHS is a SCEVUnknown and RHS a /// constant. @@ -258,10 +256,10 @@ namespace llvm { bool isAlwaysTrue() const override; const SCEV *getExpr() const override; - /// \brief Returns the left hand side of the equality. + /// Returns the left hand side of the equality. const SCEVUnknown *getLHS() const { return LHS; } - /// \brief Returns the right hand side of the equality. + /// Returns the right hand side of the equality. const SCEVConstant *getRHS() const { return RHS; } /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -270,10 +268,16 @@ namespace llvm { } }; - /// SCEVWrapPredicate - This class represents an assumption - /// made on an AddRec expression. Given an affine AddRec expression - /// {a,+,b}, we assume that it has the nssw or nusw flags (defined - /// below). + /// This class represents an assumption made on an AddRec expression. Given an + /// affine AddRec expression {a,+,b}, we assume that it has the nssw or nusw + /// flags (defined below) in the first X iterations of the loop, where X is a + /// SCEV expression returned by getPredicatedBackedgeTakenCount). + /// + /// Note that this does not imply that X is equal to the backedge taken + /// count. This means that if we have a nusw predicate for i32 {0,+,1} with a + /// predicated backedge taken count of X, we only guarantee that {0,+,1} has + /// nusw in the first X iterations. {0,+,1} may still wrap in the loop if we + /// have more than X iterations. class SCEVWrapPredicate final : public SCEVPredicate { public: /// Similar to SCEV::NoWrapFlags, but with slightly different semantics @@ -334,8 +338,8 @@ namespace llvm { return (SCEVWrapPredicate::IncrementWrapFlags)(Flags | OnFlags); } - /// \brief Returns the set of SCEVWrapPredicate no wrap flags implied - /// by a SCEVAddRecExpr. + /// Returns the set of SCEVWrapPredicate no wrap flags implied by a + /// SCEVAddRecExpr. static SCEVWrapPredicate::IncrementWrapFlags getImpliedFlags(const SCEVAddRecExpr *AR, ScalarEvolution &SE); @@ -348,7 +352,7 @@ namespace llvm { const SCEVAddRecExpr *AR, IncrementWrapFlags Flags); - /// \brief Returns the set assumed no overflow flags. + /// Returns the set assumed no overflow flags. IncrementWrapFlags getFlags() const { return Flags; } /// Implementation of the SCEVPredicate interface const SCEV *getExpr() const override; @@ -362,9 +366,9 @@ namespace llvm { } }; - /// SCEVUnionPredicate - This class represents a composition of other - /// SCEV predicates, and is the class that most clients will interact with. - /// This is equivalent to a logical "AND" of all the predicates in the union. + /// This class represents a composition of other SCEV predicates, and is the + /// class that most clients will interact with. This is equivalent to a + /// logical "AND" of all the predicates in the union. class SCEVUnionPredicate final : public SCEVPredicate { private: typedef DenseMap> @@ -382,11 +386,11 @@ namespace llvm { return Preds; } - /// \brief Adds a predicate to this union. + /// Adds a predicate to this union. void add(const SCEVPredicate *N); - /// \brief Returns a reference to a vector containing all predicates - /// which apply to \p Expr. + /// Returns a reference to a vector containing all predicates which apply to + /// \p Expr. ArrayRef getPredicatesForExpr(const SCEV *Expr); /// Implementation of the SCEVPredicate interface @@ -395,8 +399,8 @@ namespace llvm { void print(raw_ostream &OS, unsigned Depth) const override; const SCEV *getExpr() const override; - /// \brief We estimate the complexity of a union predicate as the size - /// number of predicates in the union. + /// We estimate the complexity of a union predicate as the size number of + /// predicates in the union. unsigned getComplexity() const override { return Preds.size(); } /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -458,6 +462,12 @@ namespace llvm { /// Function &F; + /// Does the module have any calls to the llvm.experimental.guard intrinsic + /// at all? If this is false, we avoid doing work that will only help if + /// thare are guards present in the IR. + /// + bool HasGuards; + /// The target library information for the target we are targeting. /// TargetLibraryInfo &TLI; @@ -476,15 +486,14 @@ namespace llvm { /// This SCEV is used to represent unknown trip counts and things. std::unique_ptr CouldNotCompute; - /// HasRecMapType - The typedef for HasRecMap. + /// The typedef for HasRecMap. /// typedef DenseMap HasRecMapType; - /// HasRecMap -- This is a cache to record whether a SCEV contains - /// any scAddRecExpr. + /// This is a cache to record whether a SCEV contains any scAddRecExpr. HasRecMapType HasRecMap; - /// ExprValueMapType - The typedef for ExprValueMap. + /// The typedef for ExprValueMap. /// typedef DenseMap> ExprValueMapType; @@ -520,9 +529,14 @@ namespace llvm { const SCEV *Exact; const SCEV *Max; + /// A predicate union guard for this ExitLimit. The result is only + /// valid if this predicate evaluates to 'true' at run-time. + SCEVUnionPredicate Pred; + /*implicit*/ ExitLimit(const SCEV *E) : Exact(E), Max(E) {} - ExitLimit(const SCEV *E, const SCEV *M) : Exact(E), Max(M) { + ExitLimit(const SCEV *E, const SCEV *M, SCEVUnionPredicate &P) + : Exact(E), Max(M), Pred(P) { assert((isa(Exact) || !isa(Max)) && "Exact is not allowed to be less precise than Max"); @@ -534,30 +548,147 @@ namespace llvm { return !isa(Exact) || !isa(Max); } + + /// Test whether this ExitLimit contains all information. + bool hasFullInfo() const { return !isa(Exact); } }; + /// Forward declaration of ExitNotTakenExtras + struct ExitNotTakenExtras; + /// Information about the number of times a particular loop exit may be /// reached before exiting the loop. struct ExitNotTakenInfo { AssertingVH ExitingBlock; const SCEV *ExactNotTaken; - PointerIntPair NextExit; - ExitNotTakenInfo() : ExitingBlock(nullptr), ExactNotTaken(nullptr) {} + ExitNotTakenExtras *ExtraInfo; + bool Complete; + + ExitNotTakenInfo() + : ExitingBlock(nullptr), ExactNotTaken(nullptr), ExtraInfo(nullptr), + Complete(true) {} + + ExitNotTakenInfo(BasicBlock *ExitBlock, const SCEV *Expr, + ExitNotTakenExtras *Ptr) + : ExitingBlock(ExitBlock), ExactNotTaken(Expr), ExtraInfo(Ptr), + Complete(true) {} /// Return true if all loop exits are computable. - bool isCompleteList() const { - return NextExit.getInt() == 0; + bool isCompleteList() const { return Complete; } + + /// Sets the incomplete property, indicating that one of the loop exits + /// doesn't have a corresponding ExitNotTakenInfo entry. + void setIncomplete() { Complete = false; } + + /// Returns a pointer to the predicate associated with this information, + /// or nullptr if this doesn't exist (meaning always true). + SCEVUnionPredicate *getPred() const { + if (ExtraInfo) + return &ExtraInfo->Pred; + + return nullptr; } - void setIncomplete() { NextExit.setInt(1); } + /// Return true if the SCEV predicate associated with this information + /// is always true. + bool hasAlwaysTruePred() const { + return !getPred() || getPred()->isAlwaysTrue(); + } - /// Return a pointer to the next exit's not-taken info. - ExitNotTakenInfo *getNextExit() const { - return NextExit.getPointer(); + /// Defines a simple forward iterator for ExitNotTakenInfo. + class ExitNotTakenInfoIterator + : public std::iterator { + const ExitNotTakenInfo *Start; + unsigned Position; + + public: + ExitNotTakenInfoIterator(const ExitNotTakenInfo *Start, + unsigned Position) + : Start(Start), Position(Position) {} + + const ExitNotTakenInfo &operator*() const { + if (Position == 0) + return *Start; + + return Start->ExtraInfo->Exits[Position - 1]; + } + + const ExitNotTakenInfo *operator->() const { + if (Position == 0) + return Start; + + return &Start->ExtraInfo->Exits[Position - 1]; + } + + bool operator==(const ExitNotTakenInfoIterator &RHS) const { + return Start == RHS.Start && Position == RHS.Position; + } + + bool operator!=(const ExitNotTakenInfoIterator &RHS) const { + return Start != RHS.Start || Position != RHS.Position; + } + + ExitNotTakenInfoIterator &operator++() { // Preincrement + if (!Start) + return *this; + + unsigned Elements = + Start->ExtraInfo ? Start->ExtraInfo->Exits.size() + 1 : 1; + + ++Position; + + // We've run out of elements. + if (Position == Elements) { + Start = nullptr; + Position = 0; + } + + return *this; + } + ExitNotTakenInfoIterator operator++(int) { // Postincrement + ExitNotTakenInfoIterator Tmp = *this; + ++*this; + return Tmp; + } + }; + + /// Iterators + ExitNotTakenInfoIterator begin() const { + return ExitNotTakenInfoIterator(this, 0); + } + ExitNotTakenInfoIterator end() const { + return ExitNotTakenInfoIterator(nullptr, 0); } + }; - void setNextExit(ExitNotTakenInfo *ENT) { NextExit.setPointer(ENT); } + /// Describes the extra information that a ExitNotTakenInfo can have. + struct ExitNotTakenExtras { + /// The predicate associated with the ExitNotTakenInfo struct. + SCEVUnionPredicate Pred; + + /// The extra exits in the loop. Only the ExitNotTakenExtras structure + /// pointed to by the first ExitNotTakenInfo struct (associated with the + /// first loop exit) will populate this vector to prevent having + /// redundant information. + SmallVector Exits; + }; + + /// A struct containing the information attached to a backedge. + struct EdgeInfo { + EdgeInfo(BasicBlock *Block, const SCEV *Taken, SCEVUnionPredicate &P) : + ExitBlock(Block), Taken(Taken), Pred(std::move(P)) {} + + /// The exit basic block. + BasicBlock *ExitBlock; + + /// The (exact) number of time we take the edge back. + const SCEV *Taken; + + /// The SCEV predicated associated with Taken. If Pred doesn't evaluate + /// to true, the information in Taken is not valid (or equivalent with + /// a CouldNotCompute. + SCEVUnionPredicate Pred; }; /// Information about the backedge-taken count of a loop. This currently @@ -569,16 +700,16 @@ namespace llvm { ExitNotTakenInfo ExitNotTaken; /// An expression indicating the least maximum backedge-taken count of the - /// loop that is known, or a SCEVCouldNotCompute. + /// loop that is known, or a SCEVCouldNotCompute. This expression is only + /// valid if the predicates associated with all loop exits are true. const SCEV *Max; public: BackedgeTakenInfo() : Max(nullptr) {} /// Initialize BackedgeTakenInfo from a list of exact exit counts. - BackedgeTakenInfo( - SmallVectorImpl< std::pair > &ExitCounts, - bool Complete, const SCEV *MaxCount); + BackedgeTakenInfo(SmallVectorImpl &ExitCounts, bool Complete, + const SCEV *MaxCount); /// Test whether this BackedgeTakenInfo contains any computed information, /// or whether it's all SCEVCouldNotCompute values. @@ -586,11 +717,27 @@ namespace llvm { return ExitNotTaken.ExitingBlock || !isa(Max); } + /// Test whether this BackedgeTakenInfo contains complete information. + bool hasFullInfo() const { return ExitNotTaken.isCompleteList(); } + /// Return an expression indicating the exact backedge-taken count of the - /// loop if it is known, or SCEVCouldNotCompute otherwise. This is the + /// loop if it is known or SCEVCouldNotCompute otherwise. This is the /// number of times the loop header can be guaranteed to execute, minus /// one. - const SCEV *getExact(ScalarEvolution *SE) const; + /// + /// If the SCEV predicate associated with the answer can be different + /// from AlwaysTrue, we must add a (non null) Predicates argument. + /// The SCEV predicate associated with the answer will be added to + /// Predicates. A run-time check needs to be emitted for the SCEV + /// predicate in order for the answer to be valid. + /// + /// Note that we should always know if we need to pass a predicate + /// argument or not from the way the ExitCounts vector was computed. + /// If we allowed SCEV predicates to be generated when populating this + /// vector, this information can contain them and therefore a + /// SCEVPredicate argument should be added to getExact. + const SCEV *getExact(ScalarEvolution *SE, + SCEVUnionPredicate *Predicates = nullptr) const; /// Return the number of times this loop exit may fall through to the back /// edge, or SCEVCouldNotCompute. The loop is guaranteed not to exit via @@ -611,7 +758,11 @@ namespace llvm { /// Cache the backedge-taken count of the loops for this function as they /// are computed. - DenseMap BackedgeTakenCounts; + DenseMap BackedgeTakenCounts; + + /// Cache the predicated backedge-taken count of the loops for this + /// function as they are computed. + DenseMap PredicatedBackedgeTakenCounts; /// This map contains entries for all of the PHI instructions that we /// attempt to compute constant evolutions for. This allows us to avoid @@ -630,6 +781,16 @@ namespace llvm { SmallVector, 2>> LoopDispositions; + /// Cache for \c loopHasNoAbnormalExits. + DenseMap LoopHasNoAbnormalExits; + + /// Returns true if \p L contains no instruction that can abnormally exit + /// the loop (i.e. via throwing an exception, by terminating the thread + /// cleanly or by infinite looping in a called function). Strictly + /// speaking, the last one is not leaving the loop, but is identical to + /// leaving the loop for reasoning about undefined behavior. + bool loopHasNoAbnormalExits(const Loop *L); + /// Compute a LoopDisposition value. LoopDisposition computeLoopDisposition(const SCEV *S, const Loop *L); @@ -713,33 +874,56 @@ namespace llvm { void forgetSymbolicName(Instruction *I, const SCEV *SymName); /// Return the BackedgeTakenInfo for the given loop, lazily computing new - /// values if the loop hasn't been analyzed yet. + /// values if the loop hasn't been analyzed yet. The returned result is + /// guaranteed not to be predicated. const BackedgeTakenInfo &getBackedgeTakenInfo(const Loop *L); + /// Similar to getBackedgeTakenInfo, but will add predicates as required + /// with the purpose of returning complete information. + const BackedgeTakenInfo &getPredicatedBackedgeTakenInfo(const Loop *L); + /// Compute the number of times the specified loop will iterate. - BackedgeTakenInfo computeBackedgeTakenCount(const Loop *L); + /// If AllowPredicates is set, we will create new SCEV predicates as + /// necessary in order to return an exact answer. + BackedgeTakenInfo computeBackedgeTakenCount(const Loop *L, + bool AllowPredicates = false); /// Compute the number of times the backedge of the specified loop will - /// execute if it exits via the specified block. - ExitLimit computeExitLimit(const Loop *L, BasicBlock *ExitingBlock); + /// execute if it exits via the specified block. If AllowPredicates is set, + /// this call will try to use a minimal set of SCEV predicates in order to + /// return an exact answer. + ExitLimit computeExitLimit(const Loop *L, BasicBlock *ExitingBlock, + bool AllowPredicates = false); /// Compute the number of times the backedge of the specified loop will /// execute if its exit condition were a conditional branch of ExitCond, /// TBB, and FBB. + /// + /// \p ControlsExit is true if ExitCond directly controls the exit + /// branch. In this case, we can assume that the loop exits only if the + /// condition is true and can infer that failing to meet the condition prior + /// to integer wraparound results in undefined behavior. + /// + /// If \p AllowPredicates is set, this call will try to use a minimal set of + /// SCEV predicates in order to return an exact answer. ExitLimit computeExitLimitFromCond(const Loop *L, Value *ExitCond, BasicBlock *TBB, BasicBlock *FBB, - bool IsSubExpr); + bool ControlsExit, + bool AllowPredicates = false); /// Compute the number of times the backedge of the specified loop will /// execute if its exit condition were a conditional branch of the ICmpInst - /// ExitCond, TBB, and FBB. + /// ExitCond, TBB, and FBB. If AllowPredicates is set, this call will try + /// to use a minimal set of SCEV predicates in order to return an exact + /// answer. ExitLimit computeExitLimitFromICmp(const Loop *L, ICmpInst *ExitCond, BasicBlock *TBB, BasicBlock *FBB, - bool IsSubExpr); + bool IsSubExpr, + bool AllowPredicates = false); /// Compute the number of times the backedge of the specified loop will /// execute if its exit condition were a switch with a single exiting case @@ -777,20 +961,35 @@ namespace llvm { /// Return the number of times an exit condition comparing the specified /// value to zero will execute. If not computable, return CouldNotCompute. - ExitLimit HowFarToZero(const SCEV *V, const Loop *L, bool IsSubExpr); + /// If AllowPredicates is set, this call will try to use a minimal set of + /// SCEV predicates in order to return an exact answer. + ExitLimit howFarToZero(const SCEV *V, const Loop *L, bool IsSubExpr, + bool AllowPredicates = false); /// Return the number of times an exit condition checking the specified /// value for nonzero will execute. If not computable, return /// CouldNotCompute. - ExitLimit HowFarToNonZero(const SCEV *V, const Loop *L); + ExitLimit howFarToNonZero(const SCEV *V, const Loop *L); /// Return the number of times an exit condition containing the specified /// less-than comparison will execute. If not computable, return - /// CouldNotCompute. isSigned specifies whether the less-than is signed. - ExitLimit HowManyLessThans(const SCEV *LHS, const SCEV *RHS, - const Loop *L, bool isSigned, bool IsSubExpr); - ExitLimit HowManyGreaterThans(const SCEV *LHS, const SCEV *RHS, - const Loop *L, bool isSigned, bool IsSubExpr); + /// CouldNotCompute. + /// + /// \p isSigned specifies whether the less-than is signed. + /// + /// \p ControlsExit is true when the LHS < RHS condition directly controls + /// the branch (loops exits only if condition is true). In this case, we can + /// use NoWrapFlags to skip overflow checks. + /// + /// If \p AllowPredicates is set, this call will try to use a minimal set of + /// SCEV predicates in order to return an exact answer. + ExitLimit howManyLessThans(const SCEV *LHS, const SCEV *RHS, const Loop *L, + bool isSigned, bool ControlsExit, + bool AllowPredicates = false); + + ExitLimit howManyGreaterThans(const SCEV *LHS, const SCEV *RHS, + const Loop *L, bool isSigned, bool IsSubExpr, + bool AllowPredicates = false); /// Return a predecessor of BB (which may not be an immediate predecessor) /// which has exactly one successor from which BB is reachable, or null if @@ -829,12 +1028,18 @@ namespace llvm { /// Test whether the condition described by Pred, LHS, and RHS is true /// whenever the condition described by Pred, FoundLHS, and FoundRHS is - /// true. Utility function used by isImpliedCondOperands. + /// true. Utility function used by isImpliedCondOperands. Tries to get + /// cases like "X `sgt` 0 => X - 1 `sgt` -1". bool isImpliedCondOperandsViaRanges(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS, const SCEV *FoundLHS, const SCEV *FoundRHS); + /// Return true if the condition denoted by \p LHS \p Pred \p RHS is implied + /// by a call to \c @llvm.experimental.guard in \p BB. + bool isImpliedViaGuard(BasicBlock *BB, ICmpInst::Predicate Pred, + const SCEV *LHS, const SCEV *RHS); + /// Test whether the condition described by Pred, LHS, and RHS is true /// whenever the condition described by Pred, FoundLHS, and FoundRHS is /// true. @@ -918,11 +1123,35 @@ namespace llvm { bool isMonotonicPredicate(const SCEVAddRecExpr *LHS, ICmpInst::Predicate Pred, bool &Increasing); - // Return SCEV no-wrap flags that can be proven based on reasoning - // about how poison produced from no-wrap flags on this value - // (e.g. a nuw add) would trigger undefined behavior on overflow. + /// Return SCEV no-wrap flags that can be proven based on reasoning about + /// how poison produced from no-wrap flags on this value (e.g. a nuw add) + /// would trigger undefined behavior on overflow. SCEV::NoWrapFlags getNoWrapFlagsFromUB(const Value *V); + /// Return true if the SCEV corresponding to \p I is never poison. Proving + /// this is more complex than proving that just \p I is never poison, since + /// SCEV commons expressions across control flow, and you can have cases + /// like: + /// + /// idx0 = a + b; + /// ptr[idx0] = 100; + /// if () { + /// idx1 = a +nsw b; + /// ptr[idx1] = 200; + /// } + /// + /// where the SCEV expression (+ a b) is guaranteed to not be poison (and + /// hence not sign-overflow) only if "" is true. Since both + /// `idx0` and `idx1` will be mapped to the same SCEV expression, (+ a b), + /// it is not okay to annotate (+ a b) with in the above example. + bool isSCEVExprNeverPoison(const Instruction *I); + + /// This is like \c isSCEVExprNeverPoison but it specifically works for + /// instructions that will get mapped to SCEV add recurrences. Return true + /// if \p I will never generate poison under the assumption that \p I is an + /// add recurrence on the loop \p L. + bool isAddRecNeverPoison(const Instruction *I, const Loop *L); + public: ScalarEvolution(Function &F, TargetLibraryInfo &TLI, AssumptionCache &AC, DominatorTree &DT, LoopInfo &LI); @@ -946,16 +1175,15 @@ namespace llvm { /// return true. For pointer types, this is the pointer-sized integer type. Type *getEffectiveSCEVType(Type *Ty) const; - /// containsAddRecurrence - Return true if the SCEV is a scAddRecExpr or - /// it contains scAddRecExpr. The result will be cached in HasRecMap. + /// Return true if the SCEV is a scAddRecExpr or it contains + /// scAddRecExpr. The result will be cached in HasRecMap. /// bool containsAddRecurrence(const SCEV *S); - /// getSCEVValues - Return the Value set from which the SCEV expr is - /// generated. + /// Return the Value set from which the SCEV expr is generated. SetVector *getSCEVValues(const SCEV *S); - /// eraseValueFromMap - Erase Value from ValueExprMap and ExprValueMap. + /// Erase Value from ValueExprMap and ExprValueMap. void eraseValueFromMap(Value *V); /// Return a SCEV expression for the full generality of the specified @@ -1004,7 +1232,7 @@ namespace llvm { SmallVector NewOp(Operands.begin(), Operands.end()); return getAddRecExpr(NewOp, L, Flags); } - /// \brief Returns an expression for a GEP + /// Returns an expression for a GEP /// /// \p PointeeType The type used as the basis for the pointer arithmetics /// \p BaseExpr The expression for the pointer operand. @@ -1022,10 +1250,10 @@ namespace llvm { const SCEV *getUnknown(Value *V); const SCEV *getCouldNotCompute(); - /// \brief Return a SCEV for the constant 0 of a specific type. + /// Return a SCEV for the constant 0 of a specific type. const SCEV *getZero(Type *Ty) { return getConstant(Ty, 0); } - /// \brief Return a SCEV for the constant 1 of a specific type. + /// Return a SCEV for the constant 1 of a specific type. const SCEV *getOne(Type *Ty) { return getConstant(Ty, 1); } /// Return an expression for sizeof AllocTy that is type IntTy @@ -1118,7 +1346,7 @@ namespace llvm { bool isLoopBackedgeGuardedByCond(const Loop *L, ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS); - /// \brief Returns the maximum trip count of the loop if it is a single-exit + /// Returns the maximum trip count of the loop if it is a single-exit /// loop and we can compute a small maximum for that loop. /// /// Implemented in terms of the \c getSmallConstantTripCount overload with @@ -1134,7 +1362,7 @@ namespace llvm { /// prematurely via another branch. unsigned getSmallConstantTripCount(Loop *L, BasicBlock *ExitingBlock); - /// \brief Returns the largest constant divisor of the trip count of the + /// Returns the largest constant divisor of the trip count of the /// loop if it is a single-exit loop and we can compute a small maximum for /// that loop. /// @@ -1168,6 +1396,13 @@ namespace llvm { /// const SCEV *getBackedgeTakenCount(const Loop *L); + /// Similar to getBackedgeTakenCount, except it will add a set of + /// SCEV predicates to Predicates that are required to be true in order for + /// the answer to be correct. Predicates can be checked with run-time + /// checks and can be used to perform loop versioning. + const SCEV *getPredicatedBackedgeTakenCount(const Loop *L, + SCEVUnionPredicate &Predicates); + /// Similar to getBackedgeTakenCount, except return the least SCEV value /// that is known never to be less than the actual backedge taken count. const SCEV *getMaxBackedgeTakenCount(const Loop *L); @@ -1187,7 +1422,7 @@ namespace llvm { /// def-use chain linking it to a loop. void forgetValue(Value *V); - /// \brief Called when the client has changed the disposition of values in + /// Called when the client has changed the disposition of values in /// this loop. /// /// We don't have a way to invalidate per-loop dispositions. Clear and @@ -1291,7 +1526,8 @@ namespace llvm { const SCEV *getElementSize(Instruction *Inst); /// Compute the array dimensions Sizes from the set of Terms extracted from - /// the memory access function of this SCEVAddRecExpr. + /// the memory access function of this SCEVAddRecExpr (second step of + /// delinearization). void findArrayDimensions(SmallVectorImpl &Terms, SmallVectorImpl &Sizes, const SCEV *ElementSize) const; @@ -1299,13 +1535,15 @@ namespace llvm { void print(raw_ostream &OS) const; void verify() const; - /// Collect parametric terms occurring in step expressions. + /// Collect parametric terms occurring in step expressions (first step of + /// delinearization). void collectParametricTerms(const SCEV *Expr, SmallVectorImpl &Terms); - /// Return in Subscripts the access functions for each dimension in Sizes. + /// Return in Subscripts the access functions for each dimension in Sizes + /// (third step of delinearization). void computeAccessFunctions(const SCEV *Expr, SmallVectorImpl &Subscripts, SmallVectorImpl &Sizes); @@ -1430,7 +1668,7 @@ namespace llvm { SCEVUnknown *FirstUnknown; }; - /// \brief Analysis pass that exposes the \c ScalarEvolution for a function. + /// Analysis pass that exposes the \c ScalarEvolution for a function. class ScalarEvolutionAnalysis : public AnalysisInfoMixin { friend AnalysisInfoMixin; @@ -1442,7 +1680,7 @@ namespace llvm { ScalarEvolution run(Function &F, AnalysisManager &AM); }; - /// \brief Printer pass for the \c ScalarEvolutionAnalysis results. + /// Printer pass for the \c ScalarEvolutionAnalysis results. class ScalarEvolutionPrinterPass : public PassInfoMixin { raw_ostream &OS; @@ -1487,55 +1725,79 @@ namespace llvm { public: PredicatedScalarEvolution(ScalarEvolution &SE, Loop &L); const SCEVUnionPredicate &getUnionPredicate() const; - /// \brief Returns the SCEV expression of V, in the context of the current - /// SCEV predicate. - /// The order of transformations applied on the expression of V returned - /// by ScalarEvolution is guaranteed to be preserved, even when adding new - /// predicates. + + /// Returns the SCEV expression of V, in the context of the current SCEV + /// predicate. The order of transformations applied on the expression of V + /// returned by ScalarEvolution is guaranteed to be preserved, even when + /// adding new predicates. const SCEV *getSCEV(Value *V); - /// \brief Adds a new predicate. + + /// Get the (predicated) backedge count for the analyzed loop. + const SCEV *getBackedgeTakenCount(); + + /// Adds a new predicate. void addPredicate(const SCEVPredicate &Pred); - /// \brief Attempts to produce an AddRecExpr for V by adding additional - /// SCEV predicates. If we can't transform the expression into an - /// AddRecExpr we return nullptr and not add additional SCEV predicates - /// to the current context. + + /// Attempts to produce an AddRecExpr for V by adding additional SCEV + /// predicates. If we can't transform the expression into an AddRecExpr we + /// return nullptr and not add additional SCEV predicates to the current + /// context. const SCEVAddRecExpr *getAsAddRec(Value *V); - /// \brief Proves that V doesn't overflow by adding SCEV predicate. + + /// Proves that V doesn't overflow by adding SCEV predicate. void setNoOverflow(Value *V, SCEVWrapPredicate::IncrementWrapFlags Flags); - /// \brief Returns true if we've proved that V doesn't wrap by means of a - /// SCEV predicate. + + /// Returns true if we've proved that V doesn't wrap by means of a SCEV + /// predicate. bool hasNoOverflow(Value *V, SCEVWrapPredicate::IncrementWrapFlags Flags); - /// \brief Returns the ScalarEvolution analysis used. + + /// Returns the ScalarEvolution analysis used. ScalarEvolution *getSE() const { return &SE; } + /// We need to explicitly define the copy constructor because of FlagsMap. PredicatedScalarEvolution(const PredicatedScalarEvolution&); + + /// Print the SCEV mappings done by the Predicated Scalar Evolution. + /// The printed text is indented by \p Depth. + void print(raw_ostream &OS, unsigned Depth) const; + private: - /// \brief Increments the version number of the predicate. - /// This needs to be called every time the SCEV predicate changes. + /// Increments the version number of the predicate. This needs to be called + /// every time the SCEV predicate changes. void updateGeneration(); + /// Holds a SCEV and the version number of the SCEV predicate used to /// perform the rewrite of the expression. typedef std::pair RewriteEntry; + /// Maps a SCEV to the rewrite result of that SCEV at a certain version /// number. If this number doesn't match the current Generation, we will /// need to do a rewrite. To preserve the transformation order of previous /// rewrites, we will rewrite the previous result instead of the original /// SCEV. DenseMap RewriteMap; + /// Records what NoWrap flags we've added to a Value *. ValueMap FlagsMap; + /// The ScalarEvolution analysis. ScalarEvolution &SE; + /// The analyzed Loop. const Loop &L; + /// The SCEVPredicate that forms our context. We will rewrite all /// expressions assuming that this predicate true. SCEVUnionPredicate Preds; + /// Marks the version of the SCEV predicate used. When rewriting a SCEV /// expression we mark it with the version of the predicate. We use this to /// figure out if the predicate has changed from the last rewrite of the /// SCEV. If so, we need to perform a new rewrite. unsigned Generation; + + /// The backedge taken count. + const SCEV *BackedgeCount; }; } diff --git a/include/llvm/Analysis/ScalarEvolutionExpander.h b/include/llvm/Analysis/ScalarEvolutionExpander.h index 5addbc77af3f08699808a61b4e7e1a4dc93e856d..2fa856a32f7df5599501e28931d902f097997285 100644 --- a/include/llvm/Analysis/ScalarEvolutionExpander.h +++ b/include/llvm/Analysis/ScalarEvolutionExpander.h @@ -83,6 +83,46 @@ namespace llvm { typedef IRBuilder BuilderType; BuilderType Builder; + // RAII object that stores the current insertion point and restores it when + // the object is destroyed. This includes the debug location. Duplicated + // from InsertPointGuard to add SetInsertPoint() which is used to updated + // InsertPointGuards stack when insert points are moved during SCEV + // expansion. + class SCEVInsertPointGuard { + IRBuilderBase &Builder; + AssertingVH Block; + BasicBlock::iterator Point; + DebugLoc DbgLoc; + SCEVExpander *SE; + + SCEVInsertPointGuard(const SCEVInsertPointGuard &) = delete; + SCEVInsertPointGuard &operator=(const SCEVInsertPointGuard &) = delete; + + public: + SCEVInsertPointGuard(IRBuilderBase &B, SCEVExpander *SE) + : Builder(B), Block(B.GetInsertBlock()), Point(B.GetInsertPoint()), + DbgLoc(B.getCurrentDebugLocation()), SE(SE) { + SE->InsertPointGuards.push_back(this); + } + + ~SCEVInsertPointGuard() { + // These guards should always created/destroyed in FIFO order since they + // are used to guard lexically scoped blocks of code in + // ScalarEvolutionExpander. + assert(SE->InsertPointGuards.back() == this); + SE->InsertPointGuards.pop_back(); + Builder.restoreIP(IRBuilderBase::InsertPoint(Block, Point)); + Builder.SetCurrentDebugLocation(DbgLoc); + } + + BasicBlock::iterator GetInsertPoint() const { return Point; } + void SetInsertPoint(BasicBlock::iterator I) { Point = I; } + }; + + /// Stack of pointers to saved insert points, used to keep insert points + /// consistent when instructions are moved. + SmallVector InsertPointGuards; + #ifndef NDEBUG const char *DebugType; #endif @@ -101,6 +141,11 @@ namespace llvm { #endif } + ~SCEVExpander() { + // Make sure the insert point guard stack is consistent. + assert(InsertPointGuards.empty()); + } + #ifndef NDEBUG void setDebugType(const char* s) { DebugType = s; } #endif @@ -318,6 +363,11 @@ namespace llvm { bool &InvertStep); Value *expandIVInc(PHINode *PN, Value *StepV, const Loop *L, Type *ExpandTy, Type *IntTy, bool useSubtract); + + void hoistBeforePos(DominatorTree *DT, Instruction *InstToHoist, + Instruction *Pos, PHINode *LoopPhi); + + void fixupInsertPoints(Instruction *I); }; } diff --git a/include/llvm/Analysis/ScalarEvolutionExpressions.h b/include/llvm/Analysis/ScalarEvolutionExpressions.h index 0fd26e3b6a748329259e91b99258f74d6aec3b8a..ff24cafbe680f788b83d70b7d1bd8bbd8bf65c8e 100644 --- a/include/llvm/Analysis/ScalarEvolutionExpressions.h +++ b/include/llvm/Analysis/ScalarEvolutionExpressions.h @@ -32,9 +32,7 @@ namespace llvm { scUnknown, scCouldNotCompute }; - //===--------------------------------------------------------------------===// - /// SCEVConstant - This class represents a constant integer value. - /// + /// This class represents a constant integer value. class SCEVConstant : public SCEV { friend class ScalarEvolution; @@ -53,9 +51,7 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVCastExpr - This is the base class for unary cast operator classes. - /// + /// This is the base class for unary cast operator classes. class SCEVCastExpr : public SCEV { protected: const SCEV *Op; @@ -76,10 +72,8 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVTruncateExpr - This class represents a truncation of an integer value - /// to a smaller integer value. - /// + /// This class represents a truncation of an integer value to a + /// smaller integer value. class SCEVTruncateExpr : public SCEVCastExpr { friend class ScalarEvolution; @@ -93,10 +87,8 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVZeroExtendExpr - This class represents a zero extension of a small - /// integer value to a larger integer value. - /// + /// This class represents a zero extension of a small integer value + /// to a larger integer value. class SCEVZeroExtendExpr : public SCEVCastExpr { friend class ScalarEvolution; @@ -110,10 +102,8 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVSignExtendExpr - This class represents a sign extension of a small - /// integer value to a larger integer value. - /// + /// This class represents a sign extension of a small integer value + /// to a larger integer value. class SCEVSignExtendExpr : public SCEVCastExpr { friend class ScalarEvolution; @@ -128,10 +118,8 @@ namespace llvm { }; - //===--------------------------------------------------------------------===// - /// SCEVNAryExpr - This node is a base class providing common - /// functionality for n'ary operators. - /// + /// This node is a base class providing common functionality for + /// n'ary operators. class SCEVNAryExpr : public SCEV { protected: // Since SCEVs are immutable, ScalarEvolution allocates operand @@ -167,15 +155,15 @@ namespace llvm { } bool hasNoUnsignedWrap() const { - return getNoWrapFlags(SCEV::FlagNUW) != SCEV::FlagAnyWrap; + return getNoWrapFlags(FlagNUW) != FlagAnyWrap; } bool hasNoSignedWrap() const { - return getNoWrapFlags(SCEV::FlagNSW) != SCEV::FlagAnyWrap; + return getNoWrapFlags(FlagNSW) != FlagAnyWrap; } bool hasNoSelfWrap() const { - return getNoWrapFlags(SCEV::FlagNW) != SCEV::FlagAnyWrap; + return getNoWrapFlags(FlagNW) != FlagAnyWrap; } /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -188,10 +176,7 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVCommutativeExpr - This node is the base class for n'ary commutative - /// operators. - /// + /// This node is the base class for n'ary commutative operators. class SCEVCommutativeExpr : public SCEVNAryExpr { protected: SCEVCommutativeExpr(const FoldingSetNodeIDRef ID, @@ -214,9 +199,7 @@ namespace llvm { }; - //===--------------------------------------------------------------------===// - /// SCEVAddExpr - This node represents an addition of some number of SCEVs. - /// + /// This node represents an addition of some number of SCEVs. class SCEVAddExpr : public SCEVCommutativeExpr { friend class ScalarEvolution; @@ -239,9 +222,8 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVMulExpr - This node represents multiplication of some number of SCEVs. - /// + + /// This node represents multiplication of some number of SCEVs. class SCEVMulExpr : public SCEVCommutativeExpr { friend class ScalarEvolution; @@ -258,9 +240,7 @@ namespace llvm { }; - //===--------------------------------------------------------------------===// - /// SCEVUDivExpr - This class represents a binary unsigned division operation. - /// + /// This class represents a binary unsigned division operation. class SCEVUDivExpr : public SCEV { friend class ScalarEvolution; @@ -289,12 +269,11 @@ namespace llvm { }; - //===--------------------------------------------------------------------===// - /// SCEVAddRecExpr - This node represents a polynomial recurrence on the trip - /// count of the specified loop. This is the primary focus of the - /// ScalarEvolution framework; all the other SCEV subclasses are mostly just - /// supporting infrastructure to allow SCEVAddRecExpr expressions to be - /// created and analyzed. + /// This node represents a polynomial recurrence on the trip count + /// of the specified loop. This is the primary focus of the + /// ScalarEvolution framework; all the other SCEV subclasses are + /// mostly just supporting infrastructure to allow SCEVAddRecExpr + /// expressions to be created and analyzed. /// /// All operands of an AddRec are required to be loop invariant. /// @@ -311,10 +290,10 @@ namespace llvm { const SCEV *getStart() const { return Operands[0]; } const Loop *getLoop() const { return L; } - /// getStepRecurrence - This method constructs and returns the recurrence - /// indicating how much this expression steps by. If this is a polynomial - /// of degree N, it returns a chrec of degree N-1. - /// We cannot determine whether the step recurrence has self-wraparound. + /// Constructs and returns the recurrence indicating how much this + /// expression steps by. If this is a polynomial of degree N, it + /// returns a chrec of degree N-1. We cannot determine whether + /// the step recurrence has self-wraparound. const SCEV *getStepRecurrence(ScalarEvolution &SE) const { if (isAffine()) return getOperand(1); return SE.getAddRecExpr(SmallVector(op_begin()+1, @@ -322,17 +301,17 @@ namespace llvm { getLoop(), FlagAnyWrap); } - /// isAffine - Return true if this represents an expression - /// A + B*x where A and B are loop invariant values. + /// Return true if this represents an expression A + B*x where A + /// and B are loop invariant values. bool isAffine() const { // We know that the start value is invariant. This expression is thus // affine iff the step is also invariant. return getNumOperands() == 2; } - /// isQuadratic - Return true if this represents an expression - /// A + B*x + C*x^2 where A, B and C are loop invariant values. - /// This corresponds to an addrec of the form {L,+,M,+,N} + /// Return true if this represents an expression A + B*x + C*x^2 + /// where A, B and C are loop invariant values. This corresponds + /// to an addrec of the form {L,+,M,+,N} bool isQuadratic() const { return getNumOperands() == 3; } @@ -346,21 +325,21 @@ namespace llvm { SubclassData |= Flags; } - /// evaluateAtIteration - Return the value of this chain of recurrences at - /// the specified iteration number. + /// Return the value of this chain of recurrences at the specified + /// iteration number. const SCEV *evaluateAtIteration(const SCEV *It, ScalarEvolution &SE) const; - /// getNumIterationsInRange - Return the number of iterations of this loop - /// that produce values in the specified constant range. Another way of - /// looking at this is that it returns the first iteration number where the - /// value is not in the condition, thus computing the exit count. If the - /// iteration count can't be computed, an instance of SCEVCouldNotCompute is - /// returned. - const SCEV *getNumIterationsInRange(ConstantRange Range, - ScalarEvolution &SE) const; - - /// getPostIncExpr - Return an expression representing the value of - /// this expression one iteration of the loop ahead. + /// Return the number of iterations of this loop that produce + /// values in the specified constant range. Another way of + /// looking at this is that it returns the first iteration number + /// where the value is not in the condition, thus computing the + /// exit count. If the iteration count can't be computed, an + /// instance of SCEVCouldNotCompute is returned. + const SCEV *getNumIterationsInRange(const ConstantRange &Range, + ScalarEvolution &SE) const; + + /// Return an expression representing the value of this expression + /// one iteration of the loop ahead. const SCEVAddRecExpr *getPostIncExpr(ScalarEvolution &SE) const { return cast(SE.getAddExpr(this, getStepRecurrence(SE))); } @@ -371,9 +350,7 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVSMaxExpr - This class represents a signed maximum selection. - /// + /// This class represents a signed maximum selection. class SCEVSMaxExpr : public SCEVCommutativeExpr { friend class ScalarEvolution; @@ -392,9 +369,7 @@ namespace llvm { }; - //===--------------------------------------------------------------------===// - /// SCEVUMaxExpr - This class represents an unsigned maximum selection. - /// + /// This class represents an unsigned maximum selection. class SCEVUMaxExpr : public SCEVCommutativeExpr { friend class ScalarEvolution; @@ -412,11 +387,9 @@ namespace llvm { } }; - //===--------------------------------------------------------------------===// - /// SCEVUnknown - This means that we are dealing with an entirely unknown SCEV - /// value, and only represent it as its LLVM Value. This is the "bottom" - /// value for the analysis. - /// + /// This means that we are dealing with an entirely unknown SCEV + /// value, and only represent it as its LLVM Value. This is the + /// "bottom" value for the analysis. class SCEVUnknown final : public SCEV, private CallbackVH { friend class ScalarEvolution; @@ -424,13 +397,13 @@ namespace llvm { void deleted() override; void allUsesReplacedWith(Value *New) override; - /// SE - The parent ScalarEvolution value. This is used to update - /// the parent's maps when the value associated with a SCEVUnknown - /// is deleted or RAUW'd. + /// The parent ScalarEvolution value. This is used to update the + /// parent's maps when the value associated with a SCEVUnknown is + /// deleted or RAUW'd. ScalarEvolution *SE; - /// Next - The next pointer in the linked list of all - /// SCEVUnknown instances owned by a ScalarEvolution. + /// The next pointer in the linked list of all SCEVUnknown + /// instances owned by a ScalarEvolution. SCEVUnknown *Next; SCEVUnknown(const FoldingSetNodeIDRef ID, Value *V, @@ -440,15 +413,17 @@ namespace llvm { public: Value *getValue() const { return getValPtr(); } - /// isSizeOf, isAlignOf, isOffsetOf - Test whether this is a special - /// constant representing a type size, alignment, or field offset in - /// a target-independent manner, and hasn't happened to have been - /// folded with other operations into something unrecognizable. This - /// is mainly only useful for pretty-printing and other situations - /// where it isn't absolutely required for these to succeed. + /// @{ + /// Test whether this is a special constant representing a type + /// size, alignment, or field offset in a target-independent + /// manner, and hasn't happened to have been folded with other + /// operations into something unrecognizable. This is mainly only + /// useful for pretty-printing and other situations where it isn't + /// absolutely required for these to succeed. bool isSizeOf(Type *&AllocTy) const; bool isAlignOf(Type *&AllocTy) const; bool isOffsetOf(Type *&STy, Constant *&FieldNo) const; + /// @} Type *getType() const { return getValPtr()->getType(); } @@ -458,8 +433,8 @@ namespace llvm { } }; - /// SCEVVisitor - This class defines a simple visitor class that may be used - /// for various SCEV analysis purposes. + /// This class defines a simple visitor class that may be used for + /// various SCEV analysis purposes. template struct SCEVVisitor { RetVal visit(const SCEV *S) { @@ -537,8 +512,8 @@ namespace llvm { case scSMaxExpr: case scUMaxExpr: case scAddRecExpr: - for (const auto *Op : cast(S)->operands()) - push(Op); + for (const auto *Op : cast(S)->operands()) + push(Op); break; case scUDivExpr: { const SCEVUDivExpr *UDiv = cast(S); @@ -705,13 +680,6 @@ namespace llvm { private: LoopToScevMapT ⤅ }; - -/// Applies the Map (Loop -> SCEV) to the given Scev. -static inline const SCEV *apply(const SCEV *Scev, LoopToScevMapT &Map, - ScalarEvolution &SE) { - return SCEVLoopAddRecRewriter::rewrite(Scev, Map, SE); -} - } #endif diff --git a/include/llvm/Analysis/TargetLibraryInfo.def b/include/llvm/Analysis/TargetLibraryInfo.def index 7798e3c88248023dc723cbaff2f46a307db92e79..b2a593d67dcaaab12ff30981ec2e7d22a9529379 100644 --- a/include/llvm/Analysis/TargetLibraryInfo.def +++ b/include/llvm/Analysis/TargetLibraryInfo.def @@ -195,6 +195,11 @@ TLI_DEFINE_STRING_INTERNAL("__memmove_chk") /// void *__memset_chk(void *s, char v, size_t n, size_t s1size); TLI_DEFINE_ENUM_INTERNAL(memset_chk) TLI_DEFINE_STRING_INTERNAL("__memset_chk") + +// int __nvvm_reflect(const char *) +TLI_DEFINE_ENUM_INTERNAL(nvvm_reflect) +TLI_DEFINE_STRING_INTERNAL("__nvvm_reflect") + /// double __sincospi_stret(double x); TLI_DEFINE_ENUM_INTERNAL(sincospi_stret) TLI_DEFINE_STRING_INTERNAL("__sincospi_stret") diff --git a/include/llvm/Analysis/TargetLibraryInfo.h b/include/llvm/Analysis/TargetLibraryInfo.h index bc4ac000e24f9df152ad197175770177e372ef5e..7efa6f05970724323634972617a5ca75cfcfbe06 100644 --- a/include/llvm/Analysis/TargetLibraryInfo.h +++ b/include/llvm/Analysis/TargetLibraryInfo.h @@ -11,7 +11,6 @@ #define LLVM_ANALYSIS_TARGETLIBRARYINFO_H #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/Function.h" @@ -20,7 +19,9 @@ #include "llvm/Pass.h" namespace llvm { -/// VecDesc - Describes a possible vectorization of a function. +template class ArrayRef; + +/// Describes a possible vectorization of a function. /// Function 'VectorFnName' is equivalent to 'ScalarFnName' vectorized /// by a factor 'VectorizationFactor'. struct VecDesc { @@ -38,7 +39,7 @@ struct VecDesc { }; } -/// \brief Implementation of the target library information. +/// Implementation of the target library information. /// /// This class constructs tables that hold the target library information and /// make it available. However, it is somewhat expensive to compute and only @@ -70,8 +71,13 @@ class TargetLibraryInfoImpl { /// on VectorFnName rather than ScalarFnName. std::vector ScalarDescs; + /// Return true if the function type FTy is valid for the library function + /// F, regardless of whether the function is available. + bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc::Func F, + const DataLayout *DL) const; + public: - /// \brief List of known vector-functions libraries. + /// List of known vector-functions libraries. /// /// The vector-functions library defines, which functions are vectorizable /// and with which factor. The library can be specified by either frontend, @@ -92,24 +98,31 @@ public: TargetLibraryInfoImpl &operator=(const TargetLibraryInfoImpl &TLI); TargetLibraryInfoImpl &operator=(TargetLibraryInfoImpl &&TLI); - /// \brief Searches for a particular function name. + /// Searches for a particular function name. /// /// If it is one of the known library functions, return true and set F to the /// corresponding value. bool getLibFunc(StringRef funcName, LibFunc::Func &F) const; - /// \brief Forces a function to be marked as unavailable. + /// Searches for a particular function name, also checking that its type is + /// valid for the library function matching that name. + /// + /// If it is one of the known library functions, return true and set F to the + /// corresponding value. + bool getLibFunc(const Function &FDecl, LibFunc::Func &F) const; + + /// Forces a function to be marked as unavailable. void setUnavailable(LibFunc::Func F) { setState(F, Unavailable); } - /// \brief Forces a function to be marked as available. + /// Forces a function to be marked as available. void setAvailable(LibFunc::Func F) { setState(F, StandardName); } - /// \brief Forces a function to be marked as available and provide an - /// alternate name that must be used. + /// Forces a function to be marked as available and provide an alternate name + /// that must be used. void setAvailableWithName(LibFunc::Func F, StringRef Name) { if (StandardNames[F] != Name) { setState(F, CustomName); @@ -120,48 +133,47 @@ public: } } - /// \brief Disables all builtins. + /// Disables all builtins. /// /// This can be used for options like -fno-builtin. void disableAllFunctions(); - /// addVectorizableFunctions - Add a set of scalar -> vector mappings, - /// queryable via getVectorizedFunction and getScalarizedFunction. + /// Add a set of scalar -> vector mappings, queryable via + /// getVectorizedFunction and getScalarizedFunction. void addVectorizableFunctions(ArrayRef Fns); /// Calls addVectorizableFunctions with a known preset of functions for the /// given vector library. void addVectorizableFunctionsFromVecLib(enum VectorLibrary VecLib); - /// isFunctionVectorizable - Return true if the function F has a - /// vector equivalent with vectorization factor VF. + /// Return true if the function F has a vector equivalent with vectorization + /// factor VF. bool isFunctionVectorizable(StringRef F, unsigned VF) const { return !getVectorizedFunction(F, VF).empty(); } - /// isFunctionVectorizable - Return true if the function F has a - /// vector equivalent with any vectorization factor. + /// Return true if the function F has a vector equivalent with any + /// vectorization factor. bool isFunctionVectorizable(StringRef F) const; - /// getVectorizedFunction - Return the name of the equivalent of - /// F, vectorized with factor VF. If no such mapping exists, - /// return the empty string. + /// Return the name of the equivalent of F, vectorized with factor VF. If no + /// such mapping exists, return the empty string. StringRef getVectorizedFunction(StringRef F, unsigned VF) const; - /// isFunctionScalarizable - Return true if the function F has a - /// scalar equivalent, and set VF to be the vectorization factor. + /// Return true if the function F has a scalar equivalent, and set VF to be + /// the vectorization factor. bool isFunctionScalarizable(StringRef F, unsigned &VF) const { return !getScalarizedFunction(F, VF).empty(); } - /// getScalarizedFunction - Return the name of the equivalent of - /// F, scalarized. If no such mapping exists, return the empty string. + /// Return the name of the equivalent of F, scalarized. If no such mapping + /// exists, return the empty string. /// /// Set VF to the vectorization factor. StringRef getScalarizedFunction(StringRef F, unsigned &VF) const; }; -/// \brief Provides information about what library functions are available for +/// Provides information about what library functions are available for /// the current target. /// /// This both allows optimizations to handle them specially and frontends to @@ -187,7 +199,7 @@ public: return *this; } - /// \brief Searches for a particular function name. + /// Searches for a particular function name. /// /// If it is one of the known library functions, return true and set F to the /// corresponding value. @@ -195,7 +207,11 @@ public: return Impl->getLibFunc(funcName, F); } - /// \brief Tests whether a library function is available. + bool getLibFunc(const Function &FDecl, LibFunc::Func &F) const { + return Impl->getLibFunc(FDecl, F); + } + + /// Tests whether a library function is available. bool has(LibFunc::Func F) const { return Impl->getState(F) != TargetLibraryInfoImpl::Unavailable; } @@ -209,8 +225,8 @@ public: return Impl->getVectorizedFunction(F, VF); } - /// \brief Tests if the function is both available and a candidate for - /// optimized code generation. + /// Tests if the function is both available and a candidate for optimized code + /// generation. bool hasOptimizedCodeGen(LibFunc::Func F) const { if (Impl->getState(F) == TargetLibraryInfoImpl::Unavailable) return false; @@ -251,14 +267,14 @@ public: return Impl->CustomNames.find(F)->second; } - /// \brief Handle invalidation from the pass manager. + /// Handle invalidation from the pass manager. /// /// If we try to invalidate this info, just return false. It cannot become /// invalid even if the module changes. bool invalidate(Module &, const PreservedAnalyses &) { return false; } }; -/// \brief Analysis pass providing the \c TargetLibraryInfo. +/// Analysis pass providing the \c TargetLibraryInfo. /// /// Note that this pass's result cannot be invalidated, it is immutable for the /// life of the module. @@ -266,13 +282,13 @@ class TargetLibraryAnalysis : public AnalysisInfoMixin { public: typedef TargetLibraryInfo Result; - /// \brief Default construct the library analysis. + /// Default construct the library analysis. /// /// This will use the module's triple to construct the library info for that /// module. TargetLibraryAnalysis() {} - /// \brief Construct a library analysis with preset info. + /// Construct a library analysis with preset info. /// /// This will directly copy the preset info into the result without /// consulting the module's triple. @@ -288,8 +304,8 @@ public: return *this; } - TargetLibraryInfo run(Module &M); - TargetLibraryInfo run(Function &F); + TargetLibraryInfo run(Module &M, ModuleAnalysisManager &); + TargetLibraryInfo run(Function &F, FunctionAnalysisManager &); private: friend AnalysisInfoMixin; @@ -299,7 +315,7 @@ private: StringMap> Impls; - TargetLibraryInfoImpl &lookupInfoImpl(Triple T); + TargetLibraryInfoImpl &lookupInfoImpl(const Triple &T); }; class TargetLibraryInfoWrapperPass : public ImmutablePass { diff --git a/include/llvm/Analysis/TargetTransformInfo.h b/include/llvm/Analysis/TargetTransformInfo.h index 57d0cf47d6badfbe962e28223176c2d1f45f3cec..7570d22a803cba5bb1616b3d754178d27dcedd91 100644 --- a/include/llvm/Analysis/TargetTransformInfo.h +++ b/include/llvm/Analysis/TargetTransformInfo.h @@ -25,6 +25,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Operator.h" #include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include "llvm/Support/DataTypes.h" @@ -165,6 +166,14 @@ public: /// This overload allows specifying a set of candidate argument values. int getCallCost(const Function *F, ArrayRef Arguments) const; + /// \returns A value by which our inlining threshold should be multiplied. + /// This is primarily used to bump up the inlining threshold wholesale on + /// targets where calls are unusually expensive. + /// + /// TODO: This is a rather blunt instrument. Perhaps altering the costs of + /// individual classes of instructions would be better. + unsigned getInliningThresholdMultiplier() const; + /// \brief Estimate the cost of an intrinsic when lowered. /// /// Mirrors the \c getCallCost method but uses an intrinsic identifier. @@ -260,6 +269,10 @@ public: // (set to UINT_MAX to disable). This does not apply in cases where the // loop is being fully unrolled. unsigned MaxCount; + /// Set the maximum unrolling factor for full unrolling. Like MaxCount, but + /// applies even if full unrolling is selected. This allows a target to fall + /// back to Partial unrolling if full unrolling is above FullUnrollMaxCount. + unsigned FullUnrollMaxCount; /// Allow partial unrolling (unrolling of loops to expand the size of the /// loop body, not only to eliminate small constant-trip-count loops). bool Partial; @@ -267,9 +280,14 @@ public: /// loop body even when the number of loop iterations is not known at /// compile time). bool Runtime; + /// Allow generation of a loop remainder (extra iterations after unroll). + bool AllowRemainder; /// Allow emitting expensive instructions (such as divisions) when computing /// the trip count of a loop for runtime unrolling. bool AllowExpensiveTripCount; + /// Apply loop unroll on any kind of loop + /// (mainly to loops that fail runtime unrolling). + bool Force; }; /// \brief Get target-customized preferences for the generic loop unrolling @@ -313,8 +331,7 @@ public: unsigned AddrSpace = 0) const; /// \brief Return true if the target supports masked load/store - /// AVX2 and AVX-512 targets allow masks for consecutive load and store for - /// 32 and 64 bit elements. + /// AVX2 and AVX-512 targets allow masks for consecutive load and store bool isLegalMaskedStore(Type *DataType) const; bool isLegalMaskedLoad(Type *DataType) const; @@ -362,6 +379,20 @@ public: /// \brief Enable matching of interleaved access groups. bool enableInterleavedAccessVectorization() const; + /// \brief Indicate that it is potentially unsafe to automatically vectorize + /// floating-point operations because the semantics of vector and scalar + /// floating-point semantics may differ. For example, ARM NEON v7 SIMD math + /// does not support IEEE-754 denormal numbers, while depending on the + /// platform, scalar floating-point math does. + /// This applies to floating-point math operations and calls, not memory + /// operations, shuffles, or casts. + bool isFPVectorizationPotentiallyUnsafe() const; + + /// \brief Determine if the target supports unaligned memory accesses. + bool allowsMisalignedMemoryAccesses(unsigned BitWidth, unsigned AddressSpace = 0, + unsigned Alignment = 1, + bool *Fast = nullptr) const; + /// \brief Return hardware support for population count. PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) const; @@ -383,6 +414,16 @@ public: Type *Ty) const; int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, Type *Ty) const; + + /// \brief Return the expected cost for the given integer when optimising + /// for size. This is different than the other integer immediate cost + /// functions in that it is subtarget agnostic. This is useful when you e.g. + /// target one ISA such as Aarch32 but smaller encodings could be possible + /// with another such as Thumb. This return value is used as a penalty when + /// the total costs for a constant is calculated (the bigger the cost, the + /// more beneficial constant hoisting is). + int getIntImmCodeSizeCost(unsigned Opc, unsigned Idx, const APInt &Imm, + Type *Ty) const; /// @} /// \name Vector Target Information @@ -416,6 +457,10 @@ public: /// \return The width of the largest scalar or vector register type. unsigned getRegisterBitWidth(bool Vector) const; + /// \return The bitwidth of the largest vector type that should be used to + /// load/store in the given address space. + unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const; + /// \return The size of a cache line in bytes. unsigned getCacheLineSize() const; @@ -455,6 +500,11 @@ public: /// zext, etc. int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) const; + /// \return The expected cost of a sign- or zero-extended vector extract. Use + /// -1 to indicate that there is no information about the index value. + int getExtractWithExtendCost(unsigned Opcode, Type *Dst, VectorType *VecTy, + unsigned Index = -1) const; + /// \return The expected cost of control-flow related instructions such as /// Phi, Ret, Br. int getCFInstrCost(unsigned Opcode) const; @@ -514,11 +564,11 @@ public: /// \returns The cost of Intrinsic instructions. Types analysis only. int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef Tys) const; + ArrayRef Tys, FastMathFlags FMF) const; /// \returns The cost of Intrinsic instructions. Analyses the real arguments. int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef Args) const; + ArrayRef Args, FastMathFlags FMF) const; /// \returns The cost of Call instructions. int getCallInstrCost(Function *F, Type *RetTy, ArrayRef Tys) const; @@ -586,6 +636,7 @@ public: virtual int getCallCost(const Function *F, int NumArgs) = 0; virtual int getCallCost(const Function *F, ArrayRef Arguments) = 0; + virtual unsigned getInliningThresholdMultiplier() = 0; virtual int getIntrinsicCost(Intrinsic::ID IID, Type *RetTy, ArrayRef ParamTys) = 0; virtual int getIntrinsicCost(Intrinsic::ID IID, Type *RetTy, @@ -616,9 +667,16 @@ public: virtual bool shouldBuildLookupTables() = 0; virtual bool enableAggressiveInterleaving(bool LoopHasReductions) = 0; virtual bool enableInterleavedAccessVectorization() = 0; + virtual bool isFPVectorizationPotentiallyUnsafe() = 0; + virtual bool allowsMisalignedMemoryAccesses(unsigned BitWidth, + unsigned AddressSpace, + unsigned Alignment, + bool *Fast) = 0; virtual PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) = 0; virtual bool haveFastSqrt(Type *Ty) = 0; virtual int getFPOpCost(Type *Ty) = 0; + virtual int getIntImmCodeSizeCost(unsigned Opc, unsigned Idx, const APInt &Imm, + Type *Ty) = 0; virtual int getIntImmCost(const APInt &Imm, Type *Ty) = 0; virtual int getIntImmCost(unsigned Opc, unsigned Idx, const APInt &Imm, Type *Ty) = 0; @@ -626,6 +684,7 @@ public: Type *Ty) = 0; virtual unsigned getNumberOfRegisters(bool Vector) = 0; virtual unsigned getRegisterBitWidth(bool Vector) = 0; + virtual unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) = 0; virtual unsigned getCacheLineSize() = 0; virtual unsigned getPrefetchDistance() = 0; virtual unsigned getMinPrefetchStride() = 0; @@ -639,6 +698,8 @@ public: virtual int getShuffleCost(ShuffleKind Kind, Type *Tp, int Index, Type *SubTp) = 0; virtual int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) = 0; + virtual int getExtractWithExtendCost(unsigned Opcode, Type *Dst, + VectorType *VecTy, unsigned Index) = 0; virtual int getCFInstrCost(unsigned Opcode) = 0; virtual int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) = 0; @@ -660,9 +721,11 @@ public: virtual int getReductionCost(unsigned Opcode, Type *Ty, bool IsPairwiseForm) = 0; virtual int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef Tys) = 0; + ArrayRef Tys, + FastMathFlags FMF) = 0; virtual int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef Args) = 0; + ArrayRef Args, + FastMathFlags FMF) = 0; virtual int getCallInstrCost(Function *F, Type *RetTy, ArrayRef Tys) = 0; virtual unsigned getNumberOfParts(Type *Tp) = 0; @@ -705,6 +768,9 @@ public: ArrayRef Arguments) override { return Impl.getCallCost(F, Arguments); } + unsigned getInliningThresholdMultiplier() override { + return Impl.getInliningThresholdMultiplier(); + } int getIntrinsicCost(Intrinsic::ID IID, Type *RetTy, ArrayRef ParamTys) override { return Impl.getIntrinsicCost(IID, RetTy, ParamTys); @@ -772,6 +838,14 @@ public: bool enableInterleavedAccessVectorization() override { return Impl.enableInterleavedAccessVectorization(); } + bool isFPVectorizationPotentiallyUnsafe() override { + return Impl.isFPVectorizationPotentiallyUnsafe(); + } + bool allowsMisalignedMemoryAccesses(unsigned BitWidth, unsigned AddressSpace, + unsigned Alignment, bool *Fast) override { + return Impl.allowsMisalignedMemoryAccesses(BitWidth, AddressSpace, + Alignment, Fast); + } PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) override { return Impl.getPopcntSupport(IntTyWidthInBit); } @@ -779,6 +853,10 @@ public: int getFPOpCost(Type *Ty) override { return Impl.getFPOpCost(Ty); } + int getIntImmCodeSizeCost(unsigned Opc, unsigned Idx, const APInt &Imm, + Type *Ty) override { + return Impl.getIntImmCodeSizeCost(Opc, Idx, Imm, Ty); + } int getIntImmCost(const APInt &Imm, Type *Ty) override { return Impl.getIntImmCost(Imm, Ty); } @@ -796,6 +874,11 @@ public: unsigned getRegisterBitWidth(bool Vector) override { return Impl.getRegisterBitWidth(Vector); } + + unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) override { + return Impl.getLoadStoreVecRegBitWidth(AddrSpace); + } + unsigned getCacheLineSize() override { return Impl.getCacheLineSize(); } @@ -824,6 +907,10 @@ public: int getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) override { return Impl.getCastInstrCost(Opcode, Dst, Src); } + int getExtractWithExtendCost(unsigned Opcode, Type *Dst, VectorType *VecTy, + unsigned Index) override { + return Impl.getExtractWithExtendCost(Opcode, Dst, VecTy, Index); + } int getCFInstrCost(unsigned Opcode) override { return Impl.getCFInstrCost(Opcode); } @@ -857,13 +944,14 @@ public: bool IsPairwiseForm) override { return Impl.getReductionCost(Opcode, Ty, IsPairwiseForm); } - int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef Tys) override { - return Impl.getIntrinsicInstrCost(ID, RetTy, Tys); + int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, ArrayRef Tys, + FastMathFlags FMF) override { + return Impl.getIntrinsicInstrCost(ID, RetTy, Tys, FMF); } int getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef Args) override { - return Impl.getIntrinsicInstrCost(ID, RetTy, Args); + ArrayRef Args, + FastMathFlags FMF) override { + return Impl.getIntrinsicInstrCost(ID, RetTy, Args, FMF); } int getCallInstrCost(Function *F, Type *RetTy, ArrayRef Tys) override { @@ -937,7 +1025,7 @@ public: return *this; } - Result run(const Function &F); + Result run(const Function &F, AnalysisManager &); private: friend AnalysisInfoMixin; diff --git a/include/llvm/Analysis/TargetTransformInfoImpl.h b/include/llvm/Analysis/TargetTransformInfoImpl.h index 39eba4d6e582ef22cab6d4fca144da4f61d221a6..a97624bc2ab082cf9dc616205a971255d71c7c07 100644 --- a/include/llvm/Analysis/TargetTransformInfoImpl.h +++ b/include/llvm/Analysis/TargetTransformInfoImpl.h @@ -102,8 +102,8 @@ public: } } - unsigned getGEPCost(Type *PointeeType, const Value *Ptr, - ArrayRef Operands) { + int getGEPCost(Type *PointeeType, const Value *Ptr, + ArrayRef Operands) { // In the basic model, we just assume that all-constant GEPs will be folded // into their uses via addressing modes. for (unsigned Idx = 0, Size = Operands.size(); Idx != Size; ++Idx) @@ -128,6 +128,8 @@ public: return TTI::TCC_Basic * (NumArgs + 1); } + unsigned getInliningThresholdMultiplier() { return 1; } + unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy, ArrayRef ParamTys) { switch (IID) { @@ -240,6 +242,13 @@ public: bool enableInterleavedAccessVectorization() { return false; } + bool isFPVectorizationPotentiallyUnsafe() { return false; } + + bool allowsMisalignedMemoryAccesses(unsigned BitWidth, + unsigned AddressSpace, + unsigned Alignment, + bool *Fast) { return false; } + TTI::PopcntSupportKind getPopcntSupport(unsigned IntTyWidthInBit) { return TTI::PSK_Software; } @@ -248,6 +257,11 @@ public: unsigned getFPOpCost(Type *Ty) { return TargetTransformInfo::TCC_Basic; } + int getIntImmCodeSizeCost(unsigned Opcode, unsigned Idx, const APInt &Imm, + Type *Ty) { + return 0; + } + unsigned getIntImmCost(const APInt &Imm, Type *Ty) { return TTI::TCC_Basic; } unsigned getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, @@ -264,6 +278,8 @@ public: unsigned getRegisterBitWidth(bool Vector) { return 32; } + unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) { return 128; } + unsigned getCacheLineSize() { return 0; } unsigned getPrefetchDistance() { return 0; } @@ -289,6 +305,11 @@ public: unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) { return 1; } + unsigned getExtractWithExtendCost(unsigned Opcode, Type *Dst, + VectorType *VecTy, unsigned Index) { + return 1; + } + unsigned getCFInstrCost(unsigned Opcode) { return 1; } unsigned getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy) { @@ -324,11 +345,11 @@ public: } unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef Tys) { + ArrayRef Tys, FastMathFlags FMF) { return 1; } unsigned getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, - ArrayRef Args) { + ArrayRef Args, FastMathFlags FMF) { return 1; } @@ -412,8 +433,8 @@ public: using BaseT::getGEPCost; - unsigned getGEPCost(Type *PointeeType, const Value *Ptr, - ArrayRef Operands) { + int getGEPCost(Type *PointeeType, const Value *Ptr, + ArrayRef Operands) { const GlobalValue *BaseGV = nullptr; if (Ptr != nullptr) { // TODO: will remove this when pointers have an opaque type. diff --git a/include/llvm/Analysis/TypeMetadataUtils.h b/include/llvm/Analysis/TypeMetadataUtils.h new file mode 100644 index 0000000000000000000000000000000000000000..c3f688f5d7f12c6ee1198eef9aa5e8e29d49366f --- /dev/null +++ b/include/llvm/Analysis/TypeMetadataUtils.h @@ -0,0 +1,45 @@ +//===- TypeMetadataUtils.h - Utilities related to type metadata --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains functions that make it easier to manipulate type metadata +// for devirtualization. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_TYPEMETADATAUTILS_H +#define LLVM_ANALYSIS_TYPEMETADATAUTILS_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/CallSite.h" + +namespace llvm { + +/// A call site that could be devirtualized. +struct DevirtCallSite { + /// The offset from the address point to the virtual function. + uint64_t Offset; + /// The call site itself. + CallSite CS; +}; + +/// Given a call to the intrinsic @llvm.type.test, find all devirtualizable +/// call sites based on the call and return them in DevirtCalls. +void findDevirtualizableCallsForTypeTest( + SmallVectorImpl &DevirtCalls, + SmallVectorImpl &Assumes, CallInst *CI); + +/// Given a call to the intrinsic @llvm.type.checked.load, find all +/// devirtualizable call sites based on the call and return them in DevirtCalls. +void findDevirtualizableCallsForTypeCheckedLoad( + SmallVectorImpl &DevirtCalls, + SmallVectorImpl &LoadedPtrs, + SmallVectorImpl &Preds, bool &HasNonCallUses, CallInst *CI); +} + +#endif diff --git a/include/llvm/Analysis/ValueTracking.h b/include/llvm/Analysis/ValueTracking.h index 6357e1ff54d00b5b579fb2151fd5528c821ac845..2c6221d4933f8f9f145464cab19e34d2c8ad5305 100644 --- a/include/llvm/Analysis/ValueTracking.h +++ b/include/llvm/Analysis/ValueTracking.h @@ -15,17 +15,20 @@ #ifndef LLVM_ANALYSIS_VALUETRACKING_H #define LLVM_ANALYSIS_VALUETRACKING_H -#include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/Support/DataTypes.h" namespace llvm { +template class ArrayRef; class APInt; class AddOperator; class AssumptionCache; class DataLayout; class DominatorTree; + class GEPOperator; class Instruction; class Loop; class LoopInfo; @@ -34,6 +37,10 @@ namespace llvm { class TargetLibraryInfo; class Value; + namespace Intrinsic { + enum ID : unsigned; + } + /// Determine which bits of V are known to be either zero or one and return /// them in the KnownZero/KnownOne bit sets. /// @@ -58,29 +65,29 @@ namespace llvm { const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// ComputeSignBit - Determine whether the sign bit is known to be zero or - /// one. Convenience wrapper around computeKnownBits. + /// Determine whether the sign bit is known to be zero or one. Convenience + /// wrapper around computeKnownBits. void ComputeSignBit(Value *V, bool &KnownZero, bool &KnownOne, const DataLayout &DL, unsigned Depth = 0, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// isKnownToBeAPowerOfTwo - Return true if the given value is known to have - /// exactly one bit set when defined. For vectors return true if every - /// element is known to be a power of two when defined. Supports values with - /// integer or pointer type and vectors of integers. If 'OrZero' is set then - /// return true if the given value is either a power of two or zero. + /// Return true if the given value is known to have exactly one bit set when + /// defined. For vectors return true if every element is known to be a power + /// of two when defined. Supports values with integer or pointer type and + /// vectors of integers. If 'OrZero' is set, then return true if the given + /// value is either a power of two or zero. bool isKnownToBeAPowerOfTwo(Value *V, const DataLayout &DL, bool OrZero = false, unsigned Depth = 0, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// isKnownNonZero - Return true if the given value is known to be non-zero - /// when defined. For vectors return true if every element is known to be - /// non-zero when defined. Supports values with integer or pointer type and - /// vectors of integers. + /// Return true if the given value is known to be non-zero when defined. For + /// vectors, return true if every element is known to be non-zero when + /// defined. Supports values with integer or pointer type and vectors of + /// integers. bool isKnownNonZero(Value *V, const DataLayout &DL, unsigned Depth = 0, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, @@ -99,16 +106,23 @@ namespace llvm { const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// isKnownNonEqual - Return true if the given values are known to be - /// non-equal when defined. Supports scalar integer types only. + /// Returns true if the given value is known be negative (i.e. non-positive + /// and non-zero). + bool isKnownNegative(Value *V, const DataLayout &DL, unsigned Depth = 0, + AssumptionCache *AC = nullptr, + const Instruction *CxtI = nullptr, + const DominatorTree *DT = nullptr); + + /// Return true if the given values are known to be non-equal when defined. + /// Supports scalar integer types only. bool isKnownNonEqual(Value *V1, Value *V2, const DataLayout &DL, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use - /// this predicate to simplify operations downstream. Mask is known to be - /// zero for bits that V cannot have. + /// Return true if 'V & Mask' is known to be zero. We use this predicate to + /// simplify operations downstream. Mask is known to be zero for bits that V + /// cannot have. /// /// This function is defined on values with integer type, values with pointer /// type, and vectors of integers. In the case @@ -120,48 +134,52 @@ namespace llvm { const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// ComputeNumSignBits - Return the number of times the sign bit of the - /// register is replicated into the other bits. We know that at least 1 bit - /// is always equal to the sign bit (itself), but other cases can give us - /// information. For example, immediately after an "ashr X, 2", we know that - /// the top 3 bits are all equal to each other, so we return 3. - /// - /// 'Op' must have a scalar integer type. - /// + /// Return the number of times the sign bit of the register is replicated into + /// the other bits. We know that at least 1 bit is always equal to the sign + /// bit (itself), but other cases can give us information. For example, + /// immediately after an "ashr X, 2", we know that the top 3 bits are all + /// equal to each other, so we return 3. For vectors, return the number of + /// sign bits for the vector element with the mininum number of known sign + /// bits. unsigned ComputeNumSignBits(Value *Op, const DataLayout &DL, unsigned Depth = 0, AssumptionCache *AC = nullptr, const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); - /// ComputeMultiple - This function computes the integer multiple of Base that - /// equals V. If successful, it returns true and returns the multiple in - /// Multiple. If unsuccessful, it returns false. Also, if V can be - /// simplified to an integer, then the simplified V is returned in Val. Look - /// through sext only if LookThroughSExt=true. + /// This function computes the integer multiple of Base that equals V. If + /// successful, it returns true and returns the multiple in Multiple. If + /// unsuccessful, it returns false. Also, if V can be simplified to an + /// integer, then the simplified V is returned in Val. Look through sext only + /// if LookThroughSExt=true. bool ComputeMultiple(Value *V, unsigned Base, Value *&Multiple, bool LookThroughSExt = false, unsigned Depth = 0); - /// CannotBeNegativeZero - Return true if we can prove that the specified FP - /// value is never equal to -0.0. - /// - bool CannotBeNegativeZero(const Value *V, unsigned Depth = 0); - - /// CannotBeOrderedLessThanZero - Return true if we can prove that the - /// specified FP value is either a NaN or never less than 0.0. - /// - bool CannotBeOrderedLessThanZero(const Value *V, unsigned Depth = 0); - - /// isBytewiseValue - If the specified value can be set by repeating the same - /// byte in memory, return the i8 value that it is represented with. This is - /// true for all i8 values obviously, but is also true for i32 0, i32 -1, - /// i16 0xF0F0, double 0.0 etc. If the value can't be handled with a repeated - /// byte store (e.g. i16 0x1234), return null. + /// Map a call instruction to an intrinsic ID. Libcalls which have equivalent + /// intrinsics are treated as-if they were intrinsics. + Intrinsic::ID getIntrinsicForCallSite(ImmutableCallSite ICS, + const TargetLibraryInfo *TLI); + + /// Return true if we can prove that the specified FP value is never equal to + /// -0.0. + bool CannotBeNegativeZero(const Value *V, const TargetLibraryInfo *TLI, + unsigned Depth = 0); + + /// Return true if we can prove that the specified FP value is either a NaN or + /// never less than 0.0. + bool CannotBeOrderedLessThanZero(const Value *V, const TargetLibraryInfo *TLI, + unsigned Depth = 0); + + /// If the specified value can be set by repeating the same byte in memory, + /// return the i8 value that it is represented with. This is true for all i8 + /// values obviously, but is also true for i32 0, i32 -1, i16 0xF0F0, double + /// 0.0 etc. If the value can't be handled with a repeated byte store (e.g. + /// i16 0x1234), return null. Value *isBytewiseValue(Value *V); - /// FindInsertedValue - Given an aggregrate and an sequence of indices, see if - /// the scalar value indexed is already around as a register, for example if - /// it were inserted directly into the aggregrate. + /// Given an aggregrate and an sequence of indices, see if the scalar value + /// indexed is already around as a register, for example if it were inserted + /// directly into the aggregrate. /// /// If InsertBefore is not null, this function will duplicate (modified) /// insertvalues when a part of a nested struct is extracted. @@ -169,9 +187,8 @@ namespace llvm { ArrayRef idx_range, Instruction *InsertBefore = nullptr); - /// GetPointerBaseWithConstantOffset - Analyze the specified pointer to see if - /// it can be expressed as a base pointer plus a constant offset. Return the - /// base and offset to the caller. + /// Analyze the specified pointer to see if it can be expressed as a base + /// pointer plus a constant offset. Return the base and offset to the caller. Value *GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, const DataLayout &DL); static inline const Value * @@ -181,24 +198,28 @@ namespace llvm { DL); } - /// getConstantStringInfo - This function computes the length of a - /// null-terminated C string pointed to by V. If successful, it returns true - /// and returns the string in Str. If unsuccessful, it returns false. This - /// does not include the trailing nul character by default. If TrimAtNul is - /// set to false, then this returns any trailing nul characters as well as any - /// other characters that come after it. + /// Returns true if the GEP is based on a pointer to a string (array of i8), + /// and is indexing into this string. + bool isGEPBasedOnPointerToString(const GEPOperator *GEP); + + /// This function computes the length of a null-terminated C string pointed to + /// by V. If successful, it returns true and returns the string in Str. If + /// unsuccessful, it returns false. This does not include the trailing null + /// character by default. If TrimAtNul is set to false, then this returns any + /// trailing null characters as well as any other characters that come after + /// it. bool getConstantStringInfo(const Value *V, StringRef &Str, uint64_t Offset = 0, bool TrimAtNul = true); - /// GetStringLength - If we can compute the length of the string pointed to by - /// the specified pointer, return 'len+1'. If we can't, return 0. + /// If we can compute the length of the string pointed to by the specified + /// pointer, return 'len+1'. If we can't, return 0. uint64_t GetStringLength(Value *V); - /// GetUnderlyingObject - This method strips off any GEP address adjustments - /// and pointer casts from the specified value, returning the original object - /// being addressed. Note that the returned value has pointer type if the - /// specified value does. If the MaxLookup value is non-zero, it limits the - /// number of instructions to be stripped off. + /// This method strips off any GEP address adjustments and pointer casts from + /// the specified value, returning the original object being addressed. Note + /// that the returned value has pointer type if the specified value does. If + /// the MaxLookup value is non-zero, it limits the number of instructions to + /// be stripped off. Value *GetUnderlyingObject(Value *V, const DataLayout &DL, unsigned MaxLookup = 6); static inline const Value *GetUnderlyingObject(const Value *V, @@ -239,13 +260,11 @@ namespace llvm { const DataLayout &DL, LoopInfo *LI = nullptr, unsigned MaxLookup = 6); - /// onlyUsedByLifetimeMarkers - Return true if the only users of this pointer - /// are lifetime markers. + /// Return true if the only users of this pointer are lifetime markers. bool onlyUsedByLifetimeMarkers(const Value *V); - /// isSafeToSpeculativelyExecute - Return true if the instruction does not - /// have any effects besides calculating the result and does not have - /// undefined behavior. + /// Return true if the instruction does not have any effects besides + /// calculating the result and does not have undefined behavior. /// /// This method never returns true for an instruction that returns true for /// mayHaveSideEffects; however, this method also does some other checks in @@ -269,8 +288,7 @@ namespace llvm { /// for such instructions, moving them may change the resulting value. bool isSafeToSpeculativelyExecute(const Value *V, const Instruction *CtxI = nullptr, - const DominatorTree *DT = nullptr, - const TargetLibraryInfo *TLI = nullptr); + const DominatorTree *DT = nullptr); /// Returns true if the result or effects of the given instructions \p I /// depend on or influence global memory. @@ -282,19 +300,18 @@ namespace llvm { /// operands are not memory dependent. bool mayBeMemoryDependent(const Instruction &I); - /// isKnownNonNull - Return true if this pointer couldn't possibly be null by - /// its definition. This returns true for allocas, non-extern-weak globals - /// and byval arguments. - bool isKnownNonNull(const Value *V, const TargetLibraryInfo *TLI = nullptr); + /// Return true if this pointer couldn't possibly be null by its definition. + /// This returns true for allocas, non-extern-weak globals, and byval + /// arguments. + bool isKnownNonNull(const Value *V); - /// isKnownNonNullAt - Return true if this pointer couldn't possibly be null. - /// If the context instruction is specified perform context-sensitive analysis - /// and return true if the pointer couldn't possibly be null at the specified + /// Return true if this pointer couldn't possibly be null. If the context + /// instruction is specified, perform context-sensitive analysis and return + /// true if the pointer couldn't possibly be null at the specified /// instruction. bool isKnownNonNullAt(const Value *V, const Instruction *CtxI = nullptr, - const DominatorTree *DT = nullptr, - const TargetLibraryInfo *TLI = nullptr); + const DominatorTree *DT = nullptr); /// Return true if it is valid to use the assumptions provided by an /// assume intrinsic, I, at the point in the control-flow identified by the @@ -325,6 +342,11 @@ namespace llvm { const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); + /// Returns true if the arithmetic part of the \p II 's result is + /// used only along the paths control dependent on the computation + /// not overflowing, \p II being an .with.overflow intrinsic. + bool isOverflowIntrinsicNoWrap(IntrinsicInst *II, DominatorTree &DT); + /// Return true if this function can prove that the instruction I will /// always transfer execution to one of its successors (including the next /// instruction that follows within a basic block). E.g. this is not @@ -429,18 +451,20 @@ namespace llvm { /// E.g. if RangeMD is !{i32 0, i32 10, i32 15, i32 20} then return [0, 20). ConstantRange getConstantRangeFromMetadata(MDNode &RangeMD); - /// Return true if RHS is known to be implied by LHS. A & B must be i1 - /// (boolean) values or a vector of such values. Note that the truth table for - /// implication is the same as <=u on i1 values (but not <=s!). The truth - /// table for both is: + /// Return true if RHS is known to be implied true by LHS. Return false if + /// RHS is known to be implied false by LHS. Otherwise, return None if no + /// implication can be made. + /// A & B must be i1 (boolean) values or a vector of such values. Note that + /// the truth table for implication is the same as <=u on i1 values (but not + /// <=s!). The truth table for both is: /// | T | F (B) /// T | T | F /// F | T | T /// (A) - bool isImpliedCondition(Value *LHS, Value *RHS, const DataLayout &DL, - unsigned Depth = 0, AssumptionCache *AC = nullptr, - const Instruction *CxtI = nullptr, - const DominatorTree *DT = nullptr); + Optional isImpliedCondition( + Value *LHS, Value *RHS, const DataLayout &DL, bool InvertAPred = false, + unsigned Depth = 0, AssumptionCache *AC = nullptr, + const Instruction *CxtI = nullptr, const DominatorTree *DT = nullptr); } // end namespace llvm #endif diff --git a/include/llvm/Analysis/VectorUtils.h b/include/llvm/Analysis/VectorUtils.h index 531803adf5e487c0a3535f71fd6a372b2aafd4ad..eaa068b89c774c7d06e5648fd3d1125a816e9163 100644 --- a/include/llvm/Analysis/VectorUtils.h +++ b/include/llvm/Analysis/VectorUtils.h @@ -14,15 +14,13 @@ #ifndef LLVM_TRANSFORMS_UTILS_VECTORUTILS_H #define LLVM_TRANSFORMS_UTILS_VECTORUTILS_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/MapVector.h" #include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Intrinsics.h" namespace llvm { -struct DemandedBits; +template class ArrayRef; +class DemandedBits; class GetElementPtrInst; class Loop; class ScalarEvolution; @@ -30,6 +28,10 @@ class TargetTransformInfo; class Type; class Value; +namespace Intrinsic { +enum ID : unsigned; +} + /// \brief Identify if the intrinsic is trivially vectorizable. /// This method returns true if the intrinsic's argument types are all /// scalars for the scalar form of the intrinsic and all vectors for @@ -40,26 +42,11 @@ bool isTriviallyVectorizable(Intrinsic::ID ID); /// ctlz,cttz and powi special intrinsics whose argument is scalar. bool hasVectorInstrinsicScalarOpd(Intrinsic::ID ID, unsigned ScalarOpdIdx); -/// \brief Identify if call has a unary float signature -/// It returns input intrinsic ID if call has a single argument, -/// argument type and call instruction type should be floating -/// point type and call should only reads memory. -/// else return not_intrinsic. -Intrinsic::ID checkUnaryFloatSignature(const CallInst &I, - Intrinsic::ID ValidIntrinsicID); - -/// \brief Identify if call has a binary float signature -/// It returns input intrinsic ID if call has two arguments, -/// arguments type and call instruction type should be floating -/// point type and call should only reads memory. -/// else return not_intrinsic. -Intrinsic::ID checkBinaryFloatSignature(const CallInst &I, - Intrinsic::ID ValidIntrinsicID); - /// \brief Returns intrinsic ID for call. /// For the input call instruction it finds mapping intrinsic and returns /// its intrinsic ID, in case it does not found it return not_intrinsic. -Intrinsic::ID getIntrinsicIDForCall(CallInst *CI, const TargetLibraryInfo *TLI); +Intrinsic::ID getVectorIntrinsicIDForCall(const CallInst *CI, + const TargetLibraryInfo *TLI); /// \brief Find the operand of the GEP that should be checked for consecutive /// stores. This ignores trailing indices that have no effect on the final @@ -126,7 +113,16 @@ MapVector computeMinimumValueSizes(ArrayRef Blocks, DemandedBits &DB, const TargetTransformInfo *TTI=nullptr); - + +/// Specifically, let Kinds = [MD_tbaa, MD_alias_scope, MD_noalias, MD_fpmath, +/// MD_nontemporal]. For K in Kinds, we get the MDNode for K from each of the +/// elements of VL, compute their "intersection" (i.e., the most generic +/// metadata value that covers all of the individual values), and set I's +/// metadata for M equal to the intersection value. +/// +/// This function always sets a (possibly null) value for each K in Kinds. +Instruction *propagateMetadata(Instruction *I, ArrayRef VL); + } // llvm namespace #endif diff --git a/include/llvm/Bitcode/BitcodeWriterPass.h b/include/llvm/Bitcode/BitcodeWriterPass.h index a4521bfc5630ae9eaa11c6530b44261fbfc3bea4..946255b878a6dc8858f1419d094e4bacb7a651fe 100644 --- a/include/llvm/Bitcode/BitcodeWriterPass.h +++ b/include/llvm/Bitcode/BitcodeWriterPass.h @@ -16,12 +16,12 @@ #define LLVM_BITCODE_BITCODEWRITERPASS_H #include "llvm/ADT/StringRef.h" +#include "llvm/IR/PassManager.h" namespace llvm { class Module; class ModulePass; class raw_ostream; -class PreservedAnalyses; /// \brief Create and return a pass that writes the module to the specified /// ostream. Note that this pass is designed for use with the legacy pass @@ -30,11 +30,15 @@ class PreservedAnalyses; /// If \c ShouldPreserveUseListOrder, encode use-list order so it can be /// reproduced when deserialized. /// -/// If \c EmitSummaryIndex, emit the summary index (currently -/// for use in ThinLTO optimization). +/// If \c EmitSummaryIndex, emit the summary index (currently for use in ThinLTO +/// optimization). +/// +/// If \c EmitModuleHash, compute and emit the module hash in the bitcode +/// (currently for use in ThinLTO incremental build). ModulePass *createBitcodeWriterPass(raw_ostream &Str, bool ShouldPreserveUseListOrder = false, - bool EmitSummaryIndex = false); + bool EmitSummaryIndex = false, + bool EmitModuleHash = false); /// \brief Pass for writing a module of IR out to a bitcode file. /// @@ -44,6 +48,7 @@ class BitcodeWriterPass { raw_ostream &OS; bool ShouldPreserveUseListOrder; bool EmitSummaryIndex; + bool EmitModuleHash; public: /// \brief Construct a bitcode writer pass around a particular output stream. @@ -55,13 +60,14 @@ public: /// for use in ThinLTO optimization). explicit BitcodeWriterPass(raw_ostream &OS, bool ShouldPreserveUseListOrder = false, - bool EmitSummaryIndex = false) + bool EmitSummaryIndex = false, + bool EmitModuleHash = false) : OS(OS), ShouldPreserveUseListOrder(ShouldPreserveUseListOrder), - EmitSummaryIndex(EmitSummaryIndex) {} + EmitSummaryIndex(EmitSummaryIndex), EmitModuleHash(EmitModuleHash) {} /// \brief Run the bitcode writer pass, and output the module to the selected /// output stream. - PreservedAnalyses run(Module &M); + PreservedAnalyses run(Module &M, ModuleAnalysisManager &); static StringRef name() { return "BitcodeWriterPass"; } }; diff --git a/include/llvm/Bitcode/BitstreamReader.h b/include/llvm/Bitcode/BitstreamReader.h index 628a83cb0de0396b285526ae8be57977a40bd01f..b331ceea051c32212fcf09346ee8ba05247f1f08 100644 --- a/include/llvm/Bitcode/BitstreamReader.h +++ b/include/llvm/Bitcode/BitstreamReader.h @@ -446,6 +446,8 @@ public: using SimpleBitstreamCursor::canSkipToPos; using SimpleBitstreamCursor::AtEndOfStream; using SimpleBitstreamCursor::GetCurrentBitNo; + using SimpleBitstreamCursor::getCurrentByteNo; + using SimpleBitstreamCursor::getPointerToByte; using SimpleBitstreamCursor::getBitStreamReader; using SimpleBitstreamCursor::JumpToBit; using SimpleBitstreamCursor::fillCurWord; diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index 3d0752628c76c834a15b2efd6244a36e3704ef42..52d4f01b798528751d83c018f7285ac4ab2f7be9 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -22,7 +22,7 @@ namespace llvm { namespace bitc { - // The only top-level block type defined is for a module. +// The only top-level block type defined is for a module. enum BlockIDs { // Blocks MODULE_BLOCK_ID = FIRST_APPLICATION_BLOCKID, @@ -70,452 +70,468 @@ enum IdentificationCodes { /// also accepts N-1. enum { BITCODE_CURRENT_EPOCH = 0 }; - /// MODULE blocks have a number of optional fields and subblocks. - enum ModuleCodes { - MODULE_CODE_VERSION = 1, // VERSION: [version#] - MODULE_CODE_TRIPLE = 2, // TRIPLE: [strchr x N] - MODULE_CODE_DATALAYOUT = 3, // DATALAYOUT: [strchr x N] - MODULE_CODE_ASM = 4, // ASM: [strchr x N] - MODULE_CODE_SECTIONNAME = 5, // SECTIONNAME: [strchr x N] - - // FIXME: Remove DEPLIB in 4.0. - MODULE_CODE_DEPLIB = 6, // DEPLIB: [strchr x N] - - // GLOBALVAR: [pointer type, isconst, initid, - // linkage, alignment, section, visibility, threadlocal] - MODULE_CODE_GLOBALVAR = 7, - - // FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment, - // section, visibility, gc, unnamed_addr] - MODULE_CODE_FUNCTION = 8, - - // ALIAS: [alias type, aliasee val#, linkage, visibility] - MODULE_CODE_ALIAS_OLD = 9, - - // MODULE_CODE_PURGEVALS: [numvals] - MODULE_CODE_PURGEVALS = 10, - - MODULE_CODE_GCNAME = 11, // GCNAME: [strchr x N] - MODULE_CODE_COMDAT = 12, // COMDAT: [selection_kind, name] - - MODULE_CODE_VSTOFFSET = 13, // VSTOFFSET: [offset] - - // ALIAS: [alias value type, addrspace, aliasee val#, linkage, visibility] - MODULE_CODE_ALIAS = 14, - - MODULE_CODE_METADATA_VALUES_UNUSED = 15, - - // SOURCE_FILENAME: [namechar x N] - MODULE_CODE_SOURCE_FILENAME = 16, - }; - - /// PARAMATTR blocks have code for defining a parameter attribute set. - enum AttributeCodes { - // FIXME: Remove `PARAMATTR_CODE_ENTRY_OLD' in 4.0 - PARAMATTR_CODE_ENTRY_OLD = 1, // ENTRY: [paramidx0, attr0, - // paramidx1, attr1...] - PARAMATTR_CODE_ENTRY = 2, // ENTRY: [paramidx0, attrgrp0, - // paramidx1, attrgrp1, ...] - PARAMATTR_GRP_CODE_ENTRY = 3 // ENTRY: [id, attr0, att1, ...] - }; - - /// TYPE blocks have codes for each type primitive they use. - enum TypeCodes { - TYPE_CODE_NUMENTRY = 1, // NUMENTRY: [numentries] - - // Type Codes - TYPE_CODE_VOID = 2, // VOID - TYPE_CODE_FLOAT = 3, // FLOAT - TYPE_CODE_DOUBLE = 4, // DOUBLE - TYPE_CODE_LABEL = 5, // LABEL - TYPE_CODE_OPAQUE = 6, // OPAQUE - TYPE_CODE_INTEGER = 7, // INTEGER: [width] - TYPE_CODE_POINTER = 8, // POINTER: [pointee type] - - TYPE_CODE_FUNCTION_OLD = 9, // FUNCTION: [vararg, attrid, retty, - // paramty x N] - - TYPE_CODE_HALF = 10, // HALF - - TYPE_CODE_ARRAY = 11, // ARRAY: [numelts, eltty] - TYPE_CODE_VECTOR = 12, // VECTOR: [numelts, eltty] - - // These are not with the other floating point types because they're - // a late addition, and putting them in the right place breaks - // binary compatibility. - TYPE_CODE_X86_FP80 = 13, // X86 LONG DOUBLE - TYPE_CODE_FP128 = 14, // LONG DOUBLE (112 bit mantissa) - TYPE_CODE_PPC_FP128= 15, // PPC LONG DOUBLE (2 doubles) - - TYPE_CODE_METADATA = 16, // METADATA - - TYPE_CODE_X86_MMX = 17, // X86 MMX - - TYPE_CODE_STRUCT_ANON = 18, // STRUCT_ANON: [ispacked, eltty x N] - TYPE_CODE_STRUCT_NAME = 19, // STRUCT_NAME: [strchr x N] - TYPE_CODE_STRUCT_NAMED = 20,// STRUCT_NAMED: [ispacked, eltty x N] - - TYPE_CODE_FUNCTION = 21, // FUNCTION: [vararg, retty, paramty x N] - - TYPE_CODE_TOKEN = 22 // TOKEN - }; - - enum OperandBundleTagCode { - OPERAND_BUNDLE_TAG = 1, // TAG: [strchr x N] - }; - - // The type symbol table only has one code (TST_ENTRY_CODE). - enum TypeSymtabCodes { - TST_CODE_ENTRY = 1 // TST_ENTRY: [typeid, namechar x N] - }; - - // Value symbol table codes. - enum ValueSymtabCodes { - VST_CODE_ENTRY = 1, // VST_ENTRY: [valueid, namechar x N] - VST_CODE_BBENTRY = 2, // VST_BBENTRY: [bbid, namechar x N] - VST_CODE_FNENTRY = 3, // VST_FNENTRY: [valueid, offset, namechar x N] - // VST_COMBINED_GVDEFENTRY: [valueid, sumoffset, guid] - VST_CODE_COMBINED_GVDEFENTRY = 4, - // VST_COMBINED_ENTRY: [valueid, refguid] - VST_CODE_COMBINED_ENTRY = 5 - }; - - // The module path symbol table only has one code (MST_CODE_ENTRY). - enum ModulePathSymtabCodes { - MST_CODE_ENTRY = 1, // MST_ENTRY: [modid, namechar x N] - }; - - // The summary section uses different codes in the per-module - // and combined index cases. - enum GlobalValueSummarySymtabCodes { - // PERMODULE: [valueid, linkage, instcount, numrefs, numrefs x valueid, - // n x (valueid, callsitecount)] - FS_PERMODULE = 1, - // PERMODULE_PROFILE: [valueid, linkage, instcount, numrefs, - // numrefs x valueid, - // n x (valueid, callsitecount, profilecount)] - FS_PERMODULE_PROFILE = 2, - // PERMODULE_GLOBALVAR_INIT_REFS: [valueid, linkage, n x valueid] - FS_PERMODULE_GLOBALVAR_INIT_REFS = 3, - // COMBINED: [modid, linkage, instcount, numrefs, numrefs x valueid, - // n x (valueid, callsitecount)] - FS_COMBINED = 4, - // COMBINED_PROFILE: [modid, linkage, instcount, numrefs, - // numrefs x valueid, - // n x (valueid, callsitecount, profilecount)] - FS_COMBINED_PROFILE = 5, - // COMBINED_GLOBALVAR_INIT_REFS: [modid, linkage, n x valueid] - FS_COMBINED_GLOBALVAR_INIT_REFS = 6, - }; - - enum MetadataCodes { - METADATA_STRING_OLD = 1, // MDSTRING: [values] - METADATA_VALUE = 2, // VALUE: [type num, value num] - METADATA_NODE = 3, // NODE: [n x md num] - METADATA_NAME = 4, // STRING: [values] - METADATA_DISTINCT_NODE = 5, // DISTINCT_NODE: [n x md num] - METADATA_KIND = 6, // [n x [id, name]] - METADATA_LOCATION = 7, // [distinct, line, col, scope, inlined-at?] - METADATA_OLD_NODE = 8, // OLD_NODE: [n x (type num, value num)] - METADATA_OLD_FN_NODE = 9, // OLD_FN_NODE: [n x (type num, value num)] - METADATA_NAMED_NODE = 10, // NAMED_NODE: [n x mdnodes] - METADATA_ATTACHMENT = 11, // [m x [value, [n x [id, mdnode]]] - METADATA_GENERIC_DEBUG = 12, // [distinct, tag, vers, header, n x md num] - METADATA_SUBRANGE = 13, // [distinct, count, lo] - METADATA_ENUMERATOR = 14, // [distinct, value, name] - METADATA_BASIC_TYPE = 15, // [distinct, tag, name, size, align, enc] - METADATA_FILE = 16, // [distinct, filename, directory] - METADATA_DERIVED_TYPE = 17, // [distinct, ...] - METADATA_COMPOSITE_TYPE= 18, // [distinct, ...] - METADATA_SUBROUTINE_TYPE=19, // [distinct, flags, types] - METADATA_COMPILE_UNIT = 20, // [distinct, ...] - METADATA_SUBPROGRAM = 21, // [distinct, ...] - METADATA_LEXICAL_BLOCK = 22, // [distinct, scope, file, line, column] - METADATA_LEXICAL_BLOCK_FILE=23,//[distinct, scope, file, discriminator] - METADATA_NAMESPACE = 24, // [distinct, scope, file, name, line] - METADATA_TEMPLATE_TYPE = 25, // [distinct, scope, name, type, ...] - METADATA_TEMPLATE_VALUE= 26, // [distinct, scope, name, type, value, ...] - METADATA_GLOBAL_VAR = 27, // [distinct, ...] - METADATA_LOCAL_VAR = 28, // [distinct, ...] - METADATA_EXPRESSION = 29, // [distinct, n x element] - METADATA_OBJC_PROPERTY = 30, // [distinct, name, file, line, ...] - METADATA_IMPORTED_ENTITY=31, // [distinct, tag, scope, entity, line, name] - METADATA_MODULE = 32, // [distinct, scope, name, ...] - METADATA_MACRO = 33, // [distinct, macinfo, line, name, value] - METADATA_MACRO_FILE = 34, // [distinct, macinfo, line, file, ...] - METADATA_STRINGS = 35, // [count, offset] blob([lengths][chars]) - }; - - // The constants block (CONSTANTS_BLOCK_ID) describes emission for each - // constant and maintains an implicit current type value. - enum ConstantsCodes { - CST_CODE_SETTYPE = 1, // SETTYPE: [typeid] - CST_CODE_NULL = 2, // NULL - CST_CODE_UNDEF = 3, // UNDEF - CST_CODE_INTEGER = 4, // INTEGER: [intval] - CST_CODE_WIDE_INTEGER = 5, // WIDE_INTEGER: [n x intval] - CST_CODE_FLOAT = 6, // FLOAT: [fpval] - CST_CODE_AGGREGATE = 7, // AGGREGATE: [n x value number] - CST_CODE_STRING = 8, // STRING: [values] - CST_CODE_CSTRING = 9, // CSTRING: [values] - CST_CODE_CE_BINOP = 10, // CE_BINOP: [opcode, opval, opval] - CST_CODE_CE_CAST = 11, // CE_CAST: [opcode, opty, opval] - CST_CODE_CE_GEP = 12, // CE_GEP: [n x operands] - CST_CODE_CE_SELECT = 13, // CE_SELECT: [opval, opval, opval] - CST_CODE_CE_EXTRACTELT = 14, // CE_EXTRACTELT: [opty, opval, opval] - CST_CODE_CE_INSERTELT = 15, // CE_INSERTELT: [opval, opval, opval] - CST_CODE_CE_SHUFFLEVEC = 16, // CE_SHUFFLEVEC: [opval, opval, opval] - CST_CODE_CE_CMP = 17, // CE_CMP: [opty, opval, opval, pred] - CST_CODE_INLINEASM_OLD = 18, // INLINEASM: [sideeffect|alignstack, - // asmstr,conststr] - CST_CODE_CE_SHUFVEC_EX = 19, // SHUFVEC_EX: [opty, opval, opval, opval] - CST_CODE_CE_INBOUNDS_GEP = 20,// INBOUNDS_GEP: [n x operands] - CST_CODE_BLOCKADDRESS = 21, // CST_CODE_BLOCKADDRESS [fnty, fnval, bb#] - CST_CODE_DATA = 22, // DATA: [n x elements] - CST_CODE_INLINEASM = 23 // INLINEASM: [sideeffect|alignstack| - // asmdialect,asmstr,conststr] - }; - - /// CastOpcodes - These are values used in the bitcode files to encode which - /// cast a CST_CODE_CE_CAST or a XXX refers to. The values of these enums - /// have no fixed relation to the LLVM IR enum values. Changing these will - /// break compatibility with old files. - enum CastOpcodes { - CAST_TRUNC = 0, - CAST_ZEXT = 1, - CAST_SEXT = 2, - CAST_FPTOUI = 3, - CAST_FPTOSI = 4, - CAST_UITOFP = 5, - CAST_SITOFP = 6, - CAST_FPTRUNC = 7, - CAST_FPEXT = 8, - CAST_PTRTOINT = 9, - CAST_INTTOPTR = 10, - CAST_BITCAST = 11, - CAST_ADDRSPACECAST = 12 - }; - - /// BinaryOpcodes - These are values used in the bitcode files to encode which - /// binop a CST_CODE_CE_BINOP or a XXX refers to. The values of these enums - /// have no fixed relation to the LLVM IR enum values. Changing these will - /// break compatibility with old files. - enum BinaryOpcodes { - BINOP_ADD = 0, - BINOP_SUB = 1, - BINOP_MUL = 2, - BINOP_UDIV = 3, - BINOP_SDIV = 4, // overloaded for FP - BINOP_UREM = 5, - BINOP_SREM = 6, // overloaded for FP - BINOP_SHL = 7, - BINOP_LSHR = 8, - BINOP_ASHR = 9, - BINOP_AND = 10, - BINOP_OR = 11, - BINOP_XOR = 12 - }; - - /// These are values used in the bitcode files to encode AtomicRMW operations. - /// The values of these enums have no fixed relation to the LLVM IR enum - /// values. Changing these will break compatibility with old files. - enum RMWOperations { - RMW_XCHG = 0, - RMW_ADD = 1, - RMW_SUB = 2, - RMW_AND = 3, - RMW_NAND = 4, - RMW_OR = 5, - RMW_XOR = 6, - RMW_MAX = 7, - RMW_MIN = 8, - RMW_UMAX = 9, - RMW_UMIN = 10 - }; - - /// OverflowingBinaryOperatorOptionalFlags - Flags for serializing - /// OverflowingBinaryOperator's SubclassOptionalData contents. - enum OverflowingBinaryOperatorOptionalFlags { - OBO_NO_UNSIGNED_WRAP = 0, - OBO_NO_SIGNED_WRAP = 1 - }; - - /// PossiblyExactOperatorOptionalFlags - Flags for serializing - /// PossiblyExactOperator's SubclassOptionalData contents. - enum PossiblyExactOperatorOptionalFlags { - PEO_EXACT = 0 - }; - - /// Encoded AtomicOrdering values. - enum AtomicOrderingCodes { - ORDERING_NOTATOMIC = 0, - ORDERING_UNORDERED = 1, - ORDERING_MONOTONIC = 2, - ORDERING_ACQUIRE = 3, - ORDERING_RELEASE = 4, - ORDERING_ACQREL = 5, - ORDERING_SEQCST = 6 - }; - - /// Encoded SynchronizationScope values. - enum AtomicSynchScopeCodes { - SYNCHSCOPE_SINGLETHREAD = 0, - SYNCHSCOPE_CROSSTHREAD = 1 - }; - - /// Markers and flags for call instruction. - enum CallMarkersFlags { - CALL_TAIL = 0, - CALL_CCONV = 1, - CALL_MUSTTAIL = 14, - CALL_EXPLICIT_TYPE = 15, - CALL_NOTAIL = 16, - CALL_FMF = 17 // Call has optional fast-math-flags. - }; - - // The function body block (FUNCTION_BLOCK_ID) describes function bodies. It - // can contain a constant block (CONSTANTS_BLOCK_ID). - enum FunctionCodes { - FUNC_CODE_DECLAREBLOCKS = 1, // DECLAREBLOCKS: [n] - - FUNC_CODE_INST_BINOP = 2, // BINOP: [opcode, ty, opval, opval] - FUNC_CODE_INST_CAST = 3, // CAST: [opcode, ty, opty, opval] - FUNC_CODE_INST_GEP_OLD = 4, // GEP: [n x operands] - FUNC_CODE_INST_SELECT = 5, // SELECT: [ty, opval, opval, opval] - FUNC_CODE_INST_EXTRACTELT = 6, // EXTRACTELT: [opty, opval, opval] - FUNC_CODE_INST_INSERTELT = 7, // INSERTELT: [ty, opval, opval, opval] - FUNC_CODE_INST_SHUFFLEVEC = 8, // SHUFFLEVEC: [ty, opval, opval, opval] - FUNC_CODE_INST_CMP = 9, // CMP: [opty, opval, opval, pred] - - FUNC_CODE_INST_RET = 10, // RET: [opty,opval] - FUNC_CODE_INST_BR = 11, // BR: [bb#, bb#, cond] or [bb#] - FUNC_CODE_INST_SWITCH = 12, // SWITCH: [opty, op0, op1, ...] - FUNC_CODE_INST_INVOKE = 13, // INVOKE: [attr, fnty, op0,op1, ...] - // 14 is unused. - FUNC_CODE_INST_UNREACHABLE = 15, // UNREACHABLE - - FUNC_CODE_INST_PHI = 16, // PHI: [ty, val0,bb0, ...] - // 17 is unused. - // 18 is unused. - FUNC_CODE_INST_ALLOCA = 19, // ALLOCA: [instty, opty, op, align] - FUNC_CODE_INST_LOAD = 20, // LOAD: [opty, op, align, vol] - // 21 is unused. - // 22 is unused. - FUNC_CODE_INST_VAARG = 23, // VAARG: [valistty, valist, instty] - // This store code encodes the pointer type, rather than the value type - // this is so information only available in the pointer type (e.g. address - // spaces) is retained. - FUNC_CODE_INST_STORE_OLD = 24, // STORE: [ptrty,ptr,val, align, vol] - // 25 is unused. - FUNC_CODE_INST_EXTRACTVAL = 26, // EXTRACTVAL: [n x operands] - FUNC_CODE_INST_INSERTVAL = 27, // INSERTVAL: [n x operands] - // fcmp/icmp returning Int1TY or vector of Int1Ty. Same as CMP, exists to - // support legacy vicmp/vfcmp instructions. - FUNC_CODE_INST_CMP2 = 28, // CMP2: [opty, opval, opval, pred] - // new select on i1 or [N x i1] - FUNC_CODE_INST_VSELECT = 29, // VSELECT: [ty,opval,opval,predty,pred] - FUNC_CODE_INST_INBOUNDS_GEP_OLD = 30, // INBOUNDS_GEP: [n x operands] - FUNC_CODE_INST_INDIRECTBR = 31, // INDIRECTBR: [opty, op0, op1, ...] - // 32 is unused. - FUNC_CODE_DEBUG_LOC_AGAIN = 33, // DEBUG_LOC_AGAIN - - FUNC_CODE_INST_CALL = 34, // CALL: [attr, cc, fnty, fnid, args...] - - FUNC_CODE_DEBUG_LOC = 35, // DEBUG_LOC: [Line,Col,ScopeVal, IAVal] - FUNC_CODE_INST_FENCE = 36, // FENCE: [ordering, synchscope] - FUNC_CODE_INST_CMPXCHG_OLD = 37, // CMPXCHG: [ptrty,ptr,cmp,new, align, vol, - // ordering, synchscope] - FUNC_CODE_INST_ATOMICRMW = 38, // ATOMICRMW: [ptrty,ptr,val, operation, - // align, vol, - // ordering, synchscope] - FUNC_CODE_INST_RESUME = 39, // RESUME: [opval] - FUNC_CODE_INST_LANDINGPAD_OLD = 40, // LANDINGPAD: [ty,val,val,num,id0,val0...] - FUNC_CODE_INST_LOADATOMIC = 41, // LOAD: [opty, op, align, vol, - // ordering, synchscope] - FUNC_CODE_INST_STOREATOMIC_OLD = 42, // STORE: [ptrty,ptr,val, align, vol - // ordering, synchscope] - FUNC_CODE_INST_GEP = 43, // GEP: [inbounds, n x operands] - FUNC_CODE_INST_STORE = 44, // STORE: [ptrty,ptr,valty,val, align, vol] - FUNC_CODE_INST_STOREATOMIC = 45, // STORE: [ptrty,ptr,val, align, vol - FUNC_CODE_INST_CMPXCHG = 46, // CMPXCHG: [ptrty,ptr,valty,cmp,new, align, - // vol,ordering,synchscope] - FUNC_CODE_INST_LANDINGPAD = 47, // LANDINGPAD: [ty,val,num,id0,val0...] - FUNC_CODE_INST_CLEANUPRET = 48, // CLEANUPRET: [val] or [val,bb#] - FUNC_CODE_INST_CATCHRET = 49, // CATCHRET: [val,bb#] - FUNC_CODE_INST_CATCHPAD = 50, // CATCHPAD: [bb#,bb#,num,args...] - FUNC_CODE_INST_CLEANUPPAD = 51, // CLEANUPPAD: [num,args...] - FUNC_CODE_INST_CATCHSWITCH = 52, // CATCHSWITCH: [num,args...] or [num,args...,bb] - // 53 is unused. - // 54 is unused. - FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...] - }; - - enum UseListCodes { - USELIST_CODE_DEFAULT = 1, // DEFAULT: [index..., value-id] - USELIST_CODE_BB = 2 // BB: [index..., bb-id] - }; - - enum AttributeKindCodes { - // = 0 is unused - ATTR_KIND_ALIGNMENT = 1, - ATTR_KIND_ALWAYS_INLINE = 2, - ATTR_KIND_BY_VAL = 3, - ATTR_KIND_INLINE_HINT = 4, - ATTR_KIND_IN_REG = 5, - ATTR_KIND_MIN_SIZE = 6, - ATTR_KIND_NAKED = 7, - ATTR_KIND_NEST = 8, - ATTR_KIND_NO_ALIAS = 9, - ATTR_KIND_NO_BUILTIN = 10, - ATTR_KIND_NO_CAPTURE = 11, - ATTR_KIND_NO_DUPLICATE = 12, - ATTR_KIND_NO_IMPLICIT_FLOAT = 13, - ATTR_KIND_NO_INLINE = 14, - ATTR_KIND_NON_LAZY_BIND = 15, - ATTR_KIND_NO_RED_ZONE = 16, - ATTR_KIND_NO_RETURN = 17, - ATTR_KIND_NO_UNWIND = 18, - ATTR_KIND_OPTIMIZE_FOR_SIZE = 19, - ATTR_KIND_READ_NONE = 20, - ATTR_KIND_READ_ONLY = 21, - ATTR_KIND_RETURNED = 22, - ATTR_KIND_RETURNS_TWICE = 23, - ATTR_KIND_S_EXT = 24, - ATTR_KIND_STACK_ALIGNMENT = 25, - ATTR_KIND_STACK_PROTECT = 26, - ATTR_KIND_STACK_PROTECT_REQ = 27, - ATTR_KIND_STACK_PROTECT_STRONG = 28, - ATTR_KIND_STRUCT_RET = 29, - ATTR_KIND_SANITIZE_ADDRESS = 30, - ATTR_KIND_SANITIZE_THREAD = 31, - ATTR_KIND_SANITIZE_MEMORY = 32, - ATTR_KIND_UW_TABLE = 33, - ATTR_KIND_Z_EXT = 34, - ATTR_KIND_BUILTIN = 35, - ATTR_KIND_COLD = 36, - ATTR_KIND_OPTIMIZE_NONE = 37, - ATTR_KIND_IN_ALLOCA = 38, - ATTR_KIND_NON_NULL = 39, - ATTR_KIND_JUMP_TABLE = 40, - ATTR_KIND_DEREFERENCEABLE = 41, - ATTR_KIND_DEREFERENCEABLE_OR_NULL = 42, - ATTR_KIND_CONVERGENT = 43, - ATTR_KIND_SAFESTACK = 44, - ATTR_KIND_ARGMEMONLY = 45, - ATTR_KIND_SWIFT_SELF = 46, - ATTR_KIND_SWIFT_ERROR = 47, - ATTR_KIND_NO_RECURSE = 48, - ATTR_KIND_INACCESSIBLEMEM_ONLY = 49, - ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50 - }; - - enum ComdatSelectionKindCodes { - COMDAT_SELECTION_KIND_ANY = 1, - COMDAT_SELECTION_KIND_EXACT_MATCH = 2, - COMDAT_SELECTION_KIND_LARGEST = 3, - COMDAT_SELECTION_KIND_NO_DUPLICATES = 4, - COMDAT_SELECTION_KIND_SAME_SIZE = 5, - }; +/// MODULE blocks have a number of optional fields and subblocks. +enum ModuleCodes { + MODULE_CODE_VERSION = 1, // VERSION: [version#] + MODULE_CODE_TRIPLE = 2, // TRIPLE: [strchr x N] + MODULE_CODE_DATALAYOUT = 3, // DATALAYOUT: [strchr x N] + MODULE_CODE_ASM = 4, // ASM: [strchr x N] + MODULE_CODE_SECTIONNAME = 5, // SECTIONNAME: [strchr x N] + + // FIXME: Remove DEPLIB in 4.0. + MODULE_CODE_DEPLIB = 6, // DEPLIB: [strchr x N] + + // GLOBALVAR: [pointer type, isconst, initid, + // linkage, alignment, section, visibility, threadlocal] + MODULE_CODE_GLOBALVAR = 7, + + // FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment, + // section, visibility, gc, unnamed_addr] + MODULE_CODE_FUNCTION = 8, + + // ALIAS: [alias type, aliasee val#, linkage, visibility] + MODULE_CODE_ALIAS_OLD = 9, + + // MODULE_CODE_PURGEVALS: [numvals] + MODULE_CODE_PURGEVALS = 10, + + MODULE_CODE_GCNAME = 11, // GCNAME: [strchr x N] + MODULE_CODE_COMDAT = 12, // COMDAT: [selection_kind, name] + + MODULE_CODE_VSTOFFSET = 13, // VSTOFFSET: [offset] + + // ALIAS: [alias value type, addrspace, aliasee val#, linkage, visibility] + MODULE_CODE_ALIAS = 14, + + MODULE_CODE_METADATA_VALUES_UNUSED = 15, + + // SOURCE_FILENAME: [namechar x N] + MODULE_CODE_SOURCE_FILENAME = 16, + + // HASH: [5*i32] + MODULE_CODE_HASH = 17, + + // IFUNC: [ifunc value type, addrspace, resolver val#, linkage, visibility] + MODULE_CODE_IFUNC = 18, +}; + +/// PARAMATTR blocks have code for defining a parameter attribute set. +enum AttributeCodes { + // FIXME: Remove `PARAMATTR_CODE_ENTRY_OLD' in 4.0 + PARAMATTR_CODE_ENTRY_OLD = 1, // ENTRY: [paramidx0, attr0, + // paramidx1, attr1...] + PARAMATTR_CODE_ENTRY = 2, // ENTRY: [paramidx0, attrgrp0, + // paramidx1, attrgrp1, ...] + PARAMATTR_GRP_CODE_ENTRY = 3 // ENTRY: [id, attr0, att1, ...] +}; + +/// TYPE blocks have codes for each type primitive they use. +enum TypeCodes { + TYPE_CODE_NUMENTRY = 1, // NUMENTRY: [numentries] + + // Type Codes + TYPE_CODE_VOID = 2, // VOID + TYPE_CODE_FLOAT = 3, // FLOAT + TYPE_CODE_DOUBLE = 4, // DOUBLE + TYPE_CODE_LABEL = 5, // LABEL + TYPE_CODE_OPAQUE = 6, // OPAQUE + TYPE_CODE_INTEGER = 7, // INTEGER: [width] + TYPE_CODE_POINTER = 8, // POINTER: [pointee type] + + TYPE_CODE_FUNCTION_OLD = 9, // FUNCTION: [vararg, attrid, retty, + // paramty x N] + + TYPE_CODE_HALF = 10, // HALF + + TYPE_CODE_ARRAY = 11, // ARRAY: [numelts, eltty] + TYPE_CODE_VECTOR = 12, // VECTOR: [numelts, eltty] + + // These are not with the other floating point types because they're + // a late addition, and putting them in the right place breaks + // binary compatibility. + TYPE_CODE_X86_FP80 = 13, // X86 LONG DOUBLE + TYPE_CODE_FP128 = 14, // LONG DOUBLE (112 bit mantissa) + TYPE_CODE_PPC_FP128 = 15, // PPC LONG DOUBLE (2 doubles) + + TYPE_CODE_METADATA = 16, // METADATA + + TYPE_CODE_X86_MMX = 17, // X86 MMX + + TYPE_CODE_STRUCT_ANON = 18, // STRUCT_ANON: [ispacked, eltty x N] + TYPE_CODE_STRUCT_NAME = 19, // STRUCT_NAME: [strchr x N] + TYPE_CODE_STRUCT_NAMED = 20, // STRUCT_NAMED: [ispacked, eltty x N] + + TYPE_CODE_FUNCTION = 21, // FUNCTION: [vararg, retty, paramty x N] + + TYPE_CODE_TOKEN = 22 // TOKEN +}; + +enum OperandBundleTagCode { + OPERAND_BUNDLE_TAG = 1, // TAG: [strchr x N] +}; + +// The type symbol table only has one code (TST_ENTRY_CODE). +enum TypeSymtabCodes { + TST_CODE_ENTRY = 1 // TST_ENTRY: [typeid, namechar x N] +}; + +// Value symbol table codes. +enum ValueSymtabCodes { + VST_CODE_ENTRY = 1, // VST_ENTRY: [valueid, namechar x N] + VST_CODE_BBENTRY = 2, // VST_BBENTRY: [bbid, namechar x N] + VST_CODE_FNENTRY = 3, // VST_FNENTRY: [valueid, offset, namechar x N] + // VST_COMBINED_ENTRY: [valueid, refguid] + VST_CODE_COMBINED_ENTRY = 5 +}; + +// The module path symbol table only has one code (MST_CODE_ENTRY). +enum ModulePathSymtabCodes { + MST_CODE_ENTRY = 1, // MST_ENTRY: [modid, namechar x N] + MST_CODE_HASH = 2, // MST_HASH: [5*i32] +}; + +// The summary section uses different codes in the per-module +// and combined index cases. +enum GlobalValueSummarySymtabCodes { + // PERMODULE: [valueid, flags, instcount, numrefs, numrefs x valueid, + // n x (valueid, callsitecount)] + FS_PERMODULE = 1, + // PERMODULE_PROFILE: [valueid, flags, instcount, numrefs, + // numrefs x valueid, + // n x (valueid, callsitecount, profilecount)] + FS_PERMODULE_PROFILE = 2, + // PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, n x valueid] + FS_PERMODULE_GLOBALVAR_INIT_REFS = 3, + // COMBINED: [valueid, modid, flags, instcount, numrefs, numrefs x valueid, + // n x (valueid, callsitecount)] + FS_COMBINED = 4, + // COMBINED_PROFILE: [valueid, modid, flags, instcount, numrefs, + // numrefs x valueid, + // n x (valueid, callsitecount, profilecount)] + FS_COMBINED_PROFILE = 5, + // COMBINED_GLOBALVAR_INIT_REFS: [valueid, modid, flags, n x valueid] + FS_COMBINED_GLOBALVAR_INIT_REFS = 6, + // ALIAS: [valueid, flags, valueid] + FS_ALIAS = 7, + // COMBINED_ALIAS: [valueid, modid, flags, valueid] + FS_COMBINED_ALIAS = 8, + // COMBINED_ORIGINAL_NAME: [original_name_hash] + FS_COMBINED_ORIGINAL_NAME = 9, + // VERSION of the summary, bumped when adding flags for instance. + FS_VERSION = 10, +}; + +enum MetadataCodes { + METADATA_STRING_OLD = 1, // MDSTRING: [values] + METADATA_VALUE = 2, // VALUE: [type num, value num] + METADATA_NODE = 3, // NODE: [n x md num] + METADATA_NAME = 4, // STRING: [values] + METADATA_DISTINCT_NODE = 5, // DISTINCT_NODE: [n x md num] + METADATA_KIND = 6, // [n x [id, name]] + METADATA_LOCATION = 7, // [distinct, line, col, scope, inlined-at?] + METADATA_OLD_NODE = 8, // OLD_NODE: [n x (type num, value num)] + METADATA_OLD_FN_NODE = 9, // OLD_FN_NODE: [n x (type num, value num)] + METADATA_NAMED_NODE = 10, // NAMED_NODE: [n x mdnodes] + METADATA_ATTACHMENT = 11, // [m x [value, [n x [id, mdnode]]] + METADATA_GENERIC_DEBUG = 12, // [distinct, tag, vers, header, n x md num] + METADATA_SUBRANGE = 13, // [distinct, count, lo] + METADATA_ENUMERATOR = 14, // [distinct, value, name] + METADATA_BASIC_TYPE = 15, // [distinct, tag, name, size, align, enc] + METADATA_FILE = 16, // [distinct, filename, directory] + METADATA_DERIVED_TYPE = 17, // [distinct, ...] + METADATA_COMPOSITE_TYPE = 18, // [distinct, ...] + METADATA_SUBROUTINE_TYPE = 19, // [distinct, flags, types, cc] + METADATA_COMPILE_UNIT = 20, // [distinct, ...] + METADATA_SUBPROGRAM = 21, // [distinct, ...] + METADATA_LEXICAL_BLOCK = 22, // [distinct, scope, file, line, column] + METADATA_LEXICAL_BLOCK_FILE = 23, //[distinct, scope, file, discriminator] + METADATA_NAMESPACE = 24, // [distinct, scope, file, name, line] + METADATA_TEMPLATE_TYPE = 25, // [distinct, scope, name, type, ...] + METADATA_TEMPLATE_VALUE = 26, // [distinct, scope, name, type, value, ...] + METADATA_GLOBAL_VAR = 27, // [distinct, ...] + METADATA_LOCAL_VAR = 28, // [distinct, ...] + METADATA_EXPRESSION = 29, // [distinct, n x element] + METADATA_OBJC_PROPERTY = 30, // [distinct, name, file, line, ...] + METADATA_IMPORTED_ENTITY = 31, // [distinct, tag, scope, entity, line, name] + METADATA_MODULE = 32, // [distinct, scope, name, ...] + METADATA_MACRO = 33, // [distinct, macinfo, line, name, value] + METADATA_MACRO_FILE = 34, // [distinct, macinfo, line, file, ...] + METADATA_STRINGS = 35, // [count, offset] blob([lengths][chars]) + METADATA_GLOBAL_DECL_ATTACHMENT = 36, // [valueid, n x [id, mdnode]] +}; + +// The constants block (CONSTANTS_BLOCK_ID) describes emission for each +// constant and maintains an implicit current type value. +enum ConstantsCodes { + CST_CODE_SETTYPE = 1, // SETTYPE: [typeid] + CST_CODE_NULL = 2, // NULL + CST_CODE_UNDEF = 3, // UNDEF + CST_CODE_INTEGER = 4, // INTEGER: [intval] + CST_CODE_WIDE_INTEGER = 5, // WIDE_INTEGER: [n x intval] + CST_CODE_FLOAT = 6, // FLOAT: [fpval] + CST_CODE_AGGREGATE = 7, // AGGREGATE: [n x value number] + CST_CODE_STRING = 8, // STRING: [values] + CST_CODE_CSTRING = 9, // CSTRING: [values] + CST_CODE_CE_BINOP = 10, // CE_BINOP: [opcode, opval, opval] + CST_CODE_CE_CAST = 11, // CE_CAST: [opcode, opty, opval] + CST_CODE_CE_GEP = 12, // CE_GEP: [n x operands] + CST_CODE_CE_SELECT = 13, // CE_SELECT: [opval, opval, opval] + CST_CODE_CE_EXTRACTELT = 14, // CE_EXTRACTELT: [opty, opval, opval] + CST_CODE_CE_INSERTELT = 15, // CE_INSERTELT: [opval, opval, opval] + CST_CODE_CE_SHUFFLEVEC = 16, // CE_SHUFFLEVEC: [opval, opval, opval] + CST_CODE_CE_CMP = 17, // CE_CMP: [opty, opval, opval, pred] + CST_CODE_INLINEASM_OLD = 18, // INLINEASM: [sideeffect|alignstack, + // asmstr,conststr] + CST_CODE_CE_SHUFVEC_EX = 19, // SHUFVEC_EX: [opty, opval, opval, opval] + CST_CODE_CE_INBOUNDS_GEP = 20, // INBOUNDS_GEP: [n x operands] + CST_CODE_BLOCKADDRESS = 21, // CST_CODE_BLOCKADDRESS [fnty, fnval, bb#] + CST_CODE_DATA = 22, // DATA: [n x elements] + CST_CODE_INLINEASM = 23 // INLINEASM: [sideeffect|alignstack| + // asmdialect,asmstr,conststr] +}; + +/// CastOpcodes - These are values used in the bitcode files to encode which +/// cast a CST_CODE_CE_CAST or a XXX refers to. The values of these enums +/// have no fixed relation to the LLVM IR enum values. Changing these will +/// break compatibility with old files. +enum CastOpcodes { + CAST_TRUNC = 0, + CAST_ZEXT = 1, + CAST_SEXT = 2, + CAST_FPTOUI = 3, + CAST_FPTOSI = 4, + CAST_UITOFP = 5, + CAST_SITOFP = 6, + CAST_FPTRUNC = 7, + CAST_FPEXT = 8, + CAST_PTRTOINT = 9, + CAST_INTTOPTR = 10, + CAST_BITCAST = 11, + CAST_ADDRSPACECAST = 12 +}; + +/// BinaryOpcodes - These are values used in the bitcode files to encode which +/// binop a CST_CODE_CE_BINOP or a XXX refers to. The values of these enums +/// have no fixed relation to the LLVM IR enum values. Changing these will +/// break compatibility with old files. +enum BinaryOpcodes { + BINOP_ADD = 0, + BINOP_SUB = 1, + BINOP_MUL = 2, + BINOP_UDIV = 3, + BINOP_SDIV = 4, // overloaded for FP + BINOP_UREM = 5, + BINOP_SREM = 6, // overloaded for FP + BINOP_SHL = 7, + BINOP_LSHR = 8, + BINOP_ASHR = 9, + BINOP_AND = 10, + BINOP_OR = 11, + BINOP_XOR = 12 +}; + +/// These are values used in the bitcode files to encode AtomicRMW operations. +/// The values of these enums have no fixed relation to the LLVM IR enum +/// values. Changing these will break compatibility with old files. +enum RMWOperations { + RMW_XCHG = 0, + RMW_ADD = 1, + RMW_SUB = 2, + RMW_AND = 3, + RMW_NAND = 4, + RMW_OR = 5, + RMW_XOR = 6, + RMW_MAX = 7, + RMW_MIN = 8, + RMW_UMAX = 9, + RMW_UMIN = 10 +}; + +/// OverflowingBinaryOperatorOptionalFlags - Flags for serializing +/// OverflowingBinaryOperator's SubclassOptionalData contents. +enum OverflowingBinaryOperatorOptionalFlags { + OBO_NO_UNSIGNED_WRAP = 0, + OBO_NO_SIGNED_WRAP = 1 +}; + +/// PossiblyExactOperatorOptionalFlags - Flags for serializing +/// PossiblyExactOperator's SubclassOptionalData contents. +enum PossiblyExactOperatorOptionalFlags { PEO_EXACT = 0 }; + +/// Encoded AtomicOrdering values. +enum AtomicOrderingCodes { + ORDERING_NOTATOMIC = 0, + ORDERING_UNORDERED = 1, + ORDERING_MONOTONIC = 2, + ORDERING_ACQUIRE = 3, + ORDERING_RELEASE = 4, + ORDERING_ACQREL = 5, + ORDERING_SEQCST = 6 +}; + +/// Encoded SynchronizationScope values. +enum AtomicSynchScopeCodes { + SYNCHSCOPE_SINGLETHREAD = 0, + SYNCHSCOPE_CROSSTHREAD = 1 +}; + +/// Markers and flags for call instruction. +enum CallMarkersFlags { + CALL_TAIL = 0, + CALL_CCONV = 1, + CALL_MUSTTAIL = 14, + CALL_EXPLICIT_TYPE = 15, + CALL_NOTAIL = 16, + CALL_FMF = 17 // Call has optional fast-math-flags. +}; + +// The function body block (FUNCTION_BLOCK_ID) describes function bodies. It +// can contain a constant block (CONSTANTS_BLOCK_ID). +enum FunctionCodes { + FUNC_CODE_DECLAREBLOCKS = 1, // DECLAREBLOCKS: [n] + + FUNC_CODE_INST_BINOP = 2, // BINOP: [opcode, ty, opval, opval] + FUNC_CODE_INST_CAST = 3, // CAST: [opcode, ty, opty, opval] + FUNC_CODE_INST_GEP_OLD = 4, // GEP: [n x operands] + FUNC_CODE_INST_SELECT = 5, // SELECT: [ty, opval, opval, opval] + FUNC_CODE_INST_EXTRACTELT = 6, // EXTRACTELT: [opty, opval, opval] + FUNC_CODE_INST_INSERTELT = 7, // INSERTELT: [ty, opval, opval, opval] + FUNC_CODE_INST_SHUFFLEVEC = 8, // SHUFFLEVEC: [ty, opval, opval, opval] + FUNC_CODE_INST_CMP = 9, // CMP: [opty, opval, opval, pred] + + FUNC_CODE_INST_RET = 10, // RET: [opty,opval] + FUNC_CODE_INST_BR = 11, // BR: [bb#, bb#, cond] or [bb#] + FUNC_CODE_INST_SWITCH = 12, // SWITCH: [opty, op0, op1, ...] + FUNC_CODE_INST_INVOKE = 13, // INVOKE: [attr, fnty, op0,op1, ...] + // 14 is unused. + FUNC_CODE_INST_UNREACHABLE = 15, // UNREACHABLE + + FUNC_CODE_INST_PHI = 16, // PHI: [ty, val0,bb0, ...] + // 17 is unused. + // 18 is unused. + FUNC_CODE_INST_ALLOCA = 19, // ALLOCA: [instty, opty, op, align] + FUNC_CODE_INST_LOAD = 20, // LOAD: [opty, op, align, vol] + // 21 is unused. + // 22 is unused. + FUNC_CODE_INST_VAARG = 23, // VAARG: [valistty, valist, instty] + // This store code encodes the pointer type, rather than the value type + // this is so information only available in the pointer type (e.g. address + // spaces) is retained. + FUNC_CODE_INST_STORE_OLD = 24, // STORE: [ptrty,ptr,val, align, vol] + // 25 is unused. + FUNC_CODE_INST_EXTRACTVAL = 26, // EXTRACTVAL: [n x operands] + FUNC_CODE_INST_INSERTVAL = 27, // INSERTVAL: [n x operands] + // fcmp/icmp returning Int1TY or vector of Int1Ty. Same as CMP, exists to + // support legacy vicmp/vfcmp instructions. + FUNC_CODE_INST_CMP2 = 28, // CMP2: [opty, opval, opval, pred] + // new select on i1 or [N x i1] + FUNC_CODE_INST_VSELECT = 29, // VSELECT: [ty,opval,opval,predty,pred] + FUNC_CODE_INST_INBOUNDS_GEP_OLD = 30, // INBOUNDS_GEP: [n x operands] + FUNC_CODE_INST_INDIRECTBR = 31, // INDIRECTBR: [opty, op0, op1, ...] + // 32 is unused. + FUNC_CODE_DEBUG_LOC_AGAIN = 33, // DEBUG_LOC_AGAIN + + FUNC_CODE_INST_CALL = 34, // CALL: [attr, cc, fnty, fnid, args...] + + FUNC_CODE_DEBUG_LOC = 35, // DEBUG_LOC: [Line,Col,ScopeVal, IAVal] + FUNC_CODE_INST_FENCE = 36, // FENCE: [ordering, synchscope] + FUNC_CODE_INST_CMPXCHG_OLD = 37, // CMPXCHG: [ptrty,ptr,cmp,new, align, vol, + // ordering, synchscope] + FUNC_CODE_INST_ATOMICRMW = 38, // ATOMICRMW: [ptrty,ptr,val, operation, + // align, vol, + // ordering, synchscope] + FUNC_CODE_INST_RESUME = 39, // RESUME: [opval] + FUNC_CODE_INST_LANDINGPAD_OLD = + 40, // LANDINGPAD: [ty,val,val,num,id0,val0...] + FUNC_CODE_INST_LOADATOMIC = 41, // LOAD: [opty, op, align, vol, + // ordering, synchscope] + FUNC_CODE_INST_STOREATOMIC_OLD = 42, // STORE: [ptrty,ptr,val, align, vol + // ordering, synchscope] + FUNC_CODE_INST_GEP = 43, // GEP: [inbounds, n x operands] + FUNC_CODE_INST_STORE = 44, // STORE: [ptrty,ptr,valty,val, align, vol] + FUNC_CODE_INST_STOREATOMIC = 45, // STORE: [ptrty,ptr,val, align, vol + FUNC_CODE_INST_CMPXCHG = 46, // CMPXCHG: [ptrty,ptr,valty,cmp,new, align, + // vol,ordering,synchscope] + FUNC_CODE_INST_LANDINGPAD = 47, // LANDINGPAD: [ty,val,num,id0,val0...] + FUNC_CODE_INST_CLEANUPRET = 48, // CLEANUPRET: [val] or [val,bb#] + FUNC_CODE_INST_CATCHRET = 49, // CATCHRET: [val,bb#] + FUNC_CODE_INST_CATCHPAD = 50, // CATCHPAD: [bb#,bb#,num,args...] + FUNC_CODE_INST_CLEANUPPAD = 51, // CLEANUPPAD: [num,args...] + FUNC_CODE_INST_CATCHSWITCH = + 52, // CATCHSWITCH: [num,args...] or [num,args...,bb] + // 53 is unused. + // 54 is unused. + FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...] +}; + +enum UseListCodes { + USELIST_CODE_DEFAULT = 1, // DEFAULT: [index..., value-id] + USELIST_CODE_BB = 2 // BB: [index..., bb-id] +}; + +enum AttributeKindCodes { + // = 0 is unused + ATTR_KIND_ALIGNMENT = 1, + ATTR_KIND_ALWAYS_INLINE = 2, + ATTR_KIND_BY_VAL = 3, + ATTR_KIND_INLINE_HINT = 4, + ATTR_KIND_IN_REG = 5, + ATTR_KIND_MIN_SIZE = 6, + ATTR_KIND_NAKED = 7, + ATTR_KIND_NEST = 8, + ATTR_KIND_NO_ALIAS = 9, + ATTR_KIND_NO_BUILTIN = 10, + ATTR_KIND_NO_CAPTURE = 11, + ATTR_KIND_NO_DUPLICATE = 12, + ATTR_KIND_NO_IMPLICIT_FLOAT = 13, + ATTR_KIND_NO_INLINE = 14, + ATTR_KIND_NON_LAZY_BIND = 15, + ATTR_KIND_NO_RED_ZONE = 16, + ATTR_KIND_NO_RETURN = 17, + ATTR_KIND_NO_UNWIND = 18, + ATTR_KIND_OPTIMIZE_FOR_SIZE = 19, + ATTR_KIND_READ_NONE = 20, + ATTR_KIND_READ_ONLY = 21, + ATTR_KIND_RETURNED = 22, + ATTR_KIND_RETURNS_TWICE = 23, + ATTR_KIND_S_EXT = 24, + ATTR_KIND_STACK_ALIGNMENT = 25, + ATTR_KIND_STACK_PROTECT = 26, + ATTR_KIND_STACK_PROTECT_REQ = 27, + ATTR_KIND_STACK_PROTECT_STRONG = 28, + ATTR_KIND_STRUCT_RET = 29, + ATTR_KIND_SANITIZE_ADDRESS = 30, + ATTR_KIND_SANITIZE_THREAD = 31, + ATTR_KIND_SANITIZE_MEMORY = 32, + ATTR_KIND_UW_TABLE = 33, + ATTR_KIND_Z_EXT = 34, + ATTR_KIND_BUILTIN = 35, + ATTR_KIND_COLD = 36, + ATTR_KIND_OPTIMIZE_NONE = 37, + ATTR_KIND_IN_ALLOCA = 38, + ATTR_KIND_NON_NULL = 39, + ATTR_KIND_JUMP_TABLE = 40, + ATTR_KIND_DEREFERENCEABLE = 41, + ATTR_KIND_DEREFERENCEABLE_OR_NULL = 42, + ATTR_KIND_CONVERGENT = 43, + ATTR_KIND_SAFESTACK = 44, + ATTR_KIND_ARGMEMONLY = 45, + ATTR_KIND_SWIFT_SELF = 46, + ATTR_KIND_SWIFT_ERROR = 47, + ATTR_KIND_NO_RECURSE = 48, + ATTR_KIND_INACCESSIBLEMEM_ONLY = 49, + ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50, + ATTR_KIND_ALLOC_SIZE = 51, + ATTR_KIND_WRITEONLY = 52 +}; + +enum ComdatSelectionKindCodes { + COMDAT_SELECTION_KIND_ANY = 1, + COMDAT_SELECTION_KIND_EXACT_MATCH = 2, + COMDAT_SELECTION_KIND_LARGEST = 3, + COMDAT_SELECTION_KIND_NO_DUPLICATES = 4, + COMDAT_SELECTION_KIND_SAME_SIZE = 5, +}; } // End bitc namespace } // End llvm namespace diff --git a/include/llvm/Bitcode/ReaderWriter.h b/include/llvm/Bitcode/ReaderWriter.h index f8582cca8971f721c7a80b8898c3bd9a2a35df95..76a60a0b8d25c7c2c181ed22c203557b9ba2441f 100644 --- a/include/llvm/Bitcode/ReaderWriter.h +++ b/include/llvm/Bitcode/ReaderWriter.h @@ -60,6 +60,11 @@ namespace llvm { std::string getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context); + /// Return true if \p Buffer contains a bitcode file with ObjC code (category + /// or class) in it. + bool isBitcodeContainingObjCCategory(MemoryBufferRef Buffer, + LLVMContext &Context); + /// Read the header of the specified bitcode buffer and extract just the /// producer string information. If successful, this returns a string. On /// error, this returns "". @@ -71,28 +76,14 @@ namespace llvm { LLVMContext &Context); /// Check if the given bitcode buffer contains a summary block. - bool hasGlobalValueSummary(MemoryBufferRef Buffer, - DiagnosticHandlerFunction DiagnosticHandler); + bool + hasGlobalValueSummary(MemoryBufferRef Buffer, + const DiagnosticHandlerFunction &DiagnosticHandler); /// Parse the specified bitcode buffer, returning the module summary index. - /// If IsLazy is true, parse the entire module summary into - /// the index. Otherwise skip the module summary section, and only create - /// an index object with a map from value name to the value's summary offset. - /// The index is used to perform lazy summary reading later. ErrorOr> getModuleSummaryIndex(MemoryBufferRef Buffer, - DiagnosticHandlerFunction DiagnosticHandler, - bool IsLazy = false); - - /// This method supports lazy reading of summary data from the - /// combined index during function importing. When reading the combined index - /// file, getModuleSummaryIndex is first invoked with IsLazy=true. - /// Then this method is called for each value considered for importing, - /// to parse the summary information for the given value name into - /// the index. - std::error_code readGlobalValueSummary( - MemoryBufferRef Buffer, DiagnosticHandlerFunction DiagnosticHandler, - StringRef ValueName, std::unique_ptr Index); + const DiagnosticHandlerFunction &DiagnosticHandler); /// \brief Write the specified module to the specified raw output stream. /// @@ -107,12 +98,17 @@ namespace llvm { /// for use in ThinLTO optimization). void WriteBitcodeToFile(const Module *M, raw_ostream &Out, bool ShouldPreserveUseListOrder = false, - bool EmitSummaryIndex = false); + const ModuleSummaryIndex *Index = nullptr, + bool GenerateHash = false); /// Write the specified module summary index to the given raw output stream, /// where it will be written in a new bitcode block. This is used when - /// writing the combined index file for ThinLTO. - void WriteIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out); + /// writing the combined index file for ThinLTO. When writing a subset of the + /// index for a distributed backend, provide the \p ModuleToSummariesForIndex + /// map. + void WriteIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out, + std::map + *ModuleToSummariesForIndex = nullptr); /// isBitcodeWrapper - Return true if the given bytes are the magic bytes /// for an LLVM IR bitcode wrapper. @@ -171,14 +167,15 @@ namespace llvm { const unsigned char *&BufEnd, bool VerifyBufferSize) { // Must contain the offset and size field! - if (BufEnd - BufPtr < BWH_SizeField + 4) + if (unsigned(BufEnd - BufPtr) < BWH_SizeField + 4) return true; unsigned Offset = support::endian::read32le(&BufPtr[BWH_OffsetField]); unsigned Size = support::endian::read32le(&BufPtr[BWH_SizeField]); + uint64_t BitcodeOffsetEnd = (uint64_t)Offset + (uint64_t)Size; // Verify that Offset+Size fits in the file. - if (VerifyBufferSize && Offset+Size > unsigned(BufEnd-BufPtr)) + if (VerifyBufferSize && BitcodeOffsetEnd > uint64_t(BufEnd-BufPtr)) return true; BufPtr += Offset; BufEnd = BufPtr+Size; diff --git a/include/llvm/CodeGen/Analysis.h b/include/llvm/CodeGen/Analysis.h index 38e64ad3be29acf962edee743bc2ace2af10d149..2e4dc49a1e26bb0e925ef3628bc9938519135adc 100644 --- a/include/llvm/CodeGen/Analysis.h +++ b/include/llvm/CodeGen/Analysis.h @@ -17,10 +17,12 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instructions.h" +#include "llvm/Support/CodeGen.h" namespace llvm { class GlobalValue; diff --git a/include/llvm/CodeGen/AsmPrinter.h b/include/llvm/CodeGen/AsmPrinter.h index 8dbbebfb24b51c3ae282305a894d036fb3e94f9b..de618d17357339bd9201b2c41e657043a92ea7a0 100644 --- a/include/llvm/CodeGen/AsmPrinter.h +++ b/include/llvm/CodeGen/AsmPrinter.h @@ -34,6 +34,7 @@ class ConstantArray; class DIE; class DIEAbbrev; class GCMetadataPrinter; +class GlobalIndirectSymbol; class GlobalValue; class GlobalVariable; class MachineBasicBlock; @@ -147,6 +148,8 @@ public: DwarfDebug *getDwarfDebug() { return DD; } DwarfDebug *getDwarfDebug() const { return DD; } + bool isPositionIndependent() const; + /// Return true if assembly output should contain comments. /// bool isVerbose() const { return VerboseAsm; } @@ -546,6 +549,9 @@ private: void EmitXXStructorList(const DataLayout &DL, const Constant *List, bool isCtor); GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy &C); + /// Emit GlobalAlias or GlobalIFunc. + void emitGlobalIndirectSymbol(Module &M, + const GlobalIndirectSymbol& GIS); }; } diff --git a/include/llvm/CodeGen/BasicTTIImpl.h b/include/llvm/CodeGen/BasicTTIImpl.h index db9960c1aa081eae1fe72044b847dc6a9544caa0..69951afb623c3777aef9ade42fb4091260cac606 100644 --- a/include/llvm/CodeGen/BasicTTIImpl.h +++ b/include/llvm/CodeGen/BasicTTIImpl.h @@ -105,6 +105,11 @@ public: /// \name Scalar TTI Implementations /// @{ + bool allowsMisalignedMemoryAccesses(unsigned BitWidth, unsigned AddressSpace, + unsigned Alignment, bool *Fast) const { + MVT M = MVT::getIntegerVT(BitWidth); + return getTLI()->allowsMisalignedMemoryAccesses(M, AddressSpace, Alignment, Fast); + } bool hasBranchDivergence() { return false; } @@ -152,6 +157,11 @@ public: return getTLI()->isTypeLegal(VT); } + int getGEPCost(Type *PointeeType, const Value *Ptr, + ArrayRef Operands) { + return BaseT::getGEPCost(PointeeType, Ptr, Operands); + } + unsigned getIntrinsicCost(Intrinsic::ID IID, Type *RetTy, ArrayRef Arguments) { return BaseT::getIntrinsicCost(IID, RetTy, Arguments); @@ -216,6 +226,8 @@ public: return BaseT::getOperationCost(Opcode, Ty, OpTy); } + unsigned getInliningThresholdMultiplier() { return 1; } + void getUnrollingPreferences(Loop *L, TTI::UnrollingPreferences &UP) { // This unrolling functionality is target independent, but to provide some // motivation for its intended use, for x86: @@ -313,6 +325,8 @@ public: } // Else, assume that we need to scalarize this op. + // TODO: If one of the types get legalized by splitting, handle this + // similarly to what getCastInstrCost() does. if (Ty->isVectorTy()) { unsigned Num = Ty->getVectorNumElements(); unsigned Cost = static_cast(this) @@ -407,9 +421,25 @@ public: return SrcLT.first * 1; } - // If we are converting vectors and the operation is illegal, or - // if the vectors are legalized to different types, estimate the - // scalarization costs. + // If we are legalizing by splitting, query the concrete TTI for the cost + // of casting the original vector twice. We also need to factor int the + // cost of the split itself. Count that as 1, to be consistent with + // TLI->getTypeLegalizationCost(). + if ((TLI->getTypeAction(Src->getContext(), TLI->getValueType(DL, Src)) == + TargetLowering::TypeSplitVector) || + (TLI->getTypeAction(Dst->getContext(), TLI->getValueType(DL, Dst)) == + TargetLowering::TypeSplitVector)) { + Type *SplitDst = VectorType::get(Dst->getVectorElementType(), + Dst->getVectorNumElements() / 2); + Type *SplitSrc = VectorType::get(Src->getVectorElementType(), + Src->getVectorNumElements() / 2); + T *TTI = static_cast(this); + return TTI->getVectorSplitCost() + + (2 * TTI->getCastInstrCost(Opcode, SplitDst, SplitSrc)); + } + + // In other cases where the source or destination are illegal, assume + // the operation will get scalarized. unsigned Num = Dst->getVectorNumElements(); unsigned Cost = static_cast(this)->getCastInstrCost( Opcode, Dst->getScalarType(), Src->getScalarType()); @@ -433,6 +463,14 @@ public: llvm_unreachable("Unhandled cast"); } + unsigned getExtractWithExtendCost(unsigned Opcode, Type *Dst, + VectorType *VecTy, unsigned Index) { + return static_cast(this)->getVectorInstrCost( + Instruction::ExtractElement, VecTy, Index) + + static_cast(this)->getCastInstrCost(Opcode, Dst, + VecTy->getElementType()); + } + unsigned getCFInstrCost(unsigned Opcode) { // Branches are assumed to be predicted. return 0; @@ -459,6 +497,8 @@ public: } // Otherwise, assume that the cast is scalarized. + // TODO: If one of the types get legalized by splitting, handle this + // similarly to what getCastInstrCost() does. if (ValTy->isVectorTy()) { unsigned Num = ValTy->getVectorNumElements(); if (CondTy) @@ -467,8 +507,7 @@ public: Opcode, ValTy->getScalarType(), CondTy); // Return the cost of multiple scalar invocation plus the cost of - // inserting - // and extracting the values. + // inserting and extracting the values. return getScalarizationOverhead(ValTy, true, false) + Num * Cost; } @@ -532,6 +571,51 @@ public: unsigned Cost = static_cast(this)->getMemoryOpCost( Opcode, VecTy, Alignment, AddressSpace); + // Legalize the vector type, and get the legalized and unlegalized type + // sizes. + MVT VecTyLT = getTLI()->getTypeLegalizationCost(DL, VecTy).second; + unsigned VecTySize = + static_cast(this)->getDataLayout().getTypeStoreSize(VecTy); + unsigned VecTyLTSize = VecTyLT.getStoreSize(); + + // Return the ceiling of dividing A by B. + auto ceil = [](unsigned A, unsigned B) { return (A + B - 1) / B; }; + + // Scale the cost of the memory operation by the fraction of legalized + // instructions that will actually be used. We shouldn't account for the + // cost of dead instructions since they will be removed. + // + // E.g., An interleaved load of factor 8: + // %vec = load <16 x i64>, <16 x i64>* %ptr + // %v0 = shufflevector %vec, undef, <0, 8> + // + // If <16 x i64> is legalized to 8 v2i64 loads, only 2 of the loads will be + // used (those corresponding to elements [0:1] and [8:9] of the unlegalized + // type). The other loads are unused. + // + // We only scale the cost of loads since interleaved store groups aren't + // allowed to have gaps. + if (Opcode == Instruction::Load && VecTySize > VecTyLTSize) { + + // The number of loads of a legal type it will take to represent a load + // of the unlegalized vector type. + unsigned NumLegalInsts = ceil(VecTySize, VecTyLTSize); + + // The number of elements of the unlegalized type that correspond to a + // single legal instruction. + unsigned NumEltsPerLegalInst = ceil(NumElts, NumLegalInsts); + + // Determine which legal instructions will be used. + BitVector UsedInsts(NumLegalInsts, false); + for (unsigned Index : Indices) + for (unsigned Elt = 0; Elt < NumSubElts; ++Elt) + UsedInsts.set((Index + Elt * Factor) / NumEltsPerLegalInst); + + // Scale the cost of the load by the fraction of legal instructions that + // will be used. + Cost *= UsedInsts.count() / NumLegalInsts; + } + // Then plus the cost of interleave operation. if (Opcode == Instruction::Load) { // The interleave cost is similar to extract sub vectors' elements @@ -587,13 +671,14 @@ public: /// Get intrinsic cost based on arguments unsigned getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy, - ArrayRef Args) { + ArrayRef Args, FastMathFlags FMF) { switch (IID) { default: { SmallVector Types; for (Value *Op : Args) Types.push_back(Op->getType()); - return static_cast(this)->getIntrinsicInstrCost(IID, RetTy, Types); + return static_cast(this)->getIntrinsicInstrCost(IID, RetTy, Types, + FMF); } case Intrinsic::masked_scatter: { Value *Mask = Args[3]; @@ -619,8 +704,9 @@ public: /// Get intrinsic cost based on argument types unsigned getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy, - ArrayRef Tys) { - unsigned ISD = 0; + ArrayRef Tys, FastMathFlags FMF) { + SmallVector ISDs; + unsigned SingleCallCost = 10; // Library call cost. Make it expensive. switch (IID) { default: { // Assume that we need to scalarize this intrinsic. @@ -646,74 +732,78 @@ public: return 1; // Return cost of a scalar intrinsic. Assume it to be cheap. unsigned ScalarCost = static_cast(this)->getIntrinsicInstrCost( - IID, ScalarRetTy, ScalarTys); + IID, ScalarRetTy, ScalarTys, FMF); return ScalarCalls * ScalarCost + ScalarizationCost; } // Look for intrinsics that can be lowered directly or turned into a scalar // intrinsic call. case Intrinsic::sqrt: - ISD = ISD::FSQRT; + ISDs.push_back(ISD::FSQRT); break; case Intrinsic::sin: - ISD = ISD::FSIN; + ISDs.push_back(ISD::FSIN); break; case Intrinsic::cos: - ISD = ISD::FCOS; + ISDs.push_back(ISD::FCOS); break; case Intrinsic::exp: - ISD = ISD::FEXP; + ISDs.push_back(ISD::FEXP); break; case Intrinsic::exp2: - ISD = ISD::FEXP2; + ISDs.push_back(ISD::FEXP2); break; case Intrinsic::log: - ISD = ISD::FLOG; + ISDs.push_back(ISD::FLOG); break; case Intrinsic::log10: - ISD = ISD::FLOG10; + ISDs.push_back(ISD::FLOG10); break; case Intrinsic::log2: - ISD = ISD::FLOG2; + ISDs.push_back(ISD::FLOG2); break; case Intrinsic::fabs: - ISD = ISD::FABS; + ISDs.push_back(ISD::FABS); break; case Intrinsic::minnum: - ISD = ISD::FMINNUM; + ISDs.push_back(ISD::FMINNUM); + if (FMF.noNaNs()) + ISDs.push_back(ISD::FMINNAN); break; case Intrinsic::maxnum: - ISD = ISD::FMAXNUM; + ISDs.push_back(ISD::FMAXNUM); + if (FMF.noNaNs()) + ISDs.push_back(ISD::FMAXNAN); break; case Intrinsic::copysign: - ISD = ISD::FCOPYSIGN; + ISDs.push_back(ISD::FCOPYSIGN); break; case Intrinsic::floor: - ISD = ISD::FFLOOR; + ISDs.push_back(ISD::FFLOOR); break; case Intrinsic::ceil: - ISD = ISD::FCEIL; + ISDs.push_back(ISD::FCEIL); break; case Intrinsic::trunc: - ISD = ISD::FTRUNC; + ISDs.push_back(ISD::FTRUNC); break; case Intrinsic::nearbyint: - ISD = ISD::FNEARBYINT; + ISDs.push_back(ISD::FNEARBYINT); break; case Intrinsic::rint: - ISD = ISD::FRINT; + ISDs.push_back(ISD::FRINT); break; case Intrinsic::round: - ISD = ISD::FROUND; + ISDs.push_back(ISD::FROUND); break; case Intrinsic::pow: - ISD = ISD::FPOW; + ISDs.push_back(ISD::FPOW); break; case Intrinsic::fma: - ISD = ISD::FMA; + ISDs.push_back(ISD::FMA); break; case Intrinsic::fmuladd: - ISD = ISD::FMA; + ISDs.push_back(ISD::FMA); break; // FIXME: We should return 0 whenever getIntrinsicCost == TCC_Free. case Intrinsic::lifetime_start: @@ -725,31 +815,48 @@ public: case Intrinsic::masked_load: return static_cast(this) ->getMaskedMemoryOpCost(Instruction::Load, RetTy, 0, 0); + case Intrinsic::ctpop: + ISDs.push_back(ISD::CTPOP); + // In case of legalization use TCC_Expensive. This is cheaper than a + // library call but still not a cheap instruction. + SingleCallCost = TargetTransformInfo::TCC_Expensive; + break; + // FIXME: ctlz, cttz, ... } const TargetLoweringBase *TLI = getTLI(); std::pair LT = TLI->getTypeLegalizationCost(DL, RetTy); - if (TLI->isOperationLegalOrPromote(ISD, LT.second)) { - if (IID == Intrinsic::fabs && - TLI->isFAbsFree(LT.second)) { - return 0; - } + SmallVector LegalCost; + SmallVector CustomCost; + for (unsigned ISD : ISDs) { + if (TLI->isOperationLegalOrPromote(ISD, LT.second)) { + if (IID == Intrinsic::fabs && TLI->isFAbsFree(LT.second)) { + return 0; + } - // The operation is legal. Assume it costs 1. - // If the type is split to multiple registers, assume that there is some - // overhead to this. - // TODO: Once we have extract/insert subvector cost we need to use them. - if (LT.first > 1) - return LT.first * 2; - return LT.first * 1; + // The operation is legal. Assume it costs 1. + // If the type is split to multiple registers, assume that there is some + // overhead to this. + // TODO: Once we have extract/insert subvector cost we need to use them. + if (LT.first > 1) + LegalCost.push_back(LT.first * 2); + else + LegalCost.push_back(LT.first * 1); + } else if (!TLI->isOperationExpand(ISD, LT.second)) { + // If the operation is custom lowered then assume + // that the code is twice as expensive. + CustomCost.push_back(LT.first * 2); + } } - if (!TLI->isOperationExpand(ISD, LT.second)) { - // If the operation is custom lowered then assume - // thare the code is twice as expensive. - return LT.first * 2; - } + auto MinLegalCostI = std::min_element(LegalCost.begin(), LegalCost.end()); + if (MinLegalCostI != LegalCost.end()) + return *MinLegalCostI; + + auto MinCustomCostI = std::min_element(CustomCost.begin(), CustomCost.end()); + if (MinCustomCostI != CustomCost.end()) + return *MinCustomCostI; // If we can't lower fmuladd into an FMA estimate the cost as a floating // point mul followed by an add. @@ -773,7 +880,7 @@ public: ScalarTys.push_back(Ty); } unsigned ScalarCost = static_cast(this)->getIntrinsicInstrCost( - IID, RetTy->getScalarType(), ScalarTys); + IID, RetTy->getScalarType(), ScalarTys, FMF); for (unsigned i = 0, ie = Tys.size(); i != ie; ++i) { if (Tys[i]->isVectorTy()) { ScalarizationCost += getScalarizationOverhead(Tys[i], false, true); @@ -785,7 +892,7 @@ public: } // This is going to be turned into a library call, make it expensive. - return 10; + return SingleCallCost; } /// \brief Compute a cost of the given call instruction. @@ -825,6 +932,8 @@ public: return ShuffleCost + ArithCost + getScalarizationOverhead(Ty, false, true); } + unsigned getVectorSplitCost() { return 1; } + /// @} }; diff --git a/include/llvm/CodeGen/CallingConvLower.h b/include/llvm/CodeGen/CallingConvLower.h index faf4896e467201015bad9b9aa55143c2e6cd97f0..92e58564e04085d3ed39a2edd5a2aff3991474ef 100644 --- a/include/llvm/CodeGen/CallingConvLower.h +++ b/include/llvm/CodeGen/CallingConvLower.h @@ -513,6 +513,14 @@ public: SmallVectorImpl &Forwards, ArrayRef RegParmTypes, CCAssignFn Fn); + /// Returns true if the results of the two calling conventions are compatible. + /// This is usually part of the check for tailcall eligibility. + static bool resultsCompatible(CallingConv::ID CalleeCC, + CallingConv::ID CallerCC, MachineFunction &MF, + LLVMContext &C, + const SmallVectorImpl &Ins, + CCAssignFn CalleeFn, CCAssignFn CallerFn); + private: /// MarkAllocated - Mark a register and all of its aliases as allocated. void MarkAllocated(unsigned Reg); diff --git a/include/llvm/CodeGen/CommandFlags.h b/include/llvm/CodeGen/CommandFlags.h index e0a4b539b74e6831b880e0292d1dde74de3c4630..6376c06768b3a753f0edda3a733beeb66f71d848 100644 --- a/include/llvm/CodeGen/CommandFlags.h +++ b/include/llvm/CodeGen/CommandFlags.h @@ -46,20 +46,23 @@ MAttrs("mattr", cl::desc("Target specific attributes (-mattr=help for details)"), cl::value_desc("a1,+a2,-a3,...")); -cl::opt -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 RelocModel( + "relocation-model", cl::desc("Choose relocation model"), + cl::values( + 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 inline Optional getRelocModel() { + if (RelocModel.getNumOccurrences()) { + Reloc::Model R = RelocModel; + return R; + } + return None; +} cl::opt TMModel("thread-model", @@ -87,6 +90,22 @@ CMModel("code-model", "Large code model"), clEnumValEnd)); +cl::opt +ExceptionModel("exception-model", + cl::desc("exception model"), + cl::init(ExceptionHandling::None), + cl::values(clEnumValN(ExceptionHandling::None, "default", + "default exception handling model"), + clEnumValN(ExceptionHandling::DwarfCFI, "dwarf", + "DWARF-like CFI based exception handling"), + clEnumValN(ExceptionHandling::SjLj, "sjlj", + "SjLj exception handling"), + clEnumValN(ExceptionHandling::ARM, "arm", + "ARM EHABI exceptions"), + clEnumValN(ExceptionHandling::WinEH, "wineh", + "Windows exception model"), + clEnumValEnd)); + cl::opt FileType("filetype", cl::init(TargetMachine::CGFT_AssemblyFile), cl::desc("Choose a file type (not all types are supported by all targets):"), @@ -197,11 +216,6 @@ TrapFuncName("trap-func", cl::Hidden, cl::desc("Emit a call to trap function rather than a trap instruction"), cl::init("")); -cl::opt -EnablePIE("enable-pie", - cl::desc("Assume the creation of a position independent executable."), - cl::init(false)); - cl::opt UseCtors("use-ctors", cl::desc("Use .ctors instead of .init_array."), @@ -216,10 +230,6 @@ cl::opt StartAfter("start-after", cl::value_desc("pass-name"), cl::init("")); -cl::opt - RunPass("run-pass", cl::desc("Run compiler only for one specific pass"), - cl::value_desc("pass-name"), cl::init("")); - cl::opt DataSections("data-sections", cl::desc("Emit data into separate sections"), cl::init(false)); @@ -290,12 +300,12 @@ static inline TargetOptions InitTargetOptionsFromCodeGenFlags() { Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; Options.StackAlignmentOverride = OverrideStackAlignment; Options.StackSymbolOrdering = StackSymbolOrdering; - Options.PositionIndependentExecutable = EnablePIE; Options.UseInitArray = !UseCtors; Options.DataSections = DataSections; Options.FunctionSections = FunctionSections; Options.UniqueSectionNames = UniqueSectionNames; Options.EmulatedTLS = EmulatedTLS; + Options.ExceptionModel = ExceptionModel; Options.MCOptions = InitMCTargetOptionsFromFlags(); Options.JTType = JTableType; diff --git a/include/llvm/CodeGen/DIE.h b/include/llvm/CodeGen/DIE.h index dc8ffa0d0a789c18effda952774d97fab73228f9..7d6e66fa6ec2aab73de92f0409b97d760801676a 100644 --- a/include/llvm/CodeGen/DIE.h +++ b/include/llvm/CodeGen/DIE.h @@ -20,7 +20,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/DwarfStringPoolEntry.h" #include "llvm/Support/Dwarf.h" -#include namespace llvm { class AsmPrinter; @@ -566,7 +565,7 @@ public: typedef iterator_range value_range; typedef iterator_range const_value_range; - value_iterator addValue(BumpPtrAllocator &Alloc, DIEValue V) { + value_iterator addValue(BumpPtrAllocator &Alloc, const DIEValue &V) { List.push_back(*new (Alloc) Node(V)); return value_iterator(ListTy::toIterator(List.back())); } diff --git a/include/llvm/CodeGen/FastISel.h b/include/llvm/CodeGen/FastISel.h index cc4e37059bb86539e13981fab22b3e9b3d12c418..4bff48de38e426d95db8b7ab53352b6b8a2d96f4 100644 --- a/include/llvm/CodeGen/FastISel.h +++ b/include/llvm/CodeGen/FastISel.h @@ -16,7 +16,6 @@ #define LLVM_CODEGEN_FASTISEL_H #include "llvm/ADT/DenseMap.h" -#include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/IntrinsicInst.h" @@ -24,6 +23,8 @@ namespace llvm { +class MachineConstantPool; + /// \brief This is a fast-path instruction selection class that generates poor /// code and doesn't support illegal types or non-trivial lowering, but runs /// quickly. @@ -40,12 +41,15 @@ public: bool IsByVal : 1; bool IsInAlloca : 1; bool IsReturned : 1; + bool IsSwiftSelf : 1; + bool IsSwiftError : 1; uint16_t Alignment; ArgListEntry() : Val(nullptr), Ty(nullptr), IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false), IsNest(false), IsByVal(false), - IsInAlloca(false), IsReturned(false), Alignment(0) {} + IsInAlloca(false), IsReturned(false), IsSwiftSelf(false), + IsSwiftError(false), Alignment(0) {} /// \brief Set CallLoweringInfo attribute flags based on a call instruction /// and called function attributes. @@ -448,7 +452,7 @@ protected: /// \brief Emit an unconditional branch to the given block, unless it is the /// immediate (fall-through) successor, and update the CFG. - void fastEmitBranch(MachineBasicBlock *MBB, DebugLoc DL); + void fastEmitBranch(MachineBasicBlock *MBB, const DebugLoc &DL); /// Emit an unconditional branch to \p FalseMBB, obtains the branch weight /// and adds TrueMBB and FalseMBB to the successor list. diff --git a/include/llvm/CodeGen/FaultMaps.h b/include/llvm/CodeGen/FaultMaps.h index f4b646322143245ca47448c96e0d86759b678d87..9b5a3e1ba0500fa6085a4d86b8f296a1d644646b 100644 --- a/include/llvm/CodeGen/FaultMaps.h +++ b/include/llvm/CodeGen/FaultMaps.h @@ -10,7 +10,6 @@ #ifndef LLVM_CODEGEN_FAULTMAPS_H #define LLVM_CODEGEN_FAULTMAPS_H -#include "llvm/ADT/DenseMap.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Format.h" diff --git a/include/llvm/CodeGen/FunctionLoweringInfo.h b/include/llvm/CodeGen/FunctionLoweringInfo.h index b916c30fddf6d57e8148ef9ba15732056ff8b668..010e34179efc133ed7e9fc22bbff7c8114ac72f4 100644 --- a/include/llvm/CodeGen/FunctionLoweringInfo.h +++ b/include/llvm/CodeGen/FunctionLoweringInfo.h @@ -72,6 +72,37 @@ public: /// MBBMap - A mapping from LLVM basic blocks to their machine code entry. DenseMap MBBMap; + typedef SmallVector SwiftErrorVRegs; + typedef SmallVector SwiftErrorValues; + /// A function can only have a single swifterror argument. And if it does + /// have a swifterror argument, it must be the first entry in + /// SwiftErrorVals. + SwiftErrorValues SwiftErrorVals; + + /// Track the virtual register for each swifterror value in a given basic + /// block. Entries in SwiftErrorVRegs have the same ordering as entries + /// in SwiftErrorVals. + /// Note that another choice that is more straight-forward is to use + /// Map>. It + /// maintains a map from swifterror values to virtual registers for each + /// machine basic block. This choice does not require a one-to-one + /// correspondence between SwiftErrorValues and SwiftErrorVRegs. But because + /// of efficiency concern, we do not choose it. + llvm::DenseMap SwiftErrorMap; + + /// Track the virtual register for each swifterror value at the end of a basic + /// block when we need the assignment of a virtual register before the basic + /// block is visited. When we actually visit the basic block, we will make + /// sure the swifterror value is in the correct virtual register. + llvm::DenseMap + SwiftErrorWorklist; + + /// Find the swifterror virtual register in SwiftErrorMap. We will assert + /// failure when the value does not exist in swifterror map. + unsigned findSwiftErrorVReg(const MachineBasicBlock*, const Value*) const; + /// Set the swifterror virtual register in SwiftErrorMap. + void setSwiftErrorVReg(const MachineBasicBlock *MBB, const Value*, unsigned); + /// ValueMap - Since we emit code for the function a basic block at a time, /// we must remember which virtual registers hold the values for /// cross-basic-block values. @@ -140,7 +171,7 @@ public: struct LiveOutInfo { unsigned NumSignBits : 31; - bool IsValid : 1; + unsigned IsValid : 1; APInt KnownOne, KnownZero; LiveOutInfo() : NumSignBits(0), IsValid(true), KnownOne(1, 0), KnownZero(1, 0) {} diff --git a/include/llvm/CodeGen/GCMetadata.h b/include/llvm/CodeGen/GCMetadata.h index 163117b0781ccc7f55b4afe5484718ec63a42a1b..e6afcbc8ded28a81fc775331976752943fab2464 100644 --- a/include/llvm/CodeGen/GCMetadata.h +++ b/include/llvm/CodeGen/GCMetadata.h @@ -40,6 +40,7 @@ #include "llvm/IR/DebugLoc.h" #include "llvm/Pass.h" #include +#include namespace llvm { class AsmPrinter; @@ -54,7 +55,7 @@ struct GCPoint { DebugLoc Loc; GCPoint(GC::PointKind K, MCSymbol *L, DebugLoc DL) - : Kind(K), Label(L), Loc(DL) {} + : Kind(K), Label(L), Loc(std::move(DL)) {} }; /// GCRoot - Metadata for a pointer to an object managed by the garbage @@ -120,7 +121,7 @@ public: /// addSafePoint - Notes the existence of a safe point. Num is the ID of the /// label just prior to the safe point (if the code generator is using /// MachineModuleInfo). - void addSafePoint(GC::PointKind Kind, MCSymbol *Label, DebugLoc DL) { + void addSafePoint(GC::PointKind Kind, MCSymbol *Label, const DebugLoc &DL) { SafePoints.emplace_back(Kind, Label, DL); } diff --git a/include/llvm/CodeGen/GlobalISel/CallLowering.h b/include/llvm/CodeGen/GlobalISel/CallLowering.h index 117c81c1cafa2763331f367ea3db7e919235db67..bbd0b6d8859385bc67496d9aa3812099a489cc26 100644 --- a/include/llvm/CodeGen/GlobalISel/CallLowering.h +++ b/include/llvm/CodeGen/GlobalISel/CallLowering.h @@ -40,13 +40,13 @@ class CallLowering { public: CallLowering(const TargetLowering *TLI) : TLI(TLI) {} virtual ~CallLowering() {} - + /// This hook must be implemented to lower outgoing return values, described /// by \p Val, into the specified virtual register \p VReg. /// This hook is used by GlobalISel. /// /// \return True if the lowering succeeds, false otherwise. - virtual bool LowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, + virtual bool lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, unsigned VReg) const { return false; } @@ -61,7 +61,7 @@ class CallLowering { /// /// \return True if the lowering succeeded, false otherwise. virtual bool - LowerFormalArguments(MachineIRBuilder &MIRBuilder, + lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function::ArgumentListType &Args, const SmallVectorImpl &VRegs) const { return false; diff --git a/include/llvm/CodeGen/GlobalISel/GISelAccessor.h b/include/llvm/CodeGen/GlobalISel/GISelAccessor.h new file mode 100644 index 0000000000000000000000000000000000000000..7c5ec9f3adc0663fc9b2eae1f8c85989f753f447 --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/GISelAccessor.h @@ -0,0 +1,33 @@ +//===-- GISelAccessor.h - GISel Accessor ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// This file declares the API to access the various APIs related +/// to GlobalISel. +// +//===----------------------------------------------------------------------===/ + +#ifndef LLVM_CODEGEN_GLOBALISEL_GISELACCESSOR_H +#define LLVM_CODEGEN_GLOBALISEL_GISELACCESSOR_H + +namespace llvm { +class CallLowering; +class RegisterBankInfo; + +/// The goal of this helper class is to gather the accessor to all +/// the APIs related to GlobalISel. +/// It should be derived to feature an actual accessor to the GISel APIs. +/// The reason why this is not simply done into the subtarget is to avoid +/// spreading ifdefs around. +struct GISelAccessor { + virtual ~GISelAccessor() {} + virtual const CallLowering *getCallLowering() const { return nullptr;} + virtual const RegisterBankInfo *getRegBankInfo() const { return nullptr;} +}; +} // End namespace llvm; +#endif diff --git a/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/include/llvm/CodeGen/GlobalISel/IRTranslator.h index fcd6e1a3452e85ab8c68d6fefb21aa1868083386..833e87493cad1084c9568771685d04675ef5e0c3 100644 --- a/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ b/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -66,32 +66,47 @@ private: DenseMap BBToMBB; - /* A bunch of methods targeting ADD, SUB, etc. */ - // Return true if the translation was successful, false - // otherwise. - // Note: The MachineIRBuilder would encapsulate a - // MachineRegisterInfo to create virtual registers. - // - // Algo: - // 1. Look for a virtual register for each operand or - // create one. - // 2 Update the ValToVReg accordingly. - // 2.alt. For constant arguments, if they are compile time constants, - // produce an immediate in the right operand and do not touch - // ValToReg. Actually we will go with a virtual register for each - // constants because it may be expensive to actually materialize the - // constant. Moreover, if the constant spans on several instructions, - // CSE may not catch them. - // => Update ValToVReg and remember that we saw a constant in Constants. - // We will materialize all the constants in finalize. - // Note: we would need to do something so that we can recognize such operand - // as constants. - // 3. Create the generic instruction. - bool translateADD(const Instruction &Inst); - + /// Methods for translating form LLVM IR to MachineInstr. + /// \see ::translate for general information on the translate methods. + /// @{ + + /// Translate \p Inst into its corresponding MachineInstr instruction(s). + /// Insert the newly translated instruction(s) right where the MIRBuilder + /// is set. + /// + /// The general algorithm is: + /// 1. Look for a virtual register for each operand or + /// create one. + /// 2 Update the ValToVReg accordingly. + /// 2.alt. For constant arguments, if they are compile time constants, + /// produce an immediate in the right operand and do not touch + /// ValToReg. Actually we will go with a virtual register for each + /// constants because it may be expensive to actually materialize the + /// constant. Moreover, if the constant spans on several instructions, + /// CSE may not catch them. + /// => Update ValToVReg and remember that we saw a constant in Constants. + /// We will materialize all the constants in finalize. + /// Note: we would need to do something so that we can recognize such operand + /// as constants. + /// 3. Create the generic instruction. + /// + /// \return true if the translation succeeded. + bool translate(const Instruction &Inst); + + /// Translate \p Inst into a binary operation \p Opcode. + /// \pre \p Inst is a binary operation. + bool translateBinaryOp(unsigned Opcode, const Instruction &Inst); + + /// Translate branch (br) instruction. + /// \pre \p Inst is a branch instruction. bool translateBr(const Instruction &Inst); + /// Translate return (ret) instruction. + /// The target needs to implement CallLowering::lowerReturn for + /// this to succeed. + /// \pre \p Inst is a return instruction. bool translateReturn(const Instruction &Inst); + /// @} // Builder for machine instruction a la IRBuilder. // I.e., compared to regular MIBuilder, this one also inserts the instruction @@ -102,11 +117,6 @@ private: /// MachineRegisterInfo used to create virtual registers. MachineRegisterInfo *MRI; - // Return true if the translation from LLVM IR to Machine IR - // suceeded. - // See translateXXX for details. - bool translate(const Instruction &); - // * Insert all the code needed to materialize the constants // at the proper place. E.g., Entry block or dominator block // of each constant depending on how fancy we want to be. diff --git a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index 36032599b0c72f38385c3eb32f705de33cf49c03..efdc59a9cddf58a589b430e5eb5691992f6c024d 100644 --- a/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -50,9 +50,6 @@ class MachineIRBuilder { return *TII; } - /// Current insertion point for new instructions. - MachineBasicBlock::iterator getInsertPt(); - public: /// Getter for the function we currently build. MachineFunction &getMF() { @@ -66,6 +63,9 @@ public: return *MBB; } + /// Current insertion point for new instructions. + MachineBasicBlock::iterator getInsertPt(); + /// Setters for the insertion point. /// @{ /// Set the MachineFunction where to build instructions. diff --git a/include/llvm/CodeGen/GlobalISel/RegBankSelect.h b/include/llvm/CodeGen/GlobalISel/RegBankSelect.h new file mode 100644 index 0000000000000000000000000000000000000000..b393744e67cb6f0ea6525ce7d1437362d4ff04ff --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/RegBankSelect.h @@ -0,0 +1,614 @@ +//== llvm/CodeGen/GlobalISel/RegBankSelect.h - Reg Bank Selector -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file describes the interface of the MachineFunctionPass +/// responsible for assigning the generic virtual registers to register bank. + +/// By default, the reg bank selector relies on local decisions to +/// assign the register bank. In other words, it looks at one instruction +/// at a time to decide where the operand of that instruction should live. +/// +/// At higher optimization level, we could imagine that the reg bank selector +/// would use more global analysis and do crazier thing like duplicating +/// instructions and so on. This is future work. +/// +/// For now, the pass uses a greedy algorithm to decide where the operand +/// of an instruction should live. It asks the target which banks may be +/// used for each operand of the instruction and what is the cost. Then, +/// it chooses the solution which minimize the cost of the instruction plus +/// the cost of any move that may be needed to to the values into the right +/// register bank. +/// In other words, the cost for an instruction on a register bank RegBank +/// is: Cost of I on RegBank plus the sum of the cost for bringing the +/// input operands from their current register bank to RegBank. +/// Thus, the following formula: +/// cost(I, RegBank) = cost(I.Opcode, RegBank) + +/// sum(for each arg in I.arguments: costCrossCopy(arg.RegBank, RegBank)) +/// +/// E.g., Let say we are assigning the register bank for the instruction +/// defining v2. +/// v0(A_REGBANK) = ... +/// v1(A_REGBANK) = ... +/// v2 = G_ADD i32 v0, v1 <-- MI +/// +/// The target may say it can generate G_ADD i32 on register bank A and B +/// with a cost of respectively 5 and 1. +/// Then, let say the cost of a cross register bank copies from A to B is 1. +/// The reg bank selector would compare the following two costs: +/// cost(MI, A_REGBANK) = cost(G_ADD, A_REGBANK) + cost(v0.RegBank, A_REGBANK) + +/// cost(v1.RegBank, A_REGBANK) +/// = 5 + cost(A_REGBANK, A_REGBANK) + cost(A_REGBANK, +/// A_REGBANK) +/// = 5 + 0 + 0 = 5 +/// cost(MI, B_REGBANK) = cost(G_ADD, B_REGBANK) + cost(v0.RegBank, B_REGBANK) + +/// cost(v1.RegBank, B_REGBANK) +/// = 1 + cost(A_REGBANK, B_REGBANK) + cost(A_REGBANK, +/// B_REGBANK) +/// = 1 + 1 + 1 = 3 +/// Therefore, in this specific example, the reg bank selector would choose +/// bank B for MI. +/// v0(A_REGBANK) = ... +/// v1(A_REGBANK) = ... +/// tmp0(B_REGBANK) = COPY v0 +/// tmp1(B_REGBANK) = COPY v1 +/// v2(B_REGBANK) = G_ADD i32 tmp0, tmp1 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H +#define LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H + +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" + +namespace llvm { +// Forward declarations. +class BlockFrequency; +class MachineBranchProbabilityInfo; +class MachineBlockFrequencyInfo; +class MachineRegisterInfo; +class TargetRegisterInfo; + +/// This pass implements the reg bank selector pass used in the GlobalISel +/// pipeline. At the end of this pass, all register operands have been assigned +class RegBankSelect : public MachineFunctionPass { +public: + static char ID; + + /// List of the modes supported by the RegBankSelect pass. + enum Mode { + /// Assign the register banks as fast as possible (default). + Fast, + /// Greedily minimize the cost of assigning register banks. + /// This should produce code of greater quality, but will + /// require more compile time. + Greedy + }; + + /// Abstract class used to represent an insertion point in a CFG. + /// This class records an insertion point and materializes it on + /// demand. + /// It allows to reason about the frequency of this insertion point, + /// without having to logically materialize it (e.g., on an edge), + /// before we actually need to insert something. + class InsertPoint { + protected: + /// Tell if the insert point has already been materialized. + bool WasMaterialized = false; + /// Materialize the insertion point. + /// + /// If isSplit() is true, this involves actually splitting + /// the block or edge. + /// + /// \post getPointImpl() returns a valid iterator. + /// \post getInsertMBBImpl() returns a valid basic block. + /// \post isSplit() == false ; no more splitting should be required. + virtual void materialize() = 0; + + /// Return the materialized insertion basic block. + /// Code will be inserted into that basic block. + /// + /// \pre ::materialize has been called. + virtual MachineBasicBlock &getInsertMBBImpl() = 0; + + /// Return the materialized insertion point. + /// Code will be inserted before that point. + /// + /// \pre ::materialize has been called. + virtual MachineBasicBlock::iterator getPointImpl() = 0; + + public: + virtual ~InsertPoint() {} + + /// The first call to this method will cause the splitting to + /// happen if need be, then sub sequent calls just return + /// the iterator to that point. I.e., no more splitting will + /// occur. + /// + /// \return The iterator that should be used with + /// MachineBasicBlock::insert. I.e., additional code happens + /// before that point. + MachineBasicBlock::iterator getPoint() { + if (!WasMaterialized) { + WasMaterialized = true; + assert(canMaterialize() && "Impossible to materialize this point"); + materialize(); + } + // When we materialized the point we should have done the splitting. + assert(!isSplit() && "Wrong pre-condition"); + return getPointImpl(); + } + + /// The first call to this method will cause the splitting to + /// happen if need be, then sub sequent calls just return + /// the basic block that contains the insertion point. + /// I.e., no more splitting will occur. + /// + /// \return The basic block should be used with + /// MachineBasicBlock::insert and ::getPoint. The new code should + /// happen before that point. + MachineBasicBlock &getInsertMBB() { + if (!WasMaterialized) { + WasMaterialized = true; + assert(canMaterialize() && "Impossible to materialize this point"); + materialize(); + } + // When we materialized the point we should have done the splitting. + assert(!isSplit() && "Wrong pre-condition"); + return getInsertMBBImpl(); + } + + /// Insert \p MI in the just before ::getPoint() + MachineBasicBlock::iterator insert(MachineInstr &MI) { + return getInsertMBB().insert(getPoint(), &MI); + } + + /// Does this point involve splitting an edge or block? + /// As soon as ::getPoint is called and thus, the point + /// materialized, the point will not require splitting anymore, + /// i.e., this will return false. + virtual bool isSplit() const { return false; } + + /// Frequency of the insertion point. + /// \p P is used to access the various analysis that will help to + /// get that information, like MachineBlockFrequencyInfo. If \p P + /// does not contain enough enough to return the actual frequency, + /// this returns 1. + virtual uint64_t frequency(const Pass &P) const { return 1; } + + /// Check whether this insertion point can be materialized. + /// As soon as ::getPoint is called and thus, the point materialized + /// calling this method does not make sense. + virtual bool canMaterialize() const { return false; } + }; + + /// Insertion point before or after an instruction. + class InstrInsertPoint : public InsertPoint { + private: + /// Insertion point. + MachineInstr &Instr; + /// Does the insertion point is before or after Instr. + bool Before; + + void materialize() override; + + MachineBasicBlock::iterator getPointImpl() override { + if (Before) + return Instr; + return Instr.getNextNode() ? *Instr.getNextNode() + : Instr.getParent()->end(); + } + + MachineBasicBlock &getInsertMBBImpl() override { + return *Instr.getParent(); + } + + public: + /// Create an insertion point before (\p Before=true) or after \p Instr. + InstrInsertPoint(MachineInstr &Instr, bool Before = true); + bool isSplit() const override; + uint64_t frequency(const Pass &P) const override; + + // Worst case, we need to slice the basic block, but that is still doable. + bool canMaterialize() const override { return true; } + }; + + /// Insertion point at the beginning or end of a basic block. + class MBBInsertPoint : public InsertPoint { + private: + /// Insertion point. + MachineBasicBlock &MBB; + /// Does the insertion point is at the beginning or end of MBB. + bool Beginning; + + void materialize() override { /*Nothing to do to materialize*/ + } + + MachineBasicBlock::iterator getPointImpl() override { + return Beginning ? MBB.begin() : MBB.end(); + } + + MachineBasicBlock &getInsertMBBImpl() override { return MBB; } + + public: + MBBInsertPoint(MachineBasicBlock &MBB, bool Beginning = true) + : InsertPoint(), MBB(MBB), Beginning(Beginning) { + // If we try to insert before phis, we should use the insertion + // points on the incoming edges. + assert((!Beginning || MBB.getFirstNonPHI() == MBB.begin()) && + "Invalid beginning point"); + // If we try to insert after the terminators, we should use the + // points on the outcoming edges. + assert((Beginning || MBB.getFirstTerminator() == MBB.end()) && + "Invalid end point"); + } + bool isSplit() const override { return false; } + uint64_t frequency(const Pass &P) const override; + bool canMaterialize() const override { return true; }; + }; + + /// Insertion point on an edge. + class EdgeInsertPoint : public InsertPoint { + private: + /// Source of the edge. + MachineBasicBlock &Src; + /// Destination of the edge. + /// After the materialization is done, this hold the basic block + /// that resulted from the splitting. + MachineBasicBlock *DstOrSplit; + /// P is used to update the analysis passes as applicable. + Pass &P; + + void materialize() override; + + MachineBasicBlock::iterator getPointImpl() override { + // DstOrSplit should be the Split block at this point. + // I.e., it should have one predecessor, Src, and one successor, + // the original Dst. + assert(DstOrSplit && DstOrSplit->isPredecessor(&Src) && + DstOrSplit->pred_size() == 1 && DstOrSplit->succ_size() == 1 && + "Did not split?!"); + return DstOrSplit->begin(); + } + + MachineBasicBlock &getInsertMBBImpl() override { return *DstOrSplit; } + + public: + EdgeInsertPoint(MachineBasicBlock &Src, MachineBasicBlock &Dst, Pass &P) + : InsertPoint(), Src(Src), DstOrSplit(&Dst), P(P) {} + bool isSplit() const override { + return Src.succ_size() > 1 && DstOrSplit->pred_size() > 1; + } + uint64_t frequency(const Pass &P) const override; + bool canMaterialize() const override; + }; + + /// Struct used to represent the placement of a repairing point for + /// a given operand. + class RepairingPlacement { + public: + /// Define the kind of action this repairing needs. + enum RepairingKind { + /// Nothing to repair, just drop this action. + None, + /// Reparing code needs to happen before InsertPoints. + Insert, + /// (Re)assign the register bank of the operand. + Reassign, + /// Mark this repairing placement as impossible. + Impossible + }; + + /// Convenient types for a list of insertion points. + /// @{ + typedef SmallVector, 2> InsertionPoints; + typedef InsertionPoints::iterator insertpt_iterator; + typedef InsertionPoints::const_iterator const_insertpt_iterator; + /// @} + + private: + /// Kind of repairing. + RepairingKind Kind; + /// Index of the operand that will be repaired. + unsigned OpIdx; + /// Are all the insert points materializeable? + bool CanMaterialize; + /// Is there any of the insert points needing splitting? + bool HasSplit; + /// Insertion point for the repair code. + /// The repairing code needs to happen just before these points. + InsertionPoints InsertPoints; + /// Some insertion points may need to update the liveness and such. + Pass &P; + + public: + /// Create a repairing placement for the \p OpIdx-th operand of + /// \p MI. \p TRI is used to make some checks on the register aliases + /// if the machine operand is a physical register. \p P is used to + /// to update liveness information and such when materializing the + /// points. + RepairingPlacement(MachineInstr &MI, unsigned OpIdx, + const TargetRegisterInfo &TRI, Pass &P, + RepairingKind Kind = RepairingKind::Insert); + + /// Getters. + /// @{ + RepairingKind getKind() const { return Kind; } + unsigned getOpIdx() const { return OpIdx; } + bool canMaterialize() const { return CanMaterialize; } + bool hasSplit() { return HasSplit; } + /// @} + + /// Overloaded methods to add an insertion point. + /// @{ + /// Add a MBBInsertionPoint to the list of InsertPoints. + void addInsertPoint(MachineBasicBlock &MBB, bool Beginning); + /// Add a InstrInsertionPoint to the list of InsertPoints. + void addInsertPoint(MachineInstr &MI, bool Before); + /// Add an EdgeInsertionPoint (\p Src, \p Dst) to the list of InsertPoints. + void addInsertPoint(MachineBasicBlock &Src, MachineBasicBlock &Dst); + /// Add an InsertPoint to the list of insert points. + /// This method takes the ownership of &\p Point. + void addInsertPoint(InsertPoint &Point); + /// @} + + /// Accessors related to the insertion points. + /// @{ + insertpt_iterator begin() { return InsertPoints.begin(); } + insertpt_iterator end() { return InsertPoints.end(); } + + const_insertpt_iterator begin() const { return InsertPoints.begin(); } + const_insertpt_iterator end() const { return InsertPoints.end(); } + + unsigned getNumInsertPoints() const { return InsertPoints.size(); } + /// @} + + /// Change the type of this repairing placement to \p NewKind. + /// It is not possible to switch a repairing placement to the + /// RepairingKind::Insert. There is no fundamental problem with + /// that, but no uses as well, so do not support it for now. + /// + /// \pre NewKind != RepairingKind::Insert + /// \post getKind() == NewKind + void switchTo(RepairingKind NewKind) { + assert(NewKind != Kind && "Already of the right Kind"); + Kind = NewKind; + InsertPoints.clear(); + CanMaterialize = NewKind != RepairingKind::Impossible; + HasSplit = false; + assert(NewKind != RepairingKind::Insert && + "We would need more MI to switch to Insert"); + } + }; + +private: + /// Helper class used to represent the cost for mapping an instruction. + /// When mapping an instruction, we may introduce some repairing code. + /// In most cases, the repairing code is local to the instruction, + /// thus, we can omit the basic block frequency from the cost. + /// However, some alternatives may produce non-local cost, e.g., when + /// repairing a phi, and thus we then need to scale the local cost + /// to the non-local cost. This class does this for us. + /// \note: We could simply always scale the cost. The problem is that + /// there are higher chances that we saturate the cost easier and end + /// up having the same cost for actually different alternatives. + /// Another option would be to use APInt everywhere. + class MappingCost { + private: + /// Cost of the local instructions. + /// This cost is free of basic block frequency. + uint64_t LocalCost; + /// Cost of the non-local instructions. + /// This cost should include the frequency of the related blocks. + uint64_t NonLocalCost; + /// Frequency of the block where the local instructions live. + uint64_t LocalFreq; + + MappingCost(uint64_t LocalCost, uint64_t NonLocalCost, uint64_t LocalFreq) + : LocalCost(LocalCost), NonLocalCost(NonLocalCost), + LocalFreq(LocalFreq) {} + + /// Check if this cost is saturated. + bool isSaturated() const; + + public: + /// Create a MappingCost assuming that most of the instructions + /// will occur in a basic block with \p LocalFreq frequency. + MappingCost(const BlockFrequency &LocalFreq); + + /// Add \p Cost to the local cost. + /// \return true if this cost is saturated, false otherwise. + bool addLocalCost(uint64_t Cost); + + /// Add \p Cost to the non-local cost. + /// Non-local cost should reflect the frequency of their placement. + /// \return true if this cost is saturated, false otherwise. + bool addNonLocalCost(uint64_t Cost); + + /// Saturate the cost to the maximal representable value. + void saturate(); + + /// Return an instance of MappingCost that represents an + /// impossible mapping. + static MappingCost ImpossibleCost(); + + /// Check if this is less than \p Cost. + bool operator<(const MappingCost &Cost) const; + /// Check if this is equal to \p Cost. + bool operator==(const MappingCost &Cost) const; + /// Check if this is not equal to \p Cost. + bool operator!=(const MappingCost &Cost) const { return !(*this == Cost); } + /// Check if this is greater than \p Cost. + bool operator>(const MappingCost &Cost) const { + return *this != Cost && Cost < *this; + } + }; + + /// Interface to the target lowering info related + /// to register banks. + const RegisterBankInfo *RBI; + + /// MRI contains all the register class/bank information that this + /// pass uses and updates. + MachineRegisterInfo *MRI; + + /// Information on the register classes for the current function. + const TargetRegisterInfo *TRI; + + /// Get the frequency of blocks. + /// This is required for non-fast mode. + MachineBlockFrequencyInfo *MBFI; + + /// Get the frequency of the edges. + /// This is required for non-fast mode. + MachineBranchProbabilityInfo *MBPI; + + /// Helper class used for every code morphing. + MachineIRBuilder MIRBuilder; + + /// Optimization mode of the pass. + Mode OptMode; + + /// Assign the register bank of each operand of \p MI. + void assignInstr(MachineInstr &MI); + + /// Initialize the field members using \p MF. + void init(MachineFunction &MF); + + /// Check if \p Reg is already assigned what is described by \p ValMapping. + /// \p OnlyAssign == true means that \p Reg just needs to be assigned a + /// register bank. I.e., no repairing is necessary to have the + /// assignment match. + bool assignmentMatch(unsigned Reg, + const RegisterBankInfo::ValueMapping &ValMapping, + bool &OnlyAssign) const; + + /// Insert repairing code for \p Reg as specified by \p ValMapping. + /// The repairing placement is specified by \p RepairPt. + /// \p NewVRegs contains all the registers required to remap \p Reg. + /// In other words, the number of registers in NewVRegs must be equal + /// to ValMapping.BreakDown.size(). + /// + /// The transformation could be sketched as: + /// \code + /// ... = op Reg + /// \endcode + /// Becomes + /// \code + /// = COPY or extract Reg + /// ... = op Reg + /// \endcode + /// + /// and + /// \code + /// Reg = op ... + /// \endcode + /// Becomes + /// \code + /// Reg = op ... + /// Reg = COPY or build_sequence + /// \endcode + /// + /// \pre NewVRegs.size() == ValMapping.BreakDown.size() + /// + /// \note The caller is supposed to do the rewriting of op if need be. + /// I.e., Reg = op ... => = NewOp ... + void repairReg(MachineOperand &MO, + const RegisterBankInfo::ValueMapping &ValMapping, + RegBankSelect::RepairingPlacement &RepairPt, + const iterator_range::const_iterator> + &NewVRegs); + + /// Return the cost of the instruction needed to map \p MO to \p ValMapping. + /// The cost is free of basic block frequencies. + /// \pre MO.isReg() + /// \pre MO is assigned to a register bank. + /// \pre ValMapping is a valid mapping for MO. + uint64_t + getRepairCost(const MachineOperand &MO, + const RegisterBankInfo::ValueMapping &ValMapping) const; + + /// Find the best mapping for \p MI from \p PossibleMappings. + /// \return a reference on the best mapping in \p PossibleMappings. + RegisterBankInfo::InstructionMapping & + findBestMapping(MachineInstr &MI, + RegisterBankInfo::InstructionMappings &PossibleMappings, + SmallVectorImpl &RepairPts); + + /// Compute the cost of mapping \p MI with \p InstrMapping and + /// compute the repairing placement for such mapping in \p + /// RepairPts. + /// \p BestCost is used to specify when the cost becomes too high + /// and thus it is not worth computing the RepairPts. Moreover if + /// \p BestCost == nullptr, the mapping cost is actually not + /// computed. + MappingCost + computeMapping(MachineInstr &MI, + const RegisterBankInfo::InstructionMapping &InstrMapping, + SmallVectorImpl &RepairPts, + const MappingCost *BestCost = nullptr); + + /// When \p RepairPt involves splitting to repair \p MO for the + /// given \p ValMapping, try to change the way we repair such that + /// the splitting is not required anymore. + /// + /// \pre \p RepairPt.hasSplit() + /// \pre \p MO == MO.getParent()->getOperand(\p RepairPt.getOpIdx()) + /// \pre \p ValMapping is the mapping of \p MO for MO.getParent() + /// that implied \p RepairPt. + void tryAvoidingSplit(RegBankSelect::RepairingPlacement &RepairPt, + const MachineOperand &MO, + const RegisterBankInfo::ValueMapping &ValMapping) const; + + /// Apply \p Mapping to \p MI. \p RepairPts represents the different + /// mapping action that need to happen for the mapping to be + /// applied. + void applyMapping(MachineInstr &MI, + const RegisterBankInfo::InstructionMapping &InstrMapping, + SmallVectorImpl &RepairPts); + +public: + /// Create a RegBankSelect pass with the specified \p RunningMode. + RegBankSelect(Mode RunningMode = Fast); + + const char *getPassName() const override { + return "RegBankSelect"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + /// Walk through \p MF and assign a register bank to every virtual register + /// that are still mapped to nothing. + /// The target needs to provide a RegisterBankInfo and in particular + /// override RegisterBankInfo::getInstrMapping. + /// + /// Simplified algo: + /// \code + /// RBI = MF.subtarget.getRegBankInfo() + /// MIRBuilder.setMF(MF) + /// for each bb in MF + /// for each inst in bb + /// MIRBuilder.setInstr(inst) + /// MappingCosts = RBI.getMapping(inst); + /// Idx = findIdxOfMinCost(MappingCosts) + /// CurRegBank = MappingCosts[Idx].RegBank + /// MRI.setRegBank(inst.getOperand(0).getReg(), CurRegBank) + /// for each argument in inst + /// if (CurRegBank != argument.RegBank) + /// ArgReg = argument.getReg() + /// Tmp = MRI.createNewVirtual(MRI.getSize(ArgReg), CurRegBank) + /// MIRBuilder.buildInstr(COPY, Tmp, ArgReg) + /// inst.getOperand(argument.getOperandNo()).setReg(Tmp) + /// \endcode + bool runOnMachineFunction(MachineFunction &MF) override; +}; +} // End namespace llvm. + +#endif diff --git a/include/llvm/CodeGen/GlobalISel/RegisterBank.h b/include/llvm/CodeGen/GlobalISel/RegisterBank.h new file mode 100644 index 0000000000000000000000000000000000000000..e886382fd8e83403eeaed1a19a4473b02ce76fd0 --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/RegisterBank.h @@ -0,0 +1,101 @@ +//==-- llvm/CodeGen/GlobalISel/RegisterBank.h - Register Bank ----*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file declares the API of register banks. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_REGBANK_H +#define LLVM_CODEGEN_GLOBALISEL_REGBANK_H + +#include "llvm/ADT/BitVector.h" + +namespace llvm { +// Forward declarations. +class RegisterBankInfo; +class raw_ostream; +class TargetRegisterClass; +class TargetRegisterInfo; + +/// This class implements the register bank concept. +/// Two instances of RegisterBank must have different ID. +/// This property is enforced by the RegisterBankInfo class. +class RegisterBank { +private: + unsigned ID; + const char *Name; + unsigned Size; + BitVector ContainedRegClasses; + + /// Sentinel value used to recognize register bank not properly + /// initialized yet. + static const unsigned InvalidID; + + /// Only the RegisterBankInfo can create RegisterBank. + /// The default constructor will leave the object in + /// an invalid state. I.e. isValid() == false. + /// The field must be updated to fix that. + RegisterBank(); + + friend RegisterBankInfo; + +public: + /// Get the identifier of this register bank. + unsigned getID() const { return ID; } + + /// Get a user friendly name of this register bank. + /// Should be used only for debugging purposes. + const char *getName() const { return Name; } + + /// Get the maximal size in bits that fits in this register bank. + unsigned getSize() const { return Size; } + + /// Check whether this instance is ready to be used. + bool isValid() const; + + /// Check if this register bank is valid. In other words, + /// if it has been properly constructed. + /// + /// \note This method does not check anything when assertions are disabled. + /// + /// \return True is the check was successful. + bool verify(const TargetRegisterInfo &TRI) const; + + /// Check whether this register bank covers \p RC. + /// In other words, check if this register bank fully covers + /// the registers that \p RC contains. + /// \pre isValid() + bool covers(const TargetRegisterClass &RC) const; + + /// Check whether \p OtherRB is the same as this. + bool operator==(const RegisterBank &OtherRB) const; + bool operator!=(const RegisterBank &OtherRB) const { + return !this->operator==(OtherRB); + } + + /// Dump the register mask on dbgs() stream. + /// The dump is verbose. + void dump(const TargetRegisterInfo *TRI = nullptr) const; + + /// Print the register mask on OS. + /// If IsForDebug is false, then only the name of the register bank + /// is printed. Otherwise, all the fields are printing. + /// TRI is then used to print the name of the register classes that + /// this register bank covers. + void print(raw_ostream &OS, bool IsForDebug = false, + const TargetRegisterInfo *TRI = nullptr) const; +}; + +inline raw_ostream &operator<<(raw_ostream &OS, const RegisterBank &RegBank) { + RegBank.print(OS); + return OS; +} +} // End namespace llvm. + +#endif diff --git a/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h b/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..19d170365858b0f0a3505f482d36ece6837b6815 --- /dev/null +++ b/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h @@ -0,0 +1,602 @@ +//==-- llvm/CodeGen/GlobalISel/RegisterBankInfo.h ----------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file declares the API for the register bank info. +/// This API is responsible for handling the register banks. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_REGBANKINFO_H +#define LLVM_CODEGEN_GLOBALISEL_REGBANKINFO_H + +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/GlobalISel/RegisterBank.h" +#include "llvm/CodeGen/MachineValueType.h" // For SimpleValueType. +#include "llvm/Support/ErrorHandling.h" + +#include +#include // For unique_ptr. + +namespace llvm { +class MachineInstr; +class MachineRegisterInfo; +class TargetInstrInfo; +class TargetRegisterInfo; +class raw_ostream; + +/// Holds all the information related to register banks. +class RegisterBankInfo { +public: + /// Helper struct that represents how a value is partially mapped + /// into a register. + /// The StartIdx and Length represent what region of the orginal + /// value this partial mapping covers. + /// This can be represented as a Mask of contiguous bit starting + /// at StartIdx bit and spanning Length bits. + /// StartIdx is the number of bits from the less significant bits. + struct PartialMapping { + /// Number of bits at which this partial mapping starts in the + /// original value. The bits are counted from less significant + /// bits to most significant bits. + unsigned StartIdx; + /// Length of this mapping in bits. This is how many bits this + /// partial mapping covers in the original value: + /// from StartIdx to StartIdx + Length -1. + unsigned Length; + /// Register bank where the partial value lives. + const RegisterBank *RegBank; + + PartialMapping() = default; + + /// Provide a shortcut for quickly building PartialMapping. + PartialMapping(unsigned StartIdx, unsigned Length, + const RegisterBank &RegBank) + : StartIdx(StartIdx), Length(Length), RegBank(&RegBank) {} + + /// \return the index of in the original value of the most + /// significant bit that this partial mapping covers. + unsigned getHighBitIdx() const { return StartIdx + Length - 1; } + + /// Print this partial mapping on dbgs() stream. + void dump() const; + + /// Print this partial mapping on \p OS; + void print(raw_ostream &OS) const; + + /// Check that the Mask is compatible with the RegBank. + /// Indeed, if the RegBank cannot accomadate the "active bits" of the mask, + /// there is no way this mapping is valid. + /// + /// \note This method does not check anything when assertions are disabled. + /// + /// \return True is the check was successful. + bool verify() const; + }; + + /// Helper struct that represents how a value is mapped through + /// different register banks. + struct ValueMapping { + /// How the value is broken down between the different register banks. + SmallVector BreakDown; + + /// Verify that this mapping makes sense for a value of \p ExpectedBitWidth. + /// \note This method does not check anything when assertions are disabled. + /// + /// \return True is the check was successful. + bool verify(unsigned ExpectedBitWidth) const; + + /// Print this on dbgs() stream. + void dump() const; + + /// Print this on \p OS; + void print(raw_ostream &OS) const; + }; + + /// Helper class that represents how the value of an instruction may be + /// mapped and what is the related cost of such mapping. + class InstructionMapping { + /// Identifier of the mapping. + /// This is used to communicate between the target and the optimizers + /// which mapping should be realized. + unsigned ID; + /// Cost of this mapping. + unsigned Cost; + /// Mapping of all the operands. + std::unique_ptr OperandsMapping; + /// Number of operands. + unsigned NumOperands; + + ValueMapping &getOperandMapping(unsigned i) { + assert(i < getNumOperands() && "Out of bound operand"); + return OperandsMapping[i]; + } + + public: + /// Constructor for the mapping of an instruction. + /// \p NumOperands must be equal to number of all the operands of + /// the related instruction. + /// The rationale is that it is more efficient for the optimizers + /// to be able to assume that the mapping of the ith operand is + /// at the index i. + /// + /// \pre ID != InvalidMappingID + InstructionMapping(unsigned ID, unsigned Cost, unsigned NumOperands) + : ID(ID), Cost(Cost), NumOperands(NumOperands) { + assert(getID() != InvalidMappingID && + "Use the default constructor for invalid mapping"); + OperandsMapping.reset(new ValueMapping[getNumOperands()]); + } + + /// Default constructor. + /// Use this constructor to express that the mapping is invalid. + InstructionMapping() : ID(InvalidMappingID), Cost(0), NumOperands(0) {} + + /// Get the cost. + unsigned getCost() const { return Cost; } + + /// Get the ID. + unsigned getID() const { return ID; } + + /// Get the number of operands. + unsigned getNumOperands() const { return NumOperands; } + + /// Get the value mapping of the ith operand. + const ValueMapping &getOperandMapping(unsigned i) const { + return const_cast(this)->getOperandMapping(i); + } + + /// Get the value mapping of the ith operand. + void setOperandMapping(unsigned i, const ValueMapping &ValMapping) { + getOperandMapping(i) = ValMapping; + } + + /// Check whether this object is valid. + /// This is a lightweight check for obvious wrong instance. + bool isValid() const { return getID() != InvalidMappingID; } + + /// Set the operand mapping for the \p OpIdx-th operand. + /// The mapping will consist of only one element in the break down list. + /// This element will map to \p RegBank and fully define a mask, whose + /// bitwidth matches the size of \p MaskSize. + void setOperandMapping(unsigned OpIdx, unsigned MaskSize, + const RegisterBank &RegBank); + + /// Verifiy that this mapping makes sense for \p MI. + /// \pre \p MI must be connected to a MachineFunction. + /// + /// \note This method does not check anything when assertions are disabled. + /// + /// \return True is the check was successful. + bool verify(const MachineInstr &MI) const; + + /// Print this on dbgs() stream. + void dump() const; + + /// Print this on \p OS; + void print(raw_ostream &OS) const; + }; + + /// Convenient type to represent the alternatives for mapping an + /// instruction. + /// \todo When we move to TableGen this should be an array ref. + typedef SmallVector InstructionMappings; + + /// Helper class use to get/create the virtual registers that will be used + /// to replace the MachineOperand when applying a mapping. + class OperandsMapper { + /// The OpIdx-th cell contains the index in NewVRegs where the VRegs of the + /// OpIdx-th operand starts. -1 means we do not have such mapping yet. + std::unique_ptr OpToNewVRegIdx; + /// Hold the registers that will be used to map MI with InstrMapping. + SmallVector NewVRegs; + /// Current MachineRegisterInfo, used to create new virtual registers. + MachineRegisterInfo &MRI; + /// Instruction being remapped. + MachineInstr &MI; + /// New mapping of the instruction. + const InstructionMapping &InstrMapping; + + /// Constant value identifying that the index in OpToNewVRegIdx + /// for an operand has not been set yet. + static const int DontKnowIdx; + + /// Get the range in NewVRegs to store all the partial + /// values for the \p OpIdx-th operand. + /// + /// \return The iterator range for the space created. + // + /// \pre getMI().getOperand(OpIdx).isReg() + iterator_range::iterator> + getVRegsMem(unsigned OpIdx); + + /// Get the end iterator for a range starting at \p StartIdx and + /// spannig \p NumVal in NewVRegs. + /// \pre StartIdx + NumVal <= NewVRegs.size() + SmallVectorImpl::const_iterator + getNewVRegsEnd(unsigned StartIdx, unsigned NumVal) const; + SmallVectorImpl::iterator getNewVRegsEnd(unsigned StartIdx, + unsigned NumVal); + + public: + /// Create an OperandsMapper that will hold the information to apply \p + /// InstrMapping to \p MI. + /// \pre InstrMapping.verify(MI) + OperandsMapper(MachineInstr &MI, const InstructionMapping &InstrMapping, + MachineRegisterInfo &MRI); + + /// Getters. + /// @{ + /// The MachineInstr being remapped. + MachineInstr &getMI() const { return MI; } + + /// The final mapping of the instruction. + const InstructionMapping &getInstrMapping() const { return InstrMapping; } + /// @} + + /// Create as many new virtual registers as needed for the mapping of the \p + /// OpIdx-th operand. + /// The number of registers is determined by the number of breakdown for the + /// related operand in the instruction mapping. + /// + /// \pre getMI().getOperand(OpIdx).isReg() + /// + /// \post All the partial mapping of the \p OpIdx-th operand have been + /// assigned a new virtual register. + void createVRegs(unsigned OpIdx); + + /// Set the virtual register of the \p PartialMapIdx-th partial mapping of + /// the OpIdx-th operand to \p NewVReg. + /// + /// \pre getMI().getOperand(OpIdx).isReg() + /// \pre getInstrMapping().getOperandMapping(OpIdx).BreakDown.size() > + /// PartialMapIdx + /// \pre NewReg != 0 + /// + /// \post the \p PartialMapIdx-th register of the value mapping of the \p + /// OpIdx-th operand has been set. + void setVRegs(unsigned OpIdx, unsigned PartialMapIdx, unsigned NewVReg); + + /// Get all the virtual registers required to map the \p OpIdx-th operand of + /// the instruction. + /// + /// This return an empty range when createVRegs or setVRegs has not been + /// called. + /// The iterator may be invalidated by a call to setVRegs or createVRegs. + /// + /// When \p ForDebug is true, we will not check that the list of new virtual + /// registers does not contain uninitialized values. + /// + /// \pre getMI().getOperand(OpIdx).isReg() + /// \pre ForDebug || All partial mappings have been set a register + iterator_range::const_iterator> + getVRegs(unsigned OpIdx, bool ForDebug = false) const; + + /// Print this operands mapper on dbgs() stream. + void dump() const; + + /// Print this operands mapper on \p OS stream. + void print(raw_ostream &OS, bool ForDebug = false) const; + }; + +protected: + /// Hold the set of supported register banks. + std::unique_ptr RegBanks; + /// Total number of register banks. + unsigned NumRegBanks; + + /// Mapping from MVT::SimpleValueType to register banks. + std::unique_ptr VTToRegBank; + + /// Create a RegisterBankInfo that can accomodate up to \p NumRegBanks + /// RegisterBank instances. + /// + /// \note For the verify method to succeed all the \p NumRegBanks + /// must be initialized by createRegisterBank and updated with + /// addRegBankCoverage RegisterBank. + RegisterBankInfo(unsigned NumRegBanks); + + /// This constructor is meaningless. + /// It just provides a default constructor that can be used at link time + /// when GlobalISel is not built. + /// That way, targets can still inherit from this class without doing + /// crazy gymnastic to avoid link time failures. + /// \note That works because the constructor is inlined. + RegisterBankInfo() { + llvm_unreachable("This constructor should not be executed"); + } + + /// Create a new register bank with the given parameter and add it + /// to RegBanks. + /// \pre \p ID must not already be used. + /// \pre \p ID < NumRegBanks. + void createRegisterBank(unsigned ID, const char *Name); + + /// Add \p RCId to the set of register class that the register bank, + /// identified \p ID, covers. + /// This method transitively adds all the sub classes and the subreg-classes + /// of \p RCId to the set of covered register classes. + /// It also adjusts the size of the register bank to reflect the maximal + /// size of a value that can be hold into that register bank. + /// + /// If \p AddTypeMapping is true, this method also records what types can + /// be mapped to \p ID. Although this done by default, targets may want to + /// disable it, espicially if a given type may be mapped on different + /// register bank. Indeed, in such case, this method only records the + /// first register bank where the type matches. + /// This information is only used to provide default mapping + /// (see getInstrMappingImpl). + /// + /// \note This method does *not* add the super classes of \p RCId. + /// The rationale is if \p ID covers the registers of \p RCId, that + /// does not necessarily mean that \p ID covers the set of registers + /// of RCId's superclasses. + /// This method does *not* add the superreg classes as well for consistents. + /// The expected use is to add the coverage top-down with respect to the + /// register hierarchy. + /// + /// \todo TableGen should just generate the BitSet vector for us. + void addRegBankCoverage(unsigned ID, unsigned RCId, + const TargetRegisterInfo &TRI, + bool AddTypeMapping = true); + + /// Get the register bank identified by \p ID. + RegisterBank &getRegBank(unsigned ID) { + assert(ID < getNumRegBanks() && "Accessing an unknown register bank"); + return RegBanks[ID]; + } + + /// Get the register bank that has been recorded to cover \p SVT. + const RegisterBank *getRegBankForType(MVT::SimpleValueType SVT) const { + if (!VTToRegBank) + return nullptr; + assert(SVT < MVT::SimpleValueType::LAST_VALUETYPE && "Out-of-bound access"); + return VTToRegBank.get()[SVT]; + } + + /// Record \p RegBank as the register bank that covers \p SVT. + /// If a record was already set for \p SVT, the mapping is not + /// updated, unless \p Force == true + /// + /// \post if getRegBankForType(SVT)\@pre == nullptr then + /// getRegBankForType(SVT) == &RegBank + /// \post if Force == true then getRegBankForType(SVT) == &RegBank + void recordRegBankForType(const RegisterBank &RegBank, + MVT::SimpleValueType SVT, bool Force = false) { + if (!VTToRegBank) { + VTToRegBank.reset( + new const RegisterBank *[MVT::SimpleValueType::LAST_VALUETYPE]); + std::fill(&VTToRegBank[0], + &VTToRegBank[MVT::SimpleValueType::LAST_VALUETYPE], nullptr); + } + assert(SVT < MVT::SimpleValueType::LAST_VALUETYPE && "Out-of-bound access"); + // If we want to override the mapping or the mapping does not exits yet, + // set the register bank for SVT. + if (Force || !getRegBankForType(SVT)) + VTToRegBank.get()[SVT] = &RegBank; + } + + /// Try to get the mapping of \p MI. + /// See getInstrMapping for more details on what a mapping represents. + /// + /// Unlike getInstrMapping the returned InstructionMapping may be invalid + /// (isValid() == false). + /// This means that the target independent code is not smart enough + /// to get the mapping of \p MI and thus, the target has to provide the + /// information for \p MI. + /// + /// This implementation is able to get the mapping of: + /// - Target specific instructions by looking at the encoding constraints. + /// - Any instruction if all the register operands are already been assigned + /// a register, a register class, or a register bank. + /// - Copies and phis if at least one of the operand has been assigned a + /// register, a register class, or a register bank. + /// In other words, this method will likely fail to find a mapping for + /// any generic opcode that has not been lowered by target specific code. + InstructionMapping getInstrMappingImpl(const MachineInstr &MI) const; + + /// Get the register bank for the \p OpIdx-th operand of \p MI form + /// the encoding constraints, if any. + /// + /// \return A register bank that covers the register class of the + /// related encoding constraints or nullptr if \p MI did not provide + /// enough information to deduce it. + const RegisterBank * + getRegBankFromConstraints(const MachineInstr &MI, unsigned OpIdx, + const TargetInstrInfo &TII, + const TargetRegisterInfo &TRI) const; + + /// Helper method to apply something that is like the default mapping. + /// Basically, that means that \p OpdMapper.getMI() is left untouched + /// aside from the reassignment of the register operand that have been + /// remapped. + /// If the mapping of one of the operand spans several registers, this + /// method will abort as this is not like a default mapping anymore. + /// + /// \pre For OpIdx in {0..\p OpdMapper.getMI().getNumOperands()) + /// the range OpdMapper.getVRegs(OpIdx) is empty or of size 1. + static void applyDefaultMapping(const OperandsMapper &OpdMapper); + + /// See ::applyMapping. + virtual void applyMappingImpl(const OperandsMapper &OpdMapper) const { + llvm_unreachable("The target has to implement that part"); + } + +public: + virtual ~RegisterBankInfo() {} + + /// Get the register bank identified by \p ID. + const RegisterBank &getRegBank(unsigned ID) const { + return const_cast(this)->getRegBank(ID); + } + + /// Get the register bank of \p Reg. + /// If Reg has not been assigned a register, a register class, + /// or a register bank, then this returns nullptr. + /// + /// \pre Reg != 0 (NoRegister) + const RegisterBank *getRegBank(unsigned Reg, const MachineRegisterInfo &MRI, + const TargetRegisterInfo &TRI) const; + + /// Get the total number of register banks. + unsigned getNumRegBanks() const { return NumRegBanks; } + + /// Get a register bank that covers \p RC. + /// + /// \pre \p RC is a user-defined register class (as opposed as one + /// generated by TableGen). + /// + /// \note The mapping RC -> RegBank could be built while adding the + /// coverage for the register banks. However, we do not do it, because, + /// at least for now, we only need this information for register classes + /// that are used in the description of instruction. In other words, + /// there are just a handful of them and we do not want to waste space. + /// + /// \todo This should be TableGen'ed. + virtual const RegisterBank & + getRegBankFromRegClass(const TargetRegisterClass &RC) const { + llvm_unreachable("The target must override this method"); + } + + /// Get the cost of a copy from \p B to \p A, or put differently, + /// get the cost of A = COPY B. Since register banks may cover + /// different size, \p Size specifies what will be the size in bits + /// that will be copied around. + /// + /// \note Since this is a copy, both registers have the same size. + virtual unsigned copyCost(const RegisterBank &A, const RegisterBank &B, + unsigned Size) const { + // Optimistically assume that copies are coalesced. I.e., when + // they are on the same bank, they are free. + // Otherwise assume a non-zero cost of 1. The targets are supposed + // to override that properly anyway if they care. + return &A != &B; + } + + /// Identifier used when the related instruction mapping instance + /// is generated by target independent code. + /// Make sure not to use that identifier to avoid possible collision. + static const unsigned DefaultMappingID; + + /// Identifier used when the related instruction mapping instance + /// is generated by the default constructor. + /// Make sure not to use that identifier. + static const unsigned InvalidMappingID; + + /// Get the mapping of the different operands of \p MI + /// on the register bank. + /// This mapping should be the direct translation of \p MI. + /// In other words, when \p MI is mapped with the returned mapping, + /// only the register banks of the operands of \p MI need to be updated. + /// In particular, neither the opcode or the type of \p MI needs to be + /// updated for this direct mapping. + /// + /// The target independent implementation gives a mapping based on + /// the register classes for the target specific opcode. + /// It uses the ID RegisterBankInfo::DefaultMappingID for that mapping. + /// Make sure you do not use that ID for the alternative mapping + /// for MI. See getInstrAlternativeMappings for the alternative + /// mappings. + /// + /// For instance, if \p MI is a vector add, the mapping should + /// not be a scalarization of the add. + /// + /// \post returnedVal.verify(MI). + /// + /// \note If returnedVal does not verify MI, this would probably mean + /// that the target does not support that instruction. + virtual InstructionMapping getInstrMapping(const MachineInstr &MI) const; + + /// Get the alternative mappings for \p MI. + /// Alternative in the sense different from getInstrMapping. + virtual InstructionMappings + getInstrAlternativeMappings(const MachineInstr &MI) const; + + /// Get the possible mapping for \p MI. + /// A mapping defines where the different operands may live and at what cost. + /// For instance, let us consider: + /// v0(16) = G_ADD <2 x i8> v1, v2 + /// The possible mapping could be: + /// + /// {/*ID*/VectorAdd, /*Cost*/1, /*v0*/{(0xFFFF, VPR)}, /*v1*/{(0xFFFF, VPR)}, + /// /*v2*/{(0xFFFF, VPR)}} + /// {/*ID*/ScalarAddx2, /*Cost*/2, /*v0*/{(0x00FF, GPR),(0xFF00, GPR)}, + /// /*v1*/{(0x00FF, GPR),(0xFF00, GPR)}, + /// /*v2*/{(0x00FF, GPR),(0xFF00, GPR)}} + /// + /// \note The first alternative of the returned mapping should be the + /// direct translation of \p MI current form. + /// + /// \post !returnedVal.empty(). + InstructionMappings getInstrPossibleMappings(const MachineInstr &MI) const; + + /// Apply \p OpdMapper.getInstrMapping() to \p OpdMapper.getMI(). + /// After this call \p OpdMapper.getMI() may not be valid anymore. + /// \p OpdMapper.getInstrMapping().getID() carries the information of + /// what has been chosen to map \p OpdMapper.getMI(). This ID is set + /// by the various getInstrXXXMapping method. + /// + /// Therefore, getting the mapping and applying it should be kept in + /// sync. + void applyMapping(const OperandsMapper &OpdMapper) const { + // The only mapping we know how to handle is the default mapping. + if (OpdMapper.getInstrMapping().getID() == DefaultMappingID) + return applyDefaultMapping(OpdMapper); + // For other mapping, the target needs to do the right thing. + // If that means calling applyDefaultMapping, fine, but this + // must be explicitly stated. + applyMappingImpl(OpdMapper); + } + + /// Get the size in bits of \p Reg. + /// Utility method to get the size of any registers. Unlike + /// MachineRegisterInfo::getSize, the register does not need to be a + /// virtual register. + /// + /// \pre \p Reg != 0 (NoRegister). + static unsigned getSizeInBits(unsigned Reg, const MachineRegisterInfo &MRI, + const TargetRegisterInfo &TRI); + + /// Check that information hold by this instance make sense for the + /// given \p TRI. + /// + /// \note This method does not check anything when assertions are disabled. + /// + /// \return True is the check was successful. + bool verify(const TargetRegisterInfo &TRI) const; +}; + +inline raw_ostream & +operator<<(raw_ostream &OS, + const RegisterBankInfo::PartialMapping &PartMapping) { + PartMapping.print(OS); + return OS; +} + +inline raw_ostream & +operator<<(raw_ostream &OS, const RegisterBankInfo::ValueMapping &ValMapping) { + ValMapping.print(OS); + return OS; +} + +inline raw_ostream & +operator<<(raw_ostream &OS, + const RegisterBankInfo::InstructionMapping &InstrMapping) { + InstrMapping.print(OS); + return OS; +} + +inline raw_ostream & +operator<<(raw_ostream &OS, const RegisterBankInfo::OperandsMapper &OpdMapper) { + OpdMapper.print(OS, /*ForDebug*/ false); + return OS; +} +} // End namespace llvm. + +#endif diff --git a/include/llvm/CodeGen/GlobalISel/Types.h b/include/llvm/CodeGen/GlobalISel/Types.h index 879091d3c4d0c0ab476aa21de28dad336dbc808a..7d974878d3b9f0d2c1773023e4174a37ee9e896e 100644 --- a/include/llvm/CodeGen/GlobalISel/Types.h +++ b/include/llvm/CodeGen/GlobalISel/Types.h @@ -16,7 +16,6 @@ #define LLVM_CODEGEN_GLOBALISEL_TYPES_H #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/IR/Value.h" namespace llvm { diff --git a/include/llvm/CodeGen/ISDOpcodes.h b/include/llvm/CodeGen/ISDOpcodes.h index 158ff3cd36a83f5e998f474c540f16b6b8597cfc..89cb7a86f99f6f035560ea4d190c6e4719bb0bda 100644 --- a/include/llvm/CodeGen/ISDOpcodes.h +++ b/include/llvm/CodeGen/ISDOpcodes.h @@ -257,6 +257,9 @@ namespace ISD { /// value as an integer 0/1 value. FGETSIGN, + /// Returns platform specific canonical encoding of a floating point number. + FCANONICALIZE, + /// BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a vector with the /// specified, possibly variable, elements. The number of elements is /// required to be a power of two. The types of the operands must all be @@ -483,6 +486,12 @@ namespace ISD { /// the same bit size (e.g. f32 <-> i32). This can also be used for /// int-to-int or fp-to-fp conversions, but that is a noop, deleted by /// getNode(). + /// + /// This operator is subtly different from the bitcast instruction from + /// LLVM-IR since this node may change the bits in the register. For + /// example, this occurs on big-endian NEON and big-endian MSA where the + /// layout of the bits in the register depends on the vector type and this + /// operator acts as a shuffle operation for some vector type combinations. BITCAST, /// ADDRSPACECAST - This operator converts between pointers of different @@ -869,56 +878,52 @@ namespace ISD { SETCC_INVALID // Marker value. }; - /// isSignedIntSetCC - Return true if this is a setcc instruction that - /// performs a signed comparison when used with integer operands. + /// Return true if this is a setcc instruction that performs a signed + /// comparison when used with integer operands. inline bool isSignedIntSetCC(CondCode Code) { return Code == SETGT || Code == SETGE || Code == SETLT || Code == SETLE; } - /// isUnsignedIntSetCC - Return true if this is a setcc instruction that - /// performs an unsigned comparison when used with integer operands. + /// Return true if this is a setcc instruction that performs an unsigned + /// comparison when used with integer operands. inline bool isUnsignedIntSetCC(CondCode Code) { return Code == SETUGT || Code == SETUGE || Code == SETULT || Code == SETULE; } - /// isTrueWhenEqual - Return true if the specified condition returns true if - /// the two operands to the condition are equal. Note that if one of the two - /// operands is a NaN, this value is meaningless. + /// Return true if the specified condition returns true if the two operands to + /// the condition are equal. Note that if one of the two operands is a NaN, + /// this value is meaningless. inline bool isTrueWhenEqual(CondCode Cond) { return ((int)Cond & 1) != 0; } - /// getUnorderedFlavor - This function returns 0 if the condition is always - /// false if an operand is a NaN, 1 if the condition is always true if the - /// operand is a NaN, and 2 if the condition is undefined if the operand is a - /// NaN. + /// This function returns 0 if the condition is always false if an operand is + /// a NaN, 1 if the condition is always true if the operand is a NaN, and 2 if + /// the condition is undefined if the operand is a NaN. inline unsigned getUnorderedFlavor(CondCode Cond) { return ((int)Cond >> 3) & 3; } - /// getSetCCInverse - Return the operation corresponding to !(X op Y), where - /// 'op' is a valid SetCC operation. + /// Return the operation corresponding to !(X op Y), where 'op' is a valid + /// SetCC operation. CondCode getSetCCInverse(CondCode Operation, bool isInteger); - /// getSetCCSwappedOperands - Return the operation corresponding to (Y op X) - /// when given the operation for (X op Y). + /// Return the operation corresponding to (Y op X) when given the operation + /// for (X op Y). CondCode getSetCCSwappedOperands(CondCode Operation); - /// getSetCCOrOperation - Return the result of a logical OR between different - /// comparisons of identical values: ((X op1 Y) | (X op2 Y)). This - /// function returns SETCC_INVALID if it is not possible to represent the - /// resultant comparison. + /// Return the result of a logical OR between different comparisons of + /// identical values: ((X op1 Y) | (X op2 Y)). This function returns + /// SETCC_INVALID if it is not possible to represent the resultant comparison. CondCode getSetCCOrOperation(CondCode Op1, CondCode Op2, bool isInteger); - /// getSetCCAndOperation - Return the result of a logical AND between - /// different comparisons of identical values: ((X op1 Y) & (X op2 Y)). This - /// function returns SETCC_INVALID if it is not possible to represent the - /// resultant comparison. + /// Return the result of a logical AND between different comparisons of + /// identical values: ((X op1 Y) & (X op2 Y)). This function returns + /// SETCC_INVALID if it is not possible to represent the resultant comparison. CondCode getSetCCAndOperation(CondCode Op1, CondCode Op2, bool isInteger); //===--------------------------------------------------------------------===// - /// CvtCode enum - This enum defines the various converts CONVERT_RNDSAT - /// supports. + /// This enum defines the various converts CONVERT_RNDSAT supports. enum CvtCode { CVT_FF, /// Float from Float CVT_FS, /// Float from Signed diff --git a/include/llvm/CodeGen/LiveInterval.h b/include/llvm/CodeGen/LiveInterval.h index 177280916a183472b70300972bbff9a73a868d24..04e840dea2caa5af83574244fa0ce7d053e986ca 100644 --- a/include/llvm/CodeGen/LiveInterval.h +++ b/include/llvm/CodeGen/LiveInterval.h @@ -613,6 +613,9 @@ namespace llvm { BumpPtrAllocator &Allocator) : LiveRange(Other, Allocator), Next(nullptr), LaneMask(LaneMask) { } + + void print(raw_ostream &OS) const; + void dump() const; }; private: @@ -712,10 +715,6 @@ namespace llvm { /// are not considered valid and should only exist temporarily). void removeEmptySubRanges(); - /// Construct main live range by merging the SubRanges of @p LI. - void constructMainRangeFromSubranges(const SlotIndexes &Indexes, - VNInfo::Allocator &VNIAllocator); - /// getSize - Returns the sum of sizes of all the LiveRange's. /// unsigned getSize() const; @@ -759,6 +758,12 @@ namespace llvm { void freeSubRange(SubRange *S); }; + inline raw_ostream &operator<<(raw_ostream &OS, + const LiveInterval::SubRange &SR) { + SR.print(OS); + return OS; + } + inline raw_ostream &operator<<(raw_ostream &OS, const LiveInterval &LI) { LI.print(OS); return OS; @@ -868,75 +873,5 @@ namespace llvm { void Distribute(LiveInterval &LI, LiveInterval *LIV[], MachineRegisterInfo &MRI); }; - - /// Helper class that can divide MachineOperands of a virtual register into - /// equivalence classes of connected components. - /// MachineOperands belong to the same equivalence class when they are part of - /// the same SubRange segment or adjacent segments (adjacent in control - /// flow); Different subranges affected by the same MachineOperand belong to - /// the same equivalence class. - /// - /// Example: - /// vreg0:sub0 = ... - /// vreg0:sub1 = ... - /// vreg0:sub2 = ... - /// ... - /// xxx = op vreg0:sub1 - /// vreg0:sub1 = ... - /// store vreg0:sub0_sub1 - /// - /// The example contains 3 different equivalence classes: - /// - One for the (dead) vreg0:sub2 definition - /// - One containing the first vreg0:sub1 definition and its use, - /// but not the second definition! - /// - The remaining class contains all other operands involving vreg0. - /// - /// We provide a utility function here to rename disjunct classes to different - /// virtual registers. - class ConnectedSubRegClasses { - LiveIntervals &LIS; - MachineRegisterInfo &MRI; - - public: - ConnectedSubRegClasses(LiveIntervals &LIS, MachineRegisterInfo &MRI) - : LIS(LIS), MRI(MRI) {} - - /// Split unrelated subregister components and rename them to new vregs. - void renameComponents(LiveInterval &LI) const; - - private: - struct SubRangeInfo { - ConnectedVNInfoEqClasses ConEQ; - LiveInterval::SubRange *SR; - unsigned Index; - - SubRangeInfo(LiveIntervals &LIS, LiveInterval::SubRange &SR, - unsigned Index) - : ConEQ(LIS), SR(&SR), Index(Index) {} - }; - - /// \brief Build a vector of SubRange infos and a union find set of - /// equivalence classes. - /// Returns true if more than 1 equivalence class was found. - bool findComponents(IntEqClasses &Classes, - SmallVectorImpl &SubRangeInfos, - LiveInterval &LI) const; - - /// \brief Distribute the LiveInterval segments into the new LiveIntervals - /// belonging to their class. - void distribute(const IntEqClasses &Classes, - const SmallVectorImpl &SubRangeInfos, - const SmallVectorImpl &Intervals) const; - - /// \brief Constructs main liverange and add missing undef+dead flags. - void computeMainRangesFixFlags(const IntEqClasses &Classes, - const SmallVectorImpl &SubRangeInfos, - const SmallVectorImpl &Intervals) const; - - /// Rewrite Machine Operands to use the new vreg belonging to their class. - void rewriteOperands(const IntEqClasses &Classes, - const SmallVectorImpl &SubRangeInfos, - const SmallVectorImpl &Intervals) const; - }; } #endif diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h index d72b6c315cc4b257adf734be32317ebadd821abc..d4ee0582cc4120464a2d6986393aee19982fb7e6 100644 --- a/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -31,7 +31,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetRegisterInfo.h" #include -#include namespace llvm { @@ -406,10 +405,10 @@ extern cl::opt UseSegmentSetForPhysRegs; void splitSeparateComponents(LiveInterval &LI, SmallVectorImpl &SplitLIs); - /// Assure dead subregister definitions have their own vreg assigned. - /// This calls ConnectedSubRegClasses::splitSeparateSubRegComponent() - /// on each virtual register. - void renameDisconnectedComponents(); + /// For live interval \p LI with correct SubRanges construct matching + /// information for the main live range. Expects the main live range to not + /// have any segments or value numbers. + void constructMainRangeFromSubranges(LiveInterval &LI); private: /// Compute live intervals for all virtual registers. diff --git a/include/llvm/CodeGen/LivePhysRegs.h b/include/llvm/CodeGen/LivePhysRegs.h index 3bdf5ae8d0132075a3f96d6d23531f0c890c59bb..1cea9d5b90d64aaa06b885a60f40222fd97185ff 100644 --- a/include/llvm/CodeGen/LivePhysRegs.h +++ b/include/llvm/CodeGen/LivePhysRegs.h @@ -84,12 +84,8 @@ public: void removeReg(unsigned Reg) { assert(TRI && "LivePhysRegs is not initialized."); assert(Reg <= TRI->getNumRegs() && "Expected a physical register."); - for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/true); - SubRegs.isValid(); ++SubRegs) - LiveRegs.erase(*SubRegs); - for (MCSuperRegIterator SuperRegs(Reg, TRI, /*IncludeSelf=*/false); - SuperRegs.isValid(); ++SuperRegs) - LiveRegs.erase(*SuperRegs); + for (MCRegAliasIterator R(Reg, TRI, true); R.isValid(); ++R) + LiveRegs.erase(*R); } /// \brief Removes physical registers clobbered by the regmask operand @p MO. @@ -97,10 +93,15 @@ public: SmallVectorImpl> *Clobbers); /// \brief Returns true if register @p Reg is contained in the set. This also - /// works if only the super register of @p Reg has been defined, because we - /// always add also all sub-registers to the set. + /// works if only the super register of @p Reg has been defined, because + /// addReg() always adds all sub-registers to the set as well. + /// Note: Returns false if just some sub registers are live, use available() + /// when searching a free register. bool contains(unsigned Reg) const { return LiveRegs.count(Reg); } + /// Returns true if register \p Reg and no aliasing register is in the set. + bool available(const MachineRegisterInfo &MRI, unsigned Reg) const; + /// \brief Simulates liveness when stepping backwards over an /// instruction(bundle): Remove Defs, add uses. This is the recommended way of /// calculating liveness. @@ -116,15 +117,20 @@ public: void stepForward(const MachineInstr &MI, SmallVectorImpl> &Clobbers); - /// \brief Adds all live-in registers of basic block @p MBB; After prologue/ - /// epilogue insertion \p AddPristines should be set to true to insert the + /// Adds all live-in registers of basic block @p MBB. + /// Live in registers are the registers in the blocks live-in list and the /// pristine registers. - void addLiveIns(const MachineBasicBlock *MBB, bool AddPristines = false); + void addLiveIns(const MachineBasicBlock &MBB); + + /// Adds all live-out registers of basic block @p MBB. + /// Live out registers are the union of the live-in registers of the successor + /// blocks and pristine registers. Live out registers of the end block are the + /// callee saved registers. + void addLiveOuts(const MachineBasicBlock &MBB); - /// \brief Adds all live-out registers of basic block @p MBB; After prologue/ - /// epilogue insertion \p AddPristinesAndCSRs should be set to true. - void addLiveOuts(const MachineBasicBlock *MBB, - bool AddPristinesAndCSRs = false); + /// Like addLiveOuts() but does not add pristine registers/callee saved + /// registers. + void addLiveOutsNoPristines(const MachineBasicBlock &MBB); typedef SparseSet::const_iterator const_iterator; const_iterator begin() const { return LiveRegs.begin(); } diff --git a/include/llvm/CodeGen/LiveRangeEdit.h b/include/llvm/CodeGen/LiveRangeEdit.h index 2271e3352aa27885f69b6c72e1a35e93a44f9e00..4250777682ba516994bce094cf3f620c4917cf21 100644 --- a/include/llvm/CodeGen/LiveRangeEdit.h +++ b/include/llvm/CodeGen/LiveRangeEdit.h @@ -72,6 +72,10 @@ private: /// ScannedRemattable - true when remattable values have been identified. bool ScannedRemattable; + /// DeadRemats - The saved instructions which have already been dead after + /// rematerialization but not deleted yet -- to be done in postOptimization. + SmallPtrSet *DeadRemats; + /// Remattable - Values defined by remattable instructions as identified by /// tii.isTriviallyReMaterializable(). SmallPtrSet Remattable; @@ -96,7 +100,8 @@ private: SmallVector, SmallPtrSet > ToShrinkSet; /// Helper for eliminateDeadDefs. - void eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink); + void eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink, + AliasAnalysis *AA); /// MachineRegisterInfo callback to notify when new virtual /// registers are created. @@ -116,13 +121,16 @@ public: /// @param vrm Map of virtual registers to physical registers for this /// function. If NULL, no virtual register map updates will /// be done. This could be the case if called before Regalloc. + /// @param deadRemats The collection of all the instructions defining an + /// original reg and are dead after remat. LiveRangeEdit(LiveInterval *parent, SmallVectorImpl &newRegs, MachineFunction &MF, LiveIntervals &lis, VirtRegMap *vrm, - Delegate *delegate = nullptr) + Delegate *delegate = nullptr, + SmallPtrSet *deadRemats = nullptr) : Parent(parent), NewRegs(newRegs), MRI(MF.getRegInfo()), LIS(lis), - VRM(vrm), TII(*MF.getSubtarget().getInstrInfo()), - TheDelegate(delegate), FirstNew(newRegs.size()), - ScannedRemattable(false) { + VRM(vrm), TII(*MF.getSubtarget().getInstrInfo()), TheDelegate(delegate), + FirstNew(newRegs.size()), ScannedRemattable(false), + DeadRemats(deadRemats) { MRI.setDelegate(this); } @@ -142,6 +150,16 @@ public: bool empty() const { return size() == 0; } unsigned get(unsigned idx) const { return NewRegs[idx+FirstNew]; } + /// pop_back - It allows LiveRangeEdit users to drop new registers. + /// The context is when an original def instruction of a register is + /// dead after rematerialization, we still want to keep it for following + /// rematerializations. We save the def instruction in DeadRemats, + /// and replace the original dst register with a new dummy register so + /// the live range of original dst register can be shrinked normally. + /// We don't want to allocate phys register for the dummy register, so + /// we want to drop it from the NewRegs set. + void pop_back() { NewRegs.pop_back(); } + ArrayRef regs() const { return makeArrayRef(NewRegs).slice(FirstNew); } @@ -175,15 +193,15 @@ public: /// Remat - Information needed to rematerialize at a specific location. struct Remat { VNInfo *ParentVNI; // parent_'s value at the remat location. - MachineInstr *OrigMI; // Instruction defining ParentVNI. + MachineInstr *OrigMI; // Instruction defining OrigVNI. It contains the + // real expr for remat. explicit Remat(VNInfo *ParentVNI) : ParentVNI(ParentVNI), OrigMI(nullptr) {} }; /// canRematerializeAt - Determine if ParentVNI can be rematerialized at /// UseIdx. It is assumed that parent_.getVNINfoAt(UseIdx) == ParentVNI. /// When cheapAsAMove is set, only cheap remats are allowed. - bool canRematerializeAt(Remat &RM, - SlotIndex UseIdx, + bool canRematerializeAt(Remat &RM, VNInfo *OrigVNI, SlotIndex UseIdx, bool cheapAsAMove); /// rematerializeAt - Rematerialize RM.ParentVNI into DestReg by inserting an @@ -208,6 +226,12 @@ public: return Rematted.count(ParentVNI); } + void markDeadRemat(MachineInstr *inst) { + // DeadRemats is an optional field. + if (DeadRemats) + DeadRemats->insert(inst); + } + /// eraseVirtReg - Notify the delegate that Reg is no longer in use, and try /// to erase it from LIS. void eraseVirtReg(unsigned Reg); @@ -218,8 +242,9 @@ public: /// RegsBeingSpilled lists registers currently being spilled by the register /// allocator. These registers should not be split into new intervals /// as currently those new intervals are not guaranteed to spill. - void eliminateDeadDefs(SmallVectorImpl &Dead, - ArrayRef RegsBeingSpilled = None); + void eliminateDeadDefs(SmallVectorImpl &Dead, + ArrayRef RegsBeingSpilled = None, + AliasAnalysis *AA = nullptr); /// calculateRegClassAndHint - Recompute register class and hint for each new /// register. diff --git a/include/llvm/CodeGen/LiveVariables.h b/include/llvm/CodeGen/LiveVariables.h index 55b97dc3e71d94306be66c173fb50e4f56a36c3a..bc210dda08c09449508cdede5abd169e44e60fb7 100644 --- a/include/llvm/CodeGen/LiveVariables.h +++ b/include/llvm/CodeGen/LiveVariables.h @@ -91,9 +91,9 @@ public: /// removeKill - Delete a kill corresponding to the specified /// machine instruction. Returns true if there was a kill /// corresponding to this instruction, false otherwise. - bool removeKill(MachineInstr *MI) { - std::vector::iterator - I = std::find(Kills.begin(), Kills.end(), MI); + bool removeKill(MachineInstr &MI) { + std::vector::iterator I = + std::find(Kills.begin(), Kills.end(), &MI); if (I == Kills.end()) return false; Kills.erase(I); @@ -155,10 +155,10 @@ private: // Intermediate data structures /// HandleRegMask - Call HandlePhysRegKill for all registers clobbered by Mask. void HandleRegMask(const MachineOperand&); - void HandlePhysRegUse(unsigned Reg, MachineInstr *MI); + void HandlePhysRegUse(unsigned Reg, MachineInstr &MI); void HandlePhysRegDef(unsigned Reg, MachineInstr *MI, SmallVectorImpl &Defs); - void UpdatePhysRegDefs(MachineInstr *MI, SmallVectorImpl &Defs); + void UpdatePhysRegDefs(MachineInstr &MI, SmallVectorImpl &Defs); /// FindLastRefOrPartRef - Return the last reference or partial reference of /// the specified register. @@ -176,7 +176,7 @@ private: // Intermediate data structures /// is coming from. void analyzePHINodes(const MachineFunction& Fn); - void runOnInstr(MachineInstr *MI, SmallVectorImpl &Defs); + void runOnInstr(MachineInstr &MI, SmallVectorImpl &Defs); void runOnBlock(MachineBasicBlock *MBB, unsigned NumRegs); public: @@ -185,37 +185,37 @@ public: /// RegisterDefIsDead - Return true if the specified instruction defines the /// specified register, but that definition is dead. - bool RegisterDefIsDead(MachineInstr *MI, unsigned Reg) const; + bool RegisterDefIsDead(MachineInstr &MI, unsigned Reg) const; //===--------------------------------------------------------------------===// // API to update live variable information /// replaceKillInstruction - Update register kill info by replacing a kill /// instruction with a new one. - void replaceKillInstruction(unsigned Reg, MachineInstr *OldMI, - MachineInstr *NewMI); + void replaceKillInstruction(unsigned Reg, MachineInstr &OldMI, + MachineInstr &NewMI); /// addVirtualRegisterKilled - Add information about the fact that the /// specified register is killed after being used by the specified /// instruction. If AddIfNotFound is true, add a implicit operand if it's /// not found. - void addVirtualRegisterKilled(unsigned IncomingReg, MachineInstr *MI, + void addVirtualRegisterKilled(unsigned IncomingReg, MachineInstr &MI, bool AddIfNotFound = false) { - if (MI->addRegisterKilled(IncomingReg, TRI, AddIfNotFound)) - getVarInfo(IncomingReg).Kills.push_back(MI); + if (MI.addRegisterKilled(IncomingReg, TRI, AddIfNotFound)) + getVarInfo(IncomingReg).Kills.push_back(&MI); } /// removeVirtualRegisterKilled - Remove the specified kill of the virtual /// register from the live variable information. Returns true if the /// variable was marked as killed by the specified instruction, /// false otherwise. - bool removeVirtualRegisterKilled(unsigned reg, MachineInstr *MI) { + bool removeVirtualRegisterKilled(unsigned reg, MachineInstr &MI) { if (!getVarInfo(reg).removeKill(MI)) return false; bool Removed = false; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI->getOperand(i); + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI.getOperand(i); if (MO.isReg() && MO.isKill() && MO.getReg() == reg) { MO.setIsKill(false); Removed = true; @@ -230,28 +230,28 @@ public: /// removeVirtualRegistersKilled - Remove all killed info for the specified /// instruction. - void removeVirtualRegistersKilled(MachineInstr *MI); + void removeVirtualRegistersKilled(MachineInstr &MI); /// addVirtualRegisterDead - Add information about the fact that the specified /// register is dead after being used by the specified instruction. If /// AddIfNotFound is true, add a implicit operand if it's not found. - void addVirtualRegisterDead(unsigned IncomingReg, MachineInstr *MI, + void addVirtualRegisterDead(unsigned IncomingReg, MachineInstr &MI, bool AddIfNotFound = false) { - if (MI->addRegisterDead(IncomingReg, TRI, AddIfNotFound)) - getVarInfo(IncomingReg).Kills.push_back(MI); + if (MI.addRegisterDead(IncomingReg, TRI, AddIfNotFound)) + getVarInfo(IncomingReg).Kills.push_back(&MI); } /// removeVirtualRegisterDead - Remove the specified kill of the virtual /// register from the live variable information. Returns true if the /// variable was marked dead at the specified instruction, false /// otherwise. - bool removeVirtualRegisterDead(unsigned reg, MachineInstr *MI) { + bool removeVirtualRegisterDead(unsigned reg, MachineInstr &MI) { if (!getVarInfo(reg).removeKill(MI)) return false; bool Removed = false; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI->getOperand(i); + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI.getOperand(i); if (MO.isReg() && MO.isDef() && MO.getReg() == reg) { MO.setIsDead(false); Removed = true; @@ -278,9 +278,8 @@ public: void MarkVirtRegAliveInBlock(VarInfo& VRInfo, MachineBasicBlock* DefBlock, MachineBasicBlock *BB, std::vector &WorkList); - void HandleVirtRegDef(unsigned reg, MachineInstr *MI); - void HandleVirtRegUse(unsigned reg, MachineBasicBlock *MBB, - MachineInstr *MI); + void HandleVirtRegDef(unsigned reg, MachineInstr &MI); + void HandleVirtRegUse(unsigned reg, MachineBasicBlock *MBB, MachineInstr &MI); bool isLiveIn(unsigned Reg, const MachineBasicBlock &MBB) { return getVarInfo(Reg).isLiveIn(MBB, Reg, *MRI); diff --git a/include/llvm/CodeGen/MIRParser/MIRParser.h b/include/llvm/CodeGen/MIRParser/MIRParser.h index a569d5ec1f5e81eed5d771d339fb581e74bfa551..dd0780397f4293db4301a92eee9c02079fd06b2b 100644 --- a/include/llvm/CodeGen/MIRParser/MIRParser.h +++ b/include/llvm/CodeGen/MIRParser/MIRParser.h @@ -18,7 +18,6 @@ #ifndef LLVM_CODEGEN_MIRPARSER_MIRPARSER_H #define LLVM_CODEGEN_MIRPARSER_MIRPARSER_H -#include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/MachineFunctionInitializer.h" #include "llvm/IR/Module.h" #include "llvm/Support/MemoryBuffer.h" @@ -26,6 +25,7 @@ namespace llvm { +class StringRef; class MIRParserImpl; class SMDiagnostic; diff --git a/include/llvm/CodeGen/MIRYamlMapping.h b/include/llvm/CodeGen/MIRYamlMapping.h index 9d5eb60e488aef9f6d528b8316cfb71d965f68e2..7f9c4483333624e758cc5500d367d45585bf3f68 100644 --- a/include/llvm/CodeGen/MIRYamlMapping.h +++ b/include/llvm/CodeGen/MIRYamlMapping.h @@ -7,9 +7,6 @@ // //===----------------------------------------------------------------------===// // -// The MIR serialization library is currently a work in progress. It can't -// serialize machine functions at this time. -// // This file implements the mapping between various MIR data structures and // their corresponding YAML representation. // diff --git a/include/llvm/CodeGen/MachineBasicBlock.h b/include/llvm/CodeGen/MachineBasicBlock.h index ad04e521e25c9d2940ed506c25d3f99aa64685e9..d5f918eb2bb909b945646405e9f50a8ef6037d3c 100644 --- a/include/llvm/CodeGen/MachineBasicBlock.h +++ b/include/llvm/CodeGen/MachineBasicBlock.h @@ -342,10 +342,6 @@ public: /// via an exception handler. void setIsEHPad(bool V = true) { IsEHPad = V; } - /// If this block has a successor that is a landing pad, return it. Otherwise - /// return NULL. - const MachineBasicBlock *getLandingPadSuccessor() const; - bool hasEHPadSuccessor() const; /// Returns true if this is the entry block of an EH funclet. @@ -506,7 +502,13 @@ public: /// /// This function updates LiveVariables, MachineDominatorTree, and /// MachineLoopInfo, as applicable. - MachineBasicBlock *SplitCriticalEdge(MachineBasicBlock *Succ, Pass *P); + MachineBasicBlock *SplitCriticalEdge(MachineBasicBlock *Succ, Pass &P); + + /// Check if the edge between this block and the given successor \p + /// Succ, can be split. If this returns true a subsequent call to + /// SplitCriticalEdge is guaranteed to return a valid basic block if + /// no changes occured in the meantime. + bool canSplitCriticalEdge(const MachineBasicBlock *Succ) const; void pop_front() { Insts.pop_front(); } void pop_back() { Insts.pop_back(); } @@ -672,9 +674,9 @@ public: // Debugging methods. void dump() const; - void print(raw_ostream &OS, SlotIndexes* = nullptr) const; + void print(raw_ostream &OS, const SlotIndexes* = nullptr) const; void print(raw_ostream &OS, ModuleSlotTracker &MST, - SlotIndexes * = nullptr) const; + const SlotIndexes* = nullptr) const; // Printing method used by LoopInfo. void printAsOperand(raw_ostream &OS, bool PrintType = true) const; diff --git a/include/llvm/CodeGen/MachineBlockFrequencyInfo.h b/include/llvm/CodeGen/MachineBlockFrequencyInfo.h index feb394e7a69e0026dd7fa40c611503883acf0b84..7a236086ed09c030cec8ef47ebfea0db23047ccb 100644 --- a/include/llvm/CodeGen/MachineBlockFrequencyInfo.h +++ b/include/llvm/CodeGen/MachineBlockFrequencyInfo.h @@ -14,6 +14,7 @@ #ifndef LLVM_CODEGEN_MACHINEBLOCKFREQUENCYINFO_H #define LLVM_CODEGEN_MACHINEBLOCKFREQUENCYINFO_H +#include "llvm/ADT/Optional.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/Support/BlockFrequency.h" #include @@ -50,7 +51,10 @@ public: /// BlockFrequency getBlockFreq(const MachineBasicBlock *MBB) const; + Optional getBlockProfileCount(const MachineBasicBlock *MBB) const; + const MachineFunction *getFunction() const; + const MachineBranchProbabilityInfo *getMBPI() const; void view() const; // Print the block frequency Freq to OS using the current functions entry diff --git a/include/llvm/CodeGen/MachineCombinerPattern.h b/include/llvm/CodeGen/MachineCombinerPattern.h index f3891227746fe97b996d8509264b716824f35572..11238016d447b2082210f86e97fcdebe07b7568e 100644 --- a/include/llvm/CodeGen/MachineCombinerPattern.h +++ b/include/llvm/CodeGen/MachineCombinerPattern.h @@ -38,7 +38,40 @@ enum class MachineCombinerPattern { MULSUBX_OP1, MULSUBX_OP2, MULADDXI_OP1, - MULSUBXI_OP1 + MULSUBXI_OP1, + // Floating Point + FMULADDS_OP1, + FMULADDS_OP2, + FMULSUBS_OP1, + FMULSUBS_OP2, + FMULADDD_OP1, + FMULADDD_OP2, + FMULSUBD_OP1, + FMULSUBD_OP2, + FMLAv1i32_indexed_OP1, + FMLAv1i32_indexed_OP2, + FMLAv1i64_indexed_OP1, + FMLAv1i64_indexed_OP2, + FMLAv2f32_OP2, + FMLAv2f32_OP1, + FMLAv2f64_OP1, + FMLAv2f64_OP2, + FMLAv2i32_indexed_OP1, + FMLAv2i32_indexed_OP2, + FMLAv2i64_indexed_OP1, + FMLAv2i64_indexed_OP2, + FMLAv4f32_OP1, + FMLAv4f32_OP2, + FMLAv4i32_indexed_OP1, + FMLAv4i32_indexed_OP2, + FMLSv1i32_indexed_OP2, + FMLSv1i64_indexed_OP2, + FMLSv2i32_indexed_OP2, + FMLSv2i64_indexed_OP2, + FMLSv2f32_OP2, + FMLSv2f64_OP2, + FMLSv4i32_indexed_OP2, + FMLSv4f32_OP2 }; } // end namespace llvm diff --git a/include/llvm/CodeGen/MachineDominators.h b/include/llvm/CodeGen/MachineDominators.h index a69936f6e267ca339f2c6444e25bdf97be8eb69f..ed7cc277e8b6ae31a4e6ddfa0a876b448f438abb 100644 --- a/include/llvm/CodeGen/MachineDominators.h +++ b/include/llvm/CodeGen/MachineDominators.h @@ -216,6 +216,8 @@ public: void releaseMemory() override; + void verifyAnalysis() const override; + void print(raw_ostream &OS, const Module*) const override; /// \brief Record that the critical edge (FromBB, ToBB) has been @@ -239,6 +241,27 @@ public: "A basic block inserted via edge splitting cannot appear twice"); CriticalEdgesToSplit.push_back({FromBB, ToBB, NewBB}); } + + /// \brief Returns *false* if the other dominator tree matches this dominator + /// tree. + inline bool compare(const MachineDominatorTree &Other) const { + const MachineDomTreeNode *R = getRootNode(); + const MachineDomTreeNode *OtherR = Other.getRootNode(); + + if (!R || !OtherR || R->getBlock() != OtherR->getBlock()) + return true; + + if (DT->compare(*Other.DT)) + return true; + + return false; + } + + /// \brief Verify the correctness of the domtree by re-computing it. + /// + /// This should only be used for debugging as it aborts the program if the + /// verification fails. + void verifyDomTree() const; }; //===------------------------------------- diff --git a/include/llvm/CodeGen/MachineFrameInfo.h b/include/llvm/CodeGen/MachineFrameInfo.h index baeaae0d85a6ba1c575cdd413a2f4c323a93c870..59755674c69e56943d5acfa670451068c85f1c74 100644 --- a/include/llvm/CodeGen/MachineFrameInfo.h +++ b/include/llvm/CodeGen/MachineFrameInfo.h @@ -138,11 +138,12 @@ class MachineFrameInfo { /// The alignment of the stack. unsigned StackAlignment; - /// Can the stack be realigned. - /// Targets that set this to false don't have the ability to overalign - /// their stack frame, and thus, overaligned allocas are all treated - /// as dynamic allocations and the target must handle them as part - /// of DYNAMIC_STACKALLOC lowering. + /// Can the stack be realigned. This can be false if the target does not + /// support stack realignment, or if the user asks us not to realign the + /// stack. In this situation, overaligned allocas are all treated as dynamic + /// allocations and the target must handle them as part of DYNAMIC_STACKALLOC + /// lowering. All non-alloca stack objects have their alignment clamped to the + /// base ABI stack alignment. /// FIXME: There is room for improvement in this case, in terms of /// grouping overaligned allocas into a "secondary stack frame" and /// then only use a single alloca to allocate this frame and only a @@ -151,39 +152,42 @@ class MachineFrameInfo { /// realignment. bool StackRealignable; + /// Whether the function has the \c alignstack attribute. + bool ForcedRealign; + /// The list of stack objects allocated. std::vector Objects; /// This contains the number of fixed objects contained on /// the stack. Because fixed objects are stored at a negative index in the /// Objects list, this is also the index to the 0th object in the list. - unsigned NumFixedObjects; + unsigned NumFixedObjects = 0; /// This boolean keeps track of whether any variable /// sized objects have been allocated yet. - bool HasVarSizedObjects; + bool HasVarSizedObjects = false; /// This boolean keeps track of whether there is a call /// to builtin \@llvm.frameaddress. - bool FrameAddressTaken; + bool FrameAddressTaken = false; /// This boolean keeps track of whether there is a call /// to builtin \@llvm.returnaddress. - bool ReturnAddressTaken; + bool ReturnAddressTaken = false; /// This boolean keeps track of whether there is a call /// to builtin \@llvm.experimental.stackmap. - bool HasStackMap; + bool HasStackMap = false; /// This boolean keeps track of whether there is a call /// to builtin \@llvm.experimental.patchpoint. - bool HasPatchPoint; + bool HasPatchPoint = false; /// The prolog/epilog code inserter calculates the final stack /// offsets for all of the fixed size objects, updating the Objects list /// above. It then updates StackSize to contain the number of bytes that need /// to be allocated on entry to the function. - uint64_t StackSize; + uint64_t StackSize = 0; /// The amount that a frame offset needs to be adjusted to /// have the actual offset from the stack/frame pointer. The exact usage of @@ -194,7 +198,7 @@ class MachineFrameInfo { /// targets, this value is only used when generating debug info (via /// TargetRegisterInfo::getFrameIndexReference); when generating code, the /// corresponding adjustments are performed directly. - int OffsetAdjustment; + int OffsetAdjustment = 0; /// The prolog/epilog code inserter may process objects that require greater /// alignment than the default alignment the target provides. @@ -203,27 +207,27 @@ class MachineFrameInfo { /// native alignment maintained by the compiler, dynamic alignment code will /// be needed. /// - unsigned MaxAlignment; + unsigned MaxAlignment = 0; /// Set to true if this function adjusts the stack -- e.g., /// when calling another function. This is only valid during and after /// prolog/epilog code insertion. - bool AdjustsStack; + bool AdjustsStack = false; /// Set to true if this function has any function calls. - bool HasCalls; + bool HasCalls = false; /// The frame index for the stack protector. - int StackProtectorIdx; + int StackProtectorIdx = -1; /// The frame index for the function context. Used for SjLj exceptions. - int FunctionContextIdx; + int FunctionContextIdx = -1; /// This contains the size of the largest call frame if the target uses frame /// setup/destroy pseudo instructions (as defined in the TargetFrameInfo /// class). This information is important for frame pointer elimination. /// It is only valid during and after prolog/epilog code insertion. - unsigned MaxCallFrameSize; + unsigned MaxCallFrameSize = 0; /// The prolog/epilog code inserter fills in this vector with each /// callee saved register saved in the frame. Beyond its use by the prolog/ @@ -232,79 +236,53 @@ class MachineFrameInfo { std::vector CSInfo; /// Has CSInfo been set yet? - bool CSIValid; + bool CSIValid = false; /// References to frame indices which are mapped /// into the local frame allocation block. SmallVector, 32> LocalFrameObjects; /// Size of the pre-allocated local frame block. - int64_t LocalFrameSize; + int64_t LocalFrameSize = 0; /// Required alignment of the local object blob, which is the strictest /// alignment of any object in it. - unsigned LocalFrameMaxAlign; + unsigned LocalFrameMaxAlign = 0; /// Whether the local object blob needs to be allocated together. If not, /// PEI should ignore the isPreAllocated flags on the stack objects and /// just allocate them normally. - bool UseLocalStackAllocationBlock; - - /// Whether the "realign-stack" option is on. - bool RealignOption; + bool UseLocalStackAllocationBlock = false; /// True if the function dynamically adjusts the stack pointer through some /// opaque mechanism like inline assembly or Win32 EH. - bool HasOpaqueSPAdjustment; + bool HasOpaqueSPAdjustment = false; /// True if the function contains operations which will lower down to /// instructions which manipulate the stack pointer. - bool HasCopyImplyingStackAdjustment; + bool HasCopyImplyingStackAdjustment = false; /// True if the function contains a call to the llvm.vastart intrinsic. - bool HasVAStart; + bool HasVAStart = false; /// True if this is a varargs function that contains a musttail call. - bool HasMustTailInVarArgFunc; + bool HasMustTailInVarArgFunc = false; /// True if this function contains a tail call. If so immutable objects like /// function arguments are no longer so. A tail call *can* override fixed /// stack objects like arguments so we can't treat them as immutable. - bool HasTailCall; + bool HasTailCall = false; /// Not null, if shrink-wrapping found a better place for the prologue. - MachineBasicBlock *Save; + MachineBasicBlock *Save = nullptr; /// Not null, if shrink-wrapping found a better place for the epilogue. - MachineBasicBlock *Restore; + MachineBasicBlock *Restore = nullptr; public: - explicit MachineFrameInfo(unsigned StackAlign, bool isStackRealign, - bool RealignOpt) - : StackAlignment(StackAlign), StackRealignable(isStackRealign), - RealignOption(RealignOpt) { - StackSize = NumFixedObjects = OffsetAdjustment = MaxAlignment = 0; - HasVarSizedObjects = false; - FrameAddressTaken = false; - ReturnAddressTaken = false; - HasStackMap = false; - HasPatchPoint = false; - AdjustsStack = false; - HasCalls = false; - StackProtectorIdx = -1; - FunctionContextIdx = -1; - MaxCallFrameSize = 0; - CSIValid = false; - LocalFrameSize = 0; - LocalFrameMaxAlign = 0; - UseLocalStackAllocationBlock = false; - HasOpaqueSPAdjustment = false; - HasCopyImplyingStackAdjustment = false; - HasVAStart = false; - HasMustTailInVarArgFunc = false; - Save = nullptr; - Restore = nullptr; - HasTailCall = false; - } + explicit MachineFrameInfo(unsigned StackAlignment, bool StackRealignable, + bool ForcedRealign) + : StackAlignment(StackAlignment), StackRealignable(StackRealignable), + ForcedRealign(ForcedRealign) {} /// Return true if there are any stack objects in this function. bool hasStackObjects() const { return !Objects.empty(); } diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h index b253691dabb62a6467f8af8c9a18204f477d73b5..c3467e1659a578dc401edeeff6a5d4bbab1a57fd 100644 --- a/include/llvm/CodeGen/MachineFunction.h +++ b/include/llvm/CodeGen/MachineFunction.h @@ -105,12 +105,17 @@ public: // that the property hold, but not that it does not hold. // Property descriptions: - // IsSSA (currently unused, intended to eventually replace - // MachineRegisterInfo::isSSA()) - // TracksLiveness: (currently unsued, intended to eventually replace - // MachineRegisterInfo::tracksLiveness()) + // IsSSA: True when the machine function is in SSA form and virtual registers + // have a single def. + // TracksLiveness: True when tracking register liveness accurately. + // While this property is set, register liveness information in basic block + // live-in lists and machine instruction operands (e.g. kill flags, implicit + // defs) is accurate. This means it can be used to change the code in ways + // that affect the values in registers, for example by the register + // scavenger. + // When this property is clear, liveness is no longer reliable. // AllVRegsAllocated: All virtual registers have been allocated; i.e. all - // register operands are physical registers. + // register operands are physical registers. enum class Property : unsigned { IsSSA, TracksLiveness, @@ -143,6 +148,10 @@ public: return !V.Properties.test(Properties); } + // Print the MachineFunctionProperties in human-readable form. If OnlySet is + // true, only print the properties that are set. + void print(raw_ostream &ROS, bool OnlySet=false) const; + private: BitVector Properties = BitVector(static_cast(Property::LastProperty)); @@ -382,7 +391,7 @@ public: /// print - Print out the MachineFunction in a format suitable for debugging /// to the specified stream. /// - void print(raw_ostream &OS, SlotIndexes* = nullptr) const; + void print(raw_ostream &OS, const SlotIndexes* = nullptr) const; /// viewCFG - This function is meant for use from the debugger. You can just /// say 'call F->viewCFG()' and a ghostview window should pop up from the @@ -493,8 +502,7 @@ public: /// CreateMachineInstr - Allocate a new MachineInstr. Use this instead /// of `new MachineInstr'. /// - MachineInstr *CreateMachineInstr(const MCInstrDesc &MCID, - DebugLoc DL, + MachineInstr *CreateMachineInstr(const MCInstrDesc &MCID, const DebugLoc &DL, bool NoImp = false); /// CloneMachineInstr - Create a new MachineInstr which is a copy of the diff --git a/include/llvm/CodeGen/MachineInstr.h b/include/llvm/CodeGen/MachineInstr.h index 4647a63853c183b9f3425036aa65396e83aaadd0..8f1cb9b6f6590a993868b142e88db886fff0ca3a 100644 --- a/include/llvm/CodeGen/MachineInstr.h +++ b/include/llvm/CodeGen/MachineInstr.h @@ -16,16 +16,13 @@ #ifndef LLVM_CODEGEN_MACHINEINSTR_H #define LLVM_CODEGEN_MACHINEINSTR_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/CodeGen/MachineOperand.h" -#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/InlineAsm.h" #include "llvm/MC/MCInstrDesc.h" @@ -34,7 +31,11 @@ namespace llvm { +class StringRef; +template class ArrayRef; template class SmallVectorImpl; +class DILocalVariable; +class DIExpression; class TargetInstrInfo; class TargetRegisterClass; class TargetRegisterInfo; @@ -263,17 +264,11 @@ public: /// Return the debug variable referenced by /// this DBG_VALUE instruction. - const DILocalVariable *getDebugVariable() const { - assert(isDebugValue() && "not a DBG_VALUE"); - return cast(getOperand(2).getMetadata()); - } + const DILocalVariable *getDebugVariable() const; /// Return the complex address expression referenced by /// this DBG_VALUE instruction. - const DIExpression *getDebugExpression() const { - assert(isDebugValue() && "not a DBG_VALUE"); - return cast(getOperand(3).getMetadata()); - } + const DIExpression *getDebugExpression() const; /// Emit an error referring to the source location of this instruction. /// This should only be used for inline assembly that is somehow @@ -531,6 +526,11 @@ public: /// Convergent instructions can not be made control-dependent on any /// additional values. bool isConvergent(QueryType Type = AnyInBundle) const { + if (isInlineAsm()) { + unsigned ExtraInfo = getOperand(InlineAsm::MIOp_ExtraInfo).getImm(); + if (ExtraInfo & InlineAsm::Extra_IsConvergent) + return true; + } return hasProperty(MCID::Convergent, Type); } @@ -922,6 +922,10 @@ public: return findRegisterDefOperandIdx(Reg, true, false, TRI) != -1; } + /// Returns true if the MachineInstr has an implicit-use operand of exactly + /// the given register (not considering sub/super-registers). + bool hasRegisterImplicitUseOperand(unsigned Reg) const; + /// Returns the operand index that is a use of the specific register or -1 /// if it is not found. It further tightens the search criteria to a use /// that kills the register if isKill is true. diff --git a/include/llvm/CodeGen/MachineInstrBuilder.h b/include/llvm/CodeGen/MachineInstrBuilder.h index 8683917a51c385e80b8b5bf208a4a5180e7c894e..37b67aa0cf5c0aef8d32929aa68d23df500b264f 100644 --- a/include/llvm/CodeGen/MachineInstrBuilder.h +++ b/include/llvm/CodeGen/MachineInstrBuilder.h @@ -10,7 +10,9 @@ // This file exposes a function named BuildMI, which is useful for dramatically // simplifying how MachineInstr's are created. It allows use of code like this: // -// M = BuildMI(X86::ADDrr8, 2).addReg(argVal1).addReg(argVal2); +// M = BuildMI(MBB, MI, DL, TII.get(X86::ADD8rr), Dst) +// .addReg(argVal1) +// .addReg(argVal2); // //===----------------------------------------------------------------------===// @@ -237,18 +239,15 @@ public: }; /// Builder interface. Specify how to create the initial instruction itself. -inline MachineInstrBuilder BuildMI(MachineFunction &MF, - DebugLoc DL, +inline MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID) { return MachineInstrBuilder(MF, MF.CreateMachineInstr(MCID, DL)); } /// This version of the builder sets up the first operand as a /// destination virtual register. -inline MachineInstrBuilder BuildMI(MachineFunction &MF, - DebugLoc DL, - const MCInstrDesc &MCID, - unsigned DestReg) { +inline MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, + const MCInstrDesc &MCID, unsigned DestReg) { return MachineInstrBuilder(MF, MF.CreateMachineInstr(MCID, DL)) .addReg(DestReg, RegState::Define); } @@ -258,8 +257,7 @@ inline MachineInstrBuilder BuildMI(MachineFunction &MF, /// operand as a destination virtual register. inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineBasicBlock::iterator I, - DebugLoc DL, - const MCInstrDesc &MCID, + const DebugLoc &DL, const MCInstrDesc &MCID, unsigned DestReg) { MachineFunction &MF = *BB.getParent(); MachineInstr *MI = MF.CreateMachineInstr(MCID, DL); @@ -267,10 +265,15 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, return MachineInstrBuilder(MF, MI).addReg(DestReg, RegState::Define); } +/// This version of the builder inserts the newly-built instruction before +/// the given position in the given MachineBasicBlock, and sets up the first +/// operand as a destination virtual register. +/// +/// If \c I is inside a bundle, then the newly inserted \a MachineInstr is +/// added to the same bundle. inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineBasicBlock::instr_iterator I, - DebugLoc DL, - const MCInstrDesc &MCID, + const DebugLoc &DL, const MCInstrDesc &MCID, unsigned DestReg) { MachineFunction &MF = *BB.getParent(); MachineInstr *MI = MF.CreateMachineInstr(MCID, DL); @@ -278,18 +281,20 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, return MachineInstrBuilder(MF, MI).addReg(DestReg, RegState::Define); } -inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, - MachineInstr *I, - DebugLoc DL, - const MCInstrDesc &MCID, +inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineInstr &I, + const DebugLoc &DL, const MCInstrDesc &MCID, unsigned DestReg) { - if (I->isInsideBundle()) { - MachineBasicBlock::instr_iterator MII(I); - return BuildMI(BB, MII, DL, MCID, DestReg); - } + // Calling the overload for instr_iterator is always correct. However, the + // definition is not available in headers, so inline the check. + if (I.isInsideBundle()) + return BuildMI(BB, MachineBasicBlock::instr_iterator(I), DL, MCID, DestReg); + return BuildMI(BB, MachineBasicBlock::iterator(I), DL, MCID, DestReg); +} - MachineBasicBlock::iterator MII = I; - return BuildMI(BB, MII, DL, MCID, DestReg); +inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineInstr *I, + const DebugLoc &DL, const MCInstrDesc &MCID, + unsigned DestReg) { + return BuildMI(BB, *I, DL, MCID, DestReg); } /// This version of the builder inserts the newly-built instruction before the @@ -297,7 +302,7 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, /// destination register. inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineBasicBlock::iterator I, - DebugLoc DL, + const DebugLoc &DL, const MCInstrDesc &MCID) { MachineFunction &MF = *BB.getParent(); MachineInstr *MI = MF.CreateMachineInstr(MCID, DL); @@ -307,7 +312,7 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineBasicBlock::instr_iterator I, - DebugLoc DL, + const DebugLoc &DL, const MCInstrDesc &MCID) { MachineFunction &MF = *BB.getParent(); MachineInstr *MI = MF.CreateMachineInstr(MCID, DL); @@ -315,23 +320,25 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, return MachineInstrBuilder(MF, MI); } -inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, - MachineInstr *I, - DebugLoc DL, +inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineInstr &I, + const DebugLoc &DL, const MCInstrDesc &MCID) { - if (I->isInsideBundle()) { - MachineBasicBlock::instr_iterator MII(I); - return BuildMI(BB, MII, DL, MCID); - } + // Calling the overload for instr_iterator is always correct. However, the + // definition is not available in headers, so inline the check. + if (I.isInsideBundle()) + return BuildMI(BB, MachineBasicBlock::instr_iterator(I), DL, MCID); + return BuildMI(BB, MachineBasicBlock::iterator(I), DL, MCID); +} - MachineBasicBlock::iterator MII = I; - return BuildMI(BB, MII, DL, MCID); +inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, MachineInstr *I, + const DebugLoc &DL, + const MCInstrDesc &MCID) { + return BuildMI(BB, *I, DL, MCID); } /// This version of the builder inserts the newly-built instruction at the end /// of the given MachineBasicBlock, and does NOT take a destination register. -inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, - DebugLoc DL, +inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, const DebugLoc &DL, const MCInstrDesc &MCID) { return BuildMI(*BB, BB->end(), DL, MCID); } @@ -339,10 +346,8 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, /// This version of the builder inserts the newly-built instruction at the /// end of the given MachineBasicBlock, and sets up the first operand as a /// destination virtual register. -inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, - DebugLoc DL, - const MCInstrDesc &MCID, - unsigned DestReg) { +inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, const DebugLoc &DL, + const MCInstrDesc &MCID, unsigned DestReg) { return BuildMI(*BB, BB->end(), DL, MCID, DestReg); } @@ -350,47 +355,19 @@ inline MachineInstrBuilder BuildMI(MachineBasicBlock *BB, /// for either a value in a register or a register-indirect+offset /// address. The convention is that a DBG_VALUE is indirect iff the /// second operand is an immediate. -inline MachineInstrBuilder BuildMI(MachineFunction &MF, DebugLoc DL, - const MCInstrDesc &MCID, bool IsIndirect, - unsigned Reg, unsigned Offset, - const MDNode *Variable, const MDNode *Expr) { - assert(isa(Variable) && "not a variable"); - assert(cast(Expr)->isValid() && "not an expression"); - assert(cast(Variable)->isValidLocationForIntrinsic(DL) && - "Expected inlined-at fields to agree"); - if (IsIndirect) - return BuildMI(MF, DL, MCID) - .addReg(Reg, RegState::Debug) - .addImm(Offset) - .addMetadata(Variable) - .addMetadata(Expr); - else { - assert(Offset == 0 && "A direct address cannot have an offset."); - return BuildMI(MF, DL, MCID) - .addReg(Reg, RegState::Debug) - .addReg(0U, RegState::Debug) - .addMetadata(Variable) - .addMetadata(Expr); - } -} +MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, + const MCInstrDesc &MCID, bool IsIndirect, + unsigned Reg, unsigned Offset, + const MDNode *Variable, const MDNode *Expr); /// This version of the builder builds a DBG_VALUE intrinsic /// for either a value in a register or a register-indirect+offset /// address and inserts it at position I. -inline MachineInstrBuilder BuildMI(MachineBasicBlock &BB, - MachineBasicBlock::iterator I, DebugLoc DL, - const MCInstrDesc &MCID, bool IsIndirect, - unsigned Reg, unsigned Offset, - const MDNode *Variable, const MDNode *Expr) { - assert(isa(Variable) && "not a variable"); - assert(cast(Expr)->isValid() && "not an expression"); - MachineFunction &MF = *BB.getParent(); - MachineInstr *MI = - BuildMI(MF, DL, MCID, IsIndirect, Reg, Offset, Variable, Expr); - BB.insert(I, MI); - return MachineInstrBuilder(MF, MI); -} - +MachineInstrBuilder BuildMI(MachineBasicBlock &BB, + MachineBasicBlock::iterator I, const DebugLoc &DL, + const MCInstrDesc &MCID, bool IsIndirect, + unsigned Reg, unsigned Offset, + const MDNode *Variable, const MDNode *Expr); inline unsigned getDefRegState(bool B) { return B ? RegState::Define : 0; @@ -414,6 +391,17 @@ inline unsigned getDebugRegState(bool B) { return B ? RegState::Debug : 0; } +/// Get all register state flags from machine operand \p RegOp. +inline unsigned getRegState(const MachineOperand &RegOp) { + assert(RegOp.isReg() && "Not a register operand"); + return getDefRegState(RegOp.isDef()) | + getImplRegState(RegOp.isImplicit()) | + getKillRegState(RegOp.isKill()) | + getDeadRegState(RegOp.isDead()) | + getUndefRegState(RegOp.isUndef()) | + getInternalReadRegState(RegOp.isInternalRead()) | + getDebugRegState(RegOp.isDebug()); +} /// Helper class for constructing bundles of MachineInstrs. /// diff --git a/include/llvm/CodeGen/MachineInstrBundle.h b/include/llvm/CodeGen/MachineInstrBundle.h index 9b374cf7991a8b2e986f2417041726dfe600a86d..c0033a5148cf574e52b0aeffd97ead7b53817ad0 100644 --- a/include/llvm/CodeGen/MachineInstrBundle.h +++ b/include/llvm/CodeGen/MachineInstrBundle.h @@ -183,10 +183,16 @@ public: /// Reg or a super-register is read. The full register is read. bool FullyRead; - /// Reg is FullyDefined and all defs of reg or an overlapping register are - /// dead. + /// Either: + /// - Reg is FullyDefined and all defs of reg or an overlapping + /// register are dead, or + /// - Reg is completely dead because "defined" by a clobber. bool DeadDef; + /// Reg is Defined and all defs of reg or an overlapping register are + /// dead. + bool PartialDeadDef; + /// There is a use operand of reg or a super-register with kill flag set. bool Killed; }; diff --git a/include/llvm/CodeGen/MachineLoopInfo.h b/include/llvm/CodeGen/MachineLoopInfo.h index 4868b7363f8242f1038dec8a7918043141a94936..224a2a1aa59f503db18fd302ee5dfcecf7c2c418 100644 --- a/include/llvm/CodeGen/MachineLoopInfo.h +++ b/include/llvm/CodeGen/MachineLoopInfo.h @@ -44,14 +44,14 @@ class MachineLoop : public LoopBase { public: MachineLoop(); - /// getTopBlock - Return the "top" block in the loop, which is the first - /// block in the linear layout, ignoring any parts of the loop not - /// contiguous with the part the contains the header. + /// Return the "top" block in the loop, which is the first block in the linear + /// layout, ignoring any parts of the loop not contiguous with the part that + /// contains the header. MachineBasicBlock *getTopBlock(); - /// getBottomBlock - Return the "bottom" block in the loop, which is the last - /// block in the linear layout, ignoring any parts of the loop not - /// contiguous with the part the contains the header. + /// Return the "bottom" block in the loop, which is the last block in the + /// linear layout, ignoring any parts of the loop not contiguous with the part + /// that contains the header. MachineBasicBlock *getBottomBlock(); void dump() const; @@ -81,72 +81,64 @@ public: LoopInfoBase& getBase() { return LI; } - /// iterator/begin/end - The interface to the top-level loops in the current - /// function. - /// + /// The iterator interface to the top-level loops in the current function. typedef LoopInfoBase::iterator iterator; inline iterator begin() const { return LI.begin(); } inline iterator end() const { return LI.end(); } bool empty() const { return LI.empty(); } - /// getLoopFor - Return the inner most loop that BB lives in. If a basic - /// block is in no loop (for example the entry node), null is returned. - /// + /// Return the innermost loop that BB lives in. If a basic block is in no loop + /// (for example the entry node), null is returned. inline MachineLoop *getLoopFor(const MachineBasicBlock *BB) const { return LI.getLoopFor(BB); } - /// operator[] - same as getLoopFor... - /// + /// Same as getLoopFor. inline const MachineLoop *operator[](const MachineBasicBlock *BB) const { return LI.getLoopFor(BB); } - /// getLoopDepth - Return the loop nesting level of the specified block... - /// + /// Return the loop nesting level of the specified block. inline unsigned getLoopDepth(const MachineBasicBlock *BB) const { return LI.getLoopDepth(BB); } - // isLoopHeader - True if the block is a loop header node + /// True if the block is a loop header node. inline bool isLoopHeader(const MachineBasicBlock *BB) const { return LI.isLoopHeader(BB); } - /// runOnFunction - Calculate the natural loop information. - /// + /// Calculate the natural loop information. bool runOnMachineFunction(MachineFunction &F) override; void releaseMemory() override { LI.releaseMemory(); } void getAnalysisUsage(AnalysisUsage &AU) const override; - /// removeLoop - This removes the specified top-level loop from this loop info - /// object. The loop is not deleted, as it will presumably be inserted into - /// another loop. + /// This removes the specified top-level loop from this loop info object. The + /// loop is not deleted, as it will presumably be inserted into another loop. inline MachineLoop *removeLoop(iterator I) { return LI.removeLoop(I); } - /// changeLoopFor - Change the top-level loop that contains BB to the - /// specified loop. This should be used by transformations that restructure - /// the loop hierarchy tree. + /// Change the top-level loop that contains BB to the specified loop. This + /// should be used by transformations that restructure the loop hierarchy + /// tree. inline void changeLoopFor(MachineBasicBlock *BB, MachineLoop *L) { LI.changeLoopFor(BB, L); } - /// changeTopLevelLoop - Replace the specified loop in the top-level loops - /// list with the indicated loop. + /// Replace the specified loop in the top-level loops list with the indicated + /// loop. inline void changeTopLevelLoop(MachineLoop *OldLoop, MachineLoop *NewLoop) { LI.changeTopLevelLoop(OldLoop, NewLoop); } - /// addTopLevelLoop - This adds the specified loop to the collection of - /// top-level loops. + /// This adds the specified loop to the collection of top-level loops. inline void addTopLevelLoop(MachineLoop *New) { LI.addTopLevelLoop(New); } - /// removeBlock - This method completely removes BB from all data structures, - /// including all of the Loop objects it is nested in and our mapping from + /// This method completely removes BB from all data structures, including all + /// of the Loop objects it is nested in and our mapping from /// MachineBasicBlocks to loops. void removeBlock(MachineBasicBlock *BB) { LI.removeBlock(BB); diff --git a/include/llvm/CodeGen/MachineMemOperand.h b/include/llvm/CodeGen/MachineMemOperand.h index 1ca0d90465a4adc87bec0a1394cf7ed0a8f3d57d..5fa7058733b37bf8c9b4f2fa9a9ba7f62f4a3de0 100644 --- a/include/llvm/CodeGen/MachineMemOperand.h +++ b/include/llvm/CodeGen/MachineMemOperand.h @@ -16,6 +16,7 @@ #ifndef LLVM_CODEGEN_MACHINEMEMOPERAND_H #define LLVM_CODEGEN_MACHINEMEMOPERAND_H +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/IR/Metadata.h" @@ -30,12 +31,11 @@ class raw_ostream; class MachineFunction; class ModuleSlotTracker; -/// MachinePointerInfo - This class contains a discriminated union of -/// information about pointers in memory operands, relating them back to LLVM IR -/// or to virtual locations (such as frame indices) that are exposed during -/// codegen. +/// This class contains a discriminated union of information about pointers in +/// memory operands, relating them back to LLVM IR or to virtual locations (such +/// as frame indices) that are exposed during codegen. struct MachinePointerInfo { - /// V - This is the IR pointer value for the access, or it is null if unknown. + /// This is the IR pointer value for the access, or it is null if unknown. /// If this is null, then the access is to a pointer in the default address /// space. PointerUnion V; @@ -57,34 +57,30 @@ struct MachinePointerInfo { return MachinePointerInfo(V.get(), Offset+O); } - /// getAddrSpace - Return the LLVM IR address space number that this pointer - /// points into. + /// Return the LLVM IR address space number that this pointer points into. unsigned getAddrSpace() const; - /// getConstantPool - Return a MachinePointerInfo record that refers to the - /// constant pool. + /// Return a MachinePointerInfo record that refers to the constant pool. static MachinePointerInfo getConstantPool(MachineFunction &MF); - /// getFixedStack - Return a MachinePointerInfo record that refers to the - /// the specified FrameIndex. + /// Return a MachinePointerInfo record that refers to the specified + /// FrameIndex. static MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset = 0); - /// getJumpTable - Return a MachinePointerInfo record that refers to a - /// jump table entry. + /// Return a MachinePointerInfo record that refers to a jump table entry. static MachinePointerInfo getJumpTable(MachineFunction &MF); - /// getGOT - Return a MachinePointerInfo record that refers to a - /// GOT entry. + /// Return a MachinePointerInfo record that refers to a GOT entry. static MachinePointerInfo getGOT(MachineFunction &MF); - /// getStack - stack pointer relative access. + /// Stack pointer relative access. static MachinePointerInfo getStack(MachineFunction &MF, int64_t Offset); }; //===----------------------------------------------------------------------===// -/// MachineMemOperand - A description of a memory reference used in the backend. +/// A description of a memory reference used in the backend. /// Instead of holding a StoreInst or LoadInst, this class holds the address /// Value of the reference along with a byte size and offset. This allows it /// to describe lowered loads and stores. Also, the special PseudoSourceValue @@ -92,43 +88,50 @@ struct MachinePointerInfo { /// that aren't explicit in the regular LLVM IR. /// class MachineMemOperand { - MachinePointerInfo PtrInfo; - uint64_t Size; - unsigned Flags; - AAMDNodes AAInfo; - const MDNode *Ranges; - public: /// Flags values. These may be or'd together. - enum MemOperandFlags { + enum Flags : uint16_t { + // No flags set. + MONone = 0, /// The memory access reads data. - MOLoad = 1, + MOLoad = 1u << 0, /// The memory access writes data. - MOStore = 2, + MOStore = 1u << 1, /// The memory access is volatile. - MOVolatile = 4, + MOVolatile = 1u << 2, /// The memory access is non-temporal. - MONonTemporal = 8, + MONonTemporal = 1u << 3, /// The memory access is invariant. - MOInvariant = 16, - // Target hints allow target passes to annotate memory operations. - MOTargetStartBit = 5, - MOTargetNumBits = 3, - // This is the number of bits we need to represent flags. - MOMaxBits = 8 + MOInvariant = 1u << 4, + + // Reserved for use by target-specific passes. + MOTargetFlag1 = 1u << 5, + MOTargetFlag2 = 1u << 6, + MOTargetFlag3 = 1u << 7, + + LLVM_MARK_AS_BITMASK_ENUM(/* LargestFlag = */ MOTargetFlag3) }; - /// MachineMemOperand - Construct an MachineMemOperand object with the - /// specified PtrInfo, flags, size, and base alignment. - MachineMemOperand(MachinePointerInfo PtrInfo, unsigned flags, uint64_t s, +private: + MachinePointerInfo PtrInfo; + uint64_t Size; + Flags FlagVals; + uint16_t BaseAlignLog2; // log_2(base_alignment) + 1 + AAMDNodes AAInfo; + const MDNode *Ranges; + +public: + /// Construct a MachineMemOperand object with the specified PtrInfo, flags, + /// size, and base alignment. + MachineMemOperand(MachinePointerInfo PtrInfo, Flags flags, uint64_t s, unsigned base_alignment, const AAMDNodes &AAInfo = AAMDNodes(), const MDNode *Ranges = nullptr); const MachinePointerInfo &getPointerInfo() const { return PtrInfo; } - /// getValue - Return the base address of the memory access. This may either - /// be a normal LLVM IR Value, or one of the special values used in CodeGen. + /// Return the base address of the memory access. This may either be a normal + /// LLVM IR Value, or one of the special values used in CodeGen. /// Special values are those obtained via /// PseudoSourceValue::getFixedStack(int), PseudoSourceValue::getStack, and /// other PseudoSourceValue member functions which return objects which stand @@ -142,59 +145,58 @@ public: const void *getOpaqueValue() const { return PtrInfo.V.getOpaqueValue(); } - /// getFlags - Return the raw flags of the source value, \see MemOperandFlags. - unsigned int getFlags() const { return Flags & ((1 << MOMaxBits) - 1); } + /// Return the raw flags of the source value, \see Flags. + Flags getFlags() const { return FlagVals; } /// Bitwise OR the current flags with the given flags. - void setFlags(unsigned f) { Flags |= (f & ((1 << MOMaxBits) - 1)); } + void setFlags(Flags f) { FlagVals |= f; } - /// getOffset - For normal values, this is a byte offset added to the base - /// address. For PseudoSourceValue::FPRel values, this is the FrameIndex - /// number. + /// For normal values, this is a byte offset added to the base address. + /// For PseudoSourceValue::FPRel values, this is the FrameIndex number. int64_t getOffset() const { return PtrInfo.Offset; } unsigned getAddrSpace() const { return PtrInfo.getAddrSpace(); } - /// getSize - Return the size in bytes of the memory reference. + /// Return the size in bytes of the memory reference. uint64_t getSize() const { return Size; } - /// getAlignment - Return the minimum known alignment in bytes of the - /// actual memory reference. + /// Return the minimum known alignment in bytes of the actual memory + /// reference. uint64_t getAlignment() const; - /// getBaseAlignment - Return the minimum known alignment in bytes of the - /// base address, without the offset. - uint64_t getBaseAlignment() const { return (1u << (Flags >> MOMaxBits)) >> 1; } + /// Return the minimum known alignment in bytes of the base address, without + /// the offset. + uint64_t getBaseAlignment() const { return (1u << BaseAlignLog2) >> 1; } - /// getAAInfo - Return the AA tags for the memory reference. + /// Return the AA tags for the memory reference. AAMDNodes getAAInfo() const { return AAInfo; } - /// getRanges - Return the range tag for the memory reference. + /// Return the range tag for the memory reference. const MDNode *getRanges() const { return Ranges; } - bool isLoad() const { return Flags & MOLoad; } - bool isStore() const { return Flags & MOStore; } - bool isVolatile() const { return Flags & MOVolatile; } - bool isNonTemporal() const { return Flags & MONonTemporal; } - bool isInvariant() const { return Flags & MOInvariant; } + bool isLoad() const { return FlagVals & MOLoad; } + bool isStore() const { return FlagVals & MOStore; } + bool isVolatile() const { return FlagVals & MOVolatile; } + bool isNonTemporal() const { return FlagVals & MONonTemporal; } + bool isInvariant() const { return FlagVals & MOInvariant; } - /// isUnordered - Returns true if this memory operation doesn't have any - /// ordering constraints other than normal aliasing. Volatile and atomic - /// memory operations can't be reordered. + /// Returns true if this memory operation doesn't have any ordering + /// constraints other than normal aliasing. Volatile and atomic memory + /// operations can't be reordered. /// /// Currently, we don't model the difference between volatile and atomic /// operations. They should retain their ordering relative to all memory /// operations. bool isUnordered() const { return !isVolatile(); } - /// refineAlignment - Update this MachineMemOperand to reflect the alignment - /// of MMO, if it has a greater alignment. This must only be used when the - /// new alignment applies to all users of this MachineMemOperand. + /// Update this MachineMemOperand to reflect the alignment of MMO, if it has a + /// greater alignment. This must only be used when the new alignment applies + /// to all users of this MachineMemOperand. void refineAlignment(const MachineMemOperand *MMO); - /// setValue - Change the SourceValue for this MachineMemOperand. This - /// should only be used when an object is being relocated and all references - /// to it are being updated. + /// Change the SourceValue for this MachineMemOperand. This should only be + /// used when an object is being relocated and all references to it are being + /// updated. void setValue(const Value *NewSV) { PtrInfo.V = NewSV; } void setValue(const PseudoSourceValue *NewSV) { PtrInfo.V = NewSV; } void setOffset(int64_t NewOffset) { PtrInfo.Offset = NewOffset; } diff --git a/include/llvm/CodeGen/MachineModuleInfoImpls.h b/include/llvm/CodeGen/MachineModuleInfoImpls.h index e7472145e71f57811c2331df41ce2454725fa017..f9fa6999073fc93cfe608ad57609ca915a36ebdd 100644 --- a/include/llvm/CodeGen/MachineModuleInfoImpls.h +++ b/include/llvm/CodeGen/MachineModuleInfoImpls.h @@ -23,44 +23,35 @@ class MCSymbol; /// MachineModuleInfoMachO - This is a MachineModuleInfoImpl implementation /// for MachO targets. class MachineModuleInfoMachO : public MachineModuleInfoImpl { - /// FnStubs - Darwin '$stub' stubs. The key is something like "Lfoo$stub", - /// the value is something like "_foo". - DenseMap FnStubs; - /// GVStubs - Darwin '$non_lazy_ptr' stubs. The key is something like /// "Lfoo$non_lazy_ptr", the value is something like "_foo". The extra bit /// is true if this GV is external. DenseMap GVStubs; - /// HiddenGVStubs - Darwin '$non_lazy_ptr' stubs. The key is something like - /// "Lfoo$non_lazy_ptr", the value is something like "_foo". Unlike GVStubs - /// these are for things with hidden visibility. The extra bit is true if - /// this GV is external. - DenseMap HiddenGVStubs; + /// ThreadLocalGVStubs - Darwin '$non_lazy_ptr' stubs. The key is something + /// like "Lfoo$non_lazy_ptr", the value is something like "_foo". The extra + /// bit is true if this GV is external. + DenseMap ThreadLocalGVStubs; virtual void anchor(); // Out of line virtual method. public: MachineModuleInfoMachO(const MachineModuleInfo &) {} - StubValueTy &getFnStubEntry(MCSymbol *Sym) { - assert(Sym && "Key cannot be null"); - return FnStubs[Sym]; - } - StubValueTy &getGVStubEntry(MCSymbol *Sym) { assert(Sym && "Key cannot be null"); return GVStubs[Sym]; } - StubValueTy &getHiddenGVStubEntry(MCSymbol *Sym) { + StubValueTy &getThreadLocalGVStubEntry(MCSymbol *Sym) { assert(Sym && "Key cannot be null"); - return HiddenGVStubs[Sym]; + return ThreadLocalGVStubs[Sym]; } /// Accessor methods to return the set of stubs in sorted order. - SymbolListTy GetFnStubList() { return getSortedStubs(FnStubs); } SymbolListTy GetGVStubList() { return getSortedStubs(GVStubs); } - SymbolListTy GetHiddenGVStubList() { return getSortedStubs(HiddenGVStubs); } + SymbolListTy GetThreadLocalGVStubList() { + return getSortedStubs(ThreadLocalGVStubs); + } }; /// MachineModuleInfoELF - This is a MachineModuleInfoImpl implementation diff --git a/include/llvm/CodeGen/MachineOperand.h b/include/llvm/CodeGen/MachineOperand.h index c43e47c36d060d0835b858a0e51e8fe2d99abfb7..ee0a9cf11e6abfe5be5b9af177d865b7e8da7884 100644 --- a/include/llvm/CodeGen/MachineOperand.h +++ b/include/llvm/CodeGen/MachineOperand.h @@ -534,6 +534,15 @@ public: Contents.MBB = MBB; } + /// Sets value of register mask operand referencing Mask. The + /// operand does not take ownership of the memory referenced by Mask, it must + /// remain valid for the lifetime of the operand. See CreateRegMask(). + /// Any physreg with a 0 bit in the mask is clobbered by the instruction. + void setRegMask(const uint32_t *RegMaskPtr) { + assert(isRegMask() && "Wrong MachineOperand mutator"); + Contents.RegMask = RegMaskPtr; + } + //===--------------------------------------------------------------------===// // Other methods. //===--------------------------------------------------------------------===// diff --git a/include/llvm/CodeGen/MachineRegisterInfo.h b/include/llvm/CodeGen/MachineRegisterInfo.h index 704fb020a2b40f3ce2f9602ca7ee6c5ca202729e..07d2d016f274b134bc84f69973d7d1ce52f7ab15 100644 --- a/include/llvm/CodeGen/MachineRegisterInfo.h +++ b/include/llvm/CodeGen/MachineRegisterInfo.h @@ -16,7 +16,10 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/iterator_range.h" +// PointerUnion needs to have access to the full RegisterBank type. +#include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBundle.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -26,6 +29,10 @@ namespace llvm { class PSetIterator; +/// Convenient type to represent either a register class or a register bank. +typedef PointerUnion + RegClassOrRegBank; + /// MachineRegisterInfo - Keep track of information for virtual and physical /// registers, including vreg register classes, use/def chains for registers, /// etc. @@ -40,18 +47,9 @@ public: }; private: - const MachineFunction *MF; + MachineFunction *MF; Delegate *TheDelegate; - /// IsSSA - True when the machine function is in SSA form and virtual - /// registers have a single def. - bool IsSSA; - - /// TracksLiveness - True while register liveness is being tracked accurately. - /// Basic block live-in lists, kill flags, and implicit defs may not be - /// accurate when after this flag is cleared. - bool TracksLiveness; - /// True if subregister liveness is tracked. bool TracksSubRegLiveness; @@ -59,8 +57,9 @@ private: /// /// Each element in this list contains the register class of the vreg and the /// start of the use/def list for the register. - IndexedMap, - VirtReg2IndexFunctor> VRegInfo; + IndexedMap, + VirtReg2IndexFunctor> + VRegInfo; /// RegAllocHints - This vector records register allocation hints for virtual /// registers. For each virtual register, it keeps a register and hint type @@ -126,7 +125,7 @@ private: MachineRegisterInfo(const MachineRegisterInfo&) = delete; void operator=(const MachineRegisterInfo&) = delete; public: - explicit MachineRegisterInfo(const MachineFunction *MF); + explicit MachineRegisterInfo(MachineFunction *MF); const TargetRegisterInfo *getTargetRegisterInfo() const { return MF->getSubtarget().getRegisterInfo(); @@ -160,27 +159,32 @@ public: // The TwoAddressInstructionPass and PHIElimination passes take the machine // function out of SSA form when they introduce multiple defs per virtual // register. - bool isSSA() const { return IsSSA; } + bool isSSA() const { + return MF->getProperties().hasProperty( + MachineFunctionProperties::Property::IsSSA); + } // leaveSSA - Indicates that the machine function is no longer in SSA form. - void leaveSSA() { IsSSA = false; } + void leaveSSA() { + MF->getProperties().clear(MachineFunctionProperties::Property::IsSSA); + } /// tracksLiveness - Returns true when tracking register liveness accurately. - /// - /// While this flag is true, register liveness information in basic block - /// live-in lists and machine instruction operands is accurate. This means it - /// can be used to change the code in ways that affect the values in - /// registers, for example by the register scavenger. - /// - /// When this flag is false, liveness is no longer reliable. - bool tracksLiveness() const { return TracksLiveness; } + /// (see MachineFUnctionProperties::Property description for details) + bool tracksLiveness() const { + return MF->getProperties().hasProperty( + MachineFunctionProperties::Property::TracksLiveness); + } /// invalidateLiveness - Indicates that register liveness is no longer being /// tracked accurately. /// /// This should be called by late passes that invalidate the liveness /// information. - void invalidateLiveness() { TracksLiveness = false; } + void invalidateLiveness() { + MF->getProperties().clear( + MachineFunctionProperties::Property::TracksLiveness); + } /// Returns true if liveness for register class @p RC should be tracked at /// the subregister level. @@ -563,9 +567,47 @@ public: // Virtual Register Info //===--------------------------------------------------------------------===// - /// getRegClass - Return the register class of the specified virtual register. + /// Return the register class of the specified virtual register. + /// This shouldn't be used directly unless \p Reg has a register class. + /// \see getRegClassOrNull when this might happen. /// const TargetRegisterClass *getRegClass(unsigned Reg) const { + assert(VRegInfo[Reg].first.is() && + "Register class not set, wrong accessor"); + return VRegInfo[Reg].first.get(); + } + + /// Return the register class of \p Reg, or null if Reg has not been assigned + /// a register class yet. + /// + /// \note A null register class can only happen when these two + /// conditions are met: + /// 1. Generic virtual registers are created. + /// 2. The machine function has not completely been through the + /// instruction selection process. + /// None of this condition is possible without GlobalISel for now. + /// In other words, if GlobalISel is not used or if the query happens after + /// the select pass, using getRegClass is safe. + const TargetRegisterClass *getRegClassOrNull(unsigned Reg) const { + const RegClassOrRegBank &Val = VRegInfo[Reg].first; + return Val.dyn_cast(); + } + + /// Return the register bank of \p Reg, or null if Reg has not been assigned + /// a register bank or has been assigned a register class. + /// \note It is possible to get the register bank from the register class via + /// RegisterBankInfo::getRegBankFromRegClass. + /// + const RegisterBank *getRegBankOrNull(unsigned Reg) const { + const RegClassOrRegBank &Val = VRegInfo[Reg].first; + return Val.dyn_cast(); + } + + /// Return the register bank or register class of \p Reg. + /// \note Before the register bank gets assigned (i.e., before the + /// RegBankSelect pass) \p Reg may not have either. + /// + const RegClassOrRegBank &getRegClassOrRegBank(unsigned Reg) const { return VRegInfo[Reg].first; } @@ -573,6 +615,10 @@ public: /// void setRegClass(unsigned Reg, const TargetRegisterClass *RC); + /// Set the register bank to \p RegBank for \p Reg. + /// + void setRegBank(unsigned Reg, const RegisterBank &RegBank); + /// constrainRegClass - Constrain the register class of the specified virtual /// register to be a common subclass of RC and the current register class, /// but only if the new class has at least MinNumRegs registers. Return the @@ -599,11 +645,11 @@ public: /// unsigned createVirtualRegister(const TargetRegisterClass *RegClass); - /// Get the size of \p VReg or 0 if VReg is not a generic + /// Get the size in bits of \p VReg or 0 if VReg is not a generic /// (target independent) virtual register. unsigned getSize(unsigned VReg) const; - /// Set the size of \p VReg to \p Size. + /// Set the size in bits of \p VReg to \p Size. /// Although the size should be set at build time, mir infrastructure /// is not yet able to do it. void setSize(unsigned VReg, unsigned Size); @@ -657,9 +703,10 @@ public: /// Return true if the specified register is modified in this function. /// This checks that no defining machine operands exist for the register or /// any of its aliases. Definitions found on functions marked noreturn are - /// ignored. The register is also considered modified when it is set in the - /// UsedPhysRegMask. - bool isPhysRegModified(unsigned PhysReg) const; + /// ignored, to consider them pass 'true' for optional parameter + /// SkipNoReturnDef. The register is also considered modified when it is set + /// in the UsedPhysRegMask. + bool isPhysRegModified(unsigned PhysReg, bool SkipNoReturnDef = false) const; /// Return true if the specified register is modified or read in this /// function. This checks that no machine operands exist for the register or diff --git a/include/llvm/CodeGen/MachineSSAUpdater.h b/include/llvm/CodeGen/MachineSSAUpdater.h index 5f988ad86320f6691e022312e23ffb993f15c096..50a7d90bf25b04c7ac170aaffc5d62c68315e85e 100644 --- a/include/llvm/CodeGen/MachineSSAUpdater.h +++ b/include/llvm/CodeGen/MachineSSAUpdater.h @@ -14,7 +14,6 @@ #ifndef LLVM_CODEGEN_MACHINESSAUPDATER_H #define LLVM_CODEGEN_MACHINESSAUPDATER_H -#include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" namespace llvm { diff --git a/include/llvm/CodeGen/MachineScheduler.h b/include/llvm/CodeGen/MachineScheduler.h index 5d5c49e49757eadde9e5c1f8c2aeb9bf4cb8e01f..06e99217903165b4432fdb81f0a25fab8466dd89 100644 --- a/include/llvm/CodeGen/MachineScheduler.h +++ b/include/llvm/CodeGen/MachineScheduler.h @@ -66,8 +66,6 @@ // // void Subtarget:: // overrideSchedPolicy(MachineSchedPolicy &Policy, -// MachineInstr *begin, -// MachineInstr *end, // unsigned NumRegionInstrs) const { // Policy. = true; // } @@ -461,6 +459,10 @@ protected: /// bottom of the DAG region without covereing any unscheduled instruction. void buildDAGWithRegPressure(); + /// Release ExitSU predecessors and setup scheduler queues. Re-position + /// the Top RP tracker in case the region beginning has changed. + void initQueues(ArrayRef TopRoots, ArrayRef BotRoots); + /// Move an instruction and update register pressure. void scheduleMI(SUnit *SU, bool IsTopNode); @@ -759,9 +761,9 @@ class GenericSchedulerBase : public MachineSchedStrategy { public: /// Represent the type of SchedCandidate found within a single queue. /// pickNodeBidirectional depends on these listed by decreasing priority. - enum CandReason { - NoCand, PhysRegCopy, RegExcess, RegCritical, Stall, Cluster, Weak, RegMax, - ResourceReduce, ResourceDemand, BotHeightReduce, BotPathReduce, + enum CandReason : uint8_t { + NoCand, Only1, PhysRegCopy, RegExcess, RegCritical, Stall, Cluster, Weak, + RegMax, ResourceReduce, ResourceDemand, BotHeightReduce, BotPathReduce, TopDepthReduce, TopPathReduce, NextDefUse, NodeOrder}; #ifndef NDEBUG @@ -775,6 +777,15 @@ public: unsigned DemandResIdx; CandPolicy(): ReduceLatency(false), ReduceResIdx(0), DemandResIdx(0) {} + + bool operator==(const CandPolicy &RHS) const { + return ReduceLatency == RHS.ReduceLatency && + ReduceResIdx == RHS.ReduceResIdx && + DemandResIdx == RHS.DemandResIdx; + } + bool operator!=(const CandPolicy &RHS) const { + return !(*this == RHS); + } }; /// Status of an instruction's critical resource consumption. @@ -807,8 +818,8 @@ public: // The reason for this candidate. CandReason Reason; - // Set of reasons that apply to multiple candidates. - uint32_t RepeatReasonSet; + // Whether this candidate should be scheduled at top/bottom. + bool AtTop; // Register pressure values for the best candidate. RegPressureDelta RPDelta; @@ -816,8 +827,17 @@ public: // Critical resource consumption of the best candidate. SchedResourceDelta ResDelta; - SchedCandidate(const CandPolicy &policy) - : Policy(policy), SU(nullptr), Reason(NoCand), RepeatReasonSet(0) {} + SchedCandidate() { reset(CandPolicy()); } + SchedCandidate(const CandPolicy &Policy) { reset(Policy); } + + void reset(const CandPolicy &NewPolicy) { + Policy = NewPolicy; + SU = nullptr; + Reason = NoCand; + AtTop = false; + RPDelta = RegPressureDelta(); + ResDelta = SchedResourceDelta(); + } bool isValid() const { return SU; } @@ -826,13 +846,11 @@ public: assert(Best.Reason != NoCand && "uninitialized Sched candidate"); SU = Best.SU; Reason = Best.Reason; + AtTop = Best.AtTop; RPDelta = Best.RPDelta; ResDelta = Best.ResDelta; } - bool isRepeat(CandReason R) { return RepeatReasonSet & (1 << R); } - void setRepeat(CandReason R) { RepeatReasonSet |= (1 << R); } - void initResourceDelta(const ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel); }; @@ -864,6 +882,11 @@ class GenericScheduler : public GenericSchedulerBase { SchedBoundary Top; SchedBoundary Bot; + /// Candidate last picked from Top boundary. + SchedCandidate TopCand; + /// Candidate last picked from Bot boundary. + SchedCandidate BotCand; + MachineSchedPolicy RegionPolicy; public: GenericScheduler(const MachineSchedContext *C): @@ -892,10 +915,12 @@ public: void releaseTopNode(SUnit *SU) override { Top.releaseTopNode(SU); + TopCand.SU = nullptr; } void releaseBottomNode(SUnit *SU) override { Bot.releaseBottomNode(SU); + BotCand.SU = nullptr; } void registerRoots() override; @@ -903,15 +928,18 @@ public: protected: void checkAcyclicLatency(); + void initCandidate(SchedCandidate &Cand, SUnit *SU, bool AtTop, + const RegPressureTracker &RPTracker, + RegPressureTracker &TempTracker); + void tryCandidate(SchedCandidate &Cand, SchedCandidate &TryCand, - SchedBoundary &Zone, - const RegPressureTracker &RPTracker, - RegPressureTracker &TempTracker); + SchedBoundary *Zone); SUnit *pickNodeBidirectional(bool &IsTopNode); void pickNodeFromQueue(SchedBoundary &Zone, + const CandPolicy &ZonePolicy, const RegPressureTracker &RPTracker, SchedCandidate &Candidate); diff --git a/include/llvm/CodeGen/MachineValueType.h b/include/llvm/CodeGen/MachineValueType.h index 8cfd5fe2b60847b563ee590ad16980fb9b1fd4fd..0bb53d1a53743b29ce2c07f419041054734e7552 100644 --- a/include/llvm/CodeGen/MachineValueType.h +++ b/include/llvm/CodeGen/MachineValueType.h @@ -28,7 +28,7 @@ namespace llvm { /// type can be represented by an MVT. class MVT { public: - enum SimpleValueType { + enum SimpleValueType : int8_t { // INVALID_SIMPLE_VALUE_TYPE - Simple value types less than zero are // considered extended value types. INVALID_SIMPLE_VALUE_TYPE = -1, @@ -142,38 +142,38 @@ class MVT { MAX_ALLOWED_VALUETYPE = 96, // Token - A value of type llvm::TokenTy - token = 249, + token = 120, // Metadata - This is MDNode or MDString. - Metadata = 250, + Metadata = 121, // iPTRAny - An int value the size of the pointer of the current // target to any address space. This must only be used internal to // tblgen. Other than for overloading, we treat iPTRAny the same as iPTR. - iPTRAny = 251, + iPTRAny = 122, // vAny - A vector with any length and element size. This is used // for intrinsics that have overloadings based on vector types. // This is only for tblgen's consumption! - vAny = 252, + vAny = 123, // fAny - Any floating-point or vector floating-point value. This is used // for intrinsics that have overloadings based on floating-point types. // This is only for tblgen's consumption! - fAny = 253, + fAny = 124, // iAny - An integer or vector integer value of any bit width. This is // used for intrinsics that have overloadings based on integer bit widths. // This is only for tblgen's consumption! - iAny = 254, + iAny = 125, // iPTR - An int value the size of the pointer of the current // target. This should only be used internal to tblgen! - iPTR = 255, + iPTR = 126, // Any - Any type. This is used for intrinsics that have overloadings. // This is only for tblgen's consumption! - Any = 256 + Any = 127 }; SimpleValueType SimpleTy; diff --git a/include/llvm/CodeGen/PBQP/Graph.h b/include/llvm/CodeGen/PBQP/Graph.h index f73383ed10007f1dcec388f0636b904d6d8b124e..8301ca4d8536627ea4ead6c8ad8223975fc7cf30 100644 --- a/include/llvm/CodeGen/PBQP/Graph.h +++ b/include/llvm/CodeGen/PBQP/Graph.h @@ -15,12 +15,11 @@ #ifndef LLVM_CODEGEN_PBQP_GRAPH_H #define LLVM_CODEGEN_PBQP_GRAPH_H -#include "llvm/ADT/ilist.h" -#include "llvm/ADT/ilist_node.h" #include "llvm/Support/Debug.h" -#include -#include -#include +#include +#include +#include +#include #include namespace llvm { @@ -72,7 +71,7 @@ namespace PBQP { return std::numeric_limits::max(); } - NodeEntry(VectorPtr Costs) : Costs(Costs) {} + NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {} AdjEdgeIdx addAdjEdgeId(EdgeId EId) { AdjEdgeIdx Idx = AdjEdgeIds.size(); @@ -103,7 +102,7 @@ namespace PBQP { class EdgeEntry { public: EdgeEntry(NodeId N1Id, NodeId N2Id, MatrixPtr Costs) - : Costs(Costs) { + : Costs(std::move(Costs)) { NIds[0] = N1Id; NIds[1] = N2Id; ThisEdgeAdjIdxs[0] = NodeEntry::getInvalidAdjEdgeIdx(); @@ -348,7 +347,8 @@ namespace PBQP { Graph() : Solver(nullptr) {} /// @brief Construct an empty PBQP graph with the given graph metadata. - Graph(GraphMetadata Metadata) : Metadata(Metadata), Solver(nullptr) {} + Graph(GraphMetadata Metadata) + : Metadata(std::move(Metadata)), Solver(nullptr) {} /// @brief Get a reference to the graph metadata. GraphMetadata& getMetadata() { return Metadata; } diff --git a/include/llvm/CodeGen/ParallelCG.h b/include/llvm/CodeGen/ParallelCG.h index 7437e110dc79a83eeca2ba6ded02da35f1d1efc2..14ef0ec408ba1c4139560d3be2b61c98842be37d 100644 --- a/include/llvm/CodeGen/ParallelCG.h +++ b/include/llvm/CodeGen/ParallelCG.h @@ -14,28 +14,32 @@ #ifndef LLVM_CODEGEN_PARALLELCG_H #define LLVM_CODEGEN_PARALLELCG_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/CodeGen.h" #include "llvm/Target/TargetMachine.h" +#include + namespace llvm { +template class ArrayRef; class Module; class TargetOptions; class raw_pwrite_stream; -/// Split M into OSs.size() partitions, and generate code for each. Writes -/// OSs.size() output files to the output streams in OSs. The resulting output -/// files if linked together are intended to be equivalent to the single output -/// file that would have been code generated from M. +/// Split M into OSs.size() partitions, and generate code for each. Takes a +/// factory function for the TargetMachine TMFactory. Writes OSs.size() output +/// files to the output streams in OSs. The resulting output files if linked +/// together are intended to be equivalent to the single output file that would +/// have been code generated from M. +/// +/// Writes bitcode for individual partitions into output streams in BCOSs, if +/// BCOSs is not empty. /// /// \returns M if OSs.size() == 1, otherwise returns std::unique_ptr(). std::unique_ptr splitCodeGen(std::unique_ptr M, ArrayRef OSs, - StringRef CPU, StringRef Features, const TargetOptions &Options, - Reloc::Model RM = Reloc::Default, - CodeModel::Model CM = CodeModel::Default, - CodeGenOpt::Level OL = CodeGenOpt::Default, + ArrayRef BCOSs, + const std::function()> &TMFactory, TargetMachine::CodeGenFileType FT = TargetMachine::CGFT_ObjectFile, bool PreserveLocals = false); diff --git a/include/llvm/CodeGen/Passes.h b/include/llvm/CodeGen/Passes.h index 61b3ea8ec274707a19f0b2f5275bb20605d2e1a9..ae9e5dfe2d65e12811857017432af474c7e60269 100644 --- a/include/llvm/CodeGen/Passes.h +++ b/include/llvm/CodeGen/Passes.h @@ -15,356 +15,21 @@ #ifndef LLVM_CODEGEN_PASSES_H #define LLVM_CODEGEN_PASSES_H -#include "llvm/Pass.h" -#include "llvm/Target/TargetMachine.h" #include #include namespace llvm { +class Function; +class FunctionPass; class MachineFunctionPass; -class PassConfigImpl; -class PassInfo; -class ScheduleDAGInstrs; -class TargetLowering; -class TargetLoweringBase; +class ModulePass; +class Pass; +class TargetMachine; class TargetRegisterClass; class raw_ostream; -struct MachineSchedContext; - -// The old pass manager infrastructure is hidden in a legacy namespace now. -namespace legacy { -class PassManagerBase; -} -using legacy::PassManagerBase; - -/// Discriminated union of Pass ID types. -/// -/// The PassConfig API prefers dealing with IDs because they are safer and more -/// efficient. IDs decouple configuration from instantiation. This way, when a -/// pass is overriden, it isn't unnecessarily instantiated. It is also unsafe to -/// refer to a Pass pointer after adding it to a pass manager, which deletes -/// redundant pass instances. -/// -/// However, it is convient to directly instantiate target passes with -/// non-default ctors. These often don't have a registered PassInfo. Rather than -/// force all target passes to implement the pass registry boilerplate, allow -/// the PassConfig API to handle either type. -/// -/// AnalysisID is sadly char*, so PointerIntPair won't work. -class IdentifyingPassPtr { - union { - AnalysisID ID; - Pass *P; - }; - bool IsInstance; -public: - IdentifyingPassPtr() : P(nullptr), IsInstance(false) {} - IdentifyingPassPtr(AnalysisID IDPtr) : ID(IDPtr), IsInstance(false) {} - IdentifyingPassPtr(Pass *InstancePtr) : P(InstancePtr), IsInstance(true) {} - - bool isValid() const { return P; } - bool isInstance() const { return IsInstance; } - - AnalysisID getID() const { - assert(!IsInstance && "Not a Pass ID"); - return ID; - } - Pass *getInstance() const { - assert(IsInstance && "Not a Pass Instance"); - return P; - } -}; - -template <> struct isPodLike { - static const bool value = true; -}; - -/// Target-Independent Code Generator Pass Configuration Options. -/// -/// This is an ImmutablePass solely for the purpose of exposing CodeGen options -/// to the internals of other CodeGen passes. -class TargetPassConfig : public ImmutablePass { -public: - /// Pseudo Pass IDs. These are defined within TargetPassConfig because they - /// are unregistered pass IDs. They are only useful for use with - /// TargetPassConfig APIs to identify multiple occurrences of the same pass. - /// - - /// EarlyTailDuplicate - A clone of the TailDuplicate pass that runs early - /// during codegen, on SSA form. - static char EarlyTailDuplicateID; - - /// PostRAMachineLICM - A clone of the LICM pass that runs during late machine - /// optimization after regalloc. - static char PostRAMachineLICMID; - -private: - PassManagerBase *PM; - AnalysisID StartBefore, StartAfter; - AnalysisID StopAfter; - bool Started; - bool Stopped; - bool AddingMachinePasses; - -protected: - TargetMachine *TM; - PassConfigImpl *Impl; // Internal data structures - bool Initialized; // Flagged after all passes are configured. - - // Target Pass Options - // Targets provide a default setting, user flags override. - // - bool DisableVerify; - - /// Default setting for -enable-tail-merge on this target. - bool EnableTailMerge; - -public: - TargetPassConfig(TargetMachine *tm, PassManagerBase &pm); - // Dummy constructor. - TargetPassConfig(); - - ~TargetPassConfig() override; - - static char ID; - - /// Get the right type of TargetMachine for this target. - template TMC &getTM() const { - return *static_cast(TM); - } - - // - void setInitialized() { Initialized = true; } - - CodeGenOpt::Level getOptLevel() const { return TM->getOptLevel(); } - - /// Set the StartAfter, StartBefore and StopAfter passes to allow running only - /// a portion of the normal code-gen pass sequence. - /// - /// If the StartAfter and StartBefore pass ID is zero, then compilation will - /// begin at the normal point; otherwise, clear the Started flag to indicate - /// that passes should not be added until the starting pass is seen. If the - /// Stop pass ID is zero, then compilation will continue to the end. - /// - /// This function expects that at least one of the StartAfter or the - /// StartBefore pass IDs is null. - void setStartStopPasses(AnalysisID StartBefore, AnalysisID StartAfter, - AnalysisID StopAfter) { - if (StartAfter) - assert(!StartBefore && "Start after and start before passes are given"); - this->StartBefore = StartBefore; - this->StartAfter = StartAfter; - this->StopAfter = StopAfter; - Started = (StartAfter == nullptr) && (StartBefore == nullptr); - } - - void setDisableVerify(bool Disable) { setOpt(DisableVerify, Disable); } - bool getEnableTailMerge() const { return EnableTailMerge; } - void setEnableTailMerge(bool Enable) { setOpt(EnableTailMerge, Enable); } - - /// Allow the target to override a specific pass without overriding the pass - /// pipeline. When passes are added to the standard pipeline at the - /// point where StandardID is expected, add TargetID in its place. - void substitutePass(AnalysisID StandardID, IdentifyingPassPtr TargetID); - - /// Insert InsertedPassID pass after TargetPassID pass. - void insertPass(AnalysisID TargetPassID, IdentifyingPassPtr InsertedPassID, - bool VerifyAfter = true, bool PrintAfter = true); - - /// Allow the target to enable a specific standard pass by default. - void enablePass(AnalysisID PassID) { substitutePass(PassID, PassID); } - - /// Allow the target to disable a specific standard pass by default. - void disablePass(AnalysisID PassID) { - substitutePass(PassID, IdentifyingPassPtr()); - } - - /// Return the pass substituted for StandardID by the target. - /// If no substitution exists, return StandardID. - IdentifyingPassPtr getPassSubstitution(AnalysisID StandardID) const; - - /// Return true if the optimized regalloc pipeline is enabled. - bool getOptimizeRegAlloc() const; - - /// Return true if shrink wrapping is enabled. - bool getEnableShrinkWrap() const; - - /// Return true if the default global register allocator is in use and - /// has not be overriden on the command line with '-regalloc=...' - bool usingDefaultRegAlloc() const; - - /// Add common target configurable passes that perform LLVM IR to IR - /// transforms following machine independent optimization. - virtual void addIRPasses(); - - /// Add passes to lower exception handling for the code generator. - void addPassesToHandleExceptions(); - - /// Add pass to prepare the LLVM IR for code generation. This should be done - /// before exception handling preparation passes. - virtual void addCodeGenPrepare(); - - /// Add common passes that perform LLVM IR to IR transforms in preparation for - /// instruction selection. - virtual void addISelPrepare(); - - /// addInstSelector - This method should install an instruction selector pass, - /// which converts from LLVM code to machine instructions. - virtual bool addInstSelector() { - return true; - } - - /// This method should install an IR translator pass, which converts from - /// LLVM code to machine instructions with possibly generic opcodes. - virtual bool addIRTranslator() { return true; } - - /// Add the complete, standard set of LLVM CodeGen passes. - /// Fully developed targets will not generally override this. - virtual void addMachinePasses(); - - /// Create an instance of ScheduleDAGInstrs to be run within the standard - /// MachineScheduler pass for this function and target at the current - /// optimization level. - /// - /// This can also be used to plug a new MachineSchedStrategy into an instance - /// of the standard ScheduleDAGMI: - /// return new ScheduleDAGMI(C, make_unique(C), /*RemoveKillFlags=*/false) - /// - /// Return NULL to select the default (generic) machine scheduler. - virtual ScheduleDAGInstrs * - createMachineScheduler(MachineSchedContext *C) const { - return nullptr; - } - - /// Similar to createMachineScheduler but used when postRA machine scheduling - /// is enabled. - virtual ScheduleDAGInstrs * - createPostMachineScheduler(MachineSchedContext *C) const { - return nullptr; - } - -protected: - // Helper to verify the analysis is really immutable. - void setOpt(bool &Opt, bool Val); - - /// Methods with trivial inline returns are convenient points in the common - /// codegen pass pipeline where targets may insert passes. Methods with - /// out-of-line standard implementations are major CodeGen stages called by - /// addMachinePasses. Some targets may override major stages when inserting - /// passes is insufficient, but maintaining overriden stages is more work. - /// - - /// addPreISelPasses - This method should add any "last minute" LLVM->LLVM - /// passes (which are run just before instruction selector). - virtual bool addPreISel() { - return true; - } - - /// addMachineSSAOptimization - Add standard passes that optimize machine - /// instructions in SSA form. - virtual void addMachineSSAOptimization(); - - /// Add passes that optimize instruction level parallelism for out-of-order - /// targets. These passes are run while the machine code is still in SSA - /// form, so they can use MachineTraceMetrics to control their heuristics. - /// - /// All passes added here should preserve the MachineDominatorTree, - /// MachineLoopInfo, and MachineTraceMetrics analyses. - virtual bool addILPOpts() { - return false; - } - - /// This method may be implemented by targets that want to run passes - /// immediately before register allocation. - virtual void addPreRegAlloc() { } - - /// createTargetRegisterAllocator - Create the register allocator pass for - /// this target at the current optimization level. - virtual FunctionPass *createTargetRegisterAllocator(bool Optimized); - - /// addFastRegAlloc - Add the minimum set of target-independent passes that - /// are required for fast register allocation. - virtual void addFastRegAlloc(FunctionPass *RegAllocPass); - - /// addOptimizedRegAlloc - Add passes related to register allocation. - /// LLVMTargetMachine provides standard regalloc passes for most targets. - virtual void addOptimizedRegAlloc(FunctionPass *RegAllocPass); - - /// addPreRewrite - Add passes to the optimized register allocation pipeline - /// after register allocation is complete, but before virtual registers are - /// rewritten to physical registers. - /// - /// These passes must preserve VirtRegMap and LiveIntervals, and when running - /// after RABasic or RAGreedy, they should take advantage of LiveRegMatrix. - /// When these passes run, VirtRegMap contains legal physreg assignments for - /// all virtual registers. - virtual bool addPreRewrite() { - return false; - } - - /// This method may be implemented by targets that want to run passes after - /// register allocation pass pipeline but before prolog-epilog insertion. - virtual void addPostRegAlloc() { } - - /// Add passes that optimize machine instructions after register allocation. - virtual void addMachineLateOptimization(); - - /// This method may be implemented by targets that want to run passes after - /// prolog-epilog insertion and before the second instruction scheduling pass. - virtual void addPreSched2() { } - - /// addGCPasses - Add late codegen passes that analyze code for garbage - /// collection. This should return true if GC info should be printed after - /// these passes. - virtual bool addGCPasses(); - - /// Add standard basic block placement passes. - virtual void addBlockPlacement(); - - /// This pass may be implemented by targets that want to run passes - /// immediately before machine code is emitted. - virtual void addPreEmitPass() { } - - /// Utilities for targets to add passes to the pass manager. - /// - - /// Add a CodeGen pass at this point in the pipeline after checking overrides. - /// Return the pass that was added, or zero if no pass was added. - /// @p printAfter if true and adding a machine function pass add an extra - /// machine printer pass afterwards - /// @p verifyAfter if true and adding a machine function pass add an extra - /// machine verification pass afterwards. - AnalysisID addPass(AnalysisID PassID, bool verifyAfter = true, - bool printAfter = true); - - /// Add a pass to the PassManager if that pass is supposed to be run, as - /// determined by the StartAfter and StopAfter options. Takes ownership of the - /// pass. - /// @p printAfter if true and adding a machine function pass add an extra - /// machine printer pass afterwards - /// @p verifyAfter if true and adding a machine function pass add an extra - /// machine verification pass afterwards. - void addPass(Pass *P, bool verifyAfter = true, bool printAfter = true); - - /// addMachinePasses helper to create the target-selected or overriden - /// regalloc pass. - FunctionPass *createRegAllocPass(bool Optimized); - - /// printAndVerify - Add a pass to dump then verify the machine function, if - /// those steps are enabled. - /// - void printAndVerify(const std::string &Banner); - - /// Add a pass to print the machine function if printing is enabled. - void addPrintPass(const std::string &Banner); - - /// Add a pass to perform basic verification of the machine function if - /// verification is enabled. - void addVerifyPass(const std::string &Banner); -}; -} // namespace llvm +} // End llvm namespace /// List of target independent CodeGen pass IDs. namespace llvm { @@ -461,6 +126,9 @@ namespace llvm { /// DeadMachineInstructionElim - This pass removes dead machine instructions. extern char &DeadMachineInstructionElimID; + /// This pass adds dead/undef flags after analyzing subregister lanes. + extern char &DetectDeadLanesID; + /// FastRegisterAllocation Pass - This pass register allocates as fast as /// possible. It is best suited for debug code where live ranges are short. /// @@ -484,11 +152,16 @@ namespace llvm { /// PrologEpilogCodeInserter - This pass inserts prolog and epilog code, /// and eliminates abstract frame references. extern char &PrologEpilogCodeInserterID; + MachineFunctionPass *createPrologEpilogInserterPass(const TargetMachine *TM); /// ExpandPostRAPseudos - This pass expands pseudo instructions after /// register allocation. extern char &ExpandPostRAPseudosID; + /// createPostRAHazardRecognizer - This pass runs the post-ra hazard + /// recognizer. + extern char &PostRAHazardRecognizerID; + /// createPostRAScheduler - This pass performs post register allocation /// scheduling. extern char &PostRASchedulerID; @@ -590,6 +263,13 @@ namespace llvm { /// \brief This pass lays out funclets contiguously. extern char &FuncletLayoutID; + /// This pass inserts the XRay instrumentation sleds if they are supported by + /// the target platform. + extern char &XRayInstrumentationID; + + /// \brief This pass implements the "patchable-function" attribute. + extern char &PatchableFunctionID; + /// createStackProtectorPass - This pass adds stack protectors to functions. /// FunctionPass *createStackProtectorPass(const TargetMachine *TM); @@ -664,6 +344,11 @@ namespace llvm { /// ModulePass *createLowerEmuTLSPass(const TargetMachine *TM); + /// This pass lowers the @llvm.load.relative intrinsic to instructions. + /// This is unsafe to do earlier because a pass may combine the constant + /// initializer into the load, which may result in an overflowing evaluation. + ModulePass *createPreISelIntrinsicLoweringPass(); + /// GlobalMerge - This pass merges internal (by default) globals into structs /// to enable reuse of a base pointer by indexed addressing modes. /// It can also be configured to focus on size optimizations only. @@ -675,6 +360,20 @@ namespace llvm { /// This pass splits the stack into a safe stack and an unsafe stack to /// protect against stack-based overflow vulnerabilities. FunctionPass *createSafeStackPass(const TargetMachine *TM = nullptr); + + /// This pass detects subregister lanes in a virtual register that are used + /// independently of other lanes and splits them into separate virtual + /// registers. + extern char &RenameIndependentSubregsID; + + /// This pass is executed POST-RA to collect which physical registers are + /// preserved by given machine function. + FunctionPass *createRegUsageInfoCollector(); + + /// Return a MachineFunction pass that identifies call sites + /// and propagates register usage information of callee to caller + /// if available with PysicalRegisterUsageInfo pass. + FunctionPass *createRegUsageInfoPropPass(); } // End llvm namespace /// Target machine pass initializer for passes with dependencies. Use with @@ -683,15 +382,18 @@ namespace llvm { /// Target machine pass initializer for passes with dependencies. Use with /// INITIALIZE_TM_PASS_BEGIN. -#define INITIALIZE_TM_PASS_END(passName, arg, name, cfg, analysis) \ - PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ - PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis, \ - PassInfo::TargetMachineCtor_t(callTargetMachineCtor< passName >)); \ - Registry.registerPass(*PI, true); \ - return PI; \ - } \ - void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ +#define INITIALIZE_TM_PASS_END(passName, arg, name, cfg, analysis) \ + PassInfo *PI = new PassInfo( \ + name, arg, &passName::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor), cfg, analysis, \ + PassInfo::TargetMachineCtor_t(callTargetMachineCtor)); \ + Registry.registerPass(*PI, true); \ + return PI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } /// This initializer registers TargetMachine constructor, so the pass being @@ -699,8 +401,8 @@ namespace llvm { /// macro to be together with INITIALIZE_PASS, which is a complete target /// independent initializer, and we don't want to make libScalarOpts depend /// on libCodeGen. -#define INITIALIZE_TM_PASS(passName, arg, name, cfg, analysis) \ - INITIALIZE_TM_PASS_BEGIN(passName, arg, name, cfg, analysis) \ - INITIALIZE_TM_PASS_END(passName, arg, name, cfg, analysis) +#define INITIALIZE_TM_PASS(passName, arg, name, cfg, analysis) \ + INITIALIZE_TM_PASS_BEGIN(passName, arg, name, cfg, analysis) \ + INITIALIZE_TM_PASS_END(passName, arg, name, cfg, analysis) #endif diff --git a/include/llvm/CodeGen/PreISelIntrinsicLowering.h b/include/llvm/CodeGen/PreISelIntrinsicLowering.h new file mode 100644 index 0000000000000000000000000000000000000000..765ca085244aa5d2150bbd267460e4b0087c1253 --- /dev/null +++ b/include/llvm/CodeGen/PreISelIntrinsicLowering.h @@ -0,0 +1,26 @@ +//===--- PreISelIntrinsicLowering.h - Pre-ISel intrinsic lowering pass ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass implements IR lowering for the llvm.load.relative intrinsic. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CODEGEN_PREISELINTRINSICLOWERING_H +#define LLVM_CODEGEN_PREISELINTRINSICLOWERING_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +struct PreISelIntrinsicLoweringPass + : PassInfoMixin { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; +} + +#endif // LLVM_CODEGEN_PREISELINTRINSICLOWERING_H diff --git a/include/llvm/CodeGen/RegAllocPBQP.h b/include/llvm/CodeGen/RegAllocPBQP.h index 4122811a9e5cebe1dbc084cd0dda5aef655f05f8..21952272ffdb97516c63aa359d087e3eea390e37 100644 --- a/include/llvm/CodeGen/RegAllocPBQP.h +++ b/include/llvm/CodeGen/RegAllocPBQP.h @@ -21,6 +21,7 @@ #include "llvm/CodeGen/PBQP/ReductionRules.h" #include "llvm/CodeGen/PBQPRAConstraint.h" #include "llvm/Support/ErrorHandling.h" +#include namespace llvm { diff --git a/include/llvm/CodeGen/RegisterScavenging.h b/include/llvm/CodeGen/RegisterScavenging.h index 122c78534253ebf0f603eb2ebee2c83f4cfde796..efe1a3c6d0f78435a1d9f7084bfdd9c97bd10ca1 100644 --- a/include/llvm/CodeGen/RegisterScavenging.h +++ b/include/llvm/CodeGen/RegisterScavenging.h @@ -7,10 +7,11 @@ // //===----------------------------------------------------------------------===// // -// This file declares the machine register scavenger class. It can provide -// information such as unused register at any point in a machine basic block. -// It also provides a mechanism to make registers available by evicting them -// to spill slots. +/// \file +/// This file declares the machine register scavenger class. It can provide +/// information such as unused register at any point in a machine basic block. +/// It also provides a mechanism to make registers available by evicting them +/// to spill slots. // //===----------------------------------------------------------------------===// @@ -71,8 +72,8 @@ public: RegScavenger() : MBB(nullptr), NumRegUnits(0), Tracking(false) {} - /// Start tracking liveness from the begin of the specific basic block. - void enterBasicBlock(MachineBasicBlock *mbb); + /// Start tracking liveness from the begin of basic block \p MBB. + void enterBasicBlock(MachineBasicBlock &MBB); /// Move the internal MBB iterator and update register states. void forward(); diff --git a/include/llvm/CodeGen/RegisterUsageInfo.h b/include/llvm/CodeGen/RegisterUsageInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..3f88032cb6385a516951168a19c9365592ec6749 --- /dev/null +++ b/include/llvm/CodeGen/RegisterUsageInfo.h @@ -0,0 +1,75 @@ +//==- RegisterUsageInfo.h - Register Usage Informartion Storage -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This pass is required to take advantage of the interprocedural register +/// allocation infrastructure. +/// +/// This pass is simple immutable pass which keeps RegMasks (calculated based on +/// actual register allocation) for functions in a module and provides simple +/// API to query this information. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_PHYSICALREGISTERUSAGEINFO_H +#define LLVM_CODEGEN_PHYSICALREGISTERUSAGEINFO_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +class PhysicalRegisterUsageInfo : public ImmutablePass { + virtual void anchor(); + +public: + static char ID; + + PhysicalRegisterUsageInfo() : ImmutablePass(ID) { + PassRegistry &Registry = *PassRegistry::getPassRegistry(); + initializePhysicalRegisterUsageInfoPass(Registry); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + /// To set TargetMachine *, which is used to print + /// analysis when command line option -print-regusage is used. + void setTargetMachine(const TargetMachine *TM_) { TM = TM_; } + + bool doInitialization(Module &M) override; + + bool doFinalization(Module &M) override; + + /// To store RegMask for given Function *. + void storeUpdateRegUsageInfo(const Function *FP, + std::vector RegMask); + + /// To query stored RegMask for given Function *, it will return nullptr if + /// function is not known. + const std::vector *getRegUsageInfo(const Function *FP); + + void print(raw_ostream &OS, const Module *M = nullptr) const override; + +private: + /// A Dense map from Function * to RegMask. + /// In RegMask 0 means register used (clobbered) by function. + /// and 1 means content of register will be preserved around function call. + DenseMap> RegMasks; + + const TargetMachine *TM; +}; +} + +#endif diff --git a/include/llvm/CodeGen/ResourcePriorityQueue.h b/include/llvm/CodeGen/ResourcePriorityQueue.h index 0097e0472e5c51cb6b9b6f9376fc9b71265cece8..9c8f5f487d382cf2733b1a8860a4ee952555c77c 100644 --- a/include/llvm/CodeGen/ResourcePriorityQueue.h +++ b/include/llvm/CodeGen/ResourcePriorityQueue.h @@ -72,7 +72,7 @@ namespace llvm { /// Heuristics for estimating register pressure. unsigned ParallelLiveRanges; - signed HorizontalVerticalBalance; + int HorizontalVerticalBalance; public: ResourcePriorityQueue(SelectionDAGISel *IS); @@ -103,14 +103,14 @@ namespace llvm { /// Single cost function reflecting benefit of scheduling SU /// in the current cycle. - signed SUSchedulingCost (SUnit *SU); + int SUSchedulingCost (SUnit *SU); /// InitNumRegDefsLeft - Determine the # of regs defined by this node. /// void initNumRegDefsLeft(SUnit *SU); void updateNumRegDefsLeft(SUnit *SU); - signed regPressureDelta(SUnit *SU, bool RawPressure = false); - signed rawRegPressureDelta (SUnit *SU, unsigned RCId); + int regPressureDelta(SUnit *SU, bool RawPressure = false); + int rawRegPressureDelta (SUnit *SU, unsigned RCId); bool empty() const override { return Queue.empty(); } diff --git a/include/llvm/CodeGen/RuntimeLibcalls.h b/include/llvm/CodeGen/RuntimeLibcalls.h index bdf8d9ce086ecb5095ce79ea8ca9193a9e9d0815..16d305c7297f949a7ac85ae7f0f0f99a86de3d7f 100644 --- a/include/llvm/CodeGen/RuntimeLibcalls.h +++ b/include/llvm/CodeGen/RuntimeLibcalls.h @@ -336,7 +336,11 @@ namespace RTLIB { // EXCEPTION HANDLING UNWIND_RESUME, - // Family ATOMICs + // Note: there's two sets of atomics libcalls; see + // for more info on the + // difference between them. + + // Atomic '__sync_*' libcalls. SYNC_VAL_COMPARE_AND_SWAP_1, SYNC_VAL_COMPARE_AND_SWAP_2, SYNC_VAL_COMPARE_AND_SWAP_4, @@ -398,6 +402,71 @@ namespace RTLIB { SYNC_FETCH_AND_UMIN_8, SYNC_FETCH_AND_UMIN_16, + // Atomic '__atomic_*' libcalls. + ATOMIC_LOAD, + ATOMIC_LOAD_1, + ATOMIC_LOAD_2, + ATOMIC_LOAD_4, + ATOMIC_LOAD_8, + ATOMIC_LOAD_16, + + ATOMIC_STORE, + ATOMIC_STORE_1, + ATOMIC_STORE_2, + ATOMIC_STORE_4, + ATOMIC_STORE_8, + ATOMIC_STORE_16, + + ATOMIC_EXCHANGE, + ATOMIC_EXCHANGE_1, + ATOMIC_EXCHANGE_2, + ATOMIC_EXCHANGE_4, + ATOMIC_EXCHANGE_8, + ATOMIC_EXCHANGE_16, + + ATOMIC_COMPARE_EXCHANGE, + ATOMIC_COMPARE_EXCHANGE_1, + ATOMIC_COMPARE_EXCHANGE_2, + ATOMIC_COMPARE_EXCHANGE_4, + ATOMIC_COMPARE_EXCHANGE_8, + ATOMIC_COMPARE_EXCHANGE_16, + + ATOMIC_FETCH_ADD_1, + ATOMIC_FETCH_ADD_2, + ATOMIC_FETCH_ADD_4, + ATOMIC_FETCH_ADD_8, + ATOMIC_FETCH_ADD_16, + + ATOMIC_FETCH_SUB_1, + ATOMIC_FETCH_SUB_2, + ATOMIC_FETCH_SUB_4, + ATOMIC_FETCH_SUB_8, + ATOMIC_FETCH_SUB_16, + + ATOMIC_FETCH_AND_1, + ATOMIC_FETCH_AND_2, + ATOMIC_FETCH_AND_4, + ATOMIC_FETCH_AND_8, + ATOMIC_FETCH_AND_16, + + ATOMIC_FETCH_OR_1, + ATOMIC_FETCH_OR_2, + ATOMIC_FETCH_OR_4, + ATOMIC_FETCH_OR_8, + ATOMIC_FETCH_OR_16, + + ATOMIC_FETCH_XOR_1, + ATOMIC_FETCH_XOR_2, + ATOMIC_FETCH_XOR_4, + ATOMIC_FETCH_XOR_8, + ATOMIC_FETCH_XOR_16, + + ATOMIC_FETCH_NAND_1, + ATOMIC_FETCH_NAND_2, + ATOMIC_FETCH_NAND_4, + ATOMIC_FETCH_NAND_8, + ATOMIC_FETCH_NAND_16, + // Stack Protector Fail. STACKPROTECTOR_CHECK_FAIL, diff --git a/include/llvm/CodeGen/ScheduleDAGInstrs.h b/include/llvm/CodeGen/ScheduleDAGInstrs.h index a83a51586897e3744a5b79e35bb7d55ba6a823e0..12124ecc4b3e3e620045a5c9bba40317a7da7410 100644 --- a/include/llvm/CodeGen/ScheduleDAGInstrs.h +++ b/include/llvm/CodeGen/ScheduleDAGInstrs.h @@ -87,8 +87,13 @@ namespace llvm { VReg2SUnitOperIdxMultiMap; typedef PointerUnion ValueType; - typedef SmallVector, 4> - UnderlyingObjectsVector; + struct UnderlyingObject : PointerIntPair { + UnderlyingObject(ValueType V, bool MayAlias) + : PointerIntPair(V, MayAlias) {} + ValueType getValue() const { return getPointer(); } + bool mayAlias() const { return getInt(); } + }; + typedef SmallVector UnderlyingObjectsVector; /// ScheduleDAGInstrs - A ScheduleDAG subclass for scheduling lists of /// MachineInstrs. diff --git a/include/llvm/CodeGen/ScheduleHazardRecognizer.h b/include/llvm/CodeGen/ScheduleHazardRecognizer.h index 8a40e7212ff6d37e3bf7ae7014dea552b9ea20eb..214be2794ba37bc576bba272f270cb82d8602cfc 100644 --- a/include/llvm/CodeGen/ScheduleHazardRecognizer.h +++ b/include/llvm/CodeGen/ScheduleHazardRecognizer.h @@ -17,6 +17,7 @@ namespace llvm { +class MachineInstr; class SUnit; /// HazardRecognizer - This determines whether or not an instruction can be @@ -70,6 +71,10 @@ public: /// emitted, to advance the hazard state. virtual void EmitInstruction(SUnit *) {} + /// This overload will be used when the hazard recognizer is being used + /// by a non-scheduling pass, which does not use SUnits. + virtual void EmitInstruction(MachineInstr *) {} + /// PreEmitNoops - This callback is invoked prior to emitting an instruction. /// It should return the number of noops to emit prior to the provided /// instruction. @@ -79,6 +84,12 @@ public: return 0; } + /// This overload will be used when the hazard recognizer is being used + /// by a non-scheduling pass, which does not use SUnits. + virtual unsigned PreEmitNoops(MachineInstr *) { + return 0; + } + /// ShouldPreferAnother - This callback may be invoked if getHazardType /// returns NoHazard. If, even though there is no hazard, it would be better to /// schedule another available instruction, this callback should return true. diff --git a/include/llvm/CodeGen/ScoreboardHazardRecognizer.h b/include/llvm/CodeGen/ScoreboardHazardRecognizer.h index ab14c2de32b0b8adcc07b0f7c9766efb06adf16c..e0c30fe4d82a6255a04e9a44d63363d07b78f974 100644 --- a/include/llvm/CodeGen/ScoreboardHazardRecognizer.h +++ b/include/llvm/CodeGen/ScoreboardHazardRecognizer.h @@ -83,11 +83,9 @@ class ScoreboardHazardRecognizer : public ScheduleHazardRecognizer { void dump() const; }; -#ifndef NDEBUG // Support for tracing ScoreboardHazardRecognizer as a component within - // another module. Follows the current thread-unsafe model of tracing. - static const char *DebugType; -#endif + // another module. + const char *DebugType; // Itinerary data for the target. const InstrItineraryData *ItinData; diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h index 941de90ff4b76f63b27fe94d9a4844fa1c7fdf0e..3c1fe58c9b39e7177ee6024892d543debc32bfae 100644 --- a/include/llvm/CodeGen/SelectionDAG.h +++ b/include/llvm/CodeGen/SelectionDAG.h @@ -249,6 +249,14 @@ public: virtual void NodeUpdated(SDNode *N); }; + struct DAGNodeDeletedListener : public DAGUpdateListener { + std::function Callback; + DAGNodeDeletedListener(SelectionDAG &DAG, + std::function Callback) + : DAGUpdateListener(DAG), Callback(Callback) {} + void NodeDeleted(SDNode *N, SDNode *E) override { Callback(N, E); } + }; + /// When true, additional steps are taken to /// ensure that getConstant() and similar functions return DAG nodes that /// have legal types. This is important after type legalization since @@ -466,22 +474,23 @@ public: /// If only legal types can be produced, this does the necessary /// transformations (e.g., if the vector element type is illegal). /// @{ - SDValue getConstant(uint64_t Val, SDLoc DL, EVT VT, bool isTarget = false, - bool isOpaque = false); - SDValue getConstant(const APInt &Val, SDLoc DL, EVT VT, bool isTarget = false, - bool isOpaque = false); - SDValue getConstant(const ConstantInt &Val, SDLoc DL, EVT VT, + SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, + bool isTarget = false, bool isOpaque = false); + SDValue getConstant(const APInt &Val, const SDLoc &DL, EVT VT, bool isTarget = false, bool isOpaque = false); - SDValue getIntPtrConstant(uint64_t Val, SDLoc DL, bool isTarget = false); - SDValue getTargetConstant(uint64_t Val, SDLoc DL, EVT VT, + SDValue getConstant(const ConstantInt &Val, const SDLoc &DL, EVT VT, + bool isTarget = false, bool isOpaque = false); + SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, + bool isTarget = false); + SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque = false) { return getConstant(Val, DL, VT, true, isOpaque); } - SDValue getTargetConstant(const APInt &Val, SDLoc DL, EVT VT, + SDValue getTargetConstant(const APInt &Val, const SDLoc &DL, EVT VT, bool isOpaque = false) { return getConstant(Val, DL, VT, true, isOpaque); } - SDValue getTargetConstant(const ConstantInt &Val, SDLoc DL, EVT VT, + SDValue getTargetConstant(const ConstantInt &Val, const SDLoc &DL, EVT VT, bool isOpaque = false) { return getConstant(Val, DL, VT, true, isOpaque); } @@ -495,26 +504,27 @@ public: /// The forms that take a double should only be used for simple constants /// that can be exactly represented in VT. No checks are made. /// @{ - SDValue getConstantFP(double Val, SDLoc DL, EVT VT, bool isTarget = false); - SDValue getConstantFP(const APFloat& Val, SDLoc DL, EVT VT, + SDValue getConstantFP(double Val, const SDLoc &DL, EVT VT, + bool isTarget = false); + SDValue getConstantFP(const APFloat &Val, const SDLoc &DL, EVT VT, bool isTarget = false); - SDValue getConstantFP(const ConstantFP &CF, SDLoc DL, EVT VT, + SDValue getConstantFP(const ConstantFP &CF, const SDLoc &DL, EVT VT, bool isTarget = false); - SDValue getTargetConstantFP(double Val, SDLoc DL, EVT VT) { + SDValue getTargetConstantFP(double Val, const SDLoc &DL, EVT VT) { return getConstantFP(Val, DL, VT, true); } - SDValue getTargetConstantFP(const APFloat& Val, SDLoc DL, EVT VT) { + SDValue getTargetConstantFP(const APFloat &Val, const SDLoc &DL, EVT VT) { return getConstantFP(Val, DL, VT, true); } - SDValue getTargetConstantFP(const ConstantFP &Val, SDLoc DL, EVT VT) { + SDValue getTargetConstantFP(const ConstantFP &Val, const SDLoc &DL, EVT VT) { return getConstantFP(Val, DL, VT, true); } /// @} - SDValue getGlobalAddress(const GlobalValue *GV, SDLoc DL, EVT VT, + SDValue getGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset = 0, bool isTargetGA = false, unsigned char TargetFlags = 0); - SDValue getTargetGlobalAddress(const GlobalValue *GV, SDLoc DL, EVT VT, + SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset = 0, unsigned char TargetFlags = 0) { return getGlobalAddress(GV, DL, VT, offset, true, TargetFlags); @@ -551,7 +561,7 @@ public: SDValue getBasicBlock(MachineBasicBlock *MBB); SDValue getBasicBlock(MachineBasicBlock *MBB, SDLoc dl); SDValue getExternalSymbol(const char *Sym, EVT VT); - SDValue getExternalSymbol(const char *Sym, SDLoc dl, EVT VT); + SDValue getExternalSymbol(const char *Sym, const SDLoc &dl, EVT VT); SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned char TargetFlags = 0); SDValue getMCSymbol(MCSymbol *Sym, EVT VT); @@ -559,7 +569,7 @@ public: SDValue getValueType(EVT); SDValue getRegister(unsigned Reg, EVT VT); SDValue getRegisterMask(const uint32_t *RegMask); - SDValue getEHLabel(SDLoc dl, SDValue Root, MCSymbol *Label); + SDValue getEHLabel(const SDLoc &dl, SDValue Root, MCSymbol *Label); SDValue getBlockAddress(const BlockAddress *BA, EVT VT, int64_t Offset = 0, bool isTarget = false, unsigned char TargetFlags = 0); @@ -569,7 +579,8 @@ public: return getBlockAddress(BA, VT, Offset, true, TargetFlags); } - SDValue getCopyToReg(SDValue Chain, SDLoc dl, unsigned Reg, SDValue N) { + SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, unsigned Reg, + SDValue N) { return getNode(ISD::CopyToReg, dl, MVT::Other, Chain, getRegister(Reg, N.getValueType()), N); } @@ -577,7 +588,7 @@ public: // This version of the getCopyToReg method takes an extra operand, which // indicates that there is potentially an incoming glue value (if Glue is not // null) and that there should be a glue result. - SDValue getCopyToReg(SDValue Chain, SDLoc dl, unsigned Reg, SDValue N, + SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, unsigned Reg, SDValue N, SDValue Glue) { SDVTList VTs = getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, getRegister(Reg, N.getValueType()), N, Glue }; @@ -586,15 +597,15 @@ public: } // Similar to last getCopyToReg() except parameter Reg is a SDValue - SDValue getCopyToReg(SDValue Chain, SDLoc dl, SDValue Reg, SDValue N, - SDValue Glue) { + SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, SDValue Reg, SDValue N, + SDValue Glue) { SDVTList VTs = getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, Reg, N, Glue }; return getNode(ISD::CopyToReg, dl, VTs, makeArrayRef(Ops, Glue.getNode() ? 4 : 3)); } - SDValue getCopyFromReg(SDValue Chain, SDLoc dl, unsigned Reg, EVT VT) { + SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, unsigned Reg, EVT VT) { SDVTList VTs = getVTList(VT, MVT::Other); SDValue Ops[] = { Chain, getRegister(Reg, VT) }; return getNode(ISD::CopyFromReg, dl, VTs, Ops); @@ -603,8 +614,8 @@ public: // This version of the getCopyFromReg method takes an extra operand, which // indicates that there is potentially an incoming glue value (if Glue is not // null) and that there should be a glue result. - SDValue getCopyFromReg(SDValue Chain, SDLoc dl, unsigned Reg, EVT VT, - SDValue Glue) { + SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, unsigned Reg, EVT VT, + SDValue Glue) { SDVTList VTs = getVTList(VT, MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, getRegister(Reg, VT), Glue }; return getNode(ISD::CopyFromReg, dl, VTs, @@ -615,20 +626,46 @@ public: /// Returns the ConvertRndSat Note: Avoid using this node because it may /// disappear in the future and most targets don't support it. - SDValue getConvertRndSat(EVT VT, SDLoc dl, SDValue Val, SDValue DTy, - SDValue STy, - SDValue Rnd, SDValue Sat, ISD::CvtCode Code); + SDValue getConvertRndSat(EVT VT, const SDLoc &dl, SDValue Val, SDValue DTy, + SDValue STy, SDValue Rnd, SDValue Sat, + ISD::CvtCode Code); /// Return an ISD::VECTOR_SHUFFLE node. The number of elements in VT, /// which must be a vector type, must match the number of mask elements /// NumElts. An integer mask element equal to -1 is treated as undefined. - SDValue getVectorShuffle(EVT VT, SDLoc dl, SDValue N1, SDValue N2, - const int *MaskElts); - SDValue getVectorShuffle(EVT VT, SDLoc dl, SDValue N1, SDValue N2, - ArrayRef MaskElts) { - assert(VT.getVectorNumElements() == MaskElts.size() && - "Must have the same number of vector elements as mask elements!"); - return getVectorShuffle(VT, dl, N1, N2, MaskElts.data()); + SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, + ArrayRef Mask); + + /// Return an ISD::BUILD_VECTOR node. The number of elements in VT, + /// which must be a vector type, must match the number of operands in Ops. + /// The operands must have the same type as (or, for integers, a type wider + /// than) VT's element type. + SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef Ops) { + // VerifySDNode (via InsertNode) checks BUILD_VECTOR later. + return getNode(ISD::BUILD_VECTOR, DL, VT, Ops); + } + + /// Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all + /// elements. VT must be a vector type. Op's type must be the same as (or, + /// for integers, a type wider than) VT's element type. + SDValue getSplatBuildVector(EVT VT, const SDLoc &DL, SDValue Op) { + // VerifySDNode (via InsertNode) checks BUILD_VECTOR later. + if (Op.getOpcode() == ISD::UNDEF) { + assert((VT.getVectorElementType() == Op.getValueType() || + (VT.isInteger() && + VT.getVectorElementType().bitsLE(Op.getValueType()))) && + "A splatted value must have a width equal or (for integers) " + "greater than the vector element type!"); + return getNode(ISD::UNDEF, SDLoc(), VT); + } + + SmallVector Ops(VT.getVectorNumElements(), Op); + return getNode(ISD::BUILD_VECTOR, DL, VT, Ops); + } + + /// Return a splat ISD::BUILD_VECTOR node, but with Op's SDLoc. + SDValue getSplatBuildVector(EVT VT, SDValue Op) { + return getSplatBuildVector(VT, SDLoc(Op), Op); } /// \brief Returns an ISD::VECTOR_SHUFFLE node semantically equivalent to @@ -639,52 +676,52 @@ public: /// Convert Op, which must be of integer type, to the /// integer type VT, by either any-extending or truncating it. - SDValue getAnyExtOrTrunc(SDValue Op, SDLoc DL, EVT VT); + SDValue getAnyExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT); /// Convert Op, which must be of integer type, to the /// integer type VT, by either sign-extending or truncating it. - SDValue getSExtOrTrunc(SDValue Op, SDLoc DL, EVT VT); + SDValue getSExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT); /// Convert Op, which must be of integer type, to the /// integer type VT, by either zero-extending or truncating it. - SDValue getZExtOrTrunc(SDValue Op, SDLoc DL, EVT VT); + SDValue getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT); /// Return the expression required to zero extend the Op /// value assuming it was the smaller SrcTy value. - SDValue getZeroExtendInReg(SDValue Op, SDLoc DL, EVT SrcTy); + SDValue getZeroExtendInReg(SDValue Op, const SDLoc &DL, EVT SrcTy); /// Return an operation which will any-extend the low lanes of the operand /// into the specified vector type. For example, /// this can convert a v16i8 into a v4i32 by any-extending the low four /// lanes of the operand from i8 to i32. - SDValue getAnyExtendVectorInReg(SDValue Op, SDLoc DL, EVT VT); + SDValue getAnyExtendVectorInReg(SDValue Op, const SDLoc &DL, EVT VT); /// Return an operation which will sign extend the low lanes of the operand /// into the specified vector type. For example, /// this can convert a v16i8 into a v4i32 by sign extending the low four /// lanes of the operand from i8 to i32. - SDValue getSignExtendVectorInReg(SDValue Op, SDLoc DL, EVT VT); + SDValue getSignExtendVectorInReg(SDValue Op, const SDLoc &DL, EVT VT); /// Return an operation which will zero extend the low lanes of the operand /// into the specified vector type. For example, /// this can convert a v16i8 into a v4i32 by zero extending the low four /// lanes of the operand from i8 to i32. - SDValue getZeroExtendVectorInReg(SDValue Op, SDLoc DL, EVT VT); + SDValue getZeroExtendVectorInReg(SDValue Op, const SDLoc &DL, EVT VT); /// Convert Op, which must be of integer type, to the integer type VT, /// by using an extension appropriate for the target's /// BooleanContent for type OpVT or truncating it. - SDValue getBoolExtOrTrunc(SDValue Op, SDLoc SL, EVT VT, EVT OpVT); + SDValue getBoolExtOrTrunc(SDValue Op, const SDLoc &SL, EVT VT, EVT OpVT); /// Create a bitwise NOT operation as (XOR Val, -1). - SDValue getNOT(SDLoc DL, SDValue Val, EVT VT); + SDValue getNOT(const SDLoc &DL, SDValue Val, EVT VT); /// \brief Create a logical NOT operation as (XOR Val, BooleanOne). - SDValue getLogicalNOT(SDLoc DL, SDValue Val, EVT VT); + SDValue getLogicalNOT(const SDLoc &DL, SDValue Val, EVT VT); /// Return a new CALLSEQ_START node, which always must have a glue result /// (to ensure it's not CSE'd). CALLSEQ_START does not have a useful SDLoc. - SDValue getCALLSEQ_START(SDValue Chain, SDValue Op, SDLoc DL) { + SDValue getCALLSEQ_START(SDValue Chain, SDValue Op, const SDLoc &DL) { SDVTList VTs = getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, Op }; return getNode(ISD::CALLSEQ_START, DL, VTs, Ops); @@ -694,7 +731,7 @@ public: /// glue result (to ensure it's not CSE'd). /// CALLSEQ_END does not have a useful SDLoc. SDValue getCALLSEQ_END(SDValue Chain, SDValue Op1, SDValue Op2, - SDValue InGlue, SDLoc DL) { + SDValue InGlue, const SDLoc &DL) { SDVTList NodeTys = getVTList(MVT::Other, MVT::Glue); SmallVector Ops; Ops.push_back(Chain); @@ -717,38 +754,38 @@ public: /// Gets or creates the specified node. /// - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef Ops); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef Ops, const SDNodeFlags *Flags = nullptr); - SDValue getNode(unsigned Opcode, SDLoc DL, ArrayRef ResultTys, + SDValue getNode(unsigned Opcode, const SDLoc &DL, ArrayRef ResultTys, ArrayRef Ops); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, ArrayRef Ops); // Specialize based on number of operands. - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2, - const SDNodeFlags *Flags = nullptr); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2, - SDValue N3); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2, - SDValue N3, SDValue N4); - SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2, - SDValue N3, SDValue N4, SDValue N5); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, + SDValue N2, const SDNodeFlags *Flags = nullptr); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, + SDValue N2, SDValue N3); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, + SDValue N2, SDValue N3, SDValue N4); + SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, + SDValue N2, SDValue N3, SDValue N4, SDValue N5); // Specialize again based on number of operands for nodes with a VTList // rather than a single VT. - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N1, + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs); + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, SDValue N); + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, SDValue N1, SDValue N2); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N1, + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, SDValue N1, SDValue N2, SDValue N3); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N1, + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, SDValue N1, SDValue N2, SDValue N3, SDValue N4); - SDValue getNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N1, + SDValue getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, SDValue N1, SDValue N2, SDValue N3, SDValue N4, SDValue N5); /// Compute a TokenFactor to force all the incoming stack arguments to be @@ -756,24 +793,24 @@ public: /// stack arguments from being clobbered. SDValue getStackArgumentTokenFactor(SDValue Chain); - SDValue getMemcpy(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src, + SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, bool AlwaysInline, bool isTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo); - SDValue getMemmove(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src, + SDValue getMemmove(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, bool isTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo); - SDValue getMemset(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src, + SDValue getMemset(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, bool isTailCall, MachinePointerInfo DstPtrInfo); /// Helper function to make it easier to build SetCC's if you just /// have an ISD::CondCode instead of an SDValue. /// - SDValue getSetCC(SDLoc DL, EVT VT, SDValue LHS, SDValue RHS, + SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond) { assert(LHS.getValueType().isVector() == RHS.getValueType().isVector() && "Cannot compare scalars to vectors"); @@ -786,8 +823,8 @@ public: /// Helper function to make it easier to build Select's if you just /// have operands and don't want to check for vector. - SDValue getSelect(SDLoc DL, EVT VT, SDValue Cond, - SDValue LHS, SDValue RHS) { + SDValue getSelect(const SDLoc &DL, EVT VT, SDValue Cond, SDValue LHS, + SDValue RHS) { assert(LHS.getValueType() == RHS.getValueType() && "Cannot use select on differing types"); assert(VT.isVector() == LHS.getValueType().isVector() && @@ -799,142 +836,137 @@ public: /// Helper function to make it easier to build SelectCC's if you /// just have an ISD::CondCode instead of an SDValue. /// - SDValue getSelectCC(SDLoc DL, SDValue LHS, SDValue RHS, - SDValue True, SDValue False, ISD::CondCode Cond) { + SDValue getSelectCC(const SDLoc &DL, SDValue LHS, SDValue RHS, SDValue True, + SDValue False, ISD::CondCode Cond) { return getNode(ISD::SELECT_CC, DL, True.getValueType(), LHS, RHS, True, False, getCondCode(Cond)); } /// VAArg produces a result and token chain, and takes a pointer /// and a source value as input. - SDValue getVAArg(EVT VT, SDLoc dl, SDValue Chain, SDValue Ptr, + SDValue getVAArg(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, SDValue SV, unsigned Align); /// Gets a node for an atomic cmpxchg op. There are two /// valid Opcodes. ISD::ATOMIC_CMO_SWAP produces the value loaded and a /// chain result. ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS produces the value loaded, /// a success flag (initially i1), and a chain. - SDValue getAtomicCmpSwap(unsigned Opcode, SDLoc dl, EVT MemVT, SDVTList VTs, - SDValue Chain, SDValue Ptr, SDValue Cmp, SDValue Swp, - MachinePointerInfo PtrInfo, unsigned Alignment, - AtomicOrdering SuccessOrdering, + SDValue getAtomicCmpSwap(unsigned Opcode, const SDLoc &dl, EVT MemVT, + SDVTList VTs, SDValue Chain, SDValue Ptr, + SDValue Cmp, SDValue Swp, MachinePointerInfo PtrInfo, + unsigned Alignment, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope); - SDValue getAtomicCmpSwap(unsigned Opcode, SDLoc dl, EVT MemVT, SDVTList VTs, - SDValue Chain, SDValue Ptr, SDValue Cmp, SDValue Swp, - MachineMemOperand *MMO, + SDValue getAtomicCmpSwap(unsigned Opcode, const SDLoc &dl, EVT MemVT, + SDVTList VTs, SDValue Chain, SDValue Ptr, + SDValue Cmp, SDValue Swp, MachineMemOperand *MMO, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope); /// Gets a node for an atomic op, produces result (if relevant) /// and chain and takes 2 operands. - SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, SDValue Chain, + SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, SDValue Chain, SDValue Ptr, SDValue Val, const Value *PtrVal, unsigned Alignment, AtomicOrdering Ordering, SynchronizationScope SynchScope); - SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, SDValue Chain, + SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, SDValue Chain, SDValue Ptr, SDValue Val, MachineMemOperand *MMO, - AtomicOrdering Ordering, - SynchronizationScope SynchScope); + AtomicOrdering Ordering, SynchronizationScope SynchScope); /// Gets a node for an atomic op, produces result and chain and /// takes 1 operand. - SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, EVT VT, + SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, EVT VT, SDValue Chain, SDValue Ptr, MachineMemOperand *MMO, - AtomicOrdering Ordering, - SynchronizationScope SynchScope); + AtomicOrdering Ordering, SynchronizationScope SynchScope); /// Gets a node for an atomic op, produces result and chain and takes N /// operands. - SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, SDVTList VTList, - ArrayRef Ops, MachineMemOperand *MMO, - AtomicOrdering SuccessOrdering, + SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, + SDVTList VTList, ArrayRef Ops, + MachineMemOperand *MMO, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope); - SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, SDVTList VTList, - ArrayRef Ops, MachineMemOperand *MMO, - AtomicOrdering Ordering, SynchronizationScope SynchScope); + SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, + SDVTList VTList, ArrayRef Ops, + MachineMemOperand *MMO, AtomicOrdering Ordering, + SynchronizationScope SynchScope); /// Creates a MemIntrinsicNode that may produce a /// result and takes a list of operands. Opcode may be INTRINSIC_VOID, /// INTRINSIC_W_CHAIN, or a target-specific opcode with a value not /// less than FIRST_TARGET_MEMORY_OPCODE. - SDValue getMemIntrinsicNode(unsigned Opcode, SDLoc dl, SDVTList VTList, - ArrayRef Ops, - EVT MemVT, MachinePointerInfo PtrInfo, - unsigned Align = 0, bool Vol = false, - bool ReadMem = true, bool WriteMem = true, - unsigned Size = 0); + SDValue getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, SDVTList VTList, + ArrayRef Ops, EVT MemVT, + MachinePointerInfo PtrInfo, unsigned Align = 0, + bool Vol = false, bool ReadMem = true, + bool WriteMem = true, unsigned Size = 0); - SDValue getMemIntrinsicNode(unsigned Opcode, SDLoc dl, SDVTList VTList, - ArrayRef Ops, - EVT MemVT, MachineMemOperand *MMO); + SDValue getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, SDVTList VTList, + ArrayRef Ops, EVT MemVT, + MachineMemOperand *MMO); /// Create a MERGE_VALUES node from the given operands. - SDValue getMergeValues(ArrayRef Ops, SDLoc dl); + SDValue getMergeValues(ArrayRef Ops, const SDLoc &dl); /// Loads are not normal binary operators: their result type is not /// determined by their operands, and they produce a value AND a token chain. /// - SDValue getLoad(EVT VT, SDLoc dl, SDValue Chain, SDValue Ptr, + SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, bool isVolatile, bool isNonTemporal, bool isInvariant, unsigned Alignment, const AAMDNodes &AAInfo = AAMDNodes(), const MDNode *Ranges = nullptr); - SDValue getLoad(EVT VT, SDLoc dl, SDValue Chain, SDValue Ptr, + SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachineMemOperand *MMO); - SDValue getExtLoad(ISD::LoadExtType ExtType, SDLoc dl, EVT VT, + SDValue getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, - EVT MemVT, bool isVolatile, - bool isNonTemporal, bool isInvariant, unsigned Alignment, + EVT MemVT, bool isVolatile, bool isNonTemporal, + bool isInvariant, unsigned Alignment, const AAMDNodes &AAInfo = AAMDNodes()); - SDValue getExtLoad(ISD::LoadExtType ExtType, SDLoc dl, EVT VT, + SDValue getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, SDValue Ptr, EVT MemVT, MachineMemOperand *MMO); - SDValue getIndexedLoad(SDValue OrigLoad, SDLoc dl, SDValue Base, + SDValue getIndexedLoad(SDValue OrigLoad, const SDLoc &dl, SDValue Base, SDValue Offset, ISD::MemIndexedMode AM); - SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, - EVT VT, SDLoc dl, - SDValue Chain, SDValue Ptr, SDValue Offset, - MachinePointerInfo PtrInfo, EVT MemVT, - bool isVolatile, bool isNonTemporal, bool isInvariant, - unsigned Alignment, const AAMDNodes &AAInfo = AAMDNodes(), + SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, + const SDLoc &dl, SDValue Chain, SDValue Ptr, SDValue Offset, + MachinePointerInfo PtrInfo, EVT MemVT, bool isVolatile, + bool isNonTemporal, bool isInvariant, unsigned Alignment, + const AAMDNodes &AAInfo = AAMDNodes(), const MDNode *Ranges = nullptr); - SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, - EVT VT, SDLoc dl, - SDValue Chain, SDValue Ptr, SDValue Offset, + SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, + const SDLoc &dl, SDValue Chain, SDValue Ptr, SDValue Offset, EVT MemVT, MachineMemOperand *MMO); /// Helper function to build ISD::STORE nodes. - SDValue getStore(SDValue Chain, SDLoc dl, SDValue Val, SDValue Ptr, + SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, bool isVolatile, bool isNonTemporal, unsigned Alignment, const AAMDNodes &AAInfo = AAMDNodes()); - SDValue getStore(SDValue Chain, SDLoc dl, SDValue Val, SDValue Ptr, + SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachineMemOperand *MMO); - SDValue getTruncStore(SDValue Chain, SDLoc dl, SDValue Val, SDValue Ptr, - MachinePointerInfo PtrInfo, EVT TVT, - bool isNonTemporal, bool isVolatile, - unsigned Alignment, + SDValue getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, + SDValue Ptr, MachinePointerInfo PtrInfo, EVT TVT, + bool isNonTemporal, bool isVolatile, unsigned Alignment, const AAMDNodes &AAInfo = AAMDNodes()); - SDValue getTruncStore(SDValue Chain, SDLoc dl, SDValue Val, SDValue Ptr, - EVT TVT, MachineMemOperand *MMO); - SDValue getIndexedStore(SDValue OrigStoe, SDLoc dl, SDValue Base, + SDValue getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, + SDValue Ptr, EVT TVT, MachineMemOperand *MMO); + SDValue getIndexedStore(SDValue OrigStoe, const SDLoc &dl, SDValue Base, SDValue Offset, ISD::MemIndexedMode AM); /// Returns sum of the base pointer and offset. - SDValue getMemBasePlusOffset(SDValue Base, unsigned Offset, SDLoc DL); + SDValue getMemBasePlusOffset(SDValue Base, unsigned Offset, const SDLoc &DL); - SDValue getMaskedLoad(EVT VT, SDLoc dl, SDValue Chain, SDValue Ptr, + SDValue getMaskedLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, SDValue Mask, SDValue Src0, EVT MemVT, MachineMemOperand *MMO, ISD::LoadExtType); - SDValue getMaskedStore(SDValue Chain, SDLoc dl, SDValue Val, + SDValue getMaskedStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, SDValue Mask, EVT MemVT, MachineMemOperand *MMO, bool IsTrunc); - SDValue getMaskedGather(SDVTList VTs, EVT VT, SDLoc dl, + SDValue getMaskedGather(SDVTList VTs, EVT VT, const SDLoc &dl, ArrayRef Ops, MachineMemOperand *MMO); - SDValue getMaskedScatter(SDVTList VTs, EVT VT, SDLoc dl, + SDValue getMaskedScatter(SDVTList VTs, EVT VT, const SDLoc &dl, ArrayRef Ops, MachineMemOperand *MMO); /// Construct a node to track a Value* through the backend. SDValue getSrcValue(const Value *v); @@ -947,8 +979,8 @@ public: SDValue getBitcast(EVT VT, SDValue V); /// Return an AddrSpaceCastSDNode. - SDValue getAddrSpaceCast(SDLoc dl, EVT VT, SDValue Ptr, - unsigned SrcAS, unsigned DestAS); + SDValue getAddrSpaceCast(const SDLoc &dl, EVT VT, SDValue Ptr, unsigned SrcAS, + unsigned DestAS); /// Return the specified value casted to /// the target's desired shift amount type. @@ -1017,45 +1049,46 @@ public: /// Note that getMachineNode returns the resultant node. If there is already /// a node of the specified opcode and operands, it returns that node instead /// of the current one. - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, SDValue Op1); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, SDValue Op1, SDValue Op2); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, SDValue Op1, SDValue Op2, SDValue Op3); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT, ArrayRef Ops); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - SDValue Op1); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - SDValue Op1, SDValue Op2); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - SDValue Op1, SDValue Op2, SDValue Op3); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - ArrayRef Ops); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - EVT VT3, SDValue Op1, SDValue Op2); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - EVT VT3, SDValue Op1, SDValue Op2, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, SDValue Op1); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, SDValue Op1, SDValue Op2); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, SDValue Op1, SDValue Op2, SDValue Op3); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, ArrayRef Ops); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, EVT VT3, SDValue Op1, SDValue Op2); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, EVT VT3, SDValue Op1, SDValue Op2, SDValue Op3); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - EVT VT3, ArrayRef Ops); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, EVT VT1, EVT VT2, - EVT VT3, EVT VT4, ArrayRef Ops); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, - ArrayRef ResultTys, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, EVT VT3, ArrayRef Ops); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT1, + EVT VT2, EVT VT3, EVT VT4, ArrayRef Ops); - MachineSDNode *getMachineNode(unsigned Opcode, SDLoc dl, SDVTList VTs, + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, + ArrayRef ResultTys, ArrayRef Ops); + MachineSDNode *getMachineNode(unsigned Opcode, const SDLoc &dl, SDVTList VTs, ArrayRef Ops); /// A convenience function for creating TargetInstrInfo::EXTRACT_SUBREG nodes. - SDValue getTargetExtractSubreg(int SRIdx, SDLoc DL, EVT VT, + SDValue getTargetExtractSubreg(int SRIdx, const SDLoc &DL, EVT VT, SDValue Operand); /// A convenience function for creating TargetInstrInfo::INSERT_SUBREG nodes. - SDValue getTargetInsertSubreg(int SRIdx, SDLoc DL, EVT VT, + SDValue getTargetInsertSubreg(int SRIdx, const SDLoc &DL, EVT VT, SDValue Operand, SDValue Subreg); /// Get the specified node if it's already available, or else return NULL. @@ -1064,16 +1097,17 @@ public: /// Creates a SDDbgValue node. SDDbgValue *getDbgValue(MDNode *Var, MDNode *Expr, SDNode *N, unsigned R, - bool IsIndirect, uint64_t Off, DebugLoc DL, + bool IsIndirect, uint64_t Off, const DebugLoc &DL, unsigned O); /// Constant SDDbgValue *getConstantDbgValue(MDNode *Var, MDNode *Expr, const Value *C, - uint64_t Off, DebugLoc DL, unsigned O); + uint64_t Off, const DebugLoc &DL, unsigned O); /// FrameIndex SDDbgValue *getFrameIndexDbgValue(MDNode *Var, MDNode *Expr, unsigned FI, - uint64_t Off, DebugLoc DL, unsigned O); + uint64_t Off, const DebugLoc &DL, + unsigned O); /// Remove the specified node from the system. If any of its /// operands then becomes dead, remove them as well. Inform UpdateListener @@ -1181,9 +1215,11 @@ public: return DbgInfo->getSDDbgValues(SD); } - /// Transfer SDDbgValues. +private: + /// Transfer SDDbgValues. Called via ReplaceAllUses{OfValue}?With void TransferDbgValues(SDValue From, SDValue To); +public: /// Return true if there are any SDDbgValue nodes associated /// with this SelectionDAG. bool hasDebugValues() const { return !DbgInfo->empty(); } @@ -1199,33 +1235,32 @@ public: void dump() const; - /// Create a stack temporary, suitable for holding the - /// specified value type. If minAlign is specified, the slot size will have - /// at least that alignment. + /// Create a stack temporary, suitable for holding the specified value type. + /// If minAlign is specified, the slot size will have at least that alignment. SDValue CreateStackTemporary(EVT VT, unsigned minAlign = 1); - /// Create a stack temporary suitable for holding - /// either of the specified value types. + /// Create a stack temporary suitable for holding either of the specified + /// value types. SDValue CreateStackTemporary(EVT VT1, EVT VT2); SDValue FoldSymbolOffset(unsigned Opcode, EVT VT, const GlobalAddressSDNode *GA, const SDNode *N2); - SDValue FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT, + SDValue FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL, EVT VT, SDNode *Cst1, SDNode *Cst2); - SDValue FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT, + SDValue FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL, EVT VT, const ConstantSDNode *Cst1, const ConstantSDNode *Cst2); - SDValue FoldConstantVectorArithmetic(unsigned Opcode, SDLoc DL, - EVT VT, ArrayRef Ops, + SDValue FoldConstantVectorArithmetic(unsigned Opcode, const SDLoc &DL, EVT VT, + ArrayRef Ops, const SDNodeFlags *Flags = nullptr); /// Constant fold a setcc to true or false. - SDValue FoldSetCC(EVT VT, SDValue N1, - SDValue N2, ISD::CondCode Cond, SDLoc dl); + SDValue FoldSetCC(EVT VT, SDValue N1, SDValue N2, ISD::CondCode Cond, + const SDLoc &dl); /// Return true if the sign bit of Op is known to be zero. /// We use this predicate to simplify operations downstream. @@ -1244,27 +1279,32 @@ public: void computeKnownBits(SDValue Op, APInt &KnownZero, APInt &KnownOne, unsigned Depth = 0) const; - /// Return the number of times the sign bit of the - /// register is replicated into the other bits. We know that at least 1 bit - /// is always equal to the sign bit (itself), but other cases can give us - /// information. For example, immediately after an "SRA X, 2", we know that - /// the top 3 bits are all equal to each other, so we return 3. Targets can - /// implement the ComputeNumSignBitsForTarget method in the TargetLowering - /// class to allow target nodes to be understood. + /// Test if the given value is known to have exactly one bit set. This differs + /// from computeKnownBits in that it doesn't necessarily determine which bit + /// is set. + bool isKnownToBeAPowerOfTwo(SDValue Val) const; + + /// Return the number of times the sign bit of the register is replicated into + /// the other bits. We know that at least 1 bit is always equal to the sign + /// bit (itself), but other cases can give us information. For example, + /// immediately after an "SRA X, 2", we know that the top 3 bits are all equal + /// to each other, so we return 3. Targets can implement the + /// ComputeNumSignBitsForTarget method in the TargetLowering class to allow + /// target nodes to be understood. unsigned ComputeNumSignBits(SDValue Op, unsigned Depth = 0) const; - /// Return true if the specified operand is an - /// ISD::ADD with a ConstantSDNode on the right-hand side, or if it is an - /// ISD::OR with a ConstantSDNode that is guaranteed to have the same - /// semantics as an ADD. This handles the equivalence: + /// Return true if the specified operand is an ISD::ADD with a ConstantSDNode + /// on the right-hand side, or if it is an ISD::OR with a ConstantSDNode that + /// is guaranteed to have the same semantics as an ADD. This handles the + /// equivalence: /// X|Cst == X+Cst iff X&Cst = 0. bool isBaseWithConstantOffset(SDValue Op) const; /// Test whether the given SDValue is known to never be NaN. bool isKnownNeverNaN(SDValue Op) const; - /// Test whether the given SDValue is known to never be - /// positive or negative Zero. + /// Test whether the given SDValue is known to never be positive or negative + /// zero. bool isKnownNeverZero(SDValue Op) const; /// Test whether two SDValues are known to compare equal. This @@ -1284,10 +1324,12 @@ public: /// vector op and fill the end of the resulting vector with UNDEFS. SDValue UnrollVectorOp(SDNode *N, unsigned ResNE = 0); - /// Return true if LD is loading 'Bytes' bytes from a location that is 'Dist' - /// units away from the location that the 'Base' load is loading from. - bool isConsecutiveLoad(LoadSDNode *LD, LoadSDNode *Base, - unsigned Bytes, int Dist) const; + /// Return true if loads are next to each other and can be + /// merged. Check that both are nonvolatile and if LD is loading + /// 'Bytes' bytes from a location that is 'Dist' units away from the + /// location that the 'Base' load is loading from. + bool areNonVolatileConsecutiveLoads(LoadSDNode *LD, LoadSDNode *Base, + unsigned Bytes, int Dist) const; /// Infer alignment of a load / store address. Return 0 if /// it cannot be inferred. @@ -1321,6 +1363,7 @@ public: void ExtractVectorElements(SDValue Op, SmallVectorImpl &Args, unsigned Start = 0, unsigned Count = 0); + /// Compute the default alignment value for the given type. unsigned getEVTAlignment(EVT MemoryVT) const; /// Test whether the given value is a constant int or similar node. @@ -1335,15 +1378,16 @@ private: void *&InsertPos); SDNode *FindModifiedNodeSlot(SDNode *N, ArrayRef Ops, void *&InsertPos); - SDNode *UpdadeSDLocOnMergedSDNode(SDNode *N, SDLoc loc); + SDNode *UpdadeSDLocOnMergedSDNode(SDNode *N, const SDLoc &loc); void DeleteNodeNotInCSEMaps(SDNode *N); void DeallocateNode(SDNode *N); void allnodes_clear(); - SDNode *GetBinarySDNode(unsigned Opcode, SDLoc DL, SDVTList VTs, SDValue N1, - SDValue N2, const SDNodeFlags *Flags = nullptr); + SDNode *GetBinarySDNode(unsigned Opcode, const SDLoc &DL, SDVTList VTs, + SDValue N1, SDValue N2, + const SDNodeFlags *Flags = nullptr); /// Look up the node specified by ID in CSEMap. If it exists, return it. If /// not, return the insertion token that will make insertion faster. This @@ -1354,7 +1398,7 @@ private: /// Look up the node specified by ID in CSEMap. If it exists, return it. If /// not, return the insertion token that will make insertion faster. Performs /// additional processing for constant nodes. - SDNode *FindNodeOrInsertPos(const FoldingSetNodeID &ID, DebugLoc DL, + SDNode *FindNodeOrInsertPos(const FoldingSetNodeID &ID, const SDLoc &DL, void *&InsertPos); /// List of non-single value types. diff --git a/include/llvm/CodeGen/SelectionDAGISel.h b/include/llvm/CodeGen/SelectionDAGISel.h index 5738662239998b2baa18af1662001230bb283f3f..7f4549d3058f480316cb52d9b6a5d125a8ff193c 100644 --- a/include/llvm/CodeGen/SelectionDAGISel.h +++ b/include/llvm/CodeGen/SelectionDAGISel.h @@ -76,8 +76,8 @@ public: /// right after selection. virtual void PostprocessISelDAG() {} - /// Select - Main hook targets implement to select a node. - virtual SDNode *Select(SDNode *N) = 0; + /// Main hook for targets to transform nodes into machine nodes. + virtual void Select(SDNode *N) = 0; /// SelectInlineAsmMemoryOperand - Select the specified address as a target /// addressing mode, according to the specified constraint. If this does @@ -111,6 +111,8 @@ public: OPC_RecordMemRef, OPC_CaptureGlueInput, OPC_MoveChild, + OPC_MoveChild0, OPC_MoveChild1, OPC_MoveChild2, OPC_MoveChild3, + OPC_MoveChild4, OPC_MoveChild5, OPC_MoveChild6, OPC_MoveChild7, OPC_MoveParent, OPC_CheckSame, OPC_CheckChild0Same, OPC_CheckChild1Same, @@ -144,8 +146,11 @@ public: OPC_EmitCopyToReg, OPC_EmitNodeXForm, OPC_EmitNode, + // Space-optimized forms that implicitly encode number of result VTs. + OPC_EmitNode0, OPC_EmitNode1, OPC_EmitNode2, OPC_MorphNodeTo, - OPC_MarkGlueResults, + // Space-optimized forms that implicitly encode number of result VTs. + OPC_MorphNodeTo0, OPC_MorphNodeTo1, OPC_MorphNodeTo2, OPC_CompleteMatch }; @@ -197,11 +202,16 @@ protected: CurDAG->ReplaceAllUsesWith(F, T); } + /// Replace all uses of \c F with \c T, then remove \c F from the DAG. + void ReplaceNode(SDNode *F, SDNode *T) { + CurDAG->ReplaceAllUsesWith(F, T); + CurDAG->RemoveDeadNode(F); + } /// SelectInlineAsmMemoryOperands - Calls to this are automatically generated /// by tblgen. Others should not call it. - void SelectInlineAsmMemoryOperands(std::vector &Ops, SDLoc DL); - + void SelectInlineAsmMemoryOperands(std::vector &Ops, + const SDLoc &DL); public: // Calls to these predicates are generated by tblgen. @@ -237,9 +247,8 @@ public: llvm_unreachable("Tblgen should generate this!"); } - SDNode *SelectCodeCommon(SDNode *NodeToMatch, - const unsigned char *MatcherTable, - unsigned TableSize); + void SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, + unsigned TableSize); /// \brief Return true if complex patterns for this target can mutate the /// DAG. @@ -250,10 +259,10 @@ public: private: // Calls to these functions are generated by tblgen. - SDNode *Select_INLINEASM(SDNode *N); - SDNode *Select_READ_REGISTER(SDNode *N); - SDNode *Select_WRITE_REGISTER(SDNode *N); - SDNode *Select_UNDEF(SDNode *N); + void Select_INLINEASM(SDNode *N); + void Select_READ_REGISTER(SDNode *N); + void Select_WRITE_REGISTER(SDNode *N); + void Select_UNDEF(SDNode *N); void CannotYetSelect(SDNode *N); private: @@ -295,11 +304,9 @@ private: /// state machines that start with a OPC_SwitchOpcode node. std::vector OpcodeOffset; - void UpdateChainsAndGlue(SDNode *NodeToMatch, SDValue InputChain, - const SmallVectorImpl &ChainNodesMatched, - SDValue InputGlue, const SmallVectorImpl &F, - bool isMorphNodeTo); - + void UpdateChains(SDNode *NodeToMatch, SDValue InputChain, + const SmallVectorImpl &ChainNodesMatched, + bool isMorphNodeTo); }; } diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index 5b7b849a80364391935308706ae49722115af99a..cfcc4117f93b6b652a4a2442c865934bfa7f0ce2 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -66,24 +66,28 @@ struct SDVTList { namespace ISD { /// Node predicates - /// Return true if the specified node is a - /// BUILD_VECTOR where all of the elements are ~0 or undef. + /// If N is a BUILD_VECTOR node whose elements are all the same constant or + /// undefined, return true and return the constant value in \p SplatValue. + bool isConstantSplatVector(const SDNode *N, APInt &SplatValue); + + /// Return true if the specified node is a BUILD_VECTOR where all of the + /// elements are ~0 or undef. bool isBuildVectorAllOnes(const SDNode *N); - /// Return true if the specified node is a - /// BUILD_VECTOR where all of the elements are 0 or undef. + /// Return true if the specified node is a BUILD_VECTOR where all of the + /// elements are 0 or undef. bool isBuildVectorAllZeros(const SDNode *N); - /// \brief Return true if the specified node is a BUILD_VECTOR node of - /// all ConstantSDNode or undef. + /// Return true if the specified node is a BUILD_VECTOR node of all + /// ConstantSDNode or undef. bool isBuildVectorOfConstantSDNodes(const SDNode *N); - /// \brief Return true if the specified node is a BUILD_VECTOR node of - /// all ConstantFPSDNode or undef. + /// Return true if the specified node is a BUILD_VECTOR node of all + /// ConstantFPSDNode or undef. bool isBuildVectorOfConstantFPSDNodes(const SDNode *N); - /// Return true if the node has at least one operand - /// and all operands of the specified node are ISD::UNDEF. + /// Return true if the node has at least one operand and all operands of the + /// specified node are ISD::UNDEF. bool allOperandsUndef(const SDNode *N); } // end llvm:ISD namespace @@ -847,8 +851,8 @@ public: if (I) DL = I->getDebugLoc(); } - unsigned getIROrder() { return IROrder; } - DebugLoc getDebugLoc() { return DL; } + unsigned getIROrder() const { return IROrder; } + const DebugLoc &getDebugLoc() const { return DL; } }; @@ -952,8 +956,8 @@ static bool isBinOpWithFlags(unsigned Opcode) { class BinaryWithFlagsSDNode : public SDNode { public: SDNodeFlags Flags; - BinaryWithFlagsSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, - const SDNodeFlags &NodeFlags) + BinaryWithFlagsSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, + SDVTList VTs, const SDNodeFlags &NodeFlags) : SDNode(Opc, Order, dl, VTs), Flags(NodeFlags) {} static bool classof(const SDNode *N) { return isBinOpWithFlags(N->getOpcode()); @@ -992,8 +996,8 @@ private: unsigned DestAddrSpace; public: - AddrSpaceCastSDNode(unsigned Order, DebugLoc dl, EVT VT, unsigned SrcAS, - unsigned DestAS); + AddrSpaceCastSDNode(unsigned Order, const DebugLoc &dl, EVT VT, + unsigned SrcAS, unsigned DestAS); unsigned getSrcAddressSpace() const { return SrcAddrSpace; } unsigned getDestAddressSpace() const { return DestAddrSpace; } @@ -1014,7 +1018,7 @@ protected: MachineMemOperand *MMO; public: - MemSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, + MemSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemoryVT, MachineMemOperand *MMO); bool readMem() const { return MMO->isLoad(); } @@ -1127,13 +1131,15 @@ class AtomicSDNode : public MemSDNode { AtomicOrdering FailureOrdering, SynchronizationScope SynchScope) { // This must match encodeMemSDNodeFlags() in SelectionDAG.cpp. - assert((SuccessOrdering & 15) == SuccessOrdering && + assert((AtomicOrdering)((unsigned)SuccessOrdering & 15) == + SuccessOrdering && "Ordering may not require more than 4 bits!"); - assert((FailureOrdering & 15) == FailureOrdering && + assert((AtomicOrdering)((unsigned)FailureOrdering & 15) == + FailureOrdering && "Ordering may not require more than 4 bits!"); assert((SynchScope & 1) == SynchScope && "SynchScope may not require more than 1 bit!"); - SubclassData |= SuccessOrdering << 8; + SubclassData |= (unsigned)SuccessOrdering << 8; SubclassData |= SynchScope << 12; this->FailureOrdering = FailureOrdering; assert(getSuccessOrdering() == SuccessOrdering && @@ -1144,7 +1150,7 @@ class AtomicSDNode : public MemSDNode { } public: - AtomicSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTL, + AtomicSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, SDVTList VTL, EVT MemVT, MachineMemOperand *MMO, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SynchronizationScope SynchScope) @@ -1196,8 +1202,8 @@ public: /// with a value not less than FIRST_TARGET_MEMORY_OPCODE. class MemIntrinsicSDNode : public MemSDNode { public: - MemIntrinsicSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs, - EVT MemoryVT, MachineMemOperand *MMO) + MemIntrinsicSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, + SDVTList VTs, EVT MemoryVT, MachineMemOperand *MMO) : MemSDNode(Opc, Order, dl, VTs, MemoryVT, MMO) { SubclassData |= 1u << 13; } @@ -1226,7 +1232,7 @@ class ShuffleVectorSDNode : public SDNode { const int *Mask; protected: friend class SelectionDAG; - ShuffleVectorSDNode(EVT VT, unsigned Order, DebugLoc dl, const int *M) + ShuffleVectorSDNode(EVT VT, unsigned Order, const DebugLoc &dl, const int *M) : SDNode(ISD::VECTOR_SHUFFLE, Order, dl, getSDVTList(VT)), Mask(M) {} public: @@ -1253,7 +1259,7 @@ public: /// Change values in a shuffle permute mask assuming /// the two vector operands have swapped position. - static void commuteMask(SmallVectorImpl &Mask) { + static void commuteMask(MutableArrayRef Mask) { unsigned NumElems = Mask.size(); for (unsigned i = 0; i != NumElems; ++i) { int idx = Mask[i]; @@ -1275,9 +1281,10 @@ class ConstantSDNode : public SDNode { const ConstantInt *Value; friend class SelectionDAG; ConstantSDNode(bool isTarget, bool isOpaque, const ConstantInt *val, - DebugLoc DL, EVT VT) - : SDNode(isTarget ? ISD::TargetConstant : ISD::Constant, - 0, DL, getSDVTList(VT)), Value(val) { + const DebugLoc &DL, EVT VT) + : SDNode(isTarget ? ISD::TargetConstant : ISD::Constant, 0, DL, + getSDVTList(VT)), + Value(val) { SubclassData |= (uint16_t)isOpaque; } public: @@ -1302,10 +1309,12 @@ public: class ConstantFPSDNode : public SDNode { const ConstantFP *Value; friend class SelectionDAG; - ConstantFPSDNode(bool isTarget, const ConstantFP *val, DebugLoc DL, EVT VT) - : SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP, - 0, DL, getSDVTList(VT)), Value(val) { - } + ConstantFPSDNode(bool isTarget, const ConstantFP *val, const DebugLoc &DL, + EVT VT) + : SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP, 0, DL, + getSDVTList(VT)), + Value(val) {} + public: const APFloat& getValueAPF() const { return Value->getValueAPF(); } @@ -1356,15 +1365,19 @@ bool isNullFPConstant(SDValue V); bool isAllOnesConstant(SDValue V); /// Returns true if \p V is a constant integer one. bool isOneConstant(SDValue V); +/// Returns true if \p V is a bitwise not operation. Assumes that an all ones +/// constant is canonicalized to be operand 1. +bool isBitwiseNot(SDValue V); class GlobalAddressSDNode : public SDNode { const GlobalValue *TheGlobal; int64_t Offset; unsigned char TargetFlags; friend class SelectionDAG; - GlobalAddressSDNode(unsigned Opc, unsigned Order, DebugLoc DL, + GlobalAddressSDNode(unsigned Opc, unsigned Order, const DebugLoc &DL, const GlobalValue *GA, EVT VT, int64_t o, unsigned char TargetFlags); + public: const GlobalValue *getGlobal() const { return TheGlobal; } @@ -1662,7 +1675,7 @@ public: class EHLabelSDNode : public SDNode { MCSymbol *Label; friend class SelectionDAG; - EHLabelSDNode(unsigned Order, DebugLoc dl, MCSymbol *L) + EHLabelSDNode(unsigned Order, const DebugLoc &dl, MCSymbol *L) : SDNode(ISD::EH_LABEL, Order, dl, getSDVTList(MVT::Other)), Label(L) {} public: @@ -1729,7 +1742,7 @@ public: class CvtRndSatSDNode : public SDNode { ISD::CvtCode CvtCode; friend class SelectionDAG; - explicit CvtRndSatSDNode(EVT VT, unsigned Order, DebugLoc dl, + explicit CvtRndSatSDNode(EVT VT, unsigned Order, const DebugLoc &dl, ISD::CvtCode Code) : SDNode(ISD::CONVERT_RNDSAT, Order, dl, getSDVTList(VT)), CvtCode(Code) { } @@ -1763,10 +1776,10 @@ public: /// Base class for LoadSDNode and StoreSDNode class LSBaseSDNode : public MemSDNode { public: - LSBaseSDNode(ISD::NodeType NodeTy, unsigned Order, DebugLoc dl, + LSBaseSDNode(ISD::NodeType NodeTy, unsigned Order, const DebugLoc &dl, SDVTList VTs, ISD::MemIndexedMode AM, EVT MemVT, MachineMemOperand *MMO) - : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { + : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) { SubclassData |= AM << 2; assert(getAddressingMode() == AM && "MemIndexedMode encoding error!"); } @@ -1796,8 +1809,9 @@ public: /// This class is used to represent ISD::LOAD nodes. class LoadSDNode : public LSBaseSDNode { friend class SelectionDAG; - LoadSDNode(unsigned Order, DebugLoc dl, SDVTList VTs, ISD::MemIndexedMode AM, - ISD::LoadExtType ETy, EVT MemVT, MachineMemOperand *MMO) + LoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, + ISD::MemIndexedMode AM, ISD::LoadExtType ETy, EVT MemVT, + MachineMemOperand *MMO) : LSBaseSDNode(ISD::LOAD, Order, dl, VTs, AM, MemVT, MMO) { SubclassData |= (unsigned short)ETy; assert(getExtensionType() == ETy && "LoadExtType encoding error!"); @@ -1823,8 +1837,9 @@ public: /// This class is used to represent ISD::STORE nodes. class StoreSDNode : public LSBaseSDNode { friend class SelectionDAG; - StoreSDNode(unsigned Order, DebugLoc dl, SDVTList VTs, ISD::MemIndexedMode AM, - bool isTrunc, EVT MemVT, MachineMemOperand *MMO) + StoreSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, + ISD::MemIndexedMode AM, bool isTrunc, EVT MemVT, + MachineMemOperand *MMO) : LSBaseSDNode(ISD::STORE, Order, dl, VTs, AM, MemVT, MMO) { SubclassData |= (unsigned short)isTrunc; assert(isTruncatingStore() == isTrunc && "isTrunc encoding error!"); @@ -1851,8 +1866,9 @@ public: class MaskedLoadStoreSDNode : public MemSDNode { public: friend class SelectionDAG; - MaskedLoadStoreSDNode(ISD::NodeType NodeTy, unsigned Order, DebugLoc dl, - SDVTList VTs, EVT MemVT, MachineMemOperand *MMO) + MaskedLoadStoreSDNode(ISD::NodeType NodeTy, unsigned Order, + const DebugLoc &dl, SDVTList VTs, EVT MemVT, + MachineMemOperand *MMO) : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) {} // In the both nodes address is Op1, mask is Op2: @@ -1872,7 +1888,7 @@ public: class MaskedLoadSDNode : public MaskedLoadStoreSDNode { public: friend class SelectionDAG; - MaskedLoadSDNode(unsigned Order, DebugLoc dl, SDVTList VTs, + MaskedLoadSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, ISD::LoadExtType ETy, EVT MemVT, MachineMemOperand *MMO) : MaskedLoadStoreSDNode(ISD::MLOAD, Order, dl, VTs, MemVT, MMO) { SubclassData |= (unsigned short)ETy; @@ -1892,8 +1908,8 @@ class MaskedStoreSDNode : public MaskedLoadStoreSDNode { public: friend class SelectionDAG; - MaskedStoreSDNode(unsigned Order, DebugLoc dl, SDVTList VTs, bool isTrunc, - EVT MemVT, MachineMemOperand *MMO) + MaskedStoreSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, + bool isTrunc, EVT MemVT, MachineMemOperand *MMO) : MaskedLoadStoreSDNode(ISD::MSTORE, Order, dl, VTs, MemVT, MMO) { SubclassData |= (unsigned short)isTrunc; } @@ -1915,8 +1931,9 @@ public: class MaskedGatherScatterSDNode : public MemSDNode { public: friend class SelectionDAG; - MaskedGatherScatterSDNode(ISD::NodeType NodeTy, unsigned Order, DebugLoc dl, - SDVTList VTs, EVT MemVT, MachineMemOperand *MMO) + MaskedGatherScatterSDNode(ISD::NodeType NodeTy, unsigned Order, + const DebugLoc &dl, SDVTList VTs, EVT MemVT, + MachineMemOperand *MMO) : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) {} // In the both nodes address is Op1, mask is Op2: @@ -1939,8 +1956,8 @@ public: class MaskedGatherSDNode : public MaskedGatherScatterSDNode { public: friend class SelectionDAG; - MaskedGatherSDNode(unsigned Order, DebugLoc dl, SDVTList VTs, EVT MemVT, - MachineMemOperand *MMO) + MaskedGatherSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, + EVT MemVT, MachineMemOperand *MMO) : MaskedGatherScatterSDNode(ISD::MGATHER, Order, dl, VTs, MemVT, MMO) {} static bool classof(const SDNode *N) { @@ -1954,8 +1971,8 @@ class MaskedScatterSDNode : public MaskedGatherScatterSDNode { public: friend class SelectionDAG; - MaskedScatterSDNode(unsigned Order, DebugLoc dl, SDVTList VTs, EVT MemVT, - MachineMemOperand *MMO) + MaskedScatterSDNode(unsigned Order, const DebugLoc &dl, SDVTList VTs, + EVT MemVT, MachineMemOperand *MMO) : MaskedGatherScatterSDNode(ISD::MSCATTER, Order, dl, VTs, MemVT, MMO) {} static bool classof(const SDNode *N) { @@ -1972,8 +1989,8 @@ public: private: friend class SelectionDAG; - MachineSDNode(unsigned Opc, unsigned Order, const DebugLoc DL, SDVTList VTs) - : SDNode(Opc, Order, DL, VTs), MemRefs(nullptr), MemRefsEnd(nullptr) {} + MachineSDNode(unsigned Opc, unsigned Order, const DebugLoc &DL, SDVTList VTs) + : SDNode(Opc, Order, DL, VTs), MemRefs(nullptr), MemRefsEnd(nullptr) {} /// Memory reference descriptions for this instruction. mmo_iterator MemRefs; diff --git a/include/llvm/CodeGen/SelectionDAGTargetInfo.h b/include/llvm/CodeGen/SelectionDAGTargetInfo.h index 2e0339b92d8e4a4b0ba5634089da8cba894a116b..ac5092af8def3ee91f080b021ba0962c164f5512 100644 --- a/include/llvm/CodeGen/SelectionDAGTargetInfo.h +++ b/include/llvm/CodeGen/SelectionDAGTargetInfo.h @@ -17,6 +17,7 @@ #define LLVM_CODEGEN_SELECTIONDAGTARGETINFO_H #include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/Support/CodeGen.h" namespace llvm { @@ -45,10 +46,13 @@ public: /// expanded in a place where calls are not feasible (e.g. within the prologue /// for another call). If the target chooses to decline an AlwaysInline /// request here, legalize will resort to using simple loads and stores. - virtual SDValue EmitTargetCodeForMemcpy( - SelectionDAG &DAG, SDLoc dl, SDValue Chain, SDValue Op1, SDValue Op2, - SDValue Op3, unsigned Align, bool isVolatile, bool AlwaysInline, - MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const { + virtual SDValue EmitTargetCodeForMemcpy(SelectionDAG &DAG, const SDLoc &dl, + SDValue Chain, SDValue Op1, + SDValue Op2, SDValue Op3, + unsigned Align, bool isVolatile, + bool AlwaysInline, + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) const { return SDValue(); } @@ -59,8 +63,8 @@ public: /// SDValue if the target declines to use custom code and a different /// lowering strategy should be used. virtual SDValue EmitTargetCodeForMemmove( - SelectionDAG &DAG, SDLoc dl, SDValue Chain, SDValue Op1, SDValue Op2, - SDValue Op3, unsigned Align, bool isVolatile, + SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Op1, + SDValue Op2, SDValue Op3, unsigned Align, bool isVolatile, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const { return SDValue(); } @@ -71,7 +75,7 @@ public: /// efficient than using a library call. This function can return a null /// SDValue if the target declines to use custom code and a different /// lowering strategy should be used. - virtual SDValue EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl, + virtual SDValue EmitTargetCodeForMemset(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Op1, SDValue Op2, SDValue Op3, unsigned Align, bool isVolatile, @@ -84,7 +88,7 @@ public: /// memcmp and the second is the chain. Both SDValues can be null if a normal /// libcall should be used. virtual std::pair - EmitTargetCodeForMemcmp(SelectionDAG &DAG, SDLoc dl, SDValue Chain, + EmitTargetCodeForMemcmp(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Op1, SDValue Op2, SDValue Op3, MachinePointerInfo Op1PtrInfo, MachinePointerInfo Op2PtrInfo) const { @@ -96,7 +100,7 @@ public: /// memchr and the second is the chain. Both SDValues can be null if a normal /// libcall should be used. virtual std::pair - EmitTargetCodeForMemchr(SelectionDAG &DAG, SDLoc dl, SDValue Chain, + EmitTargetCodeForMemchr(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Src, SDValue Char, SDValue Length, MachinePointerInfo SrcPtrInfo) const { return std::make_pair(SDValue(), SDValue()); @@ -109,7 +113,7 @@ public: /// for stpcpy) and the second is the chain. Both SDValues can be null /// if a normal libcall should be used. virtual std::pair - EmitTargetCodeForStrcpy(SelectionDAG &DAG, SDLoc DL, SDValue Chain, + EmitTargetCodeForStrcpy(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dest, SDValue Src, MachinePointerInfo DestPtrInfo, MachinePointerInfo SrcPtrInfo, bool isStpcpy) const { @@ -120,24 +124,31 @@ public: /// faster than a libcall. /// The first returned SDValue is the result of the strcmp and the second is /// the chain. Both SDValues can be null if a normal libcall should be used. - virtual std::pair EmitTargetCodeForStrcmp( - SelectionDAG &DAG, SDLoc dl, SDValue Chain, SDValue Op1, SDValue Op2, - MachinePointerInfo Op1PtrInfo, MachinePointerInfo Op2PtrInfo) const { + virtual std::pair + EmitTargetCodeForStrcmp(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, + SDValue Op1, SDValue Op2, + MachinePointerInfo Op1PtrInfo, + MachinePointerInfo Op2PtrInfo) const { return std::make_pair(SDValue(), SDValue()); } virtual std::pair - EmitTargetCodeForStrlen(SelectionDAG &DAG, SDLoc DL, SDValue Chain, + EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Src, MachinePointerInfo SrcPtrInfo) const { return std::make_pair(SDValue(), SDValue()); } virtual std::pair - EmitTargetCodeForStrnlen(SelectionDAG &DAG, SDLoc DL, SDValue Chain, + EmitTargetCodeForStrnlen(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Src, SDValue MaxLength, MachinePointerInfo SrcPtrInfo) const { return std::make_pair(SDValue(), SDValue()); } + // Return true when the decision to generate FMA's (or FMS, FMLA etc) rather + // than FMUL and ADD is delegated to the machine combiner. + virtual bool generateFMAsInMachineCombiner(CodeGenOpt::Level OptLevel) const { + return false; + } }; } // end llvm namespace diff --git a/include/llvm/CodeGen/SlotIndexes.h b/include/llvm/CodeGen/SlotIndexes.h index 71af879e14227ff401f63b3bebb65cf00932b4cb..afb0288b024fb70ed726741c81fe2e9199899b88 100644 --- a/include/llvm/CodeGen/SlotIndexes.h +++ b/include/llvm/CodeGen/SlotIndexes.h @@ -98,7 +98,7 @@ namespace llvm { Slot_Block, /// Early-clobber register use/def slot. A live range defined at - /// Slot_EarlyCLobber interferes with normal live ranges killed at + /// Slot_EarlyClobber interferes with normal live ranges killed at /// Slot_Register. Also used as the kill slot for live ranges tied to an /// early-clobber def. Slot_EarlyClobber, diff --git a/include/llvm/CodeGen/StackMaps.h b/include/llvm/CodeGen/StackMaps.h index 972a616ad779a9ad7600caf9fc8fd22b9de4bbbb..918848f6b2a13c9d7bfd988e595be247051e0eba 100644 --- a/include/llvm/CodeGen/StackMaps.h +++ b/include/llvm/CodeGen/StackMaps.h @@ -14,8 +14,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/Support/Debug.h" -#include #include namespace llvm { diff --git a/include/llvm/CodeGen/StackProtector.h b/include/llvm/CodeGen/StackProtector.h index 8cef85cb4485245d6593890623d0bcde8b697736..1b3c0eb4a4d0ac2815086dd77d21e377eefd6dca 100644 --- a/include/llvm/CodeGen/StackProtector.h +++ b/include/llvm/CodeGen/StackProtector.h @@ -75,6 +75,12 @@ private: /// times. SmallPtrSet VisitedPHIs; + // A prologue is generated. + bool HasPrologue = false; + + // IR checking code is generated. + bool HasIRCheck = false; + /// InsertStackProtectors - Insert code into the prologue and epilogue of /// the function. /// @@ -120,6 +126,10 @@ public: } SSPLayoutKind getSSPLayout(const AllocaInst *AI) const; + + // Return true if StackProtector is supposed to be handled by SelectionDAG. + bool shouldEmitSDCheck(const BasicBlock &BB) const; + void adjustForColoring(const AllocaInst *From, const AllocaInst *To); bool runOnFunction(Function &Fn) override; diff --git a/include/llvm/CodeGen/TailDuplicator.h b/include/llvm/CodeGen/TailDuplicator.h new file mode 100644 index 0000000000000000000000000000000000000000..8e65199418a6b14b310d00f3d099e362004ef8f4 --- /dev/null +++ b/include/llvm/CodeGen/TailDuplicator.h @@ -0,0 +1,92 @@ +//===-- llvm/CodeGen/TailDuplicator.h ---------------------------*- C++ -*-===// +// +// 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 TailDuplicator class. Used by the +// TailDuplication pass, and MachineBlockPlacement. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_TAILDUPLICATOR_H +#define LLVM_CODEGEN_TAILDUPLICATOR_H + +#include "llvm/CodeGen/MachineBranchProbabilityInfo.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/MachineSSAUpdater.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +namespace llvm { + +/// Utility class to perform tail duplication. +class TailDuplicator { + const TargetInstrInfo *TII; + const TargetRegisterInfo *TRI; + const MachineBranchProbabilityInfo *MBPI; + const MachineModuleInfo *MMI; + MachineRegisterInfo *MRI; + bool PreRegAlloc; + + // A list of virtual registers for which to update SSA form. + SmallVector SSAUpdateVRs; + + // For each virtual register in SSAUpdateVals keep a list of source virtual + // registers. + typedef std::vector> AvailableValsTy; + + DenseMap SSAUpdateVals; + +public: + void initMF(MachineFunction &MF, const MachineModuleInfo *MMI, + const MachineBranchProbabilityInfo *MBPI); + bool tailDuplicateBlocks(MachineFunction &MF); + static bool isSimpleBB(MachineBasicBlock *TailBB); + bool shouldTailDuplicate(const MachineFunction &MF, bool IsSimple, + MachineBasicBlock &TailBB); + bool tailDuplicateAndUpdate(MachineFunction &MF, bool IsSimple, + MachineBasicBlock *MBB); + +private: + typedef TargetInstrInfo::RegSubRegPair RegSubRegPair; + + void addSSAUpdateEntry(unsigned OrigReg, unsigned NewReg, + MachineBasicBlock *BB); + void processPHI(MachineInstr *MI, MachineBasicBlock *TailBB, + MachineBasicBlock *PredBB, + DenseMap &LocalVRMap, + SmallVectorImpl> &Copies, + const DenseSet &UsedByPhi, bool Remove); + void duplicateInstruction(MachineInstr *MI, MachineBasicBlock *TailBB, + MachineBasicBlock *PredBB, MachineFunction &MF, + DenseMap &LocalVRMap, + const DenseSet &UsedByPhi); + void updateSuccessorsPHIs(MachineBasicBlock *FromBB, bool isDead, + SmallVectorImpl &TDBBs, + SmallSetVector &Succs); + bool canCompletelyDuplicateBB(MachineBasicBlock &BB); + bool duplicateSimpleBB(MachineBasicBlock *TailBB, + SmallVectorImpl &TDBBs, + const DenseSet &RegsUsedByPhi, + SmallVectorImpl &Copies); + bool tailDuplicate(MachineFunction &MF, bool IsSimple, + MachineBasicBlock *TailBB, + SmallVectorImpl &TDBBs, + SmallVectorImpl &Copies); + void appendCopies(MachineBasicBlock *MBB, + SmallVectorImpl> &CopyInfos, + SmallVectorImpl &Copies); + + void removeDeadBlock(MachineBasicBlock *MBB); +}; + +} // End llvm namespace + +#endif diff --git a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index 61dbc00b8380f7b620fe2720cdac0b6a96ed8ac5..c856435f5ddca48c0e9abfd6a4c3c891d88838bd 100644 --- a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -15,7 +15,7 @@ #ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H #define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H -#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/SectionKind.h" #include "llvm/Target/TargetLoweringObjectFile.h" @@ -23,7 +23,6 @@ namespace llvm { class MachineModuleInfo; class Mangler; class MCAsmInfo; - class MCExpr; class MCSection; class MCSectionMachO; class MCSymbol; @@ -36,6 +35,10 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { bool UseInitArray; mutable unsigned NextUniqueID = 0; +protected: + MCSymbolRefExpr::VariantKind PLTRelativeVariantKind = + MCSymbolRefExpr::VK_None; + public: TargetLoweringObjectFileELF() : UseInitArray(false) {} @@ -82,6 +85,10 @@ public: const MCSymbol *KeySym) const override; MCSection *getStaticDtorSection(unsigned Priority, const MCSymbol *KeySym) const override; + + const MCExpr *lowerRelativeReference(const GlobalValue *LHS, + const GlobalValue *RHS, Mangler &Mang, + const TargetMachine &TM) const override; }; @@ -133,6 +140,8 @@ public: class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { + mutable unsigned NextUniqueID = 0; + public: ~TargetLoweringObjectFileCOFF() override {} diff --git a/include/llvm/CodeGen/TargetPassConfig.h b/include/llvm/CodeGen/TargetPassConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..9309655a972ed262f25cf3bada1c1e7360b80441 --- /dev/null +++ b/include/llvm/CodeGen/TargetPassConfig.h @@ -0,0 +1,376 @@ +//===-- TargetPassConfig.h - Code Generation pass options -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// Target-Independent Code Generator Pass Configuration Options pass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_TARGETPASSCONFIG_H +#define LLVM_CODEGEN_TARGETPASSCONFIG_H + +#include "llvm/Pass.h" +#include "llvm/Support/CodeGen.h" +#include + +namespace llvm { + +class PassConfigImpl; +class ScheduleDAGInstrs; +class TargetMachine; +struct MachineSchedContext; + +// The old pass manager infrastructure is hidden in a legacy namespace now. +namespace legacy { +class PassManagerBase; +} +using legacy::PassManagerBase; + +/// Discriminated union of Pass ID types. +/// +/// The PassConfig API prefers dealing with IDs because they are safer and more +/// efficient. IDs decouple configuration from instantiation. This way, when a +/// pass is overriden, it isn't unnecessarily instantiated. It is also unsafe to +/// refer to a Pass pointer after adding it to a pass manager, which deletes +/// redundant pass instances. +/// +/// However, it is convient to directly instantiate target passes with +/// non-default ctors. These often don't have a registered PassInfo. Rather than +/// force all target passes to implement the pass registry boilerplate, allow +/// the PassConfig API to handle either type. +/// +/// AnalysisID is sadly char*, so PointerIntPair won't work. +class IdentifyingPassPtr { + union { + AnalysisID ID; + Pass *P; + }; + bool IsInstance; +public: + IdentifyingPassPtr() : P(nullptr), IsInstance(false) {} + IdentifyingPassPtr(AnalysisID IDPtr) : ID(IDPtr), IsInstance(false) {} + IdentifyingPassPtr(Pass *InstancePtr) : P(InstancePtr), IsInstance(true) {} + + bool isValid() const { return P; } + bool isInstance() const { return IsInstance; } + + AnalysisID getID() const { + assert(!IsInstance && "Not a Pass ID"); + return ID; + } + Pass *getInstance() const { + assert(IsInstance && "Not a Pass Instance"); + return P; + } +}; + +template <> struct isPodLike { + static const bool value = true; +}; + +/// Target-Independent Code Generator Pass Configuration Options. +/// +/// This is an ImmutablePass solely for the purpose of exposing CodeGen options +/// to the internals of other CodeGen passes. +class TargetPassConfig : public ImmutablePass { +public: + /// Pseudo Pass IDs. These are defined within TargetPassConfig because they + /// are unregistered pass IDs. They are only useful for use with + /// TargetPassConfig APIs to identify multiple occurrences of the same pass. + /// + + /// EarlyTailDuplicate - A clone of the TailDuplicate pass that runs early + /// during codegen, on SSA form. + static char EarlyTailDuplicateID; + + /// PostRAMachineLICM - A clone of the LICM pass that runs during late machine + /// optimization after regalloc. + static char PostRAMachineLICMID; + +private: + PassManagerBase *PM; + AnalysisID StartBefore, StartAfter; + AnalysisID StopAfter; + bool Started; + bool Stopped; + bool AddingMachinePasses; + +protected: + TargetMachine *TM; + PassConfigImpl *Impl; // Internal data structures + bool Initialized; // Flagged after all passes are configured. + + // Target Pass Options + // Targets provide a default setting, user flags override. + // + bool DisableVerify; + + /// Default setting for -enable-tail-merge on this target. + bool EnableTailMerge; + +public: + TargetPassConfig(TargetMachine *tm, PassManagerBase &pm); + // Dummy constructor. + TargetPassConfig(); + + ~TargetPassConfig() override; + + static char ID; + + /// Get the right type of TargetMachine for this target. + template TMC &getTM() const { + return *static_cast(TM); + } + + // + void setInitialized() { Initialized = true; } + + CodeGenOpt::Level getOptLevel() const; + + /// Set the StartAfter, StartBefore and StopAfter passes to allow running only + /// a portion of the normal code-gen pass sequence. + /// + /// If the StartAfter and StartBefore pass ID is zero, then compilation will + /// begin at the normal point; otherwise, clear the Started flag to indicate + /// that passes should not be added until the starting pass is seen. If the + /// Stop pass ID is zero, then compilation will continue to the end. + /// + /// This function expects that at least one of the StartAfter or the + /// StartBefore pass IDs is null. + void setStartStopPasses(AnalysisID StartBefore, AnalysisID StartAfter, + AnalysisID StopAfter) { + if (StartAfter) + assert(!StartBefore && "Start after and start before passes are given"); + this->StartBefore = StartBefore; + this->StartAfter = StartAfter; + this->StopAfter = StopAfter; + Started = (StartAfter == nullptr) && (StartBefore == nullptr); + } + + void setDisableVerify(bool Disable) { setOpt(DisableVerify, Disable); } + + bool getEnableTailMerge() const { return EnableTailMerge; } + void setEnableTailMerge(bool Enable) { setOpt(EnableTailMerge, Enable); } + + /// Allow the target to override a specific pass without overriding the pass + /// pipeline. When passes are added to the standard pipeline at the + /// point where StandardID is expected, add TargetID in its place. + void substitutePass(AnalysisID StandardID, IdentifyingPassPtr TargetID); + + /// Insert InsertedPassID pass after TargetPassID pass. + void insertPass(AnalysisID TargetPassID, IdentifyingPassPtr InsertedPassID, + bool VerifyAfter = true, bool PrintAfter = true); + + /// Allow the target to enable a specific standard pass by default. + void enablePass(AnalysisID PassID) { substitutePass(PassID, PassID); } + + /// Allow the target to disable a specific standard pass by default. + void disablePass(AnalysisID PassID) { + substitutePass(PassID, IdentifyingPassPtr()); + } + + /// Return the pass substituted for StandardID by the target. + /// If no substitution exists, return StandardID. + IdentifyingPassPtr getPassSubstitution(AnalysisID StandardID) const; + + /// Return true if the pass has been substituted by the target or + /// overridden on the command line. + bool isPassSubstitutedOrOverridden(AnalysisID ID) const; + + /// Return true if the optimized regalloc pipeline is enabled. + bool getOptimizeRegAlloc() const; + + /// Return true if shrink wrapping is enabled. + bool getEnableShrinkWrap() const; + + /// Return true if the default global register allocator is in use and + /// has not be overriden on the command line with '-regalloc=...' + bool usingDefaultRegAlloc() const; + + /// Add common target configurable passes that perform LLVM IR to IR + /// transforms following machine independent optimization. + virtual void addIRPasses(); + + /// Add passes to lower exception handling for the code generator. + void addPassesToHandleExceptions(); + + /// Add pass to prepare the LLVM IR for code generation. This should be done + /// before exception handling preparation passes. + virtual void addCodeGenPrepare(); + + /// Add common passes that perform LLVM IR to IR transforms in preparation for + /// instruction selection. + virtual void addISelPrepare(); + + /// addInstSelector - This method should install an instruction selector pass, + /// which converts from LLVM code to machine instructions. + virtual bool addInstSelector() { + return true; + } + + /// This method should install an IR translator pass, which converts from + /// LLVM code to machine instructions with possibly generic opcodes. + virtual bool addIRTranslator() { return true; } + + /// This method may be implemented by targets that want to run passes + /// immediately before the register bank selection. + virtual void addPreRegBankSelect() {} + + /// This method should install a register bank selector pass, which + /// assigns register banks to virtual registers without a register + /// class or register banks. + virtual bool addRegBankSelect() { return true; } + + /// Add the complete, standard set of LLVM CodeGen passes. + /// Fully developed targets will not generally override this. + virtual void addMachinePasses(); + + /// Create an instance of ScheduleDAGInstrs to be run within the standard + /// MachineScheduler pass for this function and target at the current + /// optimization level. + /// + /// This can also be used to plug a new MachineSchedStrategy into an instance + /// of the standard ScheduleDAGMI: + /// return new ScheduleDAGMI(C, make_unique(C), /*RemoveKillFlags=*/false) + /// + /// Return NULL to select the default (generic) machine scheduler. + virtual ScheduleDAGInstrs * + createMachineScheduler(MachineSchedContext *C) const { + return nullptr; + } + + /// Similar to createMachineScheduler but used when postRA machine scheduling + /// is enabled. + virtual ScheduleDAGInstrs * + createPostMachineScheduler(MachineSchedContext *C) const { + return nullptr; + } + + /// printAndVerify - Add a pass to dump then verify the machine function, if + /// those steps are enabled. + /// + void printAndVerify(const std::string &Banner); + + /// Add a pass to print the machine function if printing is enabled. + void addPrintPass(const std::string &Banner); + + /// Add a pass to perform basic verification of the machine function if + /// verification is enabled. + void addVerifyPass(const std::string &Banner); + +protected: + // Helper to verify the analysis is really immutable. + void setOpt(bool &Opt, bool Val); + + /// Methods with trivial inline returns are convenient points in the common + /// codegen pass pipeline where targets may insert passes. Methods with + /// out-of-line standard implementations are major CodeGen stages called by + /// addMachinePasses. Some targets may override major stages when inserting + /// passes is insufficient, but maintaining overriden stages is more work. + /// + + /// addPreISelPasses - This method should add any "last minute" LLVM->LLVM + /// passes (which are run just before instruction selector). + virtual bool addPreISel() { + return true; + } + + /// addMachineSSAOptimization - Add standard passes that optimize machine + /// instructions in SSA form. + virtual void addMachineSSAOptimization(); + + /// Add passes that optimize instruction level parallelism for out-of-order + /// targets. These passes are run while the machine code is still in SSA + /// form, so they can use MachineTraceMetrics to control their heuristics. + /// + /// All passes added here should preserve the MachineDominatorTree, + /// MachineLoopInfo, and MachineTraceMetrics analyses. + virtual bool addILPOpts() { + return false; + } + + /// This method may be implemented by targets that want to run passes + /// immediately before register allocation. + virtual void addPreRegAlloc() { } + + /// createTargetRegisterAllocator - Create the register allocator pass for + /// this target at the current optimization level. + virtual FunctionPass *createTargetRegisterAllocator(bool Optimized); + + /// addFastRegAlloc - Add the minimum set of target-independent passes that + /// are required for fast register allocation. + virtual void addFastRegAlloc(FunctionPass *RegAllocPass); + + /// addOptimizedRegAlloc - Add passes related to register allocation. + /// LLVMTargetMachine provides standard regalloc passes for most targets. + virtual void addOptimizedRegAlloc(FunctionPass *RegAllocPass); + + /// addPreRewrite - Add passes to the optimized register allocation pipeline + /// after register allocation is complete, but before virtual registers are + /// rewritten to physical registers. + /// + /// These passes must preserve VirtRegMap and LiveIntervals, and when running + /// after RABasic or RAGreedy, they should take advantage of LiveRegMatrix. + /// When these passes run, VirtRegMap contains legal physreg assignments for + /// all virtual registers. + virtual bool addPreRewrite() { + return false; + } + + /// This method may be implemented by targets that want to run passes after + /// register allocation pass pipeline but before prolog-epilog insertion. + virtual void addPostRegAlloc() { } + + /// Add passes that optimize machine instructions after register allocation. + virtual void addMachineLateOptimization(); + + /// This method may be implemented by targets that want to run passes after + /// prolog-epilog insertion and before the second instruction scheduling pass. + virtual void addPreSched2() { } + + /// addGCPasses - Add late codegen passes that analyze code for garbage + /// collection. This should return true if GC info should be printed after + /// these passes. + virtual bool addGCPasses(); + + /// Add standard basic block placement passes. + virtual void addBlockPlacement(); + + /// This pass may be implemented by targets that want to run passes + /// immediately before machine code is emitted. + virtual void addPreEmitPass() { } + + /// Utilities for targets to add passes to the pass manager. + /// + + /// Add a CodeGen pass at this point in the pipeline after checking overrides. + /// Return the pass that was added, or zero if no pass was added. + /// @p printAfter if true and adding a machine function pass add an extra + /// machine printer pass afterwards + /// @p verifyAfter if true and adding a machine function pass add an extra + /// machine verification pass afterwards. + AnalysisID addPass(AnalysisID PassID, bool verifyAfter = true, + bool printAfter = true); + + /// Add a pass to the PassManager if that pass is supposed to be run, as + /// determined by the StartAfter and StopAfter options. Takes ownership of the + /// pass. + /// @p printAfter if true and adding a machine function pass add an extra + /// machine printer pass afterwards + /// @p verifyAfter if true and adding a machine function pass add an extra + /// machine verification pass afterwards. + void addPass(Pass *P, bool verifyAfter = true, bool printAfter = true); + + /// addMachinePasses helper to create the target-selected or overriden + /// regalloc pass. + FunctionPass *createRegAllocPass(bool Optimized); +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/CodeGen/UnreachableBlockElim.h b/include/llvm/CodeGen/UnreachableBlockElim.h new file mode 100644 index 0000000000000000000000000000000000000000..3e7afd4cd4337181be1595a2fb85d6322ceb18d2 --- /dev/null +++ b/include/llvm/CodeGen/UnreachableBlockElim.h @@ -0,0 +1,37 @@ +//===-- UnreachableBlockElim.h - Remove unreachable blocks for codegen --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass is an extremely simple version of the SimplifyCFG pass. Its sole +// job is to delete LLVM basic blocks that are not reachable from the entry +// node. To do this, it performs a simple depth first traversal of the CFG, +// then deletes any unvisited nodes. +// +// Note that this pass is really a hack. In particular, the instruction +// selectors for various targets should just not generate code for unreachable +// blocks. Until LLVM has a more systematic way of defining instruction +// selectors, however, we cannot really expect them to handle additional +// complexity. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_UNREACHABLEBLOCKELIM_H +#define LLVM_LIB_CODEGEN_UNREACHABLEBLOCKELIM_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class UnreachableBlockElimPass + : public PassInfoMixin { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; +} // end namespace llvm + +#endif // LLVM_LIB_CODEGEN_UNREACHABLEBLOCKELIM_H diff --git a/include/llvm/CodeGen/ValueTypes.h b/include/llvm/CodeGen/ValueTypes.h index b140036797165c83ba0d4c2b66d98e412765249f..524a90803df898ed448198301e4aca184806f34b 100644 --- a/include/llvm/CodeGen/ValueTypes.h +++ b/include/llvm/CodeGen/ValueTypes.h @@ -384,7 +384,7 @@ namespace llvm { bool isExtended2048BitVector() const LLVM_READONLY; EVT getExtendedVectorElementType() const; unsigned getExtendedVectorNumElements() const LLVM_READONLY; - unsigned getExtendedSizeInBits() const; + unsigned getExtendedSizeInBits() const LLVM_READONLY; }; } // End llvm namespace diff --git a/include/llvm/CodeGen/ValueTypes.td b/include/llvm/CodeGen/ValueTypes.td index c2fb14933734a0b49169bd91ad72393ffd5274bf..f7b1661d7451b5775ce787a4eac95d234ebc463a 100644 --- a/include/llvm/CodeGen/ValueTypes.td +++ b/include/llvm/CodeGen/ValueTypes.td @@ -96,24 +96,24 @@ def x86mmx : ValueType<64 , 64>; // X86 MMX value def FlagVT : ValueType<0 , 65>; // Pre-RA sched glue def isVoid : ValueType<0 , 66>; // Produces no value def untyped: ValueType<8 , 67>; // Produces an untyped value -def token : ValueType<0 , 249>; // TokenTy -def MetadataVT: ValueType<0, 250>; // Metadata +def token : ValueType<0 , 120>; // TokenTy +def MetadataVT: ValueType<0, 121>; // Metadata // Pseudo valuetype mapped to the current pointer size to any address space. // Should only be used in TableGen. -def iPTRAny : ValueType<0, 251>; +def iPTRAny : ValueType<0, 122>; // Pseudo valuetype to represent "vector of any size" -def vAny : ValueType<0 , 252>; +def vAny : ValueType<0 , 123>; // Pseudo valuetype to represent "float of any format" -def fAny : ValueType<0 , 253>; +def fAny : ValueType<0 , 124>; // Pseudo valuetype to represent "integer of any bit width" -def iAny : ValueType<0 , 254>; +def iAny : ValueType<0 , 125>; // Pseudo valuetype mapped to the current pointer size. -def iPTR : ValueType<0 , 255>; +def iPTR : ValueType<0 , 126>; // Pseudo valuetype to represent "any type of any size". -def Any : ValueType<0 , 256>; +def Any : ValueType<0 , 127>; diff --git a/include/llvm/CodeGen/WinEHFuncInfo.h b/include/llvm/CodeGen/WinEHFuncInfo.h index e3e395194960138eea4435853a12a9cfee260ce9..dd730495a5f61e4ff1490442c94be5c1a5969f54 100644 --- a/include/llvm/CodeGen/WinEHFuncInfo.h +++ b/include/llvm/CodeGen/WinEHFuncInfo.h @@ -109,6 +109,7 @@ struct WinEHFuncInfo { int EHRegNodeFrameIndex = INT_MAX; int EHRegNodeEndOffset = INT_MAX; + int EHGuardFrameIndex = INT_MAX; int SEHSetFrameOffset = INT_MAX; WinEHFuncInfo(); diff --git a/include/llvm/Config/config.h.cmake b/include/llvm/Config/config.h.cmake index a9f3d8e737987addbbb307d3fd764e3bcb6c2807..45b30d9171d9ac5cd8269ca0c24424ba1dcb98a1 100644 --- a/include/llvm/Config/config.h.cmake +++ b/include/llvm/Config/config.h.cmake @@ -16,9 +16,6 @@ /* Define if position independent code is enabled */ #cmakedefine ENABLE_PIC -/* Define if timestamp information (e.g., __DATE__) is allowed */ -#cmakedefine ENABLE_TIMESTAMPS ${ENABLE_TIMESTAMPS} - /* Define to 1 if you have the `arc4random' function. */ #cmakedefine HAVE_DECL_ARC4RANDOM ${HAVE_DECL_ARC4RANDOM} @@ -251,6 +248,9 @@ /* Define if you have the shl_load function. */ #undef HAVE_SHL_LOAD +/* Define to 1 if you have the `sigaltstack' function. */ +#cmakedefine HAVE_SIGALTSTACK ${HAVE_SIGALTSTACK} + /* Define to 1 if you have the `siglongjmp' function. */ #cmakedefine HAVE_SIGLONGJMP ${HAVE_SIGLONGJMP} @@ -322,6 +322,9 @@ /* Define if the setupterm() function is supported this platform. */ #cmakedefine HAVE_TERMINFO ${HAVE_TERMINFO} +/* Define if the xar_open() function is supported this platform. */ +#cmakedefine HAVE_LIBXAR ${HAVE_LIBXAR} + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H} @@ -331,6 +334,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H} +/* Define to 1 if you have the `_Unwind_Backtrace' function. */ +#cmakedefine HAVE_UNWIND_BACKTRACE ${HAVE_UNWIND_BACKTRACE} + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UTIME_H ${HAVE_UTIME_H} @@ -499,6 +505,9 @@ /* LLVM version string */ #define LLVM_VERSION_STRING "${PACKAGE_VERSION}" +/* LLVM version information */ +#cmakedefine LLVM_VERSION_INFO "${LLVM_VERSION_INFO}" + /* Define if we link Polly to the tools */ #cmakedefine LINK_POLLY_INTO_TOOLS diff --git a/include/llvm/DebugInfo/CodeView/ByteStream.h b/include/llvm/DebugInfo/CodeView/ByteStream.h new file mode 100644 index 0000000000000000000000000000000000000000..f398c93723e7a7585a2f04f0a93fc8e95c54b3f0 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/ByteStream.h @@ -0,0 +1,58 @@ +//===- ByteStream.h - Reads stream data from a byte sequence ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_BYTESTREAM_H +#define LLVM_DEBUGINFO_CODEVIEW_BYTESTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/Support/Error.h" +#include +#include +#include + +namespace llvm { +namespace codeview { +class StreamReader; + +template class ByteStream : public StreamInterface { + typedef typename std::conditional, + ArrayRef>::type ArrayType; + +public: + ByteStream() {} + explicit ByteStream(ArrayType Data) : Data(Data) {} + ~ByteStream() override {} + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) const override; + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) const override; + + Error writeBytes(uint32_t Offset, ArrayRef Buffer) const override; + + uint32_t getLength() const override; + + Error commit() const override; + + ArrayRef data() const { return Data; } + StringRef str() const; + +private: + ArrayType Data; +}; + +extern template class ByteStream; +extern template class ByteStream; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_BYTESTREAM_H diff --git a/include/llvm/DebugInfo/CodeView/CVLeafTypes.def b/include/llvm/DebugInfo/CodeView/CVLeafTypes.def deleted file mode 100644 index 164a2df3cd0a6fe8d58d9969c972198eed82a058..0000000000000000000000000000000000000000 --- a/include/llvm/DebugInfo/CodeView/CVLeafTypes.def +++ /dev/null @@ -1,211 +0,0 @@ -//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// See LEAF_ENUM_e in cvinfo.h. This should match the constants there. -// -//===----------------------------------------------------------------------===// - -#ifndef LEAF_TYPE -#define LEAF_TYPE(ename, value) -#endif - -// 16 bit type records. -LEAF_TYPE(LF_MODIFIER_16t, 0x0001) -LEAF_TYPE(LF_POINTER_16t, 0x0002) -LEAF_TYPE(LF_ARRAY_16t, 0x0003) -LEAF_TYPE(LF_CLASS_16t, 0x0004) -LEAF_TYPE(LF_STRUCTURE_16t, 0x0005) -LEAF_TYPE(LF_UNION_16t, 0x0006) -LEAF_TYPE(LF_ENUM_16t, 0x0007) -LEAF_TYPE(LF_PROCEDURE_16t, 0x0008) -LEAF_TYPE(LF_MFUNCTION_16t, 0x0009) -LEAF_TYPE(LF_VTSHAPE, 0x000a) -LEAF_TYPE(LF_COBOL0_16t, 0x000b) -LEAF_TYPE(LF_COBOL1, 0x000c) -LEAF_TYPE(LF_BARRAY_16t, 0x000d) -LEAF_TYPE(LF_LABEL, 0x000e) -LEAF_TYPE(LF_NULLLEAF, 0x000f) // LF_NULL -LEAF_TYPE(LF_NOTTRAN, 0x0010) -LEAF_TYPE(LF_DIMARRAY_16t, 0x0011) -LEAF_TYPE(LF_VFTPATH_16t, 0x0012) -LEAF_TYPE(LF_PRECOMP_16t, 0x0013) -LEAF_TYPE(LF_ENDPRECOMP, 0x0014) -LEAF_TYPE(LF_OEM_16t, 0x0015) -LEAF_TYPE(LF_TYPESERVER_ST, 0x0016) - -LEAF_TYPE(LF_SKIP_16t, 0x0200) -LEAF_TYPE(LF_ARGLIST_16t, 0x0201) -LEAF_TYPE(LF_DEFARG_16t, 0x0202) -LEAF_TYPE(LF_LIST, 0x0203) -LEAF_TYPE(LF_FIELDLIST_16t, 0x0204) -LEAF_TYPE(LF_DERIVED_16t, 0x0205) -LEAF_TYPE(LF_BITFIELD_16t, 0x0206) -LEAF_TYPE(LF_METHODLIST_16t, 0x0207) -LEAF_TYPE(LF_DIMCONU_16t, 0x0208) -LEAF_TYPE(LF_DIMCONLU_16t, 0x0209) -LEAF_TYPE(LF_DIMVARU_16t, 0x020a) -LEAF_TYPE(LF_DIMVARLU_16t, 0x020b) -LEAF_TYPE(LF_REFSYM, 0x020c) - -// 16 bit member types. Generally not length prefixed. -LEAF_TYPE(LF_BCLASS_16t, 0x0400) -LEAF_TYPE(LF_VBCLASS_16t, 0x0401) -LEAF_TYPE(LF_IVBCLASS_16t, 0x0402) -LEAF_TYPE(LF_ENUMERATE_ST, 0x0403) -LEAF_TYPE(LF_FRIENDFCN_16t, 0x0404) -LEAF_TYPE(LF_INDEX_16t, 0x0405) -LEAF_TYPE(LF_MEMBER_16t, 0x0406) -LEAF_TYPE(LF_STMEMBER_16t, 0x0407) -LEAF_TYPE(LF_METHOD_16t, 0x0408) -LEAF_TYPE(LF_NESTTYPE_16t, 0x0409) -LEAF_TYPE(LF_VFUNCTAB_16t, 0x040a) -LEAF_TYPE(LF_FRIENDCLS_16t, 0x040b) -LEAF_TYPE(LF_ONEMETHOD_16t, 0x040c) -LEAF_TYPE(LF_VFUNCOFF_16t, 0x040d) - -LEAF_TYPE(LF_TI16_MAX, 0x1000) - -LEAF_TYPE(LF_MODIFIER, 0x1001) -LEAF_TYPE(LF_POINTER, 0x1002) -LEAF_TYPE(LF_ARRAY_ST, 0x1003) -LEAF_TYPE(LF_CLASS_ST, 0x1004) -LEAF_TYPE(LF_STRUCTURE_ST, 0x1005) -LEAF_TYPE(LF_UNION_ST, 0x1006) -LEAF_TYPE(LF_ENUM_ST, 0x1007) -LEAF_TYPE(LF_PROCEDURE, 0x1008) -LEAF_TYPE(LF_MFUNCTION, 0x1009) -LEAF_TYPE(LF_COBOL0, 0x100a) -LEAF_TYPE(LF_BARRAY, 0x100b) -LEAF_TYPE(LF_DIMARRAY_ST, 0x100c) -LEAF_TYPE(LF_VFTPATH, 0x100d) -LEAF_TYPE(LF_PRECOMP_ST, 0x100e) -LEAF_TYPE(LF_OEM, 0x100f) -LEAF_TYPE(LF_ALIAS_ST, 0x1010) -LEAF_TYPE(LF_OEM2, 0x1011) - -LEAF_TYPE(LF_SKIP, 0x1200) -LEAF_TYPE(LF_ARGLIST, 0x1201) -LEAF_TYPE(LF_DEFARG_ST, 0x1202) -LEAF_TYPE(LF_FIELDLIST, 0x1203) -LEAF_TYPE(LF_DERIVED, 0x1204) -LEAF_TYPE(LF_BITFIELD, 0x1205) -LEAF_TYPE(LF_METHODLIST, 0x1206) -LEAF_TYPE(LF_DIMCONU, 0x1207) -LEAF_TYPE(LF_DIMCONLU, 0x1208) -LEAF_TYPE(LF_DIMVARU, 0x1209) -LEAF_TYPE(LF_DIMVARLU, 0x120a) - -// Member type records. These are generally not length prefixed, and appear -// inside of a field list record. -LEAF_TYPE(LF_BCLASS, 0x1400) -LEAF_TYPE(LF_VBCLASS, 0x1401) -LEAF_TYPE(LF_IVBCLASS, 0x1402) -LEAF_TYPE(LF_FRIENDFCN_ST, 0x1403) -LEAF_TYPE(LF_INDEX, 0x1404) -LEAF_TYPE(LF_MEMBER_ST, 0x1405) -LEAF_TYPE(LF_STMEMBER_ST, 0x1406) -LEAF_TYPE(LF_METHOD_ST, 0x1407) -LEAF_TYPE(LF_NESTTYPE_ST, 0x1408) -LEAF_TYPE(LF_VFUNCTAB, 0x1409) -LEAF_TYPE(LF_FRIENDCLS, 0x140a) -LEAF_TYPE(LF_ONEMETHOD_ST, 0x140b) -LEAF_TYPE(LF_VFUNCOFF, 0x140c) -LEAF_TYPE(LF_NESTTYPEEX_ST, 0x140d) -LEAF_TYPE(LF_MEMBERMODIFY_ST, 0x140e) -LEAF_TYPE(LF_MANAGED_ST, 0x140f) - -LEAF_TYPE(LF_ST_MAX, 0x1500) -LEAF_TYPE(LF_TYPESERVER, 0x1501) -LEAF_TYPE(LF_ENUMERATE, 0x1502) -LEAF_TYPE(LF_ARRAY, 0x1503) -LEAF_TYPE(LF_CLASS, 0x1504) -LEAF_TYPE(LF_STRUCTURE, 0x1505) -LEAF_TYPE(LF_UNION, 0x1506) -LEAF_TYPE(LF_ENUM, 0x1507) -LEAF_TYPE(LF_DIMARRAY, 0x1508) -LEAF_TYPE(LF_PRECOMP, 0x1509) -LEAF_TYPE(LF_ALIAS, 0x150a) -LEAF_TYPE(LF_DEFARG, 0x150b) -LEAF_TYPE(LF_FRIENDFCN, 0x150c) -LEAF_TYPE(LF_MEMBER, 0x150d) -LEAF_TYPE(LF_STMEMBER, 0x150e) -LEAF_TYPE(LF_METHOD, 0x150f) -LEAF_TYPE(LF_NESTTYPE, 0x1510) -LEAF_TYPE(LF_ONEMETHOD, 0x1511) -LEAF_TYPE(LF_NESTTYPEEX, 0x1512) -LEAF_TYPE(LF_MEMBERMODIFY, 0x1513) -LEAF_TYPE(LF_MANAGED, 0x1514) -LEAF_TYPE(LF_TYPESERVER2, 0x1515) -LEAF_TYPE(LF_STRIDED_ARRAY, 0x1516) -LEAF_TYPE(LF_HLSL, 0x1517) -LEAF_TYPE(LF_MODIFIER_EX, 0x1518) -LEAF_TYPE(LF_INTERFACE, 0x1519) -LEAF_TYPE(LF_BINTERFACE, 0x151a) -LEAF_TYPE(LF_VECTOR, 0x151b) -LEAF_TYPE(LF_MATRIX, 0x151c) -LEAF_TYPE(LF_VFTABLE, 0x151d) - -// ID leaf records. Subsequent leaf types may be referenced from .debug$S. - -LEAF_TYPE(LF_FUNC_ID, 0x1601) -LEAF_TYPE(LF_MFUNC_ID, 0x1602) -LEAF_TYPE(LF_BUILDINFO, 0x1603) -LEAF_TYPE(LF_SUBSTR_LIST, 0x1604) -LEAF_TYPE(LF_STRING_ID, 0x1605) -LEAF_TYPE(LF_UDT_SRC_LINE, 0x1606) -LEAF_TYPE(LF_UDT_MOD_SRC_LINE, 0x1607) - -// Numeric leaf types. These are generally contained in other records, and not -// encountered in the main type stream. - -LEAF_TYPE(LF_NUMERIC, 0x8000) -LEAF_TYPE(LF_CHAR, 0x8000) -LEAF_TYPE(LF_SHORT, 0x8001) -LEAF_TYPE(LF_USHORT, 0x8002) -LEAF_TYPE(LF_LONG, 0x8003) -LEAF_TYPE(LF_ULONG, 0x8004) -LEAF_TYPE(LF_REAL32, 0x8005) -LEAF_TYPE(LF_REAL64, 0x8006) -LEAF_TYPE(LF_REAL80, 0x8007) -LEAF_TYPE(LF_REAL128, 0x8008) -LEAF_TYPE(LF_QUADWORD, 0x8009) -LEAF_TYPE(LF_UQUADWORD, 0x800a) -LEAF_TYPE(LF_REAL48, 0x800b) -LEAF_TYPE(LF_COMPLEX32, 0x800c) -LEAF_TYPE(LF_COMPLEX64, 0x800d) -LEAF_TYPE(LF_COMPLEX80, 0x800e) -LEAF_TYPE(LF_COMPLEX128, 0x800f) -LEAF_TYPE(LF_VARSTRING, 0x8010) -LEAF_TYPE(LF_OCTWORD, 0x8017) -LEAF_TYPE(LF_UOCTWORD, 0x8018) -LEAF_TYPE(LF_DECIMAL, 0x8019) -LEAF_TYPE(LF_DATE, 0x801a) -LEAF_TYPE(LF_UTF8STRING, 0x801b) -LEAF_TYPE(LF_REAL16, 0x801c) - -// Padding bytes. These are emitted into alignment bytes in the type stream. - -LEAF_TYPE(LF_PAD0, 0xf0) -LEAF_TYPE(LF_PAD1, 0xf1) -LEAF_TYPE(LF_PAD2, 0xf2) -LEAF_TYPE(LF_PAD3, 0xf3) -LEAF_TYPE(LF_PAD4, 0xf4) -LEAF_TYPE(LF_PAD5, 0xf5) -LEAF_TYPE(LF_PAD6, 0xf6) -LEAF_TYPE(LF_PAD7, 0xf7) -LEAF_TYPE(LF_PAD8, 0xf8) -LEAF_TYPE(LF_PAD9, 0xf9) -LEAF_TYPE(LF_PAD10, 0xfa) -LEAF_TYPE(LF_PAD11, 0xfb) -LEAF_TYPE(LF_PAD12, 0xfc) -LEAF_TYPE(LF_PAD13, 0xfd) -LEAF_TYPE(LF_PAD14, 0xfe) -LEAF_TYPE(LF_PAD15, 0xff) - -#undef LEAF_TYPE diff --git a/include/llvm/DebugInfo/CodeView/CVRecord.h b/include/llvm/DebugInfo/CodeView/CVRecord.h new file mode 100644 index 0000000000000000000000000000000000000000..dba359fcbe82e2e61d045ded4b6f08b8b1939363 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -0,0 +1,56 @@ +//===- RecordIterator.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H +#define LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace codeview { + +template struct CVRecord { + uint32_t Length; + Kind Type; + ArrayRef Data; + ArrayRef RawData; +}; + +template struct VarStreamArrayExtractor> { + Error operator()(StreamRef Stream, uint32_t &Len, + CVRecord &Item) const { + const RecordPrefix *Prefix = nullptr; + StreamReader Reader(Stream); + uint32_t Offset = Reader.getOffset(); + + if (auto EC = Reader.readObject(Prefix)) + return EC; + Item.Length = Prefix->RecordLen; + if (Item.Length < 2) + return make_error(cv_error_code::corrupt_record); + Item.Type = static_cast(uint16_t(Prefix->RecordKind)); + + Reader.setOffset(Offset); + if (auto EC = + Reader.readBytes(Item.RawData, Item.Length + sizeof(uint16_t))) + return EC; + Item.Data = Item.RawData.slice(sizeof(RecordPrefix)); + Len = Prefix->RecordLen + 2; + return Error::success(); + } +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/CodeView/CVSymbolTypes.def b/include/llvm/DebugInfo/CodeView/CVSymbolTypes.def index 3807938ef214472ff4c1ce0711c231c465dd8856..32813d861d909a86bf8afe403eb11fa387ffd3ae 100644 --- a/include/llvm/DebugInfo/CodeView/CVSymbolTypes.def +++ b/include/llvm/DebugInfo/CodeView/CVSymbolTypes.def @@ -11,227 +11,248 @@ // //===----------------------------------------------------------------------===// -#ifndef SYMBOL_TYPE -#define SYMBOL_TYPE(ename, value) +#ifndef CV_SYMBOL +#define CV_SYMBOL(ename, value) +#endif + +#ifndef SYMBOL_RECORD +#define SYMBOL_RECORD(lf_ename, value, name) CV_SYMBOL(lf_ename, value) +#endif + +#ifndef SYMBOL_RECORD_ALIAS +#define SYMBOL_RECORD_ALIAS(lf_ename, value, name, alias_name) \ + SYMBOL_RECORD(lf_ename, value, name) #endif // 16 bit symbol types. Not very useful, provided only for reference. -SYMBOL_TYPE(S_COMPILE , 0x0001) -SYMBOL_TYPE(S_REGISTER_16t , 0x0002) -SYMBOL_TYPE(S_CONSTANT_16t , 0x0003) -SYMBOL_TYPE(S_UDT_16t , 0x0004) -SYMBOL_TYPE(S_SSEARCH , 0x0005) -SYMBOL_TYPE(S_END , 0x0006) -SYMBOL_TYPE(S_SKIP , 0x0007) -SYMBOL_TYPE(S_CVRESERVE , 0x0008) -SYMBOL_TYPE(S_OBJNAME_ST , 0x0009) -SYMBOL_TYPE(S_ENDARG , 0x000a) -SYMBOL_TYPE(S_COBOLUDT_16t , 0x000b) -SYMBOL_TYPE(S_MANYREG_16t , 0x000c) -SYMBOL_TYPE(S_RETURN , 0x000d) -SYMBOL_TYPE(S_ENTRYTHIS , 0x000e) -SYMBOL_TYPE(S_BPREL16 , 0x0100) -SYMBOL_TYPE(S_LDATA16 , 0x0101) -SYMBOL_TYPE(S_GDATA16 , 0x0102) -SYMBOL_TYPE(S_PUB16 , 0x0103) -SYMBOL_TYPE(S_LPROC16 , 0x0104) -SYMBOL_TYPE(S_GPROC16 , 0x0105) -SYMBOL_TYPE(S_THUNK16 , 0x0106) -SYMBOL_TYPE(S_BLOCK16 , 0x0107) -SYMBOL_TYPE(S_WITH16 , 0x0108) -SYMBOL_TYPE(S_LABEL16 , 0x0109) -SYMBOL_TYPE(S_CEXMODEL16 , 0x010a) -SYMBOL_TYPE(S_VFTABLE16 , 0x010b) -SYMBOL_TYPE(S_REGREL16 , 0x010c) -SYMBOL_TYPE(S_BPREL32_16t , 0x0200) -SYMBOL_TYPE(S_LDATA32_16t , 0x0201) -SYMBOL_TYPE(S_GDATA32_16t , 0x0202) -SYMBOL_TYPE(S_PUB32_16t , 0x0203) -SYMBOL_TYPE(S_LPROC32_16t , 0x0204) -SYMBOL_TYPE(S_GPROC32_16t , 0x0205) -SYMBOL_TYPE(S_THUNK32_ST , 0x0206) -SYMBOL_TYPE(S_BLOCK32_ST , 0x0207) -SYMBOL_TYPE(S_WITH32_ST , 0x0208) -SYMBOL_TYPE(S_LABEL32_ST , 0x0209) -SYMBOL_TYPE(S_CEXMODEL32 , 0x020a) -SYMBOL_TYPE(S_VFTABLE32_16t , 0x020b) -SYMBOL_TYPE(S_REGREL32_16t , 0x020c) -SYMBOL_TYPE(S_LTHREAD32_16t , 0x020d) -SYMBOL_TYPE(S_GTHREAD32_16t , 0x020e) -SYMBOL_TYPE(S_SLINK32 , 0x020f) -SYMBOL_TYPE(S_LPROCMIPS_16t , 0x0300) -SYMBOL_TYPE(S_GPROCMIPS_16t , 0x0301) -SYMBOL_TYPE(S_PROCREF_ST , 0x0400) -SYMBOL_TYPE(S_DATAREF_ST , 0x0401) -SYMBOL_TYPE(S_ALIGN , 0x0402) -SYMBOL_TYPE(S_LPROCREF_ST , 0x0403) -SYMBOL_TYPE(S_OEM , 0x0404) +CV_SYMBOL(S_COMPILE , 0x0001) +CV_SYMBOL(S_REGISTER_16t , 0x0002) +CV_SYMBOL(S_CONSTANT_16t , 0x0003) +CV_SYMBOL(S_UDT_16t , 0x0004) +CV_SYMBOL(S_SSEARCH , 0x0005) +CV_SYMBOL(S_SKIP , 0x0007) +CV_SYMBOL(S_CVRESERVE , 0x0008) +CV_SYMBOL(S_OBJNAME_ST , 0x0009) +CV_SYMBOL(S_ENDARG , 0x000a) +CV_SYMBOL(S_COBOLUDT_16t , 0x000b) +CV_SYMBOL(S_MANYREG_16t , 0x000c) +CV_SYMBOL(S_RETURN , 0x000d) +CV_SYMBOL(S_ENTRYTHIS , 0x000e) +CV_SYMBOL(S_BPREL16 , 0x0100) +CV_SYMBOL(S_LDATA16 , 0x0101) +CV_SYMBOL(S_GDATA16 , 0x0102) +CV_SYMBOL(S_PUB16 , 0x0103) +CV_SYMBOL(S_LPROC16 , 0x0104) +CV_SYMBOL(S_GPROC16 , 0x0105) +CV_SYMBOL(S_THUNK16 , 0x0106) +CV_SYMBOL(S_BLOCK16 , 0x0107) +CV_SYMBOL(S_WITH16 , 0x0108) +CV_SYMBOL(S_LABEL16 , 0x0109) +CV_SYMBOL(S_CEXMODEL16 , 0x010a) +CV_SYMBOL(S_VFTABLE16 , 0x010b) +CV_SYMBOL(S_REGREL16 , 0x010c) +CV_SYMBOL(S_BPREL32_16t , 0x0200) +CV_SYMBOL(S_LDATA32_16t , 0x0201) +CV_SYMBOL(S_GDATA32_16t , 0x0202) +CV_SYMBOL(S_PUB32_16t , 0x0203) +CV_SYMBOL(S_LPROC32_16t , 0x0204) +CV_SYMBOL(S_GPROC32_16t , 0x0205) +CV_SYMBOL(S_THUNK32_ST , 0x0206) +CV_SYMBOL(S_BLOCK32_ST , 0x0207) +CV_SYMBOL(S_WITH32_ST , 0x0208) +CV_SYMBOL(S_LABEL32_ST , 0x0209) +CV_SYMBOL(S_CEXMODEL32 , 0x020a) +CV_SYMBOL(S_VFTABLE32_16t , 0x020b) +CV_SYMBOL(S_REGREL32_16t , 0x020c) +CV_SYMBOL(S_LTHREAD32_16t , 0x020d) +CV_SYMBOL(S_GTHREAD32_16t , 0x020e) +CV_SYMBOL(S_SLINK32 , 0x020f) +CV_SYMBOL(S_LPROCMIPS_16t , 0x0300) +CV_SYMBOL(S_GPROCMIPS_16t , 0x0301) +CV_SYMBOL(S_PROCREF_ST , 0x0400) +CV_SYMBOL(S_DATAREF_ST , 0x0401) +CV_SYMBOL(S_ALIGN , 0x0402) +CV_SYMBOL(S_LPROCREF_ST , 0x0403) +CV_SYMBOL(S_OEM , 0x0404) // All post 16 bit symbol types have the 0x1000 bit set. -SYMBOL_TYPE(S_TI16_MAX , 0x1000) +CV_SYMBOL(S_TI16_MAX , 0x1000) // Mostly unused "start" symbol types. -SYMBOL_TYPE(S_REGISTER_ST , 0x1001) -SYMBOL_TYPE(S_CONSTANT_ST , 0x1002) -SYMBOL_TYPE(S_UDT_ST , 0x1003) -SYMBOL_TYPE(S_COBOLUDT_ST , 0x1004) -SYMBOL_TYPE(S_MANYREG_ST , 0x1005) -SYMBOL_TYPE(S_BPREL32_ST , 0x1006) -SYMBOL_TYPE(S_LDATA32_ST , 0x1007) -SYMBOL_TYPE(S_GDATA32_ST , 0x1008) -SYMBOL_TYPE(S_PUB32_ST , 0x1009) -SYMBOL_TYPE(S_LPROC32_ST , 0x100a) -SYMBOL_TYPE(S_GPROC32_ST , 0x100b) -SYMBOL_TYPE(S_VFTABLE32 , 0x100c) -SYMBOL_TYPE(S_REGREL32_ST , 0x100d) -SYMBOL_TYPE(S_LTHREAD32_ST , 0x100e) -SYMBOL_TYPE(S_GTHREAD32_ST , 0x100f) -SYMBOL_TYPE(S_LPROCMIPS_ST , 0x1010) -SYMBOL_TYPE(S_GPROCMIPS_ST , 0x1011) - -// Information about the frame layout of a procedure. -SYMBOL_TYPE(S_FRAMEPROC , 0x1012) - -SYMBOL_TYPE(S_COMPILE2_ST , 0x1013) -SYMBOL_TYPE(S_MANYREG2_ST , 0x1014) -SYMBOL_TYPE(S_LPROCIA64_ST , 0x1015) -SYMBOL_TYPE(S_GPROCIA64_ST , 0x1016) -SYMBOL_TYPE(S_LOCALSLOT_ST , 0x1017) -SYMBOL_TYPE(S_PARAMSLOT_ST , 0x1018) -SYMBOL_TYPE(S_ANNOTATION , 0x1019) -SYMBOL_TYPE(S_GMANPROC_ST , 0x101a) -SYMBOL_TYPE(S_LMANPROC_ST , 0x101b) -SYMBOL_TYPE(S_RESERVED1 , 0x101c) -SYMBOL_TYPE(S_RESERVED2 , 0x101d) -SYMBOL_TYPE(S_RESERVED3 , 0x101e) -SYMBOL_TYPE(S_RESERVED4 , 0x101f) -SYMBOL_TYPE(S_LMANDATA_ST , 0x1020) -SYMBOL_TYPE(S_GMANDATA_ST , 0x1021) -SYMBOL_TYPE(S_MANFRAMEREL_ST, 0x1022) -SYMBOL_TYPE(S_MANREGISTER_ST, 0x1023) -SYMBOL_TYPE(S_MANSLOT_ST , 0x1024) -SYMBOL_TYPE(S_MANMANYREG_ST , 0x1025) -SYMBOL_TYPE(S_MANREGREL_ST , 0x1026) -SYMBOL_TYPE(S_MANMANYREG2_ST, 0x1027) -SYMBOL_TYPE(S_MANTYPREF , 0x1028) -SYMBOL_TYPE(S_UNAMESPACE_ST , 0x1029) +CV_SYMBOL(S_REGISTER_ST , 0x1001) +CV_SYMBOL(S_CONSTANT_ST , 0x1002) +CV_SYMBOL(S_UDT_ST , 0x1003) +CV_SYMBOL(S_COBOLUDT_ST , 0x1004) +CV_SYMBOL(S_MANYREG_ST , 0x1005) +CV_SYMBOL(S_BPREL32_ST , 0x1006) +CV_SYMBOL(S_LDATA32_ST , 0x1007) +CV_SYMBOL(S_GDATA32_ST , 0x1008) +CV_SYMBOL(S_PUB32_ST , 0x1009) +CV_SYMBOL(S_LPROC32_ST , 0x100a) +CV_SYMBOL(S_GPROC32_ST , 0x100b) +CV_SYMBOL(S_VFTABLE32 , 0x100c) +CV_SYMBOL(S_REGREL32_ST , 0x100d) +CV_SYMBOL(S_LTHREAD32_ST , 0x100e) +CV_SYMBOL(S_GTHREAD32_ST , 0x100f) +CV_SYMBOL(S_LPROCMIPS_ST , 0x1010) +CV_SYMBOL(S_GPROCMIPS_ST , 0x1011) + +CV_SYMBOL(S_COMPILE2_ST , 0x1013) +CV_SYMBOL(S_MANYREG2_ST , 0x1014) +CV_SYMBOL(S_LPROCIA64_ST , 0x1015) +CV_SYMBOL(S_GPROCIA64_ST , 0x1016) +CV_SYMBOL(S_LOCALSLOT_ST , 0x1017) +CV_SYMBOL(S_PARAMSLOT_ST , 0x1018) +CV_SYMBOL(S_ANNOTATION , 0x1019) +CV_SYMBOL(S_GMANPROC_ST , 0x101a) +CV_SYMBOL(S_LMANPROC_ST , 0x101b) +CV_SYMBOL(S_RESERVED1 , 0x101c) +CV_SYMBOL(S_RESERVED2 , 0x101d) +CV_SYMBOL(S_RESERVED3 , 0x101e) +CV_SYMBOL(S_RESERVED4 , 0x101f) +CV_SYMBOL(S_LMANDATA_ST , 0x1020) +CV_SYMBOL(S_GMANDATA_ST , 0x1021) +CV_SYMBOL(S_MANFRAMEREL_ST, 0x1022) +CV_SYMBOL(S_MANREGISTER_ST, 0x1023) +CV_SYMBOL(S_MANSLOT_ST , 0x1024) +CV_SYMBOL(S_MANMANYREG_ST , 0x1025) +CV_SYMBOL(S_MANREGREL_ST , 0x1026) +CV_SYMBOL(S_MANMANYREG2_ST, 0x1027) +CV_SYMBOL(S_MANTYPREF , 0x1028) +CV_SYMBOL(S_UNAMESPACE_ST , 0x1029) // End of S_*_ST symbols, which do not appear to be generated by modern // compilers. -SYMBOL_TYPE(S_ST_MAX , 0x1100) - -SYMBOL_TYPE(S_OBJNAME , 0x1101) -SYMBOL_TYPE(S_THUNK32 , 0x1102) -SYMBOL_TYPE(S_BLOCK32 , 0x1103) -SYMBOL_TYPE(S_WITH32 , 0x1104) -SYMBOL_TYPE(S_LABEL32 , 0x1105) -SYMBOL_TYPE(S_REGISTER , 0x1106) -SYMBOL_TYPE(S_CONSTANT , 0x1107) -SYMBOL_TYPE(S_UDT , 0x1108) -SYMBOL_TYPE(S_COBOLUDT , 0x1109) -SYMBOL_TYPE(S_MANYREG , 0x110a) -SYMBOL_TYPE(S_BPREL32 , 0x110b) -SYMBOL_TYPE(S_LDATA32 , 0x110c) -SYMBOL_TYPE(S_GDATA32 , 0x110d) -SYMBOL_TYPE(S_PUB32 , 0x110e) -SYMBOL_TYPE(S_LPROC32 , 0x110f) -SYMBOL_TYPE(S_GPROC32 , 0x1110) -SYMBOL_TYPE(S_REGREL32 , 0x1111) -SYMBOL_TYPE(S_LTHREAD32 , 0x1112) -SYMBOL_TYPE(S_GTHREAD32 , 0x1113) -SYMBOL_TYPE(S_LPROCMIPS , 0x1114) -SYMBOL_TYPE(S_GPROCMIPS , 0x1115) -SYMBOL_TYPE(S_COMPILE2 , 0x1116) -SYMBOL_TYPE(S_MANYREG2 , 0x1117) -SYMBOL_TYPE(S_LPROCIA64 , 0x1118) -SYMBOL_TYPE(S_GPROCIA64 , 0x1119) -SYMBOL_TYPE(S_LOCALSLOT , 0x111a) -SYMBOL_TYPE(S_PARAMSLOT , 0x111b) +CV_SYMBOL(S_ST_MAX , 0x1100) + + +CV_SYMBOL(S_WITH32 , 0x1104) +CV_SYMBOL(S_MANYREG , 0x110a) +CV_SYMBOL(S_LPROCMIPS , 0x1114) +CV_SYMBOL(S_GPROCMIPS , 0x1115) +CV_SYMBOL(S_MANYREG2 , 0x1117) +CV_SYMBOL(S_LPROCIA64 , 0x1118) +CV_SYMBOL(S_GPROCIA64 , 0x1119) +CV_SYMBOL(S_LOCALSLOT , 0x111a) +CV_SYMBOL(S_PARAMSLOT , 0x111b) // Managed code symbols. -SYMBOL_TYPE(S_LMANDATA , 0x111c) -SYMBOL_TYPE(S_GMANDATA , 0x111d) -SYMBOL_TYPE(S_MANFRAMEREL , 0x111e) -SYMBOL_TYPE(S_MANREGISTER , 0x111f) -SYMBOL_TYPE(S_MANSLOT , 0x1120) -SYMBOL_TYPE(S_MANMANYREG , 0x1121) -SYMBOL_TYPE(S_MANREGREL , 0x1122) -SYMBOL_TYPE(S_MANMANYREG2 , 0x1123) -SYMBOL_TYPE(S_UNAMESPACE , 0x1124) -SYMBOL_TYPE(S_PROCREF , 0x1125) -SYMBOL_TYPE(S_DATAREF , 0x1126) -SYMBOL_TYPE(S_LPROCREF , 0x1127) -SYMBOL_TYPE(S_ANNOTATIONREF , 0x1128) -SYMBOL_TYPE(S_TOKENREF , 0x1129) -SYMBOL_TYPE(S_GMANPROC , 0x112a) -SYMBOL_TYPE(S_LMANPROC , 0x112b) -SYMBOL_TYPE(S_TRAMPOLINE , 0x112c) -SYMBOL_TYPE(S_MANCONSTANT , 0x112d) -SYMBOL_TYPE(S_ATTR_FRAMEREL , 0x112e) -SYMBOL_TYPE(S_ATTR_REGISTER , 0x112f) -SYMBOL_TYPE(S_ATTR_REGREL , 0x1130) -SYMBOL_TYPE(S_ATTR_MANYREG , 0x1131) - - -SYMBOL_TYPE(S_SEPCODE , 0x1132) -SYMBOL_TYPE(S_LOCAL_2005 , 0x1133) -SYMBOL_TYPE(S_DEFRANGE_2005 , 0x1134) -SYMBOL_TYPE(S_DEFRANGE2_2005, 0x1135) -SYMBOL_TYPE(S_SECTION , 0x1136) -SYMBOL_TYPE(S_COFFGROUP , 0x1137) -SYMBOL_TYPE(S_EXPORT , 0x1138) -SYMBOL_TYPE(S_CALLSITEINFO , 0x1139) -SYMBOL_TYPE(S_FRAMECOOKIE , 0x113a) -SYMBOL_TYPE(S_DISCARDED , 0x113b) -SYMBOL_TYPE(S_COMPILE3 , 0x113c) -SYMBOL_TYPE(S_ENVBLOCK , 0x113d) -SYMBOL_TYPE(S_LOCAL , 0x113e) -SYMBOL_TYPE(S_DEFRANGE , 0x113f) -SYMBOL_TYPE(S_DEFRANGE_SUBFIELD, 0x1140) -SYMBOL_TYPE(S_DEFRANGE_REGISTER, 0x1141) -SYMBOL_TYPE(S_DEFRANGE_FRAMEPOINTER_REL, 0x1142) -SYMBOL_TYPE(S_DEFRANGE_SUBFIELD_REGISTER, 0x1143) -SYMBOL_TYPE(S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE, 0x1144) -SYMBOL_TYPE(S_DEFRANGE_REGISTER_REL, 0x1145) +CV_SYMBOL(S_MANFRAMEREL , 0x111e) +CV_SYMBOL(S_MANREGISTER , 0x111f) +CV_SYMBOL(S_MANSLOT , 0x1120) +CV_SYMBOL(S_MANMANYREG , 0x1121) +CV_SYMBOL(S_MANREGREL , 0x1122) +CV_SYMBOL(S_MANMANYREG2 , 0x1123) +CV_SYMBOL(S_UNAMESPACE , 0x1124) +CV_SYMBOL(S_DATAREF , 0x1126) +CV_SYMBOL(S_ANNOTATIONREF , 0x1128) +CV_SYMBOL(S_TOKENREF , 0x1129) +CV_SYMBOL(S_GMANPROC , 0x112a) +CV_SYMBOL(S_LMANPROC , 0x112b) +CV_SYMBOL(S_ATTR_FRAMEREL , 0x112e) +CV_SYMBOL(S_ATTR_REGISTER , 0x112f) +CV_SYMBOL(S_ATTR_REGREL , 0x1130) +CV_SYMBOL(S_ATTR_MANYREG , 0x1131) + + +CV_SYMBOL(S_SEPCODE , 0x1132) +CV_SYMBOL(S_LOCAL_2005 , 0x1133) +CV_SYMBOL(S_DEFRANGE_2005 , 0x1134) +CV_SYMBOL(S_DEFRANGE2_2005, 0x1135) +CV_SYMBOL(S_DISCARDED , 0x113b) // Current symbol types for most procedures as of this writing. -SYMBOL_TYPE(S_LPROC32_ID , 0x1146) -SYMBOL_TYPE(S_GPROC32_ID , 0x1147) -SYMBOL_TYPE(S_LPROCMIPS_ID , 0x1148) -SYMBOL_TYPE(S_GPROCMIPS_ID , 0x1149) -SYMBOL_TYPE(S_LPROCIA64_ID , 0x114a) -SYMBOL_TYPE(S_GPROCIA64_ID , 0x114b) - -SYMBOL_TYPE(S_BUILDINFO , 0x114c) - -// Inlined call site delimiters. -SYMBOL_TYPE(S_INLINESITE , 0x114d) -SYMBOL_TYPE(S_INLINESITE_END , 0x114e) - -// Procedure info end delimiter. -SYMBOL_TYPE(S_PROC_ID_END , 0x114f) - -SYMBOL_TYPE(S_DEFRANGE_HLSL , 0x1150) -SYMBOL_TYPE(S_GDATA_HLSL , 0x1151) -SYMBOL_TYPE(S_LDATA_HLSL , 0x1152) -SYMBOL_TYPE(S_FILESTATIC , 0x1153) -SYMBOL_TYPE(S_LOCAL_DPC_GROUPSHARED, 0x1154) -SYMBOL_TYPE(S_LPROC32_DPC , 0x1155) -SYMBOL_TYPE(S_LPROC32_DPC_ID , 0x1156) -SYMBOL_TYPE(S_DEFRANGE_DPC_PTR_TAG, 0x1157) -SYMBOL_TYPE(S_DPC_SYM_TAG_MAP, 0x1158) -SYMBOL_TYPE(S_ARMSWITCHTABLE , 0x1159) -SYMBOL_TYPE(S_CALLEES , 0x115a) -SYMBOL_TYPE(S_CALLERS , 0x115b) -SYMBOL_TYPE(S_POGODATA , 0x115c) -SYMBOL_TYPE(S_INLINESITE2 , 0x115d) -SYMBOL_TYPE(S_HEAPALLOCSITE , 0x115e) -SYMBOL_TYPE(S_MOD_TYPEREF , 0x115f) -SYMBOL_TYPE(S_REF_MINIPDB , 0x1160) -SYMBOL_TYPE(S_PDBMAP , 0x1161) -SYMBOL_TYPE(S_GDATA_HLSL32 , 0x1162) -SYMBOL_TYPE(S_LDATA_HLSL32 , 0x1163) -SYMBOL_TYPE(S_GDATA_HLSL32_EX, 0x1164) -SYMBOL_TYPE(S_LDATA_HLSL32_EX, 0x1165) - -#undef SYMBOL_TYPE +CV_SYMBOL(S_LPROCMIPS_ID , 0x1148) +CV_SYMBOL(S_GPROCMIPS_ID , 0x1149) +CV_SYMBOL(S_LPROCIA64_ID , 0x114a) +CV_SYMBOL(S_GPROCIA64_ID , 0x114b) + +CV_SYMBOL(S_DEFRANGE_HLSL , 0x1150) +CV_SYMBOL(S_GDATA_HLSL , 0x1151) +CV_SYMBOL(S_LDATA_HLSL , 0x1152) +CV_SYMBOL(S_LOCAL_DPC_GROUPSHARED, 0x1154) +CV_SYMBOL(S_DEFRANGE_DPC_PTR_TAG, 0x1157) +CV_SYMBOL(S_DPC_SYM_TAG_MAP, 0x1158) +CV_SYMBOL(S_ARMSWITCHTABLE , 0x1159) +CV_SYMBOL(S_POGODATA , 0x115c) +CV_SYMBOL(S_INLINESITE2 , 0x115d) +CV_SYMBOL(S_MOD_TYPEREF , 0x115f) +CV_SYMBOL(S_REF_MINIPDB , 0x1160) +CV_SYMBOL(S_PDBMAP , 0x1161) +CV_SYMBOL(S_GDATA_HLSL32 , 0x1162) +CV_SYMBOL(S_LDATA_HLSL32 , 0x1163) +CV_SYMBOL(S_GDATA_HLSL32_EX, 0x1164) +CV_SYMBOL(S_LDATA_HLSL32_EX, 0x1165) + +// Known symbol types +SYMBOL_RECORD(S_END , 0x0006, ScopeEndSym) +SYMBOL_RECORD_ALIAS(S_INLINESITE_END , 0x114e, InlineSiteEnd, ScopeEndSym) +SYMBOL_RECORD_ALIAS(S_PROC_ID_END , 0x114f, ProcEnd, ScopeEndSym) + +SYMBOL_RECORD(S_THUNK32 , 0x1102, Thunk32Sym) +SYMBOL_RECORD(S_TRAMPOLINE , 0x112c, TrampolineSym) +SYMBOL_RECORD(S_SECTION , 0x1136, SectionSym) +SYMBOL_RECORD(S_COFFGROUP , 0x1137, CoffGroupSym) +SYMBOL_RECORD(S_EXPORT , 0x1138, ExportSym) + +SYMBOL_RECORD(S_LPROC32 , 0x110f, ProcSym) +SYMBOL_RECORD_ALIAS(S_GPROC32 , 0x1110, GlobalProcSym, ProcSym) +SYMBOL_RECORD_ALIAS(S_LPROC32_ID , 0x1146, ProcIdSym, ProcSym) +SYMBOL_RECORD_ALIAS(S_GPROC32_ID , 0x1147, GlobalProcIdSym, ProcSym) +SYMBOL_RECORD_ALIAS(S_LPROC32_DPC , 0x1155, DPCProcSym, ProcSym) +SYMBOL_RECORD_ALIAS(S_LPROC32_DPC_ID , 0x1156, DPCProcIdSym, ProcSym) + +SYMBOL_RECORD(S_REGISTER , 0x1106, RegisterSym) +SYMBOL_RECORD(S_PUB32 , 0x110e, PublicSym32) + +SYMBOL_RECORD(S_PROCREF , 0x1125, ProcRefSym) +SYMBOL_RECORD_ALIAS(S_LPROCREF, 0x1127, LocalProcRef, ProcRefSym) + + +SYMBOL_RECORD(S_ENVBLOCK , 0x113d, EnvBlockSym) + +SYMBOL_RECORD(S_INLINESITE , 0x114d, InlineSiteSym) +SYMBOL_RECORD(S_LOCAL , 0x113e, LocalSym) +SYMBOL_RECORD(S_DEFRANGE , 0x113f, DefRangeSym) +SYMBOL_RECORD(S_DEFRANGE_SUBFIELD, 0x1140, DefRangeSubfieldSym) +SYMBOL_RECORD(S_DEFRANGE_REGISTER, 0x1141, DefRangeRegisterSym) +SYMBOL_RECORD(S_DEFRANGE_FRAMEPOINTER_REL, 0x1142, DefRangeFramePointerRelSym) +SYMBOL_RECORD(S_DEFRANGE_SUBFIELD_REGISTER, 0x1143, DefRangeSubfieldRegisterSym) +SYMBOL_RECORD(S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE, 0x1144, DefRangeFramePointerRelFullScopeSym) +SYMBOL_RECORD(S_DEFRANGE_REGISTER_REL, 0x1145, DefRangeRegisterRelSym) +SYMBOL_RECORD(S_BLOCK32 , 0x1103, BlockSym) +SYMBOL_RECORD(S_LABEL32 , 0x1105, LabelSym) +SYMBOL_RECORD(S_OBJNAME , 0x1101, ObjNameSym) +SYMBOL_RECORD(S_COMPILE2 , 0x1116, Compile2Sym) +SYMBOL_RECORD(S_COMPILE3 , 0x113c, Compile3Sym) +SYMBOL_RECORD(S_FRAMEPROC , 0x1012, FrameProcSym) +SYMBOL_RECORD(S_CALLSITEINFO , 0x1139, CallSiteInfoSym) +SYMBOL_RECORD(S_FILESTATIC , 0x1153, FileStaticSym) +SYMBOL_RECORD(S_HEAPALLOCSITE , 0x115e, HeapAllocationSiteSym) +SYMBOL_RECORD(S_FRAMECOOKIE , 0x113a, FrameCookieSym) + +SYMBOL_RECORD(S_CALLEES , 0x115a, CallerSym) +SYMBOL_RECORD_ALIAS(S_CALLERS , 0x115b, CalleeSym, CallerSym) + +SYMBOL_RECORD(S_UDT , 0x1108, UDTSym) +SYMBOL_RECORD_ALIAS(S_COBOLUDT , 0x1109, CobolUDT, UDTSym) + +SYMBOL_RECORD(S_BUILDINFO , 0x114c, BuildInfoSym) +SYMBOL_RECORD(S_BPREL32 , 0x110b, BPRelativeSym) +SYMBOL_RECORD(S_REGREL32 , 0x1111, RegRelativeSym) + +SYMBOL_RECORD(S_CONSTANT , 0x1107, ConstantSym) +SYMBOL_RECORD_ALIAS(S_MANCONSTANT , 0x112d, ManagedConstant, ConstantSym) + +SYMBOL_RECORD(S_LDATA32 , 0x110c, DataSym) +SYMBOL_RECORD_ALIAS(S_GDATA32 , 0x110d, GlobalData, DataSym) +SYMBOL_RECORD_ALIAS(S_LMANDATA , 0x111c, ManagedLocalData, DataSym) +SYMBOL_RECORD_ALIAS(S_GMANDATA , 0x111d, ManagedGlobalData, DataSym) + +SYMBOL_RECORD(S_LTHREAD32 , 0x1112, ThreadLocalDataSym) +SYMBOL_RECORD_ALIAS(S_GTHREAD32 , 0x1113, GlobalTLS, ThreadLocalDataSym) + + +#undef CV_SYMBOL +#undef SYMBOL_RECORD +#undef SYMBOL_RECORD_ALIAS diff --git a/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h b/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..7c88956c984ed95314f721dda025a3a43309e6c2 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h @@ -0,0 +1,103 @@ +//===- CVSymbolVisitor.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H +#define LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H + +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h" +#include "llvm/Support/ErrorOr.h" + +namespace llvm { +namespace codeview { + +template class CVSymbolVisitor { +public: + CVSymbolVisitor(SymbolVisitorDelegate *Delegate) : Delegate(Delegate) {} + + bool hadError() const { return HadError; } + + template + bool consumeObject(ArrayRef &Data, const T *&Res) { + if (Data.size() < sizeof(*Res)) { + HadError = true; + return false; + } + Res = reinterpret_cast(Data.data()); + Data = Data.drop_front(sizeof(*Res)); + return true; + } + +/// Actions to take on known symbols. By default, they do nothing. Visit methods +/// for member records take the FieldData by non-const reference and are +/// expected to consume the trailing bytes used by the field. +/// FIXME: Make the visitor interpret the trailing bytes so that clients don't +/// need to. +#define SYMBOL_RECORD(EnumName, EnumVal, Name) \ + void visit##Name(SymbolRecordKind Kind, Name &Record) {} +#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "CVSymbolTypes.def" + + void visitSymbolRecord(const CVRecord &Record) { + ArrayRef Data = Record.Data; + auto *DerivedThis = static_cast(this); + DerivedThis->visitSymbolBegin(Record.Type, Data); + uint32_t RecordOffset = Delegate ? Delegate->getRecordOffset(Data) : 0; + switch (Record.Type) { + default: + DerivedThis->visitUnknownSymbol(Record.Type, Data); + break; +#define SYMBOL_RECORD(EnumName, EnumVal, Name) \ + case EnumName: { \ + SymbolRecordKind RK = static_cast(EnumName); \ + auto Result = Name::deserialize(RK, RecordOffset, Data); \ + if (Result.getError()) \ + return parseError(); \ + DerivedThis->visit##Name(Record.Type, *Result); \ + break; \ + } +#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ + SYMBOL_RECORD(EnumVal, EnumVal, AliasName) +#include "CVSymbolTypes.def" + } + DerivedThis->visitSymbolEnd(Record.Type, Record.Data); + } + + /// Visits the symbol records in Data. Sets the error flag on parse failures. + void visitSymbolStream(const CVSymbolArray &Symbols) { + for (const auto &I : Symbols) { + visitSymbolRecord(I); + if (hadError()) + break; + } + } + + /// Action to take on unknown symbols. By default, they are ignored. + void visitUnknownSymbol(SymbolKind Kind, ArrayRef Data) {} + + /// Paired begin/end actions for all symbols. Receives all record data, + /// including the fixed-length record prefix. + void visitSymbolBegin(SymbolKind Leaf, ArrayRef RecordData) {} + void visitSymbolEnd(SymbolKind Leaf, ArrayRef OriginalSymData) {} + + /// Helper for returning from a void function when the stream is corrupted. + void parseError() { HadError = true; } + +private: + SymbolVisitorDelegate *Delegate; + /// Whether a symbol stream parsing error was encountered. + bool HadError = false; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_CVSYMBOLVISITOR_H diff --git a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..930ac6930c243294ac61ddf1db14a45ffaf5076c --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -0,0 +1,44 @@ +//===- CVTypeVisitor.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H +#define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H + +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { + +class CVTypeVisitor { +public: + explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks); + + Error visitTypeRecord(const CVRecord &Record); + + /// Visits the type records in Data. Sets the error flag on parse failures. + Error visitTypeStream(const CVTypeArray &Types); + + Error skipPadding(ArrayRef &Data); + + /// Visits individual member records of a field list record. Member records do + /// not describe their own length, and need special handling. + Error visitFieldList(const CVRecord &Record); + +private: + /// The interface to the class that gets notified of each visitation. + TypeVisitorCallbacks &Callbacks; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H diff --git a/include/llvm/DebugInfo/CodeView/CodeView.h b/include/llvm/DebugInfo/CodeView/CodeView.h index 620bfbc288bc98b0083de6ac36a4123953593af6..1ee203b4f8fab4e1efbb4a347ef2d13e1887542d 100644 --- a/include/llvm/DebugInfo/CodeView/CodeView.h +++ b/include/llvm/DebugInfo/CodeView/CodeView.h @@ -11,10 +11,65 @@ #define LLVM_DEBUGINFO_CODEVIEW_CODEVIEW_H #include +#include namespace llvm { namespace codeview { +/// Distinguishes individual records in .debug$T section or PDB type stream. The +/// documentation and headers talk about this as the "leaf" type. +enum class TypeRecordKind : uint16_t { +#define TYPE_RECORD(lf_ename, value, name) name = value, +#include "TypeRecords.def" + // FIXME: Add serialization support + FieldList = 0x1203, +}; + +/// Duplicate copy of the above enum, but using the official CV names. Useful +/// for reference purposes and when dealing with unknown record types. +enum TypeLeafKind : uint16_t { +#define CV_TYPE(name, val) name = val, +#include "TypeRecords.def" +}; + +/// Distinguishes individual records in the Symbols subsection of a .debug$S +/// section. Equivalent to SYM_ENUM_e in cvinfo.h. +enum class SymbolRecordKind : uint16_t { +#define SYMBOL_RECORD(lf_ename, value, name) name = value, +#include "CVSymbolTypes.def" +}; + +/// Duplicate copy of the above enum, but using the official CV names. Useful +/// for reference purposes and when dealing with unknown record types. +enum SymbolKind : uint16_t { +#define CV_SYMBOL(name, val) name = val, +#include "CVSymbolTypes.def" +}; + +#define CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(Class) \ + inline Class operator|(Class a, Class b) { \ + return static_cast( \ + static_cast::type>(a) | \ + static_cast::type>(b)); \ + } \ + inline Class operator&(Class a, Class b) { \ + return static_cast( \ + static_cast::type>(a) & \ + static_cast::type>(b)); \ + } \ + inline Class operator~(Class a) { \ + return static_cast( \ + ~static_cast::type>(a)); \ + } \ + inline Class &operator|=(Class &a, Class b) { \ + a = a | b; \ + return a; \ + } \ + inline Class &operator&=(Class &a, Class b) { \ + a = a & b; \ + return a; \ + } + /// These values correspond to the CV_CPU_TYPE_e enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx enum class CPUType : uint16_t { @@ -149,20 +204,7 @@ enum class ClassOptions : uint16_t { Sealed = 0x0400, Intrinsic = 0x2000 }; - -inline ClassOptions operator|(ClassOptions a, ClassOptions b) { - return static_cast(static_cast(a) | - static_cast(b)); -} - -inline ClassOptions operator&(ClassOptions a, ClassOptions b) { - return static_cast(static_cast(a) & - static_cast(b)); -} - -inline ClassOptions operator~(ClassOptions a) { - return static_cast(~static_cast(a)); -} +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ClassOptions) enum class FrameProcedureOptions : uint32_t { None = 0x00000000, @@ -186,22 +228,7 @@ enum class FrameProcedureOptions : uint32_t { GuardCfg = 0x00200000, GuardCfw = 0x00400000 }; - -inline FrameProcedureOptions operator|(FrameProcedureOptions a, - FrameProcedureOptions b) { - return static_cast(static_cast(a) | - static_cast(b)); -} - -inline FrameProcedureOptions operator&(FrameProcedureOptions a, - FrameProcedureOptions b) { - return static_cast(static_cast(a) & - static_cast(b)); -} - -inline FrameProcedureOptions operator~(FrameProcedureOptions a) { - return static_cast(~static_cast(a)); -} +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(FrameProcedureOptions) enum class FunctionOptions : uint8_t { None = 0x00, @@ -209,20 +236,7 @@ enum class FunctionOptions : uint8_t { Constructor = 0x02, ConstructorWithVirtualBases = 0x04 }; - -inline FunctionOptions operator|(FunctionOptions a, FunctionOptions b) { - return static_cast(static_cast(a) | - static_cast(b)); -} - -inline FunctionOptions operator&(FunctionOptions a, FunctionOptions b) { - return static_cast(static_cast(a) & - static_cast(b)); -} - -inline FunctionOptions operator~(FunctionOptions a) { - return static_cast(~static_cast(a)); -} +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(FunctionOptions) enum class HfaKind : uint8_t { None = 0x00, @@ -261,20 +275,7 @@ enum class MethodOptions : uint16_t { CompilerGenerated = 0x0100, Sealed = 0x0200 }; - -inline MethodOptions operator|(MethodOptions a, MethodOptions b) { - return static_cast(static_cast(a) | - static_cast(b)); -} - -inline MethodOptions operator&(MethodOptions a, MethodOptions b) { - return static_cast(static_cast(a) & - static_cast(b)); -} - -inline MethodOptions operator~(MethodOptions a) { - return static_cast(~static_cast(a)); -} +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(MethodOptions) /// Equivalent to CV_modifier_t. enum class ModifierOptions : uint16_t { @@ -283,22 +284,10 @@ enum class ModifierOptions : uint16_t { Volatile = 0x0002, Unaligned = 0x0004 }; - -inline ModifierOptions operator|(ModifierOptions a, ModifierOptions b) { - return static_cast(static_cast(a) | - static_cast(b)); -} - -inline ModifierOptions operator&(ModifierOptions a, ModifierOptions b) { - return static_cast(static_cast(a) & - static_cast(b)); -} - -inline ModifierOptions operator~(ModifierOptions a) { - return static_cast(~static_cast(a)); -} +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ModifierOptions) enum class ModuleSubstreamKind : uint32_t { + None = 0, Symbols = 0xf1, Lines = 0xf2, StringTable = 0xf3, @@ -353,20 +342,7 @@ enum class PointerOptions : uint32_t { Restrict = 0x00001000, WinRTSmartPointer = 0x00080000 }; - -inline PointerOptions operator|(PointerOptions a, PointerOptions b) { - return static_cast(static_cast(a) | - static_cast(b)); -} - -inline PointerOptions operator&(PointerOptions a, PointerOptions b) { - return static_cast(static_cast(a) & - static_cast(b)); -} - -inline PointerOptions operator~(PointerOptions a) { - return static_cast(~static_cast(a)); -} +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(PointerOptions) /// Equivalent to CV_pmtype_e. enum class PointerToMemberRepresentation : uint16_t { @@ -381,89 +357,7 @@ enum class PointerToMemberRepresentation : uint16_t { GeneralFunction = 0x08 // member function, most general }; -/// Distinguishes individual records in .debug$T section or PDB type stream. The -/// documentation and headers talk about this as the "leaf" type. -enum TypeLeafKind : uint16_t { -#define LEAF_TYPE(name, val) name = val, -#include "CVLeafTypes.def" -}; - -enum class TypeRecordKind : uint16_t { - None = 0, - - VirtualTableShape = 0x000a, - Label = 0x000e, - EndPrecompiledHeader = 0x0014, - - Modifier = 0x1001, - Pointer = 0x1002, - Procedure = 0x1008, - MemberFunction = 0x1009, - - Oem = 0x100f, - Oem2 = 0x1011, - - ArgumentList = 0x1201, - FieldList = 0x1203, - BitField = 0x1205, - MethodList = 0x1206, - - BaseClass = 0x1400, - VirtualBaseClass = 0x1401, - IndirectVirtualBaseClass = 0x1402, - Index = 0x1404, - VirtualFunctionTablePointer = 0x1409, - - Enumerate = 0x1502, - Array = 0x1503, - Class = 0x1504, - Structure = 0x1505, - Union = 0x1506, - Enum = 0x1507, - Alias = 0x150a, - Member = 0x150d, - StaticMember = 0x150e, - Method = 0x150f, - NestedType = 0x1510, - OneMethod = 0x1511, - VirtualFunctionTable = 0x151d, - - FunctionId = 0x1601, - MemberFunctionId = 0x1602, - BuildInfo = 0x1603, - SubstringList = 0x1604, - StringId = 0x1605, - UdtSourceLine = 0x1606, - - SByte = 0x8000, - Int16 = 0x8001, - UInt16 = 0x8002, - Int32 = 0x8003, - UInt32 = 0x8004, - Single = 0x8005, - Double = 0x8006, - Float80 = 0x8007, - Float128 = 0x8008, - Int64 = 0x8009, - UInt64 = 0x800a, - Float48 = 0x800b, - Complex32 = 0x800c, - Complex64 = 0x800d, - Complex80 = 0x800e, - Complex128 = 0x800f, - VarString = 0x8010, - - Int128 = 0x8017, - UInt128 = 0x8018, - - Decimal = 0x8019, - Date = 0x801a, - Utf8String = 0x801b, - - Float16 = 0x801c -}; - -enum class VirtualTableSlotKind : uint8_t { +enum class VFTableSlotKind : uint8_t { Near16 = 0x00, Far16 = 0x01, This = 0x02, @@ -479,6 +373,177 @@ enum class WindowsRTClassKind : uint8_t { ValueClass = 0x02, Interface = 0x03 }; + +/// Corresponds to CV_LVARFLAGS bitfield. +enum class LocalSymFlags : uint16_t { + None = 0, + IsParameter = 1 << 0, + IsAddressTaken = 1 << 1, + IsCompilerGenerated = 1 << 2, + IsAggregate = 1 << 3, + IsAggregated = 1 << 4, + IsAliased = 1 << 5, + IsAlias = 1 << 6, + IsReturnValue = 1 << 7, + IsOptimizedOut = 1 << 8, + IsEnregisteredGlobal = 1 << 9, + IsEnregisteredStatic = 1 << 10, +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(LocalSymFlags) + +/// Corresponds to the CV_PROCFLAGS bitfield. +enum class ProcSymFlags : uint8_t { + None = 0, + HasFP = 1 << 0, + HasIRET = 1 << 1, + HasFRET = 1 << 2, + IsNoReturn = 1 << 3, + IsUnreachable = 1 << 4, + HasCustomCallingConv = 1 << 5, + IsNoInline = 1 << 6, + HasOptimizedDebugInfo = 1 << 7, +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ProcSymFlags) + +/// Corresponds to COMPILESYM2::Flags bitfield. +enum class CompileSym2Flags : uint32_t { + EC = 1 << 8, + NoDbgInfo = 1 << 9, + LTCG = 1 << 10, + NoDataAlign = 1 << 11, + ManagedPresent = 1 << 12, + SecurityChecks = 1 << 13, + HotPatch = 1 << 14, + CVTCIL = 1 << 15, + MSILModule = 1 << 16, +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(CompileSym2Flags) + +/// Corresponds to COMPILESYM3::Flags bitfield. +enum class CompileSym3Flags : uint32_t { + EC = 1 << 8, + NoDbgInfo = 1 << 9, + LTCG = 1 << 10, + NoDataAlign = 1 << 11, + ManagedPresent = 1 << 12, + SecurityChecks = 1 << 13, + HotPatch = 1 << 14, + CVTCIL = 1 << 15, + MSILModule = 1 << 16, + Sdl = 1 << 17, + PGO = 1 << 18, + Exp = 1 << 19, +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(CompileSym3Flags) + +enum class ExportFlags : uint16_t { + IsConstant = 1 << 0, + IsData = 1 << 1, + IsPrivate = 1 << 2, + HasNoName = 1 << 3, + HasExplicitOrdinal = 1 << 4, + IsForwarder = 1 << 5 +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ExportFlags) + +// Corresponds to BinaryAnnotationOpcode enum. +enum class BinaryAnnotationsOpCode : uint32_t { + Invalid, + CodeOffset, + ChangeCodeOffsetBase, + ChangeCodeOffset, + ChangeCodeLength, + ChangeFile, + ChangeLineOffset, + ChangeLineEndDelta, + ChangeRangeKind, + ChangeColumnStart, + ChangeColumnEndDelta, + ChangeCodeOffsetAndLineOffset, + ChangeCodeLengthAndCodeOffset, + ChangeColumnEnd, +}; + +// Corresponds to CV_cookietype_e enum. +enum class FrameCookieKind : uint8_t { + Copy, + XorStackPointer, + XorFramePointer, + XorR13, +}; + +// Corresponds to CV_HREG_e enum. +enum class RegisterId : uint16_t { + Unknown = 0, + VFrame = 30006, + AL = 1, + CL = 2, + DL = 3, + BL = 4, + AH = 5, + CH = 6, + DH = 7, + BH = 8, + AX = 9, + CX = 10, + DX = 11, + BX = 12, + SP = 13, + BP = 14, + SI = 15, + DI = 16, + EAX = 17, + ECX = 18, + EDX = 19, + EBX = 20, + ESP = 21, + EBP = 22, + ESI = 23, + EDI = 24, + ES = 25, + CS = 26, + SS = 27, + DS = 28, + FS = 29, + GS = 30, + IP = 31, + RAX = 328, + RBX = 329, + RCX = 330, + RDX = 331, + RSI = 332, + RDI = 333, + RBP = 334, + RSP = 335, + R8 = 336, + R9 = 337, + R10 = 338, + R11 = 339, + R12 = 340, + R13 = 341, + R14 = 342, + R15 = 343, +}; + +/// These values correspond to the THUNK_ORDINAL enumeration. +enum class ThunkOrdinal { + Standard, + ThisAdjustor, + Vcall, + Pcode, + UnknownLoad, + TrampIncremental, + BranchIsland +}; + +enum class TrampolineType { TrampIncremental, BranchIsland }; + +// These values correspond to the CV_SourceChksum_t enumeration. +enum class FileChecksumKind : uint8_t { None, MD5, SHA1, SHA256 }; + +enum LineFlags : uint32_t { + HaveColumns = 1, // CV_LINES_HAVE_COLUMNS +}; } } diff --git a/include/llvm/DebugInfo/CodeView/CodeViewError.h b/include/llvm/DebugInfo/CodeView/CodeViewError.h new file mode 100644 index 0000000000000000000000000000000000000000..69ff29aab6f110483e4c65c479129110157a1ab9 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/CodeViewError.h @@ -0,0 +1,44 @@ +//===- CodeViewError.h - Error extensions for CodeView ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_CODEVIEW_CODEVIEWERROR_H +#define LLVM_DEBUGINFO_PDB_CODEVIEW_CODEVIEWERROR_H + +#include "llvm/Support/Error.h" + +#include + +namespace llvm { +namespace codeview { +enum class cv_error_code { + unspecified = 1, + insufficient_buffer, + operation_unsupported, + corrupt_record, +}; + +/// Base class for errors originating when parsing raw PDB files +class CodeViewError : public ErrorInfo { +public: + static char ID; + CodeViewError(cv_error_code C); + CodeViewError(const std::string &Context); + CodeViewError(cv_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + cv_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/CodeView/EnumTables.h b/include/llvm/DebugInfo/CodeView/EnumTables.h new file mode 100644 index 0000000000000000000000000000000000000000..021288e57618066231186dcaadb32da72b97d77b --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/EnumTables.h @@ -0,0 +1,42 @@ +//===- EnumTables.h Enum to string conversion tables ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_ENUMTABLES_H +#define LLVM_DEBUGINFO_CODEVIEW_ENUMTABLES_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/ScopedPrinter.h" + +#include + +namespace llvm { +namespace codeview { +ArrayRef> getSymbolTypeNames(); +ArrayRef> getRegisterNames(); +ArrayRef> getProcSymFlagNames(); +ArrayRef> getLocalFlagNames(); +ArrayRef> getFrameCookieKindNames(); +ArrayRef> getSourceLanguageNames(); +ArrayRef> getCompileSym2FlagNames(); +ArrayRef> getCompileSym3FlagNames(); +ArrayRef> getFileChecksumNames(); +ArrayRef> getCPUTypeNames(); +ArrayRef> getFrameProcSymFlagNames(); +ArrayRef> getExportSymFlagNames(); +ArrayRef> getModuleSubstreamKindNames(); +ArrayRef> getThunkOrdinalNames(); +ArrayRef> getTrampolineNames(); +ArrayRef> +getImageSectionCharacteristicNames(); +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_ENUMTABLES_H diff --git a/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h b/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h index 1ed62487aeccc2e273bb9babb1ec46430f7f2dcc..75a075157d228a07ed00a9dc1773c2c9472a8d77 100644 --- a/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h +++ b/include/llvm/DebugInfo/CodeView/FieldListRecordBuilder.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_CODEVIEW_FIELDLISTRECORDBUILDER_H #include "llvm/DebugInfo/CodeView/ListRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" namespace llvm { namespace codeview { @@ -46,31 +47,17 @@ private: public: FieldListRecordBuilder(); - void writeBaseClass(MemberAccess Access, TypeIndex Type, uint64_t Offset); - void writeEnumerate(MemberAccess Access, uint64_t Value, StringRef Name); - void writeIndirectVirtualBaseClass(MemberAccess Access, TypeIndex Type, - TypeIndex VirtualBasePointerType, - int64_t VirtualBasePointerOffset, - uint64_t SlotIndex); - void writeMember(MemberAccess Access, TypeIndex Type, uint64_t Offset, - StringRef Name); - void writeOneMethod(MemberAccess Access, MethodKind Kind, - MethodOptions Options, TypeIndex Type, - int32_t VTableSlotOffset, StringRef Name); - void writeOneMethod(const MethodInfo &Method, StringRef Name); - void writeMethod(uint16_t OverloadCount, TypeIndex MethodList, - StringRef Name); - void writeNestedType(TypeIndex Type, StringRef Name); - void writeStaticMember(MemberAccess Access, TypeIndex Type, StringRef Name); - void writeVirtualBaseClass(MemberAccess Access, TypeIndex Type, - TypeIndex VirtualBasePointerType, - int64_t VirtualBasePointerOffset, - uint64_t SlotIndex); - void writeVirtualBaseClass(TypeRecordKind Kind, MemberAccess Access, - TypeIndex Type, TypeIndex VirtualBasePointerType, - int64_t VirtualBasePointerOffset, - uint64_t SlotIndex); - void writeVirtualFunctionTablePointer(TypeIndex Type); + void reset() { ListRecordBuilder::reset(); } + + void writeBaseClass(const BaseClassRecord &Record); + void writeEnumerator(const EnumeratorRecord &Record); + void writeDataMember(const DataMemberRecord &Record); + void writeOneMethod(const OneMethodRecord &Record); + void writeOverloadedMethod(const OverloadedMethodRecord &Record); + void writeNestedType(const NestedTypeRecord &Record); + void writeStaticDataMember(const StaticDataMemberRecord &Record); + void writeVirtualBaseClass(const VirtualBaseClassRecord &Record); + void writeVFPtr(const VFPtrRecord &Type); }; } } diff --git a/include/llvm/DebugInfo/CodeView/Line.h b/include/llvm/DebugInfo/CodeView/Line.h index bf2d55096b03547a595eaba643bbbf343e5df8df..975b503fe30b7b08180649426f3aa79d46b9c520 100644 --- a/include/llvm/DebugInfo/CodeView/Line.h +++ b/include/llvm/DebugInfo/CodeView/Line.h @@ -141,24 +141,13 @@ struct InlineeSourceLine { // ulittle32_t Files[]; }; -enum class FileChecksumKind : uint8_t { - None, - MD5, - SHA1, - SHA256 -}; - struct FileChecksum { - ulittle32_t FileNameOffset; // Offset of filename in string table substream. - uint8_t ChecksumSize; - uint8_t ChecksumKind; // FileChecksumKind + ulittle32_t FileNameOffset; // Byte offset of filename in global string table. + uint8_t ChecksumSize; // Number of bytes of checksum. + uint8_t ChecksumKind; // FileChecksumKind // Checksum bytes follow. }; -enum LineFlags : uint32_t { - HaveColumns = 1, // CV_LINES_HAVE_COLUMNS -}; - } // namespace codeview } // namespace llvm diff --git a/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h b/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h index df0a2e08a418b1bfdf86c0f576fd7dc55c02a7fd..00bf03d417a2ca24de1851b6dab3e5e27b434679 100644 --- a/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h +++ b/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h @@ -14,6 +14,7 @@ namespace llvm { namespace codeview { +class TypeTableBuilder; class ListRecordBuilder { private: @@ -28,14 +29,35 @@ protected: public: llvm::StringRef str() { return Builder.str(); } + void reset() { + Builder.reset(Kind); + ContinuationOffsets.clear(); + SubrecordStart = 0; + } + + void writeListContinuation(const ListContinuationRecord &R); + + /// Writes this list record as a possible sequence of records. + TypeIndex writeListRecord(TypeTableBuilder &Table); + protected: void finishSubRecord(); TypeRecordBuilder &getBuilder() { return Builder; } private: + size_t getLastContinuationStart() const { + return ContinuationOffsets.empty() ? 0 : ContinuationOffsets.back(); + } + size_t getLastContinuationEnd() const { return Builder.size(); } + size_t getLastContinuationSize() const { + return getLastContinuationEnd() - getLastContinuationStart(); + } + + TypeRecordKind Kind; TypeRecordBuilder Builder; SmallVector ContinuationOffsets; + size_t SubrecordStart = 0; }; } } diff --git a/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h index 0fceac7b43672d9a962785e7fdbd26747f62d31a..002f885c7c5ae8ac963ba9bca60dfe73459e0b97 100644 --- a/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h +++ b/include/llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h @@ -10,57 +10,36 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H #define LLVM_DEBUGINFO_CODEVIEW_MEMORYTYPETABLEBUILDER_H -#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" -#include -#include -#include #include namespace llvm { namespace codeview { class MemoryTypeTableBuilder : public TypeTableBuilder { -public: - class Record { - public: - explicit Record(llvm::StringRef RData); - - const char *data() const { return Data.get(); } - uint16_t size() const { return Size; } - - private: - uint16_t Size; - std::unique_ptr Data; - }; - -private: - class RecordHash : std::unary_function { - public: - size_t operator()(llvm::StringRef Val) const { - return static_cast(llvm::hash_value(Val)); - } - }; - public: MemoryTypeTableBuilder() {} + bool empty() const { return Records.empty(); } + template void ForEachRecord(TFunc Func) { uint32_t Index = TypeIndex::FirstNonSimpleIndex; - for (const std::unique_ptr &R : Records) { - Func(TypeIndex(Index), R.get()); + for (StringRef R : Records) { + Func(TypeIndex(Index), R); ++Index; } } -private: +protected: TypeIndex writeRecord(llvm::StringRef Data) override; private: - std::vector> Records; - std::unordered_map HashedRecords; + std::vector Records; + BumpPtrAllocator RecordStorage; + DenseMap HashedRecords; }; } // end namespace codeview diff --git a/include/llvm/DebugInfo/CodeView/ModuleSubstream.h b/include/llvm/DebugInfo/CodeView/ModuleSubstream.h new file mode 100644 index 0000000000000000000000000000000000000000..6affac801d4dc8c1688fcfc9f0fb8e57f42b3fec --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/ModuleSubstream.h @@ -0,0 +1,87 @@ +//===- ModuleSubstream.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H +#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { + +// Corresponds to the `CV_DebugSSubsectionHeader_t` structure. +struct ModuleSubsectionHeader { + support::ulittle32_t Kind; // codeview::ModuleSubstreamKind enum + support::ulittle32_t Length; // number of bytes occupied by this record. +}; + +// Corresponds to the `CV_DebugSLinesHeader_t` structure. +struct LineSubstreamHeader { + support::ulittle32_t RelocOffset; // Code offset of line contribution. + support::ulittle16_t RelocSegment; // Code segment of line contribution. + support::ulittle16_t Flags; // See LineFlags enumeration. + support::ulittle32_t CodeSize; // Code size of this line contribution. +}; + +// Corresponds to the `CV_DebugSLinesFileBlockHeader_t` structure. +struct LineFileBlockHeader { + support::ulittle32_t NameIndex; // Index in DBI name buffer of filename. + support::ulittle32_t NumLines; // Number of lines + support::ulittle32_t BlockSize; // Code size of block, in bytes. + // The following two variable length arrays appear immediately after the + // header. The structure definitions follow. + // LineNumberEntry Lines[NumLines]; + // ColumnNumberEntry Columns[NumLines]; +}; + +// Corresponds to `CV_Line_t` structure +struct LineNumberEntry { + support::ulittle32_t Offset; // Offset to start of code bytes for line number + support::ulittle32_t Flags; // Start:24, End:7, IsStatement:1 +}; + +// Corresponds to `CV_Column_t` structure +struct ColumnNumberEntry { + support::ulittle16_t StartColumn; + support::ulittle16_t EndColumn; +}; + +class ModuleSubstream { +public: + ModuleSubstream(); + ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data); + static Error initialize(StreamRef Stream, ModuleSubstream &Info); + uint32_t getRecordLength() const; + ModuleSubstreamKind getSubstreamKind() const; + StreamRef getRecordData() const; + +private: + ModuleSubstreamKind Kind; + StreamRef Data; +}; + +template <> struct VarStreamArrayExtractor { + Error operator()(StreamRef Stream, uint32_t &Length, + ModuleSubstream &Info) const { + if (auto EC = ModuleSubstream::initialize(Stream, Info)) + return EC; + Length = Info.getRecordLength(); + return Error::success(); + } +}; + +typedef VarStreamArray ModuleSubstreamArray; +} +} + +#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H diff --git a/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h b/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..6df230903712243f415ea0d334d4955a3a5cce16 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h @@ -0,0 +1,121 @@ +//===- ModuleSubstreamVisitor.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H +#define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" + +namespace llvm { +namespace codeview { + +struct LineColumnEntry { + support::ulittle32_t NameIndex; + FixedStreamArray LineNumbers; + FixedStreamArray Columns; +}; + +template <> class VarStreamArrayExtractor { +public: + VarStreamArrayExtractor(const LineSubstreamHeader *Header) : Header(Header) {} + + Error operator()(StreamRef Stream, uint32_t &Len, + LineColumnEntry &Item) const { + const LineFileBlockHeader *BlockHeader; + StreamReader Reader(Stream); + if (auto EC = Reader.readObject(BlockHeader)) + return EC; + bool HasColumn = Header->Flags & LineFlags::HaveColumns; + uint32_t LineInfoSize = + BlockHeader->NumLines * + (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0)); + if (BlockHeader->BlockSize < sizeof(LineFileBlockHeader)) + return make_error(cv_error_code::corrupt_record, + "Invalid line block record size"); + uint32_t Size = BlockHeader->BlockSize - sizeof(LineFileBlockHeader); + if (LineInfoSize > Size) + return make_error(cv_error_code::corrupt_record, + "Invalid line block record size"); + // The value recorded in BlockHeader->BlockSize includes the size of + // LineFileBlockHeader. + Len = BlockHeader->BlockSize; + Item.NameIndex = BlockHeader->NameIndex; + if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines)) + return EC; + if (HasColumn) { + if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines)) + return EC; + } + return Error::success(); + } + +private: + const LineSubstreamHeader *Header; +}; + +struct FileChecksumEntry { + uint32_t FileNameOffset; // Byte offset of filename in global stringtable. + FileChecksumKind Kind; // The type of checksum. + ArrayRef Checksum; // The bytes of the checksum. +}; + +template <> class VarStreamArrayExtractor { +public: + Error operator()(StreamRef Stream, uint32_t &Len, + FileChecksumEntry &Item) const { + const FileChecksum *Header; + StreamReader Reader(Stream); + if (auto EC = Reader.readObject(Header)) + return EC; + Item.FileNameOffset = Header->FileNameOffset; + Item.Kind = static_cast(Header->ChecksumKind); + if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize)) + return EC; + Len = sizeof(FileChecksum) + Header->ChecksumSize; + return Error::success(); + } +}; + +typedef VarStreamArray LineInfoArray; +typedef VarStreamArray FileChecksumArray; + +class IModuleSubstreamVisitor { +public: + virtual ~IModuleSubstreamVisitor() {} + + virtual Error visitUnknown(ModuleSubstreamKind Kind, StreamRef Data) = 0; + virtual Error visitSymbols(StreamRef Data); + virtual Error visitLines(StreamRef Data, const LineSubstreamHeader *Header, + const LineInfoArray &Lines); + virtual Error visitStringTable(StreamRef Data); + virtual Error visitFileChecksums(StreamRef Data, + const FileChecksumArray &Checksums); + virtual Error visitFrameData(StreamRef Data); + virtual Error visitInlineeLines(StreamRef Data); + virtual Error visitCrossScopeImports(StreamRef Data); + virtual Error visitCrossScopeExports(StreamRef Data); + virtual Error visitILLines(StreamRef Data); + virtual Error visitFuncMDTokenMap(StreamRef Data); + virtual Error visitTypeMDTokenMap(StreamRef Data); + virtual Error visitMergedAssemblyInput(StreamRef Data); + virtual Error visitCoffSymbolRVA(StreamRef Data); +}; + +Error visitModuleSubstream(const ModuleSubstream &R, + IModuleSubstreamVisitor &V); + +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H diff --git a/include/llvm/DebugInfo/CodeView/RecordSerialization.h b/include/llvm/DebugInfo/CodeView/RecordSerialization.h new file mode 100644 index 0000000000000000000000000000000000000000..84179f5f81f74c07cc3b82d7dafee04ec0c8a5f1 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/RecordSerialization.h @@ -0,0 +1,278 @@ +//===- RecordSerialization.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H +#define LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H + +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include +#include + +namespace llvm { +namespace codeview { +using llvm::support::little32_t; +using llvm::support::ulittle16_t; +using llvm::support::ulittle32_t; + +struct RecordPrefix { + ulittle16_t RecordLen; // Record length, starting from &Leaf. + ulittle16_t RecordKind; // Record kind enum (SymRecordKind or TypeRecordKind) +}; + +/// Reinterpret a byte array as an array of characters. Does not interpret as +/// a C string, as StringRef has several helpers (split) that make that easy. +StringRef getBytesAsCharacters(ArrayRef LeafData); +StringRef getBytesAsCString(ArrayRef LeafData); + +/// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if +/// there are not enough bytes remaining. Reinterprets the consumed bytes as a +/// T object and points 'Res' at them. +template +inline std::error_code consumeObject(U &Data, const T *&Res) { + if (Data.size() < sizeof(*Res)) + return std::make_error_code(std::errc::illegal_byte_sequence); + Res = reinterpret_cast(Data.data()); + Data = Data.drop_front(sizeof(*Res)); + return std::error_code(); +} + +inline std::error_code consume(ArrayRef &Data) { + return std::error_code(); +} + +/// Decodes a numeric "leaf" value. These are integer literals encountered in +/// the type stream. If the value is positive and less than LF_NUMERIC (1 << +/// 15), it is emitted directly in Data. Otherwise, it has a tag like LF_CHAR +/// that indicates the bitwidth and sign of the numeric data. +std::error_code consume(ArrayRef &Data, APSInt &Num); +std::error_code consume(StringRef &Data, APSInt &Num); + +/// Decodes a numeric leaf value that is known to be a particular type. +std::error_code consume_numeric(ArrayRef &Data, uint64_t &Value); + +/// Decodes signed and unsigned fixed-length integers. +std::error_code consume(ArrayRef &Data, uint32_t &Item); +std::error_code consume(StringRef &Data, uint32_t &Item); +std::error_code consume(ArrayRef &Data, int32_t &Item); + +/// Decodes a null terminated string. +std::error_code consume(ArrayRef &Data, StringRef &Item); + +/// Decodes an arbitrary object whose layout matches that of the underlying +/// byte sequence, and returns a pointer to the object. +template +std::error_code consume(ArrayRef &Data, T *&Item) { + return consumeObject(Data, Item); +} + +template struct serialize_conditional_impl { + serialize_conditional_impl(T &Item, U Func) : Item(Item), Func(Func) {} + + std::error_code deserialize(ArrayRef &Data) const { + if (!Func()) + return std::error_code(); + return consume(Data, Item); + } + + T &Item; + U Func; +}; + +template +serialize_conditional_impl serialize_conditional(T &Item, U Func) { + return serialize_conditional_impl(Item, Func); +} + +template struct serialize_array_impl { + serialize_array_impl(ArrayRef &Item, U Func) : Item(Item), Func(Func) {} + + std::error_code deserialize(ArrayRef &Data) const { + uint32_t N = Func(); + if (N == 0) + return std::error_code(); + + uint32_t Size = sizeof(T) * N; + + if (Size / sizeof(T) != N) + return std::make_error_code(std::errc::illegal_byte_sequence); + + if (Data.size() < Size) + return std::make_error_code(std::errc::illegal_byte_sequence); + + Item = ArrayRef(reinterpret_cast(Data.data()), N); + Data = Data.drop_front(Size); + return std::error_code(); + } + + ArrayRef &Item; + U Func; +}; + +template struct serialize_vector_tail_impl { + serialize_vector_tail_impl(std::vector &Item) : Item(Item) {} + + std::error_code deserialize(ArrayRef &Data) const { + T Field; + // Stop when we run out of bytes or we hit record padding bytes. + while (!Data.empty() && Data.front() < LF_PAD0) { + if (auto EC = consume(Data, Field)) + return EC; + Item.push_back(Field); + } + return std::error_code(); + } + + std::vector &Item; +}; + +struct serialize_null_term_string_array_impl { + serialize_null_term_string_array_impl(std::vector &Item) + : Item(Item) {} + + std::error_code deserialize(ArrayRef &Data) const { + if (Data.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + + StringRef Field; + // Stop when we run out of bytes or we hit record padding bytes. + while (Data.front() != 0) { + if (auto EC = consume(Data, Field)) + return EC; + Item.push_back(Field); + if (Data.empty()) + return std::make_error_code(std::errc::illegal_byte_sequence); + } + Data = Data.drop_front(1); + return std::error_code(); + } + + std::vector &Item; +}; + +template struct serialize_arrayref_tail_impl { + serialize_arrayref_tail_impl(ArrayRef &Item) : Item(Item) {} + + std::error_code deserialize(ArrayRef &Data) const { + uint32_t Count = Data.size() / sizeof(T); + Item = ArrayRef(reinterpret_cast(Data.begin()), Count); + return std::error_code(); + } + + ArrayRef &Item; +}; + +template struct serialize_numeric_impl { + serialize_numeric_impl(T &Item) : Item(Item) {} + + std::error_code deserialize(ArrayRef &Data) const { + return consume_numeric(Data, Item); + } + + T &Item; +}; + +template +serialize_array_impl serialize_array(ArrayRef &Item, U Func) { + return serialize_array_impl(Item, Func); +} + +inline serialize_null_term_string_array_impl +serialize_null_term_string_array(std::vector &Item) { + return serialize_null_term_string_array_impl(Item); +} + +template +serialize_vector_tail_impl serialize_array_tail(std::vector &Item) { + return serialize_vector_tail_impl(Item); +} + +template +serialize_arrayref_tail_impl serialize_array_tail(ArrayRef &Item) { + return serialize_arrayref_tail_impl(Item); +} + +template serialize_numeric_impl serialize_numeric(T &Item) { + return serialize_numeric_impl(Item); +} + +// This field is only present in the byte record if the condition is true. The +// condition is evaluated lazily, so it can depend on items that were +// deserialized +// earlier. +#define CV_CONDITIONAL_FIELD(I, C) \ + serialize_conditional(I, [&]() { return !!(C); }) + +// This is an array of N items, where N is evaluated lazily, so it can refer +// to a field deserialized earlier. +#define CV_ARRAY_FIELD_N(I, N) serialize_array(I, [&]() { return N; }) + +// This is an array that exhausts the remainder of the input buffer. +#define CV_ARRAY_FIELD_TAIL(I) serialize_array_tail(I) + +// This is an array that consumes null terminated strings until a double null +// is encountered. +#define CV_STRING_ARRAY_NULL_TERM(I) serialize_null_term_string_array(I) + +#define CV_NUMERIC_FIELD(I) serialize_numeric(I) + +template +std::error_code consume(ArrayRef &Data, + const serialize_conditional_impl &Item) { + return Item.deserialize(Data); +} + +template +std::error_code consume(ArrayRef &Data, + const serialize_array_impl &Item) { + return Item.deserialize(Data); +} + +inline std::error_code +consume(ArrayRef &Data, + const serialize_null_term_string_array_impl &Item) { + return Item.deserialize(Data); +} + +template +std::error_code consume(ArrayRef &Data, + const serialize_vector_tail_impl &Item) { + return Item.deserialize(Data); +} + +template +std::error_code consume(ArrayRef &Data, + const serialize_arrayref_tail_impl &Item) { + return Item.deserialize(Data); +} + +template +std::error_code consume(ArrayRef &Data, + const serialize_numeric_impl &Item) { + return Item.deserialize(Data); +} + +template +std::error_code consume(ArrayRef &Data, T &&X, U &&Y, + Args &&... Rest) { + if (auto EC = consume(Data, X)) + return EC; + return consume(Data, Y, std::forward(Rest)...); +} + +#define CV_DESERIALIZE(...) \ + if (auto EC = consume(__VA_ARGS__)) \ + return EC; +} +} + +#endif diff --git a/include/llvm/DebugInfo/CodeView/StreamArray.h b/include/llvm/DebugInfo/CodeView/StreamArray.h new file mode 100644 index 0000000000000000000000000000000000000000..b6ecc75e439382d85a45c9852845a974088d0ffe --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StreamArray.h @@ -0,0 +1,271 @@ +//===- StreamArray.h - Array backed by an arbitrary stream ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H + +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/Support/Error.h" + +#include +#include + +namespace llvm { +namespace codeview { + +/// VarStreamArrayExtractor is intended to be specialized to provide customized +/// extraction logic. On input it receives a StreamRef pointing to the +/// beginning of the next record, but where the length of the record is not yet +/// known. Upon completion, it should return an appropriate Error instance if +/// a record could not be extracted, or if one could be extracted it should +/// return success and set Len to the number of bytes this record occupied in +/// the underlying stream, and it should fill out the fields of the value type +/// Item appropriately to represent the current record. +/// +/// You can specialize this template for your own custom value types to avoid +/// having to specify a second template argument to VarStreamArray (documented +/// below). +template struct VarStreamArrayExtractor { + // Method intentionally deleted. You must provide an explicit specialization + // with the following method implemented. + Error operator()(StreamRef Stream, uint32_t &Len, T &Item) const = delete; +}; + +/// VarStreamArray represents an array of variable length records backed by a +/// stream. This could be a contiguous sequence of bytes in memory, it could +/// be a file on disk, or it could be a PDB stream where bytes are stored as +/// discontiguous blocks in a file. Usually it is desirable to treat arrays +/// as contiguous blocks of memory, but doing so with large PDB files, for +/// example, could mean allocating huge amounts of memory just to allow +/// re-ordering of stream data to be contiguous before iterating over it. By +/// abstracting this out, we need not duplicate this memory, and we can +/// iterate over arrays in arbitrarily formatted streams. Elements are parsed +/// lazily on iteration, so there is no upfront cost associated with building +/// a VarStreamArray, no matter how large it may be. +/// +/// You create a VarStreamArray by specifying a ValueType and an Extractor type. +/// If you do not specify an Extractor type, it expects you to specialize +/// VarStreamArrayExtractor for your ValueType. +/// +/// By default an Extractor is default constructed in the class, but in some +/// cases you might find it useful for an Extractor to maintain state across +/// extractions. In this case you can provide your own Extractor through a +/// secondary constructor. The following examples show various ways of +/// creating a VarStreamArray. +/// +/// // Will use VarStreamArrayExtractor as the extractor. +/// VarStreamArray MyTypeArray; +/// +/// // Will use a default-constructed MyExtractor as the extractor. +/// VarStreamArray MyTypeArray2; +/// +/// // Will use the specific instance of MyExtractor provided. +/// // MyExtractor need not be default-constructible in this case. +/// MyExtractor E(SomeContext); +/// VarStreamArray MyTypeArray3(E); +/// +template class VarStreamArrayIterator; + +template > +class VarStreamArray { + friend class VarStreamArrayIterator; + +public: + typedef VarStreamArrayIterator Iterator; + + VarStreamArray() {} + explicit VarStreamArray(const Extractor &E) : E(E) {} + + explicit VarStreamArray(StreamRef Stream) : Stream(Stream) {} + VarStreamArray(StreamRef Stream, const Extractor &E) : Stream(Stream), E(E) {} + + VarStreamArray(const VarStreamArray &Other) + : Stream(Other.Stream), E(Other.E) {} + + Iterator begin(bool *HadError = nullptr) const { + return Iterator(*this, E, HadError); + } + + Iterator end() const { return Iterator(E); } + + const Extractor &getExtractor() const { return E; } + + StreamRef getUnderlyingStream() const { return Stream; } + +private: + StreamRef Stream; + Extractor E; +}; + +template class VarStreamArrayIterator { + typedef VarStreamArrayIterator IterType; + typedef VarStreamArray ArrayType; + +public: + VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, + bool *HadError = nullptr) + : IterRef(Array.Stream), Array(&Array), HadError(HadError), Extract(E) { + auto EC = Extract(IterRef, ThisLen, ThisValue); + if (EC) { + consumeError(std::move(EC)); + markError(); + } + } + VarStreamArrayIterator() {} + explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {} + ~VarStreamArrayIterator() {} + + bool operator==(const IterType &R) const { + if (Array && R.Array) { + // Both have a valid array, make sure they're same. + assert(Array == R.Array); + return IterRef == R.IterRef; + } + + // Both iterators are at the end. + if (!Array && !R.Array) + return true; + + // One is not at the end and one is. + return false; + } + + bool operator!=(const IterType &R) { return !(*this == R); } + + const ValueType &operator*() const { + assert(Array && !HasError); + return ThisValue; + } + + IterType &operator++() { + // We are done with the current record, discard it so that we are + // positioned at the next record. + IterRef = IterRef.drop_front(ThisLen); + if (IterRef.getLength() == 0) { + // There is nothing after the current record, we must make this an end + // iterator. + moveToEnd(); + } else { + // There is some data after the current record. + auto EC = Extract(IterRef, ThisLen, ThisValue); + if (EC) { + consumeError(std::move(EC)); + markError(); + } else if (ThisLen == 0) { + // An empty record? Make this an end iterator. + moveToEnd(); + } + } + return *this; + } + + IterType operator++(int) { + IterType Original = *this; + ++*this; + return Original; + } + +private: + void moveToEnd() { + Array = nullptr; + ThisLen = 0; + } + void markError() { + moveToEnd(); + HasError = true; + if (HadError != nullptr) + *HadError = true; + } + + ValueType ThisValue; + StreamRef IterRef; + const ArrayType *Array{nullptr}; + uint32_t ThisLen{0}; + bool HasError{false}; + bool *HadError{nullptr}; + Extractor Extract; +}; + +template class FixedStreamArrayIterator; + +template class FixedStreamArray { + friend class FixedStreamArrayIterator; + +public: + FixedStreamArray() : Stream() {} + FixedStreamArray(StreamRef Stream) : Stream(Stream) { + assert(Stream.getLength() % sizeof(T) == 0); + } + + const T &operator[](uint32_t Index) const { + assert(Index < size()); + uint32_t Off = Index * sizeof(T); + ArrayRef Data; + if (auto EC = Stream.readBytes(Off, sizeof(T), Data)) { + assert(false && "Unexpected failure reading from stream"); + // This should never happen since we asserted that the stream length was + // an exact multiple of the element size. + consumeError(std::move(EC)); + } + return *reinterpret_cast(Data.data()); + } + + uint32_t size() const { return Stream.getLength() / sizeof(T); } + + FixedStreamArrayIterator begin() const { + return FixedStreamArrayIterator(*this, 0); + } + FixedStreamArrayIterator end() const { + return FixedStreamArrayIterator(*this, size()); + } + + StreamRef getUnderlyingStream() const { return Stream; } + +private: + StreamRef Stream; +}; + +template class FixedStreamArrayIterator { +public: + FixedStreamArrayIterator(const FixedStreamArray &Array, uint32_t Index) + : Array(Array), Index(Index) {} + + bool operator==(const FixedStreamArrayIterator &R) { + assert(&Array == &R.Array); + return Index == R.Index; + } + + bool operator!=(const FixedStreamArrayIterator &R) { + return !(*this == R); + } + + const T &operator*() const { return Array[Index]; } + + FixedStreamArrayIterator &operator++() { + assert(Index < Array.size()); + ++Index; + return *this; + } + + FixedStreamArrayIterator operator++(int) { + FixedStreamArrayIterator Original = *this; + ++*this; + return Original; + } + +private: + const FixedStreamArray &Array; + uint32_t Index; +}; + +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H diff --git a/include/llvm/DebugInfo/CodeView/StreamInterface.h b/include/llvm/DebugInfo/CodeView/StreamInterface.h new file mode 100644 index 0000000000000000000000000000000000000000..241aec4578700459e9c3897e752c0a107570722d --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StreamInterface.h @@ -0,0 +1,55 @@ +//===- StreamInterface.h - Base interface for a stream of data --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMINTERFACE_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMINTERFACE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Error.h" +#include + +namespace llvm { +namespace codeview { + +/// StreamInterface abstracts the notion of a data stream. This way, an +/// implementation could implement trivial reading from a contiguous memory +/// buffer or, as in the case of PDB files, reading from a set of possibly +/// discontiguous blocks. The implementation is required to return references +/// to stable memory, so if this is not possible (for example in the case of +/// a PDB file with discontiguous blocks, it must keep its own pool of temp +/// storage. +class StreamInterface { +public: + virtual ~StreamInterface() {} + + // Given an offset into the stream and a number of bytes, attempt to read + // the bytes and set the output ArrayRef to point to a reference into the + // stream, without copying any data. + virtual Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) const = 0; + + // Given an offset into the stream, read as much as possible without copying + // any data. + virtual Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) const = 0; + + // Attempt to write the given bytes into the stream at the desired offset. + // This will always necessitate a copy. Cannot shrink or grow the stream, + // only writes into existing allocated space. + virtual Error writeBytes(uint32_t Offset, ArrayRef Data) const = 0; + + virtual uint32_t getLength() const = 0; + + virtual Error commit() const = 0; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMINTERFACE_H diff --git a/include/llvm/DebugInfo/CodeView/StreamReader.h b/include/llvm/DebugInfo/CodeView/StreamReader.h new file mode 100644 index 0000000000000000000000000000000000000000..2f497c2c43f147acf3441cb67fb5b4171947f9c1 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StreamReader.h @@ -0,0 +1,111 @@ +//===- StreamReader.h - Reads bytes and objects from a stream ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include + +namespace llvm { +namespace codeview { + +class StreamRef; + +class StreamReader { +public: + StreamReader(StreamRef Stream); + + Error readLongestContiguousChunk(ArrayRef &Buffer); + Error readBytes(ArrayRef &Buffer, uint32_t Size); + Error readInteger(uint16_t &Dest); + Error readInteger(uint32_t &Dest); + Error readZeroString(StringRef &Dest); + Error readFixedString(StringRef &Dest, uint32_t Length); + Error readStreamRef(StreamRef &Ref); + Error readStreamRef(StreamRef &Ref, uint32_t Length); + + template Error readEnum(T &Dest) { + typename std::underlying_type::type N; + if (auto EC = readInteger(N)) + return EC; + Dest = static_cast(N); + return Error::success(); + } + + template Error readObject(const T *&Dest) { + ArrayRef Buffer; + if (auto EC = readBytes(Buffer, sizeof(T))) + return EC; + Dest = reinterpret_cast(Buffer.data()); + return Error::success(); + } + + template + Error readArray(ArrayRef &Array, uint32_t NumElements) { + ArrayRef Bytes; + if (NumElements == 0) { + Array = ArrayRef(); + return Error::success(); + } + + if (NumElements > UINT32_MAX/sizeof(T)) + return make_error(cv_error_code::insufficient_buffer); + + if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) + return EC; + Array = ArrayRef(reinterpret_cast(Bytes.data()), NumElements); + return Error::success(); + } + + template + Error readArray(VarStreamArray &Array, uint32_t Size) { + StreamRef S; + if (auto EC = readStreamRef(S, Size)) + return EC; + Array = VarStreamArray(S, Array.getExtractor()); + return Error::success(); + } + + template + Error readArray(FixedStreamArray &Array, uint32_t NumItems) { + if (NumItems == 0) { + Array = FixedStreamArray(); + return Error::success(); + } + uint32_t Length = NumItems * sizeof(T); + if (Length / sizeof(T) != NumItems) + return make_error(cv_error_code::corrupt_record); + if (Offset + Length > Stream.getLength()) + return make_error(cv_error_code::insufficient_buffer); + StreamRef View = Stream.slice(Offset, Length); + Array = FixedStreamArray(View); + Offset += Length; + return Error::success(); + } + + void setOffset(uint32_t Off) { Offset = Off; } + uint32_t getOffset() const { return Offset; } + uint32_t getLength() const { return Stream.getLength(); } + uint32_t bytesRemaining() const { return getLength() - getOffset(); } + +private: + StreamRef Stream; + uint32_t Offset; +}; +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H diff --git a/include/llvm/DebugInfo/CodeView/StreamRef.h b/include/llvm/DebugInfo/CodeView/StreamRef.h new file mode 100644 index 0000000000000000000000000000000000000000..a4f244a322899ad5481ff2fe0e78a40824ae2ebc --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StreamRef.h @@ -0,0 +1,104 @@ +//===- StreamRef.h - A copyable reference to a stream -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" + +namespace llvm { +namespace codeview { + +class StreamRef { +public: + StreamRef() : Stream(nullptr), ViewOffset(0), Length(0) {} + StreamRef(const StreamInterface &Stream) + : Stream(&Stream), ViewOffset(0), Length(Stream.getLength()) {} + StreamRef(const StreamInterface &Stream, uint32_t Offset, uint32_t Length) + : Stream(&Stream), ViewOffset(Offset), Length(Length) {} + + // Use StreamRef.slice() instead. + StreamRef(const StreamRef &S, uint32_t Offset, uint32_t Length) = delete; + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) const { + if (ViewOffset + Offset < Offset) + return make_error(cv_error_code::insufficient_buffer); + if (Size + Offset > Length) + return make_error(cv_error_code::insufficient_buffer); + return Stream->readBytes(ViewOffset + Offset, Size, Buffer); + } + + // Given an offset into the stream, read as much as possible without copying + // any data. + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) const { + if (Offset >= Length) + return make_error(cv_error_code::insufficient_buffer); + + if (auto EC = Stream->readLongestContiguousChunk(Offset, Buffer)) + return EC; + // This StreamRef might refer to a smaller window over a larger stream. In + // that case we will have read out more bytes than we should return, because + // we should not read past the end of the current view. + uint32_t MaxLength = Length - Offset; + if (Buffer.size() > MaxLength) + Buffer = Buffer.slice(0, MaxLength); + return Error::success(); + } + + Error writeBytes(uint32_t Offset, ArrayRef Data) const { + if (Data.size() + Offset > Length) + return make_error(cv_error_code::insufficient_buffer); + return Stream->writeBytes(ViewOffset + Offset, Data); + } + + uint32_t getLength() const { return Length; } + + Error commit() const { return Stream->commit(); } + + StreamRef drop_front(uint32_t N) const { + if (!Stream) + return StreamRef(); + + N = std::min(N, Length); + return StreamRef(*Stream, ViewOffset + N, Length - N); + } + + StreamRef keep_front(uint32_t N) const { + if (!Stream) + return StreamRef(); + N = std::min(N, Length); + return StreamRef(*Stream, ViewOffset, N); + } + + StreamRef slice(uint32_t Offset, uint32_t Len) const { + return drop_front(Offset).keep_front(Len); + } + + bool operator==(const StreamRef &Other) const { + if (Stream != Other.Stream) + return false; + if (ViewOffset != Other.ViewOffset) + return false; + if (Length != Other.Length) + return false; + return true; + } + +private: + const StreamInterface *Stream; + uint32_t ViewOffset; + uint32_t Length; +}; +} +} + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREF_H diff --git a/include/llvm/DebugInfo/CodeView/StreamWriter.h b/include/llvm/DebugInfo/CodeView/StreamWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..4d393d2ef790573cfcda0fdb2c4da9c9f454089c --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/StreamWriter.h @@ -0,0 +1,86 @@ +//===- StreamWriter.h - Writes bytes and objects to a stream ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMWRITER_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMWRITER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include + +namespace llvm { +namespace codeview { + +class StreamRef; + +class StreamWriter { +public: + StreamWriter(StreamRef Stream); + + Error writeBytes(ArrayRef Buffer); + Error writeInteger(uint16_t Dest); + Error writeInteger(uint32_t Dest); + Error writeZeroString(StringRef Str); + Error writeFixedString(StringRef Str); + Error writeStreamRef(StreamRef Ref); + Error writeStreamRef(StreamRef Ref, uint32_t Size); + + template Error writeEnum(T Num) { + return writeInteger( + static_cast::type>(Num)); + } + + template Error writeObject(const T &Obj) { + static_assert(!std::is_pointer::value, + "writeObject should not be used with pointers, to write " + "the pointed-to value dereference the pointer before calling " + "writeObject"); + return writeBytes( + ArrayRef(reinterpret_cast(&Obj), sizeof(T))); + } + + template Error writeArray(ArrayRef Array) { + if (Array.size() == 0) + return Error::success(); + + if (Array.size() > UINT32_MAX / sizeof(T)) + return make_error(cv_error_code::insufficient_buffer); + + return writeBytes( + ArrayRef(reinterpret_cast(Array.data()), + Array.size() * sizeof(T))); + } + + template + Error writeArray(VarStreamArray Array) { + return writeStreamRef(Array.getUnderlyingStream()); + } + + template Error writeArray(FixedStreamArray Array) { + return writeStreamRef(Array.getUnderlyingStream()); + } + + void setOffset(uint32_t Off) { Offset = Off; } + uint32_t getOffset() const { return Offset; } + uint32_t getLength() const { return Stream.getLength(); } + uint32_t bytesRemaining() const { return getLength() - getOffset(); } + +private: + StreamRef Stream; + uint32_t Offset; +}; +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H diff --git a/include/llvm/DebugInfo/CodeView/SymbolDumpDelegate.h b/include/llvm/DebugInfo/CodeView/SymbolDumpDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..30b0a40451cb8b9b8f7f1fbbf773b70a2f7f665f --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/SymbolDumpDelegate.h @@ -0,0 +1,37 @@ +//===-- SymbolDumpDelegate.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H +#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H + +#include "SymbolVisitorDelegate.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +#include + +namespace llvm { + +namespace codeview { + +class SymbolDumpDelegate : public SymbolVisitorDelegate { +public: + virtual ~SymbolDumpDelegate() {} + + virtual void printRelocatedField(StringRef Label, uint32_t RelocOffset, + uint32_t Offset, + StringRef *RelocSym = nullptr) = 0; + virtual void printBinaryBlockWithRelocs(StringRef Label, + ArrayRef Block) = 0; +}; +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPDELEGATE_H diff --git a/include/llvm/DebugInfo/CodeView/SymbolDumper.h b/include/llvm/DebugInfo/CodeView/SymbolDumper.h new file mode 100644 index 0000000000000000000000000000000000000000..648e40f55810bedf8b4ae7c5be3a29cf0527ab1c --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/SymbolDumper.h @@ -0,0 +1,54 @@ +//===-- SymbolDumper.h - CodeView symbol info dumper ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H +#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" + +namespace llvm { +class ScopedPrinter; + +namespace codeview { +class CVTypeDumper; + +/// Dumper for CodeView symbol streams found in COFF object files and PDB files. +class CVSymbolDumper { +public: + CVSymbolDumper(ScopedPrinter &W, CVTypeDumper &CVTD, + std::unique_ptr ObjDelegate, + bool PrintRecordBytes) + : W(W), CVTD(CVTD), ObjDelegate(std::move(ObjDelegate)), + PrintRecordBytes(PrintRecordBytes) {} + + /// Dumps one type record. Returns false if there was a type parsing error, + /// and true otherwise. This should be called in order, since the dumper + /// maintains state about previous records which are necessary for cross + /// type references. + bool dump(const CVRecord &Record); + + /// Dumps the type records in Data. Returns false if there was a type stream + /// parse error, and true otherwise. + bool dump(const CVSymbolArray &Symbols); + +private: + ScopedPrinter &W; + CVTypeDumper &CVTD; + std::unique_ptr ObjDelegate; + + bool PrintRecordBytes; +}; +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLDUMPER_H diff --git a/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/include/llvm/DebugInfo/CodeView/SymbolRecord.h index 2a02aa3b2358cb115df848b2bc0786cee83cbb30..77e894fba4a9bf15a4673d2b71caebc493d11cb2 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ b/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -10,9 +10,16 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H #define LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" namespace llvm { namespace codeview { @@ -21,95 +28,559 @@ using llvm::support::ulittle16_t; using llvm::support::ulittle32_t; using llvm::support::little32_t; -/// Distinguishes individual records in the Symbols subsection of a .debug$S -/// section. Equivalent to SYM_ENUM_e in cvinfo.h. -enum SymbolRecordKind : uint16_t { -#define SYMBOL_TYPE(ename, value) ename = value, -#include "CVSymbolTypes.def" +class SymbolRecord { +protected: + explicit SymbolRecord(SymbolRecordKind Kind) : Kind(Kind) {} + +public: + SymbolRecordKind getKind() const { return Kind; } + +private: + SymbolRecordKind Kind; }; -/// Data preceding all symbol records. -struct SymRecord { - ulittle16_t RecordLength; // Record length, starting from the next field - ulittle16_t RecordKind; // Record kind (SymbolRecordKind) - // Symbol data follows. +// S_GPROC32, S_LPROC32, S_GPROC32_ID, S_LPROC32_ID, S_LPROC32_DPC or +// S_LPROC32_DPC_ID +class ProcSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t PtrParent; + ulittle32_t PtrEnd; + ulittle32_t PtrNext; + ulittle32_t CodeSize; + ulittle32_t DbgStart; + ulittle32_t DbgEnd; + TypeIndex FunctionType; + ulittle32_t CodeOffset; + ulittle16_t Segment; + uint8_t Flags; // ProcSymFlags enum + // Name: The null-terminated name follows. + }; - SymbolRecordKind getKind() const { - return SymbolRecordKind(uint16_t(RecordKind)); + ProcSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H, + StringRef Name) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name) { } + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return ProcSym(Kind, RecordOffset, H, Name); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; }; -/// Corresponds to the CV_PROCFLAGS bitfield. -enum ProcFlags : uint8_t { - HasFP = 1 << 0, - HasIRET = 1 << 1, - HasFRET = 1 << 2, - IsNoReturn = 1 << 3, - IsUnreachable = 1 << 4, - HasCustomCallingConv = 1 << 5, - IsNoInline = 1 << 6, - HasOptimizedDebugInfo = 1 << 7, +// S_THUNK32 +class Thunk32Sym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Parent; + ulittle32_t End; + ulittle32_t Next; + ulittle32_t Off; + ulittle16_t Seg; + ulittle16_t Len; + uint8_t Ord; // ThunkOrdinal enumeration + // Name: The null-terminated name follows. + // Variant portion of thunk + }; + + Thunk32Sym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H, + StringRef Name, ArrayRef VariantData) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name), + VariantData(VariantData) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + ArrayRef VariantData; + + CV_DESERIALIZE(Data, H, Name, CV_ARRAY_FIELD_TAIL(VariantData)); + + return Thunk32Sym(Kind, RecordOffset, H, Name, VariantData); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; + ArrayRef VariantData; }; -// S_GPROC32, S_LPROC32, S_GPROC32_ID, S_LPROC32_ID, S_LPROC32_DPC or -// S_LPROC32_DPC_ID -struct ProcSym { - ulittle32_t PtrParent; - ulittle32_t PtrEnd; - ulittle32_t PtrNext; - ulittle32_t CodeSize; - ulittle32_t DbgStart; - ulittle32_t DbgEnd; - TypeIndex FunctionType; - ulittle32_t CodeOffset; - ulittle16_t Segment; - uint8_t Flags; // CV_PROCFLAGS - // Name: The null-terminated name follows. -}; - -enum BinaryAnnotationsOpCode : uint32_t { - Invalid, - CodeOffset, - ChangeCodeOffsetBase, - ChangeCodeOffset, - ChangeCodeLength, - ChangeFile, - ChangeLineOffset, - ChangeLineEndDelta, - ChangeRangeKind, - ChangeColumnStart, - ChangeColumnEndDelta, - ChangeCodeOffsetAndLineOffset, - ChangeCodeLengthAndCodeOffset, - ChangeColumnEnd, +// S_TRAMPOLINE +class TrampolineSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t Type; // TrampolineType enum + ulittle16_t Size; + ulittle32_t ThunkOff; + ulittle32_t TargetOff; + ulittle16_t ThunkSection; + ulittle16_t TargetSection; + }; + + TrampolineSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + + CV_DESERIALIZE(Data, H); + + return TrampolineSym(Kind, RecordOffset, H); + } + + uint32_t RecordOffset; + Hdr Header; +}; + +// S_SECTION +class SectionSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t SectionNumber; + uint8_t Alignment; + uint8_t Reserved; // Must be 0 + ulittle32_t Rva; + ulittle32_t Length; + ulittle32_t Characteristics; + // Name: The null-terminated name follows. + }; + + SectionSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H, + StringRef Name) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name) { + } + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + + CV_DESERIALIZE(Data, H, Name); + + return SectionSym(Kind, RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_COFFGROUP +class CoffGroupSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Size; + ulittle32_t Characteristics; + ulittle32_t Offset; + ulittle16_t Segment; + // Name: The null-terminated name follows. + }; + + CoffGroupSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *H, + StringRef Name) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*H), Name(Name) { + } + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + + CV_DESERIALIZE(Data, H, Name); + + return CoffGroupSym(Kind, RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +class ScopeEndSym : public SymbolRecord { +public: + ScopeEndSym(SymbolRecordKind Kind, uint32_t RecordOffset) + : SymbolRecord(Kind), RecordOffset(RecordOffset) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + return ScopeEndSym(Kind, RecordOffset); + } + uint32_t RecordOffset; +}; + +class CallerSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Count; + }; + + CallerSym(SymbolRecordKind Kind, uint32_t RecordOffset, const Hdr *Header, + ArrayRef Indices) + : SymbolRecord(Kind), RecordOffset(RecordOffset), Header(*Header), + Indices(Indices) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *Header; + ArrayRef Indices; + + CV_DESERIALIZE(Data, Header, CV_ARRAY_FIELD_N(Indices, Header->Count)); + + return CallerSym(Kind, RecordOffset, Header, Indices); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef Indices; +}; + +struct BinaryAnnotationIterator { + struct AnnotationData { + BinaryAnnotationsOpCode OpCode; + StringRef Name; + uint32_t U1; + uint32_t U2; + int32_t S1; + }; + + BinaryAnnotationIterator(ArrayRef Annotations) : Data(Annotations) {} + BinaryAnnotationIterator() {} + BinaryAnnotationIterator(const BinaryAnnotationIterator &Other) + : Data(Other.Data) {} + + bool operator==(BinaryAnnotationIterator Other) const { + return Data == Other.Data; + } + + bool operator!=(BinaryAnnotationIterator Other) const { + return !(*this == Other); + } + + BinaryAnnotationIterator &operator=(const BinaryAnnotationIterator Other) { + Data = Other.Data; + return *this; + } + + BinaryAnnotationIterator &operator++() { + if (!ParseCurrentAnnotation()) { + *this = BinaryAnnotationIterator(); + return *this; + } + Data = Next; + Next = ArrayRef(); + Current.reset(); + return *this; + } + + BinaryAnnotationIterator operator++(int) { + BinaryAnnotationIterator Orig(*this); + ++(*this); + return Orig; + } + + const AnnotationData &operator*() { + ParseCurrentAnnotation(); + return Current.getValue(); + } + +private: + static uint32_t GetCompressedAnnotation(ArrayRef &Annotations) { + if (Annotations.empty()) + return -1; + + uint8_t FirstByte = Annotations.front(); + Annotations = Annotations.drop_front(); + + if ((FirstByte & 0x80) == 0x00) + return FirstByte; + + if (Annotations.empty()) + return -1; + + uint8_t SecondByte = Annotations.front(); + Annotations = Annotations.drop_front(); + + if ((FirstByte & 0xC0) == 0x80) + return ((FirstByte & 0x3F) << 8) | SecondByte; + + if (Annotations.empty()) + return -1; + + uint8_t ThirdByte = Annotations.front(); + Annotations = Annotations.drop_front(); + + if (Annotations.empty()) + return -1; + + uint8_t FourthByte = Annotations.front(); + Annotations = Annotations.drop_front(); + + if ((FirstByte & 0xE0) == 0xC0) + return ((FirstByte & 0x1F) << 24) | (SecondByte << 16) | + (ThirdByte << 8) | FourthByte; + + return -1; + }; + + static int32_t DecodeSignedOperand(uint32_t Operand) { + if (Operand & 1) + return -(Operand >> 1); + return Operand >> 1; + }; + + static int32_t DecodeSignedOperand(ArrayRef &Annotations) { + return DecodeSignedOperand(GetCompressedAnnotation(Annotations)); + }; + + bool ParseCurrentAnnotation() { + if (Current.hasValue()) + return true; + + Next = Data; + uint32_t Op = GetCompressedAnnotation(Next); + AnnotationData Result; + Result.OpCode = static_cast(Op); + switch (Result.OpCode) { + case BinaryAnnotationsOpCode::Invalid: + Result.Name = "Invalid"; + Next = ArrayRef(); + break; + case BinaryAnnotationsOpCode::CodeOffset: + Result.Name = "CodeOffset"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeCodeOffsetBase: + Result.Name = "ChangeCodeOffsetBase"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeCodeOffset: + Result.Name = "ChangeCodeOffset"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeCodeLength: + Result.Name = "ChangeCodeLength"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeFile: + Result.Name = "ChangeFile"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeLineEndDelta: + Result.Name = "ChangeLineEndDelta"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeRangeKind: + Result.Name = "ChangeRangeKind"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeColumnStart: + Result.Name = "ChangeColumnStart"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeColumnEnd: + Result.Name = "ChangeColumnEnd"; + Result.U1 = GetCompressedAnnotation(Next); + break; + case BinaryAnnotationsOpCode::ChangeLineOffset: + Result.Name = "ChangeLineOffset"; + Result.S1 = DecodeSignedOperand(Next); + break; + case BinaryAnnotationsOpCode::ChangeColumnEndDelta: + Result.Name = "ChangeColumnEndDelta"; + Result.S1 = DecodeSignedOperand(Next); + break; + case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: { + Result.Name = "ChangeCodeOffsetAndLineOffset"; + uint32_t Annotation = GetCompressedAnnotation(Next); + Result.S1 = DecodeSignedOperand(Annotation >> 4); + Result.U1 = Annotation & 0xf; + break; + } + case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: { + Result.Name = "ChangeCodeLengthAndCodeOffset"; + Result.U1 = GetCompressedAnnotation(Next); + Result.U2 = GetCompressedAnnotation(Next); + break; + } + } + Current = Result; + return true; + } + + Optional Current; + ArrayRef Data; + ArrayRef Next; }; // S_INLINESITE -struct InlineSiteSym { - ulittle32_t PtrParent; - ulittle32_t PtrEnd; - TypeIndex Inlinee; - // BinaryAnnotations +class InlineSiteSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t PtrParent; + ulittle32_t PtrEnd; + TypeIndex Inlinee; + // BinaryAnnotations + }; + + InlineSiteSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef Annotations) + : SymbolRecord(SymbolRecordKind::InlineSiteSym), + RecordOffset(RecordOffset), Header(*H), Annotations(Annotations) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + ArrayRef Annotations; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Annotations)); + + return InlineSiteSym(RecordOffset, H, Annotations); + } + + llvm::iterator_range annotations() const { + return llvm::make_range(BinaryAnnotationIterator(Annotations), + BinaryAnnotationIterator()); + } + + uint32_t RecordOffset; + Hdr Header; + +private: + ArrayRef Annotations; +}; + +// S_PUB32 +class PublicSym32 : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Index; // Type index, or Metadata token if a managed symbol + ulittle32_t Off; + ulittle16_t Seg; + // Name: The null-terminated name follows. + }; + + PublicSym32(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::PublicSym32), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return PublicSym32(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_REGISTER +class RegisterSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Index; // Type index or Metadata token + ulittle16_t Register; // RegisterId enumeration + // Name: The null-terminated name follows. + }; + + RegisterSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::RegisterSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return RegisterSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_PROCREF, S_LPROCREF +class ProcRefSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t SumName; // SUC of the name (?) + ulittle32_t SymOffset; // Offset of actual symbol in $$Symbols + ulittle16_t Mod; // Module containing the actual symbol + // Name: The null-terminated name follows. + }; + + ProcRefSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::ProcRefSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return ProcRefSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; }; // S_LOCAL -struct LocalSym { - TypeIndex Type; - ulittle16_t Flags; - enum : uint16_t { - IsParameter = 1 << 0, - IsAddressTaken = 1 << 1, - IsCompilerGenerated = 1 << 2, - IsAggregate = 1 << 3, - IsAggregated = 1 << 4, - IsAliased = 1 << 5, - IsAlias = 1 << 6, - IsReturnValue = 1 << 7, - IsOptimizedOut = 1 << 8, - IsEnregisteredGlobal = 1 << 9, - IsEnregisteredStatic = 1 << 10, - }; - // Name: The null-terminated name follows. +class LocalSym : public SymbolRecord { +public: + struct Hdr { + TypeIndex Type; + ulittle16_t Flags; // LocalSymFlags enum + // Name: The null-terminated name follows. + }; + + LocalSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::LocalSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return LocalSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; }; struct LocalVariableAddrRange { @@ -126,205 +597,855 @@ struct LocalVariableAddrGap { enum : uint16_t { MaxDefRange = 0xf000 }; // S_DEFRANGE -struct DefRangeSym { - ulittle32_t Program; - LocalVariableAddrRange Range; - // LocalVariableAddrGap Gaps[]; +class DefRangeSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Program; + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + + DefRangeSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeSym), RecordOffset(RecordOffset), + Header(*H), Gaps(Gaps) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + ArrayRef Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeSym(RecordOffset, H, Gaps); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef Gaps; }; // S_DEFRANGE_SUBFIELD -struct DefRangeSubfieldSym { - ulittle32_t Program; - ulittle16_t OffsetInParent; - LocalVariableAddrRange Range; - // LocalVariableAddrGap Gaps[]; +class DefRangeSubfieldSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Program; + ulittle16_t OffsetInParent; + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + DefRangeSubfieldSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeSubfieldSym), + RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + ArrayRef Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeSubfieldSym(RecordOffset, H, Gaps); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef Gaps; }; // S_DEFRANGE_REGISTER -struct DefRangeRegisterSym { - ulittle16_t Register; - ulittle16_t MayHaveNoName; - LocalVariableAddrRange Range; - // LocalVariableAddrGap Gaps[]; +class DefRangeRegisterSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t Register; + ulittle16_t MayHaveNoName; + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + + DefRangeRegisterSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeRegisterSym), + RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {} + + DefRangeRegisterSym(uint16_t Register, uint16_t MayHaveNoName, + uint32_t OffsetStart, uint16_t ISectStart, uint16_t Range, + ArrayRef Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeRegisterSym), RecordOffset(0), + Gaps(Gaps) { + Header.Register = Register; + Header.MayHaveNoName = MayHaveNoName; + Header.Range.OffsetStart = OffsetStart; + Header.Range.ISectStart = ISectStart; + Header.Range.Range = Range; + } + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + ArrayRef Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeRegisterSym(RecordOffset, H, Gaps); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef Gaps; }; // S_DEFRANGE_SUBFIELD_REGISTER -struct DefRangeSubfieldRegisterSym { - ulittle16_t Register; // Register to which the variable is relative - ulittle16_t MayHaveNoName; - ulittle32_t OffsetInParent; - LocalVariableAddrRange Range; - // LocalVariableAddrGap Gaps[]; +class DefRangeSubfieldRegisterSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t Register; // Register to which the variable is relative + ulittle16_t MayHaveNoName; + ulittle32_t OffsetInParent; + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + + DefRangeSubfieldRegisterSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeSubfieldRegisterSym), + RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {} + + DefRangeSubfieldRegisterSym(uint16_t Register, uint16_t MayHaveNoName, + uint32_t OffsetInParent, + ArrayRef Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeSubfieldRegisterSym), + RecordOffset(0), Gaps(Gaps) { + Header.Register = Register; + Header.MayHaveNoName = MayHaveNoName; + Header.OffsetInParent = OffsetInParent; + } + + static ErrorOr + deserialize(SymbolRecordKind Kind, uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + ArrayRef Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeSubfieldRegisterSym(RecordOffset, H, Gaps); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef Gaps; }; // S_DEFRANGE_FRAMEPOINTER_REL -struct DefRangeFramePointerRelSym { - little32_t Offset; // Offset from the frame pointer register - LocalVariableAddrRange Range; - // LocalVariableAddrGap Gaps[]; -}; +class DefRangeFramePointerRelSym : public SymbolRecord { +public: + struct Hdr { + little32_t Offset; // Offset from the frame pointer register + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; -// S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE -struct DefRangeFramePointerRelFullScopeSym { - little32_t Offset; // Offset from the frame pointer register + DefRangeFramePointerRelSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelSym), + RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {} + + static ErrorOr + deserialize(SymbolRecordKind Kind, uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + ArrayRef Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeFramePointerRelSym(RecordOffset, H, Gaps); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } + + uint32_t RecordOffset; + Hdr Header; + ArrayRef Gaps; }; // S_DEFRANGE_REGISTER_REL -struct DefRangeRegisterRelSym { - ulittle16_t BaseRegister; - ulittle16_t Flags; - little32_t BasePointerOffset; - LocalVariableAddrRange Range; - // LocalVariableAddrGap Gaps[]; +class DefRangeRegisterRelSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t BaseRegister; + ulittle16_t Flags; + little32_t BasePointerOffset; + LocalVariableAddrRange Range; + // LocalVariableAddrGap Gaps[]; + }; + + DefRangeRegisterRelSym(uint32_t RecordOffset, const Hdr *H, + ArrayRef Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym), + RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {} + + DefRangeRegisterRelSym(uint16_t BaseRegister, uint16_t Flags, + int32_t BasePointerOffset, uint32_t OffsetStart, + uint16_t ISectStart, uint16_t Range, + ArrayRef Gaps) + : SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym), RecordOffset(0), + Gaps(Gaps) { + Header.BaseRegister = BaseRegister; + Header.Flags = Flags; + Header.BasePointerOffset = BasePointerOffset; + Header.Range.OffsetStart = OffsetStart; + Header.Range.ISectStart = ISectStart; + Header.Range.Range = Range; + } + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + ArrayRef Gaps; + CV_DESERIALIZE(Data, H, CV_ARRAY_FIELD_TAIL(Gaps)); + + return DefRangeRegisterRelSym(RecordOffset, H, Gaps); + } + + bool hasSpilledUDTMember() const { return Header.Flags & 1; } + uint16_t offsetInParent() const { return Header.Flags >> 4; } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, Range); + } - bool hasSpilledUDTMember() const { return Flags & 1; } - uint16_t offsetInParent() const { return Flags >> 4; } + uint32_t RecordOffset; + Hdr Header; + ArrayRef Gaps; +}; + +// S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE +class DefRangeFramePointerRelFullScopeSym : public SymbolRecord { +public: + struct Hdr { + little32_t Offset; // Offset from the frame pointer register + }; + + DefRangeFramePointerRelFullScopeSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::DefRangeFramePointerRelFullScopeSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr + deserialize(SymbolRecordKind Kind, uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return DefRangeFramePointerRelFullScopeSym(RecordOffset, H); + } + + uint32_t RecordOffset; + Hdr Header; }; // S_BLOCK32 -struct BlockSym { - ulittle32_t PtrParent; - ulittle32_t PtrEnd; - ulittle32_t CodeSize; - ulittle32_t CodeOffset; - ulittle16_t Segment; - // Name: The null-terminated name follows. +class BlockSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t PtrParent; + ulittle32_t PtrEnd; + ulittle32_t CodeSize; + ulittle32_t CodeOffset; + ulittle16_t Segment; + // Name: The null-terminated name follows. + }; + + BlockSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::BlockSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return BlockSym(RecordOffset, H, Name); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; }; // S_LABEL32 -struct LabelSym { - ulittle32_t CodeOffset; - ulittle16_t Segment; - uint8_t Flags; // CV_PROCFLAGS - // Name: The null-terminated name follows. +class LabelSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t CodeOffset; + ulittle16_t Segment; + uint8_t Flags; // CV_PROCFLAGS + // Name: The null-terminated name follows. + }; + + LabelSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::LabelSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return LabelSym(RecordOffset, H, Name); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; }; // S_OBJNAME -struct ObjNameSym { - ulittle32_t Signature; - // Name: The null-terminated name follows. +class ObjNameSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Signature; + // Name: The null-terminated name follows. + }; + + ObjNameSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::ObjNameSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return ObjNameSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_ENVBLOCK +class EnvBlockSym : public SymbolRecord { +public: + struct Hdr { + uint8_t Reserved; + // Sequence of zero terminated strings. + }; + + EnvBlockSym(uint32_t RecordOffset, const Hdr *H, + const std::vector &Fields) + : SymbolRecord(SymbolRecordKind::EnvBlockSym), RecordOffset(RecordOffset), + Header(*H), Fields(Fields) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + std::vector Fields; + CV_DESERIALIZE(Data, H, CV_STRING_ARRAY_NULL_TERM(Fields)); + + return EnvBlockSym(RecordOffset, H, Fields); + } + + uint32_t RecordOffset; + Hdr Header; + std::vector Fields; +}; + +// S_EXPORT +class ExportSym : public SymbolRecord { +public: + struct Hdr { + ulittle16_t Ordinal; + ulittle16_t Flags; // ExportFlags + // Name: The null-terminated name follows. + }; + + ExportSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::ExportSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return ExportSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_FILESTATIC +class FileStaticSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Index; // Type Index + ulittle32_t ModFilenameOffset; // Index of mod filename in string table + ulittle16_t Flags; // LocalSymFlags enum + // Name: The null-terminated name follows. + }; + + FileStaticSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::FileStaticSym), + RecordOffset(RecordOffset), Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return FileStaticSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; +}; + +// S_COMPILE2 +class Compile2Sym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t flags; // CompileSym2Flags enum + uint8_t getLanguage() const { return flags & 0xFF; } + unsigned short Machine; // CPUType enum + unsigned short VersionFrontendMajor; + unsigned short VersionFrontendMinor; + unsigned short VersionFrontendBuild; + unsigned short VersionBackendMajor; + unsigned short VersionBackendMinor; + unsigned short VersionBackendBuild; + // Version: The null-terminated version string follows. + // Optional block of zero terminated strings terminated with a double zero. + }; + + Compile2Sym(uint32_t RecordOffset, const Hdr *H, StringRef Version) + : SymbolRecord(SymbolRecordKind::Compile2Sym), RecordOffset(RecordOffset), + Header(*H), Version(Version) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Version; + CV_DESERIALIZE(Data, H, Version); + + return Compile2Sym(RecordOffset, H, Version); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Version; }; // S_COMPILE3 -struct CompileSym3 { - ulittle32_t flags; - uint8_t getLanguage() const { return flags & 0xff; } - enum Flags : uint32_t { - EC = 1 << 8, - NoDbgInfo = 1 << 9, - LTCG = 1 << 10, - NoDataAlign = 1 << 11, - ManagedPresent = 1 << 12, - SecurityChecks = 1 << 13, - HotPatch = 1 << 14, - CVTCIL = 1 << 15, - MSILModule = 1 << 16, - Sdl = 1 << 17, - PGO = 1 << 18, - Exp = 1 << 19, - }; - ulittle16_t Machine; // CPUType - ulittle16_t VersionFrontendMajor; - ulittle16_t VersionFrontendMinor; - ulittle16_t VersionFrontendBuild; - ulittle16_t VersionFrontendQFE; - ulittle16_t VersionBackendMajor; - ulittle16_t VersionBackendMinor; - ulittle16_t VersionBackendBuild; - ulittle16_t VersionBackendQFE; - // VersionString: The null-terminated version string follows. +class Compile3Sym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t flags; // CompileSym3Flags enum + uint8_t getLanguage() const { return flags & 0xff; } + ulittle16_t Machine; // CPUType enum + ulittle16_t VersionFrontendMajor; + ulittle16_t VersionFrontendMinor; + ulittle16_t VersionFrontendBuild; + ulittle16_t VersionFrontendQFE; + ulittle16_t VersionBackendMajor; + ulittle16_t VersionBackendMinor; + ulittle16_t VersionBackendBuild; + ulittle16_t VersionBackendQFE; + // VersionString: The null-terminated version string follows. + }; + + Compile3Sym(uint32_t RecordOffset, const Hdr *H, StringRef Version) + : SymbolRecord(SymbolRecordKind::Compile3Sym), RecordOffset(RecordOffset), + Header(*H), Version(Version) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Version; + CV_DESERIALIZE(Data, H, Version); + + return Compile3Sym(RecordOffset, H, Version); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Version; }; // S_FRAMEPROC -struct FrameProcSym { - ulittle32_t TotalFrameBytes; - ulittle32_t PaddingFrameBytes; - ulittle32_t OffsetToPadding; - ulittle32_t BytesOfCalleeSavedRegisters; - ulittle32_t OffsetOfExceptionHandler; - ulittle16_t SectionIdOfExceptionHandler; - ulittle32_t Flags; +class FrameProcSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t TotalFrameBytes; + ulittle32_t PaddingFrameBytes; + ulittle32_t OffsetToPadding; + ulittle32_t BytesOfCalleeSavedRegisters; + ulittle32_t OffsetOfExceptionHandler; + ulittle16_t SectionIdOfExceptionHandler; + ulittle32_t Flags; + }; + + FrameProcSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::FrameProcSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return FrameProcSym(RecordOffset, H); + } + + uint32_t RecordOffset; + Hdr Header; }; // S_CALLSITEINFO -struct CallSiteInfoSym { - ulittle32_t CodeOffset; - ulittle16_t Segment; - ulittle16_t Reserved; - TypeIndex Type; +class CallSiteInfoSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t CodeOffset; + ulittle16_t Segment; + ulittle16_t Reserved; + TypeIndex Type; + }; + + CallSiteInfoSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::CallSiteInfoSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return CallSiteInfoSym(RecordOffset, H); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; }; // S_HEAPALLOCSITE -struct HeapAllocationSiteSym { - ulittle32_t CodeOffset; - ulittle16_t Segment; - ulittle16_t CallInstructionSize; - TypeIndex Type; +class HeapAllocationSiteSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t CodeOffset; + ulittle16_t Segment; + ulittle16_t CallInstructionSize; + TypeIndex Type; + }; + + HeapAllocationSiteSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::HeapAllocationSiteSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return HeapAllocationSiteSym(RecordOffset, H); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; }; // S_FRAMECOOKIE -struct FrameCookieSym { - ulittle32_t CodeOffset; - ulittle16_t Register; - ulittle16_t CookieKind; - - enum : uint16_t { - Copy, - XorStackPointer, - XorFramePointer, - XorR13, +class FrameCookieSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t CodeOffset; + ulittle16_t Register; + uint8_t CookieKind; + uint8_t Flags; }; + + FrameCookieSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::FrameCookieSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return FrameCookieSym(RecordOffset, H); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, CodeOffset); + } + + uint32_t RecordOffset; + Hdr Header; }; // S_UDT, S_COBOLUDT -struct UDTSym { - TypeIndex Type; // Type of the UDT - // Name: The null-terminated name follows. +class UDTSym : public SymbolRecord { +public: + struct Hdr { + TypeIndex Type; // Type of the UDT + // Name: The null-terminated name follows. + }; + + UDTSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::UDTSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return UDTSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; }; // S_BUILDINFO -struct BuildInfoSym { - ulittle32_t BuildId; +class BuildInfoSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t BuildId; + }; + + BuildInfoSym(uint32_t RecordOffset, const Hdr *H) + : SymbolRecord(SymbolRecordKind::BuildInfoSym), + RecordOffset(RecordOffset), Header(*H) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + CV_DESERIALIZE(Data, H); + + return BuildInfoSym(RecordOffset, H); + } + + uint32_t RecordOffset; + Hdr Header; }; // S_BPREL32 -struct BPRelativeSym { - little32_t Offset; // Offset from the base pointer register - TypeIndex Type; // Type of the variable - // Name: The null-terminated name follows. +class BPRelativeSym : public SymbolRecord { +public: + struct Hdr { + little32_t Offset; // Offset from the base pointer register + TypeIndex Type; // Type of the variable + // Name: The null-terminated name follows. + }; + + BPRelativeSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::BPRelativeSym), + RecordOffset(RecordOffset), Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return BPRelativeSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; }; // S_REGREL32 -struct RegRelativeSym { - ulittle32_t Offset; // Offset from the register - TypeIndex Type; // Type of the variable - ulittle16_t Register; // Register to which the variable is relative - // Name: The null-terminated name follows. +class RegRelativeSym : public SymbolRecord { +public: + struct Hdr { + ulittle32_t Offset; // Offset from the register + TypeIndex Type; // Type of the variable + ulittle16_t Register; // Register to which the variable is relative + // Name: The null-terminated name follows. + }; + + RegRelativeSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::RegRelativeSym), + RecordOffset(RecordOffset), Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return RegRelativeSym(RecordOffset, H, Name); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; }; // S_CONSTANT, S_MANCONSTANT -struct ConstantSym { - TypeIndex Type; - // Value: The value of the constant. - // Name: The null-terminated name follows. +class ConstantSym : public SymbolRecord { +public: + struct Hdr { + TypeIndex Type; + // Value: The value of the constant. + // Name: The null-terminated name follows. + }; + + ConstantSym(uint32_t RecordOffset, const Hdr *H, const APSInt &Value, + StringRef Name) + : SymbolRecord(SymbolRecordKind::ConstantSym), RecordOffset(RecordOffset), + Header(*H), Value(Value), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + APSInt Value; + StringRef Name; + CV_DESERIALIZE(Data, H, Value, Name); + + return ConstantSym(RecordOffset, H, Value, Name); + } + + uint32_t RecordOffset; + Hdr Header; + APSInt Value; + StringRef Name; }; // S_LDATA32, S_GDATA32, S_LMANDATA, S_GMANDATA -struct DataSym { - TypeIndex Type; - ulittle32_t DataOffset; - ulittle16_t Segment; - // Name: The null-terminated name follows. +class DataSym : public SymbolRecord { +public: + struct Hdr { + TypeIndex Type; + ulittle32_t DataOffset; + ulittle16_t Segment; + // Name: The null-terminated name follows. + }; + + DataSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::DataSym), RecordOffset(RecordOffset), + Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return DataSym(RecordOffset, H, Name); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, DataOffset); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; }; // S_LTHREAD32, S_GTHREAD32 -struct ThreadLocalDataSym { - TypeIndex Type; - ulittle32_t DataOffset; - ulittle16_t Segment; - // Name: The null-terminated name follows. +class ThreadLocalDataSym : public SymbolRecord { +public: + struct Hdr { + TypeIndex Type; + ulittle32_t DataOffset; + ulittle16_t Segment; + // Name: The null-terminated name follows. + }; + + ThreadLocalDataSym(uint32_t RecordOffset, const Hdr *H, StringRef Name) + : SymbolRecord(SymbolRecordKind::ThreadLocalDataSym), + RecordOffset(RecordOffset), Header(*H), Name(Name) {} + + static ErrorOr deserialize(SymbolRecordKind Kind, + uint32_t RecordOffset, + ArrayRef &Data) { + const Hdr *H = nullptr; + StringRef Name; + CV_DESERIALIZE(Data, H, Name); + + return ThreadLocalDataSym(RecordOffset, H, Name); + } + + uint32_t getRelocationOffset() const { + return RecordOffset + offsetof(Hdr, DataOffset); + } + + uint32_t RecordOffset; + Hdr Header; + StringRef Name; }; +typedef CVRecord CVSymbol; +typedef VarStreamArray CVSymbolArray; + } // namespace codeview } // namespace llvm diff --git a/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h b/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..a4965168c3db7a015bd890390c13434ae5ce4c0a --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h @@ -0,0 +1,33 @@ +//===-- SymbolVisitorDelegate.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H +#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +#include + +namespace llvm { + +namespace codeview { + +class SymbolVisitorDelegate { +public: + virtual ~SymbolVisitorDelegate() {} + + virtual uint32_t getRecordOffset(ArrayRef Record) = 0; + virtual StringRef getFileNameForFileOffset(uint32_t FileOffset) = 0; + virtual StringRef getStringTable() = 0; +}; +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLVISITORDELEGATE_H diff --git a/include/llvm/DebugInfo/CodeView/TypeDumper.h b/include/llvm/DebugInfo/CodeView/TypeDumper.h new file mode 100644 index 0000000000000000000000000000000000000000..ca79ab076e5eb734ba8ae0f7e73383ac67318b16 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeDumper.h @@ -0,0 +1,105 @@ +//===-- TypeDumper.h - CodeView type info dumper ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" + +namespace llvm { +class ScopedPrinter; + +namespace codeview { + +/// Dumper for CodeView type streams found in COFF object files and PDB files. +class CVTypeDumper : public TypeVisitorCallbacks { +public: + CVTypeDumper(ScopedPrinter *W, bool PrintRecordBytes) + : W(W), PrintRecordBytes(PrintRecordBytes) {} + + StringRef getTypeName(TypeIndex TI); + void printTypeIndex(StringRef FieldName, TypeIndex TI); + + /// Dumps one type record. Returns false if there was a type parsing error, + /// and true otherwise. This should be called in order, since the dumper + /// maintains state about previous records which are necessary for cross + /// type references. + Error dump(const CVRecord &Record); + + /// Dumps the type records in Types. Returns false if there was a type stream + /// parse error, and true otherwise. + Error dump(const CVTypeArray &Types); + + /// Dumps the type records in Data. Returns false if there was a type stream + /// parse error, and true otherwise. Use this method instead of the + /// CVTypeArray overload when type records are laid out contiguously in + /// memory. + Error dump(ArrayRef Data); + + /// Gets the type index for the next type record. + unsigned getNextTypeIndex() const { + return 0x1000 + CVUDTNames.size(); + } + + /// Records the name of a type, and reserves its type index. + void recordType(StringRef Name) { CVUDTNames.push_back(Name); } + + /// Saves the name in a StringSet and creates a stable StringRef. + StringRef saveName(StringRef TypeName) { + return TypeNames.insert(TypeName).first->getKey(); + } + + void setPrinter(ScopedPrinter *P); + ScopedPrinter *getPrinter() { return W; } + + /// Action to take on unknown types. By default, they are ignored. + Error visitUnknownType(const CVRecord &Record) override; + Error visitUnknownMember(const CVRecord &Record) override; + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + Error visitTypeBegin(const CVRecord &Record) override; + Error visitTypeEnd(const CVRecord &Record) override; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visit##Name(Name##Record &Record) override; +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "TypeRecords.def" + +private: + void printMemberAttributes(MemberAttributes Attrs); + void printMemberAttributes(MemberAccess Access, MethodKind Kind, + MethodOptions Options); + + ScopedPrinter *W; + + bool PrintRecordBytes = false; + + /// Name of the current type. Only valid before visitTypeEnd. + StringRef Name; + + /// All user defined type records in .debug$T live in here. Type indices + /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to + /// index into this vector. + SmallVector CVUDTNames; + + StringSet<> TypeNames; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H diff --git a/include/llvm/DebugInfo/CodeView/TypeIndex.h b/include/llvm/DebugInfo/CodeView/TypeIndex.h index 9ff2920f5d5ad2cb119695a59421dee2026ae7e9..c2ebf3848892d79af7644e1697d9f151985acf9c 100644 --- a/include/llvm/DebugInfo/CodeView/TypeIndex.h +++ b/include/llvm/DebugInfo/CodeView/TypeIndex.h @@ -27,6 +27,8 @@ enum class SimpleTypeKind : uint32_t { UnsignedCharacter = 0x0020, // 8 bit unsigned NarrowCharacter = 0x0070, // really a char WideCharacter = 0x0071, // wide char + Character16 = 0x007a, // char16_t + Character32 = 0x007b, // char32_t SByte = 0x0068, // 8 bit signed int Byte = 0x0069, // 8 bit unsigned int @@ -42,6 +44,8 @@ enum class SimpleTypeKind : uint32_t { UInt64Quad = 0x0023, // 64 bit unsigned Int64 = 0x0076, // 64 bit signed int UInt64 = 0x0077, // 64 bit unsigned int + Int128Oct = 0x0014, // 128 bit signed int + UInt128Oct = 0x0024, // 128 bit unsigned int Int128 = 0x0078, // 128 bit signed int UInt128 = 0x0079, // 128 bit unsigned int @@ -53,15 +57,19 @@ enum class SimpleTypeKind : uint32_t { Float80 = 0x0042, // 80 bit real Float128 = 0x0043, // 128 bit real - Complex32 = 0x0050, // 32 bit complex - Complex64 = 0x0051, // 64 bit complex - Complex80 = 0x0052, // 80 bit complex - Complex128 = 0x0053, // 128 bit complex - - Boolean8 = 0x0030, // 8 bit boolean - Boolean16 = 0x0031, // 16 bit boolean - Boolean32 = 0x0032, // 32 bit boolean - Boolean64 = 0x0033 // 64 bit boolean + Complex16 = 0x0056, // 16 bit complex + Complex32 = 0x0050, // 32 bit complex + Complex32PartialPrecision = 0x0055, // 32 bit PP complex + Complex48 = 0x0054, // 48 bit complex + Complex64 = 0x0051, // 64 bit complex + Complex80 = 0x0052, // 80 bit complex + Complex128 = 0x0053, // 128 bit complex + + Boolean8 = 0x0030, // 8 bit boolean + Boolean16 = 0x0031, // 16 bit boolean + Boolean32 = 0x0032, // 32 bit boolean + Boolean64 = 0x0033, // 64 bit boolean + Boolean128 = 0x0034, // 128 bit boolean }; enum class SimpleTypeMode : uint32_t { @@ -95,7 +103,7 @@ public: uint32_t getIndex() const { return Index; } bool isSimple() const { return Index < FirstNonSimpleIndex; } - bool isNoType() const { return Index == 0; } + bool isNoneType() const { return *this == None(); } SimpleTypeKind getSimpleKind() const { assert(isSimple()); @@ -107,6 +115,7 @@ public: return static_cast(Index & SimpleModeMask); } + static TypeIndex None() { return TypeIndex(SimpleTypeKind::None); } static TypeIndex Void() { return TypeIndex(SimpleTypeKind::Void); } static TypeIndex VoidPointer32() { return TypeIndex(SimpleTypeKind::Void, SimpleTypeMode::NearPointer32); @@ -149,33 +158,34 @@ public: static TypeIndex Float32() { return TypeIndex(SimpleTypeKind::Float32); } static TypeIndex Float64() { return TypeIndex(SimpleTypeKind::Float64); } -private: - support::ulittle32_t Index; -}; + friend inline bool operator==(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() == B.getIndex(); + } -inline bool operator==(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() == B.getIndex(); -} + friend inline bool operator!=(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() != B.getIndex(); + } -inline bool operator!=(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() != B.getIndex(); -} + friend inline bool operator<(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() < B.getIndex(); + } -inline bool operator<(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() < B.getIndex(); -} + friend inline bool operator<=(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() <= B.getIndex(); + } -inline bool operator<=(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() <= B.getIndex(); -} + friend inline bool operator>(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() > B.getIndex(); + } -inline bool operator>(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() > B.getIndex(); -} + friend inline bool operator>=(const TypeIndex &A, const TypeIndex &B) { + return A.getIndex() >= B.getIndex(); + } + +private: + support::ulittle32_t Index; +}; -inline bool operator>=(const TypeIndex &A, const TypeIndex &B) { - return A.getIndex() >= B.getIndex(); -} } } diff --git a/include/llvm/DebugInfo/CodeView/TypeRecord.h b/include/llvm/DebugInfo/CodeView/TypeRecord.h index d6b323c8d8322ab017aff5fc42fbcb6cbcf2e995..42751fbd4af116262b92bdefe767777def5b6c44 100644 --- a/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ b/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -10,11 +10,15 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPERECORD_H #define LLVM_DEBUGINFO_CODEVIEW_TYPERECORD_H +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/ErrorOr.h" #include +#include namespace llvm { namespace codeview { @@ -23,6 +27,79 @@ using llvm::support::little32_t; using llvm::support::ulittle16_t; using llvm::support::ulittle32_t; +/// Equvalent to CV_fldattr_t in cvinfo.h. +struct MemberAttributes { + ulittle16_t Attrs; + enum { + MethodKindShift = 2, + }; + + /// Get the access specifier. Valid for any kind of member. + MemberAccess getAccess() const { + return MemberAccess(unsigned(Attrs) & unsigned(MethodOptions::AccessMask)); + } + + /// Indicates if a method is defined with friend, virtual, static, etc. + MethodKind getMethodKind() const { + return MethodKind( + (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> + MethodKindShift); + } + + /// Get the flags that are not included in access control or method + /// properties. + MethodOptions getFlags() const { + return MethodOptions( + unsigned(Attrs) & + ~unsigned(MethodOptions::AccessMask | MethodOptions::MethodKindMask)); + } + + /// Is this method virtual. + bool isVirtual() const { + auto MP = getMethodKind(); + return MP != MethodKind::Vanilla && MP != MethodKind::Friend && + MP != MethodKind::Static; + } + + /// Does this member introduce a new virtual method. + bool isIntroducedVirtual() const { + auto MP = getMethodKind(); + return MP == MethodKind::IntroducingVirtual || + MP == MethodKind::PureIntroducingVirtual; + } +}; + +// Does not correspond to any tag, this is the tail of an LF_POINTER record +// if it represents a member pointer. +class MemberPointerInfo { +public: + MemberPointerInfo() {} + + MemberPointerInfo(TypeIndex ContainingType, + PointerToMemberRepresentation Representation) + : ContainingType(ContainingType), Representation(Representation) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(ArrayRef &Data); + + TypeIndex getContainingType() const { return ContainingType; } + PointerToMemberRepresentation getRepresentation() const { + return Representation; + } + +private: + struct Layout { + TypeIndex ClassType; + ulittle16_t Representation; // PointerToMemberRepresentation + }; + + TypeIndex ContainingType; + PointerToMemberRepresentation Representation; +}; + class TypeRecord { protected: explicit TypeRecord(TypeRecordKind Kind) : Kind(Kind) {} @@ -34,20 +111,34 @@ private: TypeRecordKind Kind; }; +// LF_MODIFIER class ModifierRecord : public TypeRecord { public: - ModifierRecord(TypeIndex ModifiedType, ModifierOptions Options) + ModifierRecord(TypeIndex ModifiedType, ModifierOptions Modifiers) : TypeRecord(TypeRecordKind::Modifier), ModifiedType(ModifiedType), - Options(Options) {} + Modifiers(Modifiers) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); TypeIndex getModifiedType() const { return ModifiedType; } - ModifierOptions getOptions() const { return Options; } + ModifierOptions getModifiers() const { return Modifiers; } private: + struct Layout { + TypeIndex ModifiedType; + ulittle16_t Modifiers; // ModifierOptions + }; + TypeIndex ModifiedType; - ModifierOptions Options; + ModifierOptions Modifiers; }; +// LF_PROCEDURE class ProcedureRecord : public TypeRecord { public: ProcedureRecord(TypeIndex ReturnType, CallingConvention CallConv, @@ -57,6 +148,15 @@ public: CallConv(CallConv), Options(Options), ParameterCount(ParameterCount), ArgumentList(ArgumentList) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + static uint32_t getLayoutSize() { return 2 + sizeof(Layout); } + TypeIndex getReturnType() const { return ReturnType; } CallingConvention getCallConv() const { return CallConv; } FunctionOptions getOptions() const { return Options; } @@ -64,6 +164,14 @@ public: TypeIndex getArgumentList() const { return ArgumentList; } private: + struct Layout { + TypeIndex ReturnType; + CallingConvention CallConv; + FunctionOptions Options; + ulittle16_t NumParameters; + TypeIndex ArgListType; + }; + TypeIndex ReturnType; CallingConvention CallConv; FunctionOptions Options; @@ -71,6 +179,7 @@ private: TypeIndex ArgumentList; }; +// LF_MFUNCTION class MemberFunctionRecord : public TypeRecord { public: MemberFunctionRecord(TypeIndex ReturnType, TypeIndex ClassType, @@ -83,6 +192,13 @@ public: ArgumentList(ArgumentList), ThisPointerAdjustment(ThisPointerAdjustment) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + TypeIndex getReturnType() const { return ReturnType; } TypeIndex getClassType() const { return ClassType; } TypeIndex getThisType() const { return ThisType; } @@ -93,6 +209,17 @@ public: int32_t getThisPointerAdjustment() const { return ThisPointerAdjustment; } private: + struct Layout { + TypeIndex ReturnType; + TypeIndex ClassType; + TypeIndex ThisType; + CallingConvention CallConv; + FunctionOptions Options; + ulittle16_t NumParameters; + TypeIndex ArgListType; + little32_t ThisAdjustment; + }; + TypeIndex ReturnType; TypeIndex ClassType; TypeIndex ThisType; @@ -103,78 +230,210 @@ private: int32_t ThisPointerAdjustment; }; -class ArgumentListRecord : public TypeRecord { +// LF_MFUNC_ID +class MemberFuncIdRecord : public TypeRecord { public: - explicit ArgumentListRecord(llvm::ArrayRef ArgumentTypes) - : TypeRecord(TypeRecordKind::ArgumentList), ArgumentTypes(ArgumentTypes) { - } + MemberFuncIdRecord(TypeIndex ClassType, TypeIndex FunctionType, + StringRef Name) + : TypeRecord(TypeRecordKind::MemberFuncId), ClassType(ClassType), + FunctionType(FunctionType), Name(Name) {} - llvm::ArrayRef getArgumentTypes() const { return ArgumentTypes; } + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + TypeIndex getClassType() const { return ClassType; } + TypeIndex getFunctionType() const { return FunctionType; } + StringRef getName() const { return Name; } + +private: + struct Layout { + TypeIndex ClassType; + TypeIndex FunctionType; + // Name: The null-terminated name follows. + }; + TypeIndex ClassType; + TypeIndex FunctionType; + StringRef Name; +}; + +// LF_ARGLIST, LF_SUBSTR_LIST +class ArgListRecord : public TypeRecord { +public: + ArgListRecord(TypeRecordKind Kind, ArrayRef Indices) + : TypeRecord(Kind), StringIndices(Indices) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + ArrayRef getIndices() const { return StringIndices; } + + static uint32_t getLayoutSize() { return 2 + sizeof(Layout); } private: - llvm::ArrayRef ArgumentTypes; + struct Layout { + ulittle32_t NumArgs; // Number of arguments + // ArgTypes[]: Type indicies of arguments + }; + + std::vector StringIndices; }; -class PointerRecordBase : public TypeRecord { +// LF_POINTER +class PointerRecord : public TypeRecord { public: - PointerRecordBase(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, - PointerOptions Options, uint8_t Size) + static const uint32_t PointerKindShift = 0; + static const uint32_t PointerKindMask = 0x1F; + + static const uint32_t PointerModeShift = 5; + static const uint32_t PointerModeMask = 0x07; + + static const uint32_t PointerSizeShift = 13; + static const uint32_t PointerSizeMask = 0xFF; + + PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, + PointerOptions Options, uint8_t Size) + : PointerRecord(ReferentType, Kind, Mode, Options, Size, + MemberPointerInfo()) {} + + PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, + PointerOptions Options, uint8_t Size, + const MemberPointerInfo &Member) : TypeRecord(TypeRecordKind::Pointer), ReferentType(ReferentType), - PtrKind(Kind), Mode(Mode), Options(Options), Size(Size) {} + PtrKind(Kind), Mode(Mode), Options(Options), Size(Size), + MemberInfo(Member) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); TypeIndex getReferentType() const { return ReferentType; } PointerKind getPointerKind() const { return PtrKind; } PointerMode getMode() const { return Mode; } PointerOptions getOptions() const { return Options; } uint8_t getSize() const { return Size; } + MemberPointerInfo getMemberInfo() const { return MemberInfo; } + + bool isPointerToMember() const { + return Mode == PointerMode::PointerToDataMember || + Mode == PointerMode::PointerToMemberFunction; + } + bool isFlat() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Flat32)); + } + bool isConst() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Const)); + } + bool isVolatile() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Volatile)); + } + bool isUnaligned() const { + return !!(uint32_t(Options) & uint32_t(PointerOptions::Unaligned)); + } private: + struct Layout { + TypeIndex PointeeType; + ulittle32_t Attrs; // pointer attributes + // if pointer to member: + // PointerToMemberTail + PointerKind getPtrKind() const { + return PointerKind(Attrs & PointerKindMask); + } + PointerMode getPtrMode() const { + return PointerMode((Attrs >> PointerModeShift) & PointerModeMask); + } + uint8_t getPtrSize() const { + return (Attrs >> PointerSizeShift) & PointerSizeMask; + } + bool isFlat() const { return Attrs & (1 << 8); } + bool isVolatile() const { return Attrs & (1 << 9); } + bool isConst() const { return Attrs & (1 << 10); } + bool isUnaligned() const { return Attrs & (1 << 11); } + + bool isPointerToDataMember() const { + return getPtrMode() == PointerMode::PointerToDataMember; + } + bool isPointerToMemberFunction() const { + return getPtrMode() == PointerMode::PointerToMemberFunction; + } + bool isPointerToMember() const { + return isPointerToMemberFunction() || isPointerToDataMember(); + } + }; + TypeIndex ReferentType; PointerKind PtrKind; PointerMode Mode; PointerOptions Options; uint8_t Size; + MemberPointerInfo MemberInfo; }; -class PointerRecord : public PointerRecordBase { +// LF_NESTTYPE +class NestedTypeRecord : public TypeRecord { public: - PointerRecord(TypeIndex ReferentType, PointerKind Kind, PointerMode Mode, - PointerOptions Options, uint8_t Size) - : PointerRecordBase(ReferentType, Kind, Mode, Options, Size) {} -}; + NestedTypeRecord(TypeIndex Type, StringRef Name) + : TypeRecord(TypeRecordKind::NestedType), Type(Type), Name(Name) {} -class PointerToMemberRecord : public PointerRecordBase { -public: - PointerToMemberRecord(TypeIndex ReferentType, PointerKind Kind, - PointerMode Mode, PointerOptions Options, uint8_t Size, - TypeIndex ContainingType, - PointerToMemberRepresentation Representation) - : PointerRecordBase(ReferentType, Kind, Mode, Options, Size), - ContainingType(ContainingType), Representation(Representation) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); - TypeIndex getContainingType() const { return ContainingType; } - PointerToMemberRepresentation getRepresentation() const { - return Representation; - } + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + TypeIndex getNestedType() const { return Type; } + StringRef getName() const { return Name; } private: - TypeIndex ContainingType; - PointerToMemberRepresentation Representation; + struct Layout { + ulittle16_t Pad0; // Should be zero + TypeIndex Type; // Type index of nested type + // Name: Null-terminated string + }; + + TypeIndex Type; + StringRef Name; }; +// LF_ARRAY class ArrayRecord : public TypeRecord { public: ArrayRecord(TypeIndex ElementType, TypeIndex IndexType, uint64_t Size, - llvm::StringRef Name) + StringRef Name) : TypeRecord(TypeRecordKind::Array), ElementType(ElementType), IndexType(IndexType), Size(Size), Name(Name) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + TypeIndex getElementType() const { return ElementType; } TypeIndex getIndexType() const { return IndexType; } uint64_t getSize() const { return Size; } llvm::StringRef getName() const { return Name; } private: + struct Layout { + TypeIndex ElementType; + TypeIndex IndexType; + // SizeOf: LF_NUMERIC encoded size in bytes. Not element count! + // Name: The null-terminated name follows. + }; + TypeIndex ElementType; TypeIndex IndexType; uint64_t Size; @@ -189,6 +448,15 @@ protected: FieldList(FieldList), Name(Name), UniqueName(UniqueName) {} public: + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static const int HfaKindShift = 11; + static const int HfaKindMask = 0x1800; + static const int WinRTKindShift = 14; + static const int WinRTKindMask = 0xC000; + uint16_t getMemberCount() const { return MemberCount; } ClassOptions getOptions() const { return Options; } TypeIndex getFieldList() const { return FieldList; } @@ -203,17 +471,24 @@ private: StringRef UniqueName; }; -class AggregateRecord : public TagRecord { +// LF_CLASS, LF_STRUCTURE, LF_INTERFACE +class ClassRecord : public TagRecord { public: - AggregateRecord(TypeRecordKind Kind, uint16_t MemberCount, - ClassOptions Options, HfaKind Hfa, - WindowsRTClassKind WinRTKind, TypeIndex FieldList, - TypeIndex DerivationList, TypeIndex VTableShape, - uint64_t Size, StringRef Name, StringRef UniqueName) + ClassRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options, + HfaKind Hfa, WindowsRTClassKind WinRTKind, TypeIndex FieldList, + TypeIndex DerivationList, TypeIndex VTableShape, uint64_t Size, + StringRef Name, StringRef UniqueName) : TagRecord(Kind, MemberCount, Options, FieldList, Name, UniqueName), Hfa(Hfa), WinRTKind(WinRTKind), DerivationList(DerivationList), VTableShape(VTableShape), Size(Size) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + HfaKind getHfa() const { return Hfa; } WindowsRTClassKind getWinRTKind() const { return WinRTKind; } TypeIndex getDerivationList() const { return DerivationList; } @@ -221,6 +496,21 @@ public: uint64_t getSize() const { return Size; } private: + struct Layout { + ulittle16_t MemberCount; // Number of members in FieldList. + ulittle16_t Properties; // ClassOptions bitset + TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members + TypeIndex DerivedFrom; // LF_DERIVED: List of known derived classes + TypeIndex VShape; // LF_VTSHAPE: Shape of the vftable + // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC + // integer. + // Name: The null-terminated name follows. + + bool hasUniqueName() const { + return Properties & uint16_t(ClassOptions::HasUniqueName); + } + }; + HfaKind Hfa; WindowsRTClassKind WinRTKind; TypeIndex DerivationList; @@ -228,6 +518,40 @@ private: uint64_t Size; }; +// LF_UNION +struct UnionRecord : public TagRecord { + UnionRecord(uint16_t MemberCount, ClassOptions Options, HfaKind Hfa, + TypeIndex FieldList, uint64_t Size, StringRef Name, + StringRef UniqueName) + : TagRecord(TypeRecordKind::Union, MemberCount, Options, FieldList, Name, + UniqueName), + Hfa(Hfa), Size(Size) {} + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + HfaKind getHfa() const { return Hfa; } + uint64_t getSize() const { return Size; } + +private: + struct Layout { + ulittle16_t MemberCount; // Number of members in FieldList. + ulittle16_t Properties; // ClassOptions bitset + TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members + // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC + // integer. + // Name: The null-terminated name follows. + + bool hasUniqueName() const { + return Properties & uint16_t(ClassOptions::HasUniqueName); + } + }; + + HfaKind Hfa; + uint64_t Size; +}; + +// LF_ENUM class EnumRecord : public TagRecord { public: EnumRecord(uint16_t MemberCount, ClassOptions Options, TypeIndex FieldList, @@ -236,337 +560,642 @@ public: UniqueName), UnderlyingType(UnderlyingType) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + TypeIndex getUnderlyingType() const { return UnderlyingType; } private: + struct Layout { + ulittle16_t NumEnumerators; // Number of enumerators + ulittle16_t Properties; + TypeIndex UnderlyingType; + TypeIndex FieldListType; + // Name: The null-terminated name follows. + + bool hasUniqueName() const { + return Properties & uint16_t(ClassOptions::HasUniqueName); + } + }; + TypeIndex UnderlyingType; }; -class BitFieldRecord : TypeRecord { +// LF_BITFIELD +class BitFieldRecord : public TypeRecord { public: BitFieldRecord(TypeIndex Type, uint8_t BitSize, uint8_t BitOffset) : TypeRecord(TypeRecordKind::BitField), Type(Type), BitSize(BitSize), BitOffset(BitOffset) {} + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + TypeIndex getType() const { return Type; } uint8_t getBitOffset() const { return BitOffset; } uint8_t getBitSize() const { return BitSize; } private: + struct Layout { + TypeIndex Type; + uint8_t BitSize; + uint8_t BitOffset; + }; + TypeIndex Type; uint8_t BitSize; uint8_t BitOffset; }; -class VirtualTableShapeRecord : TypeRecord { +// LF_VTSHAPE +class VFTableShapeRecord : public TypeRecord { public: - explicit VirtualTableShapeRecord(ArrayRef Slots) - : TypeRecord(TypeRecordKind::VirtualTableShape), Slots(Slots) {} + explicit VFTableShapeRecord(ArrayRef Slots) + : TypeRecord(TypeRecordKind::VFTableShape), SlotsRef(Slots) {} + explicit VFTableShapeRecord(std::vector Slots) + : TypeRecord(TypeRecordKind::VFTableShape), Slots(std::move(Slots)) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + ArrayRef getSlots() const { + if (!SlotsRef.empty()) + return SlotsRef; + return Slots; + } + uint32_t getEntryCount() const { return getSlots().size(); } - ArrayRef getSlots() const { return Slots; } +private: + struct Layout { + // Number of vftable entries. Each method may have more than one entry due + // to + // things like covariant return types. + ulittle16_t VFEntryCount; + // Descriptors[]: 4-bit virtual method descriptors of type CV_VTS_desc_e. + }; private: - ArrayRef Slots; + ArrayRef SlotsRef; + std::vector Slots; }; -//===----------------------------------------------------------------------===// -// On-disk representation of type information +// LF_TYPESERVER2 +class TypeServer2Record : public TypeRecord { +public: + TypeServer2Record(StringRef Guid, uint32_t Age, StringRef Name) + : TypeRecord(TypeRecordKind::TypeServer2), Guid(Guid), Age(Age), + Name(Name) {} -// A CodeView type stream is a sequence of TypeRecords. Records larger than -// 65536 must chain on to a second record. Each TypeRecord is followed by one of -// the leaf types described below. -struct TypeRecordPrefix { - ulittle16_t Len; // Type record length, starting from &Leaf. - ulittle16_t Leaf; // Type record kind (TypeLeafKind) -}; + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); -// LF_TYPESERVER2 -struct TypeServer2 { - char Signature[16]; // GUID - ulittle32_t Age; - // Name: Name of the PDB as a null-terminated string + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + StringRef getGuid() const { return Guid; } + + uint32_t getAge() const { return Age; } + + StringRef getName() const { return Name; } + +private: + struct Layout { + char Guid[16]; // GUID + ulittle32_t Age; + // Name: Name of the PDB as a null-terminated string + }; + + StringRef Guid; + uint32_t Age; + StringRef Name; }; // LF_STRING_ID -struct StringId { - TypeIndex id; +class StringIdRecord : public TypeRecord { +public: + StringIdRecord(TypeIndex Id, StringRef String) + : TypeRecord(TypeRecordKind::StringId), Id(Id), String(String) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + TypeIndex getId() const { return Id; } + + StringRef getString() const { return String; } + +private: + struct Layout { + TypeIndex id; + // Name: Name of the PDB as a null-terminated string + }; + + TypeIndex Id; + StringRef String; }; // LF_FUNC_ID -struct FuncId { +class FuncIdRecord : public TypeRecord { +public: + FuncIdRecord(TypeIndex ParentScope, TypeIndex FunctionType, StringRef Name) + : TypeRecord(TypeRecordKind::FuncId), ParentScope(ParentScope), + FunctionType(FunctionType), Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + TypeIndex getParentScope() const { return ParentScope; } + + TypeIndex getFunctionType() const { return FunctionType; } + + StringRef getName() const { return Name; } + +private: + struct Layout { + TypeIndex ParentScope; + TypeIndex FunctionType; + // Name: The null-terminated name follows. + }; + TypeIndex ParentScope; TypeIndex FunctionType; - // Name: The null-terminated name follows. + StringRef Name; }; -// LF_CLASS, LF_STRUCT, LF_INTERFACE -struct ClassType { - ulittle16_t MemberCount; // Number of members in FieldList. - ulittle16_t Properties; // ClassOptions bitset - TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members - TypeIndex DerivedFrom; // LF_DERIVED: List of known derived classes - TypeIndex VShape; // LF_VTSHAPE: Shape of the vftable - // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC integer. - // Name: The null-terminated name follows. -}; +// LF_UDT_SRC_LINE +class UdtSourceLineRecord : public TypeRecord { +public: + UdtSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile, uint32_t LineNumber) + : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT), + SourceFile(SourceFile), LineNumber(LineNumber) {} -// LF_UNION -struct UnionType { - ulittle16_t MemberCount; // Number of members in FieldList. - ulittle16_t Properties; // ClassOptions bitset - TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members - // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC integer. - // Name: The null-terminated name follows. -}; + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); -// LF_POINTER -struct PointerType { - TypeIndex PointeeType; - ulittle32_t Attrs; // pointer attributes - // if pointer to member: - // PointerToMemberTail - - PointerKind getPtrKind() const { return PointerKind(Attrs & 0x1f); } - PointerMode getPtrMode() const { return PointerMode((Attrs >> 5) & 0x07); } - bool isFlat() const { return Attrs & (1 << 8); } - bool isVolatile() const { return Attrs & (1 << 9); } - bool isConst() const { return Attrs & (1 << 10); } - bool isUnaligned() const { return Attrs & (1 << 11); } - - bool isPointerToDataMember() const { - return getPtrMode() == PointerMode::PointerToDataMember; - } - bool isPointerToMemberFunction() const { - return getPtrMode() == PointerMode::PointerToMemberFunction; - } - bool isPointerToMember() const { - return isPointerToMemberFunction() || isPointerToDataMember(); - } -}; + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); -struct PointerToMemberTail { - TypeIndex ClassType; - ulittle16_t Representation; // PointerToMemberRepresentation -}; + TypeIndex getUDT() const { return UDT; } + TypeIndex getSourceFile() const { return SourceFile; } + uint32_t getLineNumber() const { return LineNumber; } -/// In Clang parlance, these are "qualifiers". LF_MODIFIER -struct TypeModifier { - TypeIndex ModifiedType; - ulittle16_t Modifiers; // ModifierOptions +private: + struct Layout { + TypeIndex UDT; // The user-defined type + TypeIndex SourceFile; // StringID containing the source filename + ulittle32_t LineNumber; + }; + + TypeIndex UDT; + TypeIndex SourceFile; + uint32_t LineNumber; }; -// LF_VTSHAPE -struct VTableShape { - // Number of vftable entries. Each method may have more than one entry due to - // things like covariant return types. - ulittle16_t VFEntryCount; - // Descriptors[]: 4-bit virtual method descriptors of type CV_VTS_desc_e. -}; +// LF_UDT_MOD_SRC_LINE +class UdtModSourceLineRecord : public TypeRecord { +public: + UdtModSourceLineRecord(TypeIndex UDT, TypeIndex SourceFile, + uint32_t LineNumber, uint16_t Module) + : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT), + SourceFile(SourceFile), LineNumber(LineNumber), Module(Module) {} -// LF_UDT_SRC_LINE -struct UDTSrcLine { - TypeIndex UDT; // The user-defined type - TypeIndex SourceFile; // StringID containing the source filename - ulittle32_t LineNumber; -}; + bool remapTypeIndices(ArrayRef IndexMap); -// LF_ARGLIST, LF_SUBSTR_LIST -struct ArgList { - ulittle32_t NumArgs; // Number of arguments - // ArgTypes[]: Type indicies of arguments + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data) { + const Layout *L = nullptr; + CV_DESERIALIZE(Data, L); + + return UdtModSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber, + L->Module); + } + + TypeIndex getUDT() const { return UDT; } + TypeIndex getSourceFile() const { return SourceFile; } + uint32_t getLineNumber() const { return LineNumber; } + uint16_t getModule() const { return Module; } + +private: + struct Layout { + TypeIndex UDT; // The user-defined type + TypeIndex SourceFile; // StringID containing the source filename + ulittle32_t LineNumber; + ulittle16_t Module; // Module that contributes this UDT definition + }; + + TypeIndex UDT; + TypeIndex SourceFile; + uint32_t LineNumber; + uint16_t Module; }; // LF_BUILDINFO -struct BuildInfo { - ulittle16_t NumArgs; // Number of arguments - // ArgTypes[]: Type indicies of arguments -}; +class BuildInfoRecord : public TypeRecord { +public: + BuildInfoRecord(ArrayRef ArgIndices) + : TypeRecord(TypeRecordKind::BuildInfo), + ArgIndices(ArgIndices.begin(), ArgIndices.end()) {} -// LF_ENUM -struct EnumType { - ulittle16_t NumEnumerators; // Number of enumerators - ulittle16_t Properties; - TypeIndex UnderlyingType; - TypeIndex FieldListType; - // Name: The null-terminated name follows. -}; + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); -// LF_ARRAY -struct ArrayType { - TypeIndex ElementType; - TypeIndex IndexType; - // SizeOf: LF_NUMERIC encoded size in bytes. Not element count! - // Name: The null-terminated name follows. -}; + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); -// LF_VFTABLE -struct VFTableType { - TypeIndex CompleteClass; // Class that owns this vftable. - TypeIndex OverriddenVFTable; // VFTable that this overrides. - ulittle32_t VFPtrOffset; // VFPtr offset in CompleteClass - ulittle32_t NamesLen; // Length of subsequent names array in bytes. - // Names: A sequence of null-terminated strings. First string is vftable - // names. -}; + ArrayRef getArgs() const { return ArgIndices; } -// LF_MFUNC_ID -struct MemberFuncId { - TypeIndex ClassType; - TypeIndex FunctionType; - // Name: The null-terminated name follows. +private: + struct Layout { + ulittle16_t NumArgs; // Number of arguments + // ArgTypes[]: Type indicies of arguments + }; + SmallVector ArgIndices; }; -// LF_PROCEDURE -struct ProcedureType { - TypeIndex ReturnType; - CallingConvention CallConv; - FunctionOptions Options; - ulittle16_t NumParameters; - TypeIndex ArgListType; -}; +// LF_VFTABLE +class VFTableRecord : public TypeRecord { +public: + VFTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable, + uint32_t VFPtrOffset, StringRef Name, + ArrayRef Methods) + : TypeRecord(TypeRecordKind::VFTable), + CompleteClass(CompleteClass), OverriddenVFTable(OverriddenVFTable), + VFPtrOffset(VFPtrOffset), Name(Name), MethodNamesRef(Methods) {} + VFTableRecord(TypeIndex CompleteClass, TypeIndex OverriddenVFTable, + uint32_t VFPtrOffset, StringRef Name, + const std::vector &Methods) + : TypeRecord(TypeRecordKind::VFTable), + CompleteClass(CompleteClass), OverriddenVFTable(OverriddenVFTable), + VFPtrOffset(VFPtrOffset), Name(Name), MethodNames(Methods) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + TypeIndex getCompleteClass() const { return CompleteClass; } + TypeIndex getOverriddenVTable() const { return OverriddenVFTable; } + uint32_t getVFPtrOffset() const { return VFPtrOffset; } + StringRef getName() const { return Name; } + ArrayRef getMethodNames() const { + if (!MethodNamesRef.empty()) + return MethodNamesRef; + return MethodNames; + } -// LF_MFUNCTION -struct MemberFunctionType { - TypeIndex ReturnType; - TypeIndex ClassType; - TypeIndex ThisType; - CallingConvention CallConv; - FunctionOptions Options; - ulittle16_t NumParameters; - TypeIndex ArgListType; - little32_t ThisAdjustment; +private: + struct Layout { + TypeIndex CompleteClass; // Class that owns this vftable. + TypeIndex OverriddenVFTable; // VFTable that this overrides. + ulittle32_t VFPtrOffset; // VFPtr offset in CompleteClass + ulittle32_t NamesLen; // Length of subsequent names array in bytes. + // Names: A sequence of null-terminated strings. First string is vftable + // names. + }; + + TypeIndex CompleteClass; + TypeIndex OverriddenVFTable; + ulittle32_t VFPtrOffset; + StringRef Name; + ArrayRef MethodNamesRef; + std::vector MethodNames; }; -//===----------------------------------------------------------------------===// -// Field list records, which do not include leafs or sizes +// LF_ONEMETHOD +class OneMethodRecord : public TypeRecord { +public: + OneMethodRecord(TypeIndex Type, MethodKind Kind, MethodOptions Options, + MemberAccess Access, int32_t VFTableOffset, StringRef Name) + : TypeRecord(TypeRecordKind::OneMethod), Type(Type), Kind(Kind), + Options(Options), Access(Access), VFTableOffset(VFTableOffset), + Name(Name) {} -/// Equvalent to CV_fldattr_t in cvinfo.h. -struct MemberAttributes { - ulittle16_t Attrs; + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); - /// Get the access specifier. Valid for any kind of member. - MemberAccess getAccess() const { - return MemberAccess(unsigned(Attrs) & unsigned(MethodOptions::AccessMask)); - } + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); - /// Indicates if a method is defined with friend, virtual, static, etc. - MethodKind getMethodKind() const { - return MethodKind( - (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> 2); - } - - /// Get the flags that are not included in access control or method - /// properties. - MethodOptions getFlags() const { - return MethodOptions( - unsigned(Attrs) & - ~unsigned(MethodOptions::AccessMask | MethodOptions::MethodKindMask)); - } + TypeIndex getType() const { return Type; } + MethodKind getKind() const { return Kind; } + MethodOptions getOptions() const { return Options; } + MemberAccess getAccess() const { return Access; } + int32_t getVFTableOffset() const { return VFTableOffset; } + StringRef getName() const { return Name; } - /// Is this method virtual. - bool isVirtual() const { - auto MP = getMethodKind(); - return MP != MethodKind::Vanilla && MP != MethodKind::Friend && - MP != MethodKind::Static; + bool isIntroducingVirtual() const { + return Kind == MethodKind::IntroducingVirtual || + Kind == MethodKind::PureIntroducingVirtual; } - /// Does this member introduce a new virtual method. - bool isIntroducedVirtual() const { - auto MP = getMethodKind(); - return MP == MethodKind::IntroducingVirtual || - MP == MethodKind::PureIntroducingVirtual; - } -}; +private: + struct Layout { + MemberAttributes Attrs; + TypeIndex Type; + // If is introduced virtual method: + // VFTableOffset: int32_t offset in vftable + // Name: Null-terminated string + }; -// LF_NESTTYPE -struct NestedType { - ulittle16_t Pad0; // Should be zero - TypeIndex Type; // Type index of nested type - // Name: Null-terminated string + TypeIndex Type; + MethodKind Kind; + MethodOptions Options; + MemberAccess Access; + int32_t VFTableOffset; + StringRef Name; }; -// LF_ONEMETHOD -struct OneMethod { - MemberAttributes Attrs; - TypeIndex Type; - // If is introduced virtual method: - // VFTableOffset: int32_t offset in vftable - // Name: Null-terminated string +// LF_METHODLIST +class MethodOverloadListRecord : public TypeRecord { +public: + MethodOverloadListRecord(ArrayRef Methods) + : TypeRecord(TypeRecordKind::MethodOverloadList), Methods(Methods) {} - MethodKind getMethodKind() const { - return Attrs.getMethodKind(); - } + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); - bool isVirtual() const { return Attrs.isVirtual(); } - bool isIntroducedVirtual() const { return Attrs.isIntroducedVirtual(); } -}; + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); -struct MethodListEntry { - MemberAttributes Attrs; - ulittle16_t Padding; + ArrayRef getMethods() const { return Methods; } - TypeIndex Type; - // If is introduced virtual method: - // VFTableOffset: int32_t offset in vftable +private: + struct Layout { + MemberAttributes Attrs; + ulittle16_t Padding; - MethodKind getMethodKind() const { - return Attrs.getMethodKind(); - } + TypeIndex Type; + // If is introduced virtual method: + // VFTableOffset: int32_t offset in vftable + }; - bool isVirtual() const { return Attrs.isVirtual(); } - bool isIntroducedVirtual() const { return Attrs.isIntroducedVirtual(); } + std::vector Methods; }; /// For method overload sets. LF_METHOD -struct OverloadedMethod { - ulittle16_t MethodCount; // Size of overload set - TypeIndex MethList; // Type index of methods in overload set - // Name: Null-terminated string -}; +class OverloadedMethodRecord : public TypeRecord { +public: + OverloadedMethodRecord(uint16_t NumOverloads, TypeIndex MethodList, + StringRef Name) + : TypeRecord(TypeRecordKind::OverloadedMethod), + NumOverloads(NumOverloads), MethodList(MethodList), Name(Name) {} -// LF_VFUNCTAB -struct VirtualFunctionPointer { - ulittle16_t Pad0; - TypeIndex Type; // Type of vfptr + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + uint16_t getNumOverloads() const { return NumOverloads; } + TypeIndex getMethodList() const { return MethodList; } + StringRef getName() const { return Name; } + +private: + struct Layout { + ulittle16_t MethodCount; // Size of overload set + TypeIndex MethList; // Type index of methods in overload set + // Name: Null-terminated string + }; + + uint16_t NumOverloads; + TypeIndex MethodList; + StringRef Name; }; // LF_MEMBER -struct DataMember { - MemberAttributes Attrs; // Access control attributes, etc +class DataMemberRecord : public TypeRecord { +public: + DataMemberRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset, + StringRef Name) + : TypeRecord(TypeRecordKind::DataMember), Access(Access), Type(Type), + FieldOffset(Offset), Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + MemberAccess getAccess() const { return Access; } + TypeIndex getType() const { return Type; } + uint64_t getFieldOffset() const { return FieldOffset; } + StringRef getName() const { return Name; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex Type; + // FieldOffset: LF_NUMERIC encoded byte offset + // Name: Null-terminated string + }; + + MemberAccess Access; TypeIndex Type; - // FieldOffset: LF_NUMERIC encoded byte offset - // Name: Null-terminated string + uint64_t FieldOffset; + StringRef Name; }; // LF_STMEMBER -struct StaticDataMember { - MemberAttributes Attrs; // Access control attributes, etc +class StaticDataMemberRecord : public TypeRecord { +public: + StaticDataMemberRecord(MemberAccess Access, TypeIndex Type, StringRef Name) + : TypeRecord(TypeRecordKind::StaticDataMember), Access(Access), + Type(Type), Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + MemberAccess getAccess() const { return Access; } + TypeIndex getType() const { return Type; } + StringRef getName() const { return Name; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex Type; + // Name: Null-terminated string + }; + + MemberAccess Access; TypeIndex Type; - // Name: Null-terminated string + StringRef Name; }; // LF_ENUMERATE -struct Enumerator { - MemberAttributes Attrs; // Access control attributes, etc - // EnumValue: LF_NUMERIC encoded enumerator value - // Name: Null-terminated string +class EnumeratorRecord : public TypeRecord { +public: + EnumeratorRecord(MemberAccess Access, APSInt Value, StringRef Name) + : TypeRecord(TypeRecordKind::Enumerator), Access(Access), + Value(std::move(Value)), Name(Name) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + MemberAccess getAccess() const { return Access; } + APSInt getValue() const { return Value; } + StringRef getName() const { return Name; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + // EnumValue: LF_NUMERIC encoded enumerator value + // Name: Null-terminated string + }; + + MemberAccess Access; + APSInt Value; + StringRef Name; +}; + +// LF_VFUNCTAB +class VFPtrRecord : public TypeRecord { +public: + VFPtrRecord(TypeIndex Type) + : TypeRecord(TypeRecordKind::VFPtr), Type(Type) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + TypeIndex getType() const { return Type; } + +private: + struct Layout { + ulittle16_t Pad0; + TypeIndex Type; // Type of vfptr + }; + TypeIndex Type; }; // LF_BCLASS, LF_BINTERFACE -struct BaseClass { - MemberAttributes Attrs; // Access control attributes, etc - TypeIndex BaseType; // Base class type - // BaseOffset: LF_NUMERIC encoded byte offset of base from derived. +class BaseClassRecord : public TypeRecord { +public: + BaseClassRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset) + : TypeRecord(TypeRecordKind::BaseClass), Access(Access), Type(Type), + Offset(Offset) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + MemberAccess getAccess() const { return Access; } + TypeIndex getBaseType() const { return Type; } + uint64_t getBaseOffset() const { return Offset; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex BaseType; // Base class type + // BaseOffset: LF_NUMERIC encoded byte offset of base from derived. + }; + MemberAccess Access; + TypeIndex Type; + uint64_t Offset; +}; + +// LF_VBCLASS, LF_IVBCLASS +class VirtualBaseClassRecord : public TypeRecord { +public: + VirtualBaseClassRecord(MemberAccess Access, TypeIndex BaseType, + TypeIndex VBPtrType, uint64_t Offset, uint64_t Index) + : TypeRecord(TypeRecordKind::VirtualBaseClass), Access(Access), + BaseType(BaseType), VBPtrType(VBPtrType), VBPtrOffset(Offset), + VTableIndex(Index) {} + + /// Rewrite member type indices with IndexMap. Returns false if a type index + /// is not in the map. + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + + MemberAccess getAccess() const { return Access; } + TypeIndex getBaseType() const { return BaseType; } + TypeIndex getVBPtrType() const { return VBPtrType; } + uint64_t getVBPtrOffset() const { return VBPtrOffset; } + uint64_t getVTableIndex() const { return VTableIndex; } + +private: + struct Layout { + MemberAttributes Attrs; // Access control attributes, etc. + TypeIndex BaseType; // Base class type + TypeIndex VBPtrType; // Virtual base pointer type + // VBPtrOffset: Offset of vbptr from vfptr encoded as LF_NUMERIC. + // VBTableIndex: Index of vbase within vbtable encoded as LF_NUMERIC. + }; + MemberAccess Access; + TypeIndex BaseType; + TypeIndex VBPtrType; + uint64_t VBPtrOffset; + uint64_t VTableIndex; }; -// LF_VBCLASS | LV_IVBCLASS -struct VirtualBaseClass { - MemberAttributes Attrs; // Access control attributes, etc. - TypeIndex BaseType; // Base class type - TypeIndex VBPtrType; // Virtual base pointer type - // VBPtrOffset: Offset of vbptr from vfptr encoded as LF_NUMERIC. - // VBTableIndex: Index of vbase within vbtable encoded as LF_NUMERIC. +/// LF_INDEX - Used to chain two large LF_FIELDLIST or LF_METHODLIST records +/// together. The first will end in an LF_INDEX record that points to the next. +class ListContinuationRecord : public TypeRecord { +public: + ListContinuationRecord(TypeIndex ContinuationIndex) + : TypeRecord(TypeRecordKind::ListContinuation), + ContinuationIndex(ContinuationIndex) {} + + TypeIndex getContinuationIndex() const { return ContinuationIndex; } + + bool remapTypeIndices(ArrayRef IndexMap); + + static ErrorOr deserialize(TypeRecordKind Kind, + ArrayRef &Data); + +private: + struct Layout { + ulittle16_t Pad0; + TypeIndex ContinuationIndex; + }; + TypeIndex ContinuationIndex; }; + +typedef CVRecord CVType; +typedef VarStreamArray CVTypeArray; } } diff --git a/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h b/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h index 1f48cf70666df49bc87527100e81e5c38475dfb2..eb7993baab8949d5160c7c5d5c5aa9834f4d6244 100644 --- a/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h +++ b/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h @@ -10,9 +10,10 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPERECORDBUILDER_H #define LLVM_DEBUGINFO_CODEVIEW_TYPERECORDBUILDER_H +#include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/raw_ostream.h" @@ -39,13 +40,25 @@ public: void writeEncodedInteger(int64_t Value); void writeEncodedSignedInteger(int64_t Value); void writeEncodedUnsignedInteger(uint64_t Value); - void writeNullTerminatedString(const char *Value); void writeNullTerminatedString(StringRef Value); + void writeGuid(StringRef Guid); + void writeBytes(StringRef Value) { Stream << Value; } llvm::StringRef str(); uint64_t size() const { return Stream.tell(); } + void truncate(uint64_t Size) { + // This works because raw_svector_ostream is not buffered. + assert(Size < Buffer.size()); + Buffer.resize(Size); + } + + void reset(TypeRecordKind K) { + Buffer.clear(); + writeTypeRecordKind(K); + } + private: llvm::SmallVector Buffer; llvm::raw_svector_ostream Stream; diff --git a/include/llvm/DebugInfo/CodeView/TypeRecords.def b/include/llvm/DebugInfo/CodeView/TypeRecords.def new file mode 100644 index 0000000000000000000000000000000000000000..0959f4bf19c7110ab5c84114f5cab34202f4a0e9 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeRecords.def @@ -0,0 +1,252 @@ + +//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// See LEAF_ENUM_e in cvinfo.h. This should match the constants there. +// +//===----------------------------------------------------------------------===// + +// If the type is known, then we have a record describing it in TypeRecord.h. + +#ifndef CV_TYPE +#define CV_TYPE(lf_ename, value) +#endif + +// If the type is known, then we have a record describing it in TypeRecord.h. +#ifndef TYPE_RECORD +#define TYPE_RECORD(lf_ename, value, name) CV_TYPE(lf_ename, value) +#endif + +#ifndef TYPE_RECORD_ALIAS +#define TYPE_RECORD_ALIAS(lf_ename, value, name, alias_name) \ + TYPE_RECORD(lf_ename, value, name) +#endif + +#ifndef MEMBER_RECORD +#define MEMBER_RECORD(lf_ename, value, name) TYPE_RECORD(lf_ename, value, name) +#endif + +#ifndef MEMBER_RECORD_ALIAS +#define MEMBER_RECORD_ALIAS(lf_ename, value, name, alias_name) \ + MEMBER_RECORD(lf_ename, value, name) +#endif + +TYPE_RECORD(LF_POINTER, 0x1002, Pointer) +TYPE_RECORD(LF_MODIFIER, 0x1001, Modifier) +TYPE_RECORD(LF_PROCEDURE, 0x1008, Procedure) +TYPE_RECORD(LF_MFUNCTION, 0x1009, MemberFunction) +TYPE_RECORD(LF_ARGLIST, 0x1201, ArgList) + +TYPE_RECORD(LF_ARRAY, 0x1503, Array) +TYPE_RECORD(LF_CLASS, 0x1504, Class) +TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class) +TYPE_RECORD_ALIAS(LF_INTERFACE, 0x1519, Interface, Class) +TYPE_RECORD(LF_UNION, 0x1506, Union) +TYPE_RECORD(LF_ENUM, 0x1507, Enum) +TYPE_RECORD(LF_TYPESERVER2, 0x1515, TypeServer2) +TYPE_RECORD(LF_VFTABLE, 0x151d, VFTable) +TYPE_RECORD(LF_VTSHAPE, 0x000a, VFTableShape) + +TYPE_RECORD(LF_BITFIELD, 0x1205, BitField) + +// Member type records. These are generally not length prefixed, and appear +// inside of a field list record. +MEMBER_RECORD(LF_BCLASS, 0x1400, BaseClass) +MEMBER_RECORD_ALIAS(LF_BINTERFACE, 0x151a, BaseInterface, BaseClass) + +MEMBER_RECORD(LF_VBCLASS, 0x1401, VirtualBaseClass) +MEMBER_RECORD_ALIAS(LF_IVBCLASS, 0x1402, IndirectVirtualBaseClass, + VirtualBaseClass) + +MEMBER_RECORD(LF_VFUNCTAB, 0x1409, VFPtr) +MEMBER_RECORD(LF_STMEMBER, 0x150e, StaticDataMember) +MEMBER_RECORD(LF_METHOD, 0x150f, OverloadedMethod) +MEMBER_RECORD(LF_MEMBER, 0x150d, DataMember) +MEMBER_RECORD(LF_NESTTYPE, 0x1510, NestedType) +MEMBER_RECORD(LF_ONEMETHOD, 0x1511, OneMethod) +MEMBER_RECORD(LF_ENUMERATE, 0x1502, Enumerator) +MEMBER_RECORD(LF_INDEX, 0x1404, ListContinuation) + +// ID leaf records. Subsequent leaf types may be referenced from .debug$S. +TYPE_RECORD(LF_FUNC_ID, 0x1601, FuncId) +TYPE_RECORD(LF_MFUNC_ID, 0x1602, MemberFuncId) +TYPE_RECORD(LF_BUILDINFO, 0x1603, BuildInfo) +// FIXME: We reuse the structure of ArgListRecord for substring lists, but it +// makes for confusing dumper output. +TYPE_RECORD_ALIAS(LF_SUBSTR_LIST, 0x1604, StringList, ArgList) +TYPE_RECORD(LF_STRING_ID, 0x1605, StringId) +TYPE_RECORD(LF_UDT_SRC_LINE, 0x1606, UdtSourceLine) +TYPE_RECORD(LF_UDT_MOD_SRC_LINE, 0x1607, UdtModSourceLine) + + +TYPE_RECORD(LF_METHODLIST, 0x1206, MethodOverloadList) + + +// 16 bit type records. +CV_TYPE(LF_MODIFIER_16t, 0x0001) +CV_TYPE(LF_POINTER_16t, 0x0002) +CV_TYPE(LF_ARRAY_16t, 0x0003) +CV_TYPE(LF_CLASS_16t, 0x0004) +CV_TYPE(LF_STRUCTURE_16t, 0x0005) +CV_TYPE(LF_UNION_16t, 0x0006) +CV_TYPE(LF_ENUM_16t, 0x0007) +CV_TYPE(LF_PROCEDURE_16t, 0x0008) +CV_TYPE(LF_MFUNCTION_16t, 0x0009) +CV_TYPE(LF_COBOL0_16t, 0x000b) +CV_TYPE(LF_COBOL1, 0x000c) +CV_TYPE(LF_BARRAY_16t, 0x000d) +CV_TYPE(LF_LABEL, 0x000e) +CV_TYPE(LF_NULLLEAF, 0x000f) // LF_NULL +CV_TYPE(LF_NOTTRAN, 0x0010) +CV_TYPE(LF_DIMARRAY_16t, 0x0011) +CV_TYPE(LF_VFTPATH_16t, 0x0012) +CV_TYPE(LF_PRECOMP_16t, 0x0013) +CV_TYPE(LF_ENDPRECOMP, 0x0014) +CV_TYPE(LF_OEM_16t, 0x0015) +CV_TYPE(LF_TYPESERVER_ST, 0x0016) + +CV_TYPE(LF_SKIP_16t, 0x0200) +CV_TYPE(LF_ARGLIST_16t, 0x0201) +CV_TYPE(LF_DEFARG_16t, 0x0202) +CV_TYPE(LF_LIST, 0x0203) +CV_TYPE(LF_FIELDLIST_16t, 0x0204) +CV_TYPE(LF_DERIVED_16t, 0x0205) +CV_TYPE(LF_BITFIELD_16t, 0x0206) +CV_TYPE(LF_METHODLIST_16t, 0x0207) +CV_TYPE(LF_DIMCONU_16t, 0x0208) +CV_TYPE(LF_DIMCONLU_16t, 0x0209) +CV_TYPE(LF_DIMVARU_16t, 0x020a) +CV_TYPE(LF_DIMVARLU_16t, 0x020b) +CV_TYPE(LF_REFSYM, 0x020c) + +// 16 bit member types. Generally not length prefixed. +CV_TYPE(LF_BCLASS_16t, 0x0400) +CV_TYPE(LF_VBCLASS_16t, 0x0401) +CV_TYPE(LF_IVBCLASS_16t, 0x0402) +CV_TYPE(LF_ENUMERATE_ST, 0x0403) +CV_TYPE(LF_FRIENDFCN_16t, 0x0404) +CV_TYPE(LF_INDEX_16t, 0x0405) +CV_TYPE(LF_MEMBER_16t, 0x0406) +CV_TYPE(LF_STMEMBER_16t, 0x0407) +CV_TYPE(LF_METHOD_16t, 0x0408) +CV_TYPE(LF_NESTTYPE_16t, 0x0409) +CV_TYPE(LF_VFUNCTAB_16t, 0x040a) +CV_TYPE(LF_FRIENDCLS_16t, 0x040b) +CV_TYPE(LF_ONEMETHOD_16t, 0x040c) +CV_TYPE(LF_VFUNCOFF_16t, 0x040d) + +CV_TYPE(LF_TI16_MAX, 0x1000) + +CV_TYPE(LF_ARRAY_ST, 0x1003) +CV_TYPE(LF_CLASS_ST, 0x1004) +CV_TYPE(LF_STRUCTURE_ST, 0x1005) +CV_TYPE(LF_UNION_ST, 0x1006) +CV_TYPE(LF_ENUM_ST, 0x1007) +CV_TYPE(LF_COBOL0, 0x100a) +CV_TYPE(LF_BARRAY, 0x100b) +CV_TYPE(LF_DIMARRAY_ST, 0x100c) +CV_TYPE(LF_VFTPATH, 0x100d) +CV_TYPE(LF_PRECOMP_ST, 0x100e) +CV_TYPE(LF_OEM, 0x100f) +CV_TYPE(LF_ALIAS_ST, 0x1010) +CV_TYPE(LF_OEM2, 0x1011) + +CV_TYPE(LF_SKIP, 0x1200) +CV_TYPE(LF_DEFARG_ST, 0x1202) +CV_TYPE(LF_FIELDLIST, 0x1203) +CV_TYPE(LF_DERIVED, 0x1204) +CV_TYPE(LF_DIMCONU, 0x1207) +CV_TYPE(LF_DIMCONLU, 0x1208) +CV_TYPE(LF_DIMVARU, 0x1209) +CV_TYPE(LF_DIMVARLU, 0x120a) + +// Member type records. These are generally not length prefixed, and appear +// inside of a field list record. +CV_TYPE(LF_FRIENDFCN_ST, 0x1403) +CV_TYPE(LF_MEMBER_ST, 0x1405) +CV_TYPE(LF_STMEMBER_ST, 0x1406) +CV_TYPE(LF_METHOD_ST, 0x1407) +CV_TYPE(LF_NESTTYPE_ST, 0x1408) +CV_TYPE(LF_FRIENDCLS, 0x140a) +CV_TYPE(LF_ONEMETHOD_ST, 0x140b) +CV_TYPE(LF_VFUNCOFF, 0x140c) +CV_TYPE(LF_NESTTYPEEX_ST, 0x140d) +CV_TYPE(LF_MEMBERMODIFY_ST, 0x140e) +CV_TYPE(LF_MANAGED_ST, 0x140f) + +CV_TYPE(LF_ST_MAX, 0x1500) +CV_TYPE(LF_TYPESERVER, 0x1501) +CV_TYPE(LF_DIMARRAY, 0x1508) +CV_TYPE(LF_PRECOMP, 0x1509) +CV_TYPE(LF_ALIAS, 0x150a) +CV_TYPE(LF_DEFARG, 0x150b) +CV_TYPE(LF_FRIENDFCN, 0x150c) +CV_TYPE(LF_NESTTYPEEX, 0x1512) +CV_TYPE(LF_MEMBERMODIFY, 0x1513) +CV_TYPE(LF_MANAGED, 0x1514) +CV_TYPE(LF_STRIDED_ARRAY, 0x1516) +CV_TYPE(LF_HLSL, 0x1517) +CV_TYPE(LF_MODIFIER_EX, 0x1518) +CV_TYPE(LF_VECTOR, 0x151b) +CV_TYPE(LF_MATRIX, 0x151c) + +// ID leaf records. Subsequent leaf types may be referenced from .debug$S. + +// Numeric leaf types. These are generally contained in other records, and not +// encountered in the main type stream. + +CV_TYPE(LF_NUMERIC, 0x8000) +CV_TYPE(LF_CHAR, 0x8000) +CV_TYPE(LF_SHORT, 0x8001) +CV_TYPE(LF_USHORT, 0x8002) +CV_TYPE(LF_LONG, 0x8003) +CV_TYPE(LF_ULONG, 0x8004) +CV_TYPE(LF_REAL32, 0x8005) +CV_TYPE(LF_REAL64, 0x8006) +CV_TYPE(LF_REAL80, 0x8007) +CV_TYPE(LF_REAL128, 0x8008) +CV_TYPE(LF_QUADWORD, 0x8009) +CV_TYPE(LF_UQUADWORD, 0x800a) +CV_TYPE(LF_REAL48, 0x800b) +CV_TYPE(LF_COMPLEX32, 0x800c) +CV_TYPE(LF_COMPLEX64, 0x800d) +CV_TYPE(LF_COMPLEX80, 0x800e) +CV_TYPE(LF_COMPLEX128, 0x800f) +CV_TYPE(LF_VARSTRING, 0x8010) +CV_TYPE(LF_OCTWORD, 0x8017) +CV_TYPE(LF_UOCTWORD, 0x8018) +CV_TYPE(LF_DECIMAL, 0x8019) +CV_TYPE(LF_DATE, 0x801a) +CV_TYPE(LF_UTF8STRING, 0x801b) +CV_TYPE(LF_REAL16, 0x801c) + +// Padding bytes. These are emitted into alignment bytes in the type stream. + +CV_TYPE(LF_PAD0, 0xf0) +CV_TYPE(LF_PAD1, 0xf1) +CV_TYPE(LF_PAD2, 0xf2) +CV_TYPE(LF_PAD3, 0xf3) +CV_TYPE(LF_PAD4, 0xf4) +CV_TYPE(LF_PAD5, 0xf5) +CV_TYPE(LF_PAD6, 0xf6) +CV_TYPE(LF_PAD7, 0xf7) +CV_TYPE(LF_PAD8, 0xf8) +CV_TYPE(LF_PAD9, 0xf9) +CV_TYPE(LF_PAD10, 0xfa) +CV_TYPE(LF_PAD11, 0xfb) +CV_TYPE(LF_PAD12, 0xfc) +CV_TYPE(LF_PAD13, 0xfd) +CV_TYPE(LF_PAD14, 0xfe) +CV_TYPE(LF_PAD15, 0xff) + +#undef CV_TYPE +#undef TYPE_RECORD +#undef TYPE_RECORD_ALIAS +#undef MEMBER_RECORD +#undef MEMBER_RECORD_ALIAS diff --git a/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h new file mode 100644 index 0000000000000000000000000000000000000000..af396c79d074199cc4289edde0eae174295c117b --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h @@ -0,0 +1,26 @@ +//===- TypeStreamMerger.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" + +namespace llvm { +namespace codeview { + +/// Merges one type stream into another. Returns true on success. +bool mergeTypeStreams(TypeTableBuilder &DestStream, const CVTypeArray &Types); + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H diff --git a/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h b/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h index 9de110e8236fd3aff5b27937d4abe05d4dc7d477..dfba83d62fcee45d7d57779dd5682e9feb4511c5 100644 --- a/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h +++ b/include/llvm/DebugInfo/CodeView/TypeSymbolEmitter.h @@ -10,11 +10,12 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESYMBOLEMITTER_H #define LLVM_DEBUGINFO_CODEVIEW_TYPESYMBOLEMITTER_H -#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" namespace llvm { +class StringRef; + namespace codeview { class TypeSymbolEmitter { diff --git a/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h index 2c950e8af792b25ac39f968159e0ac0fbf39317e..5b2aa6186147029d733bbce0be0b3a34f5822524 100644 --- a/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ b/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h @@ -10,13 +10,15 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H #define LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H -#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/Support/Compiler.h" namespace llvm { + +class StringRef; + namespace codeview { class FieldListRecordBuilder; @@ -38,20 +40,28 @@ public: TypeIndex writeModifier(const ModifierRecord &Record); TypeIndex writeProcedure(const ProcedureRecord &Record); TypeIndex writeMemberFunction(const MemberFunctionRecord &Record); - TypeIndex writeArgumentList(const ArgumentListRecord &Record); - TypeIndex writeRecord(TypeRecordBuilder &builder); + TypeIndex writeArgList(const ArgListRecord &Record); TypeIndex writePointer(const PointerRecord &Record); - TypeIndex writePointerToMember(const PointerToMemberRecord &Record); TypeIndex writeArray(const ArrayRecord &Record); - TypeIndex writeAggregate(const AggregateRecord &Record); + TypeIndex writeClass(const ClassRecord &Record); + TypeIndex writeUnion(const UnionRecord &Record); TypeIndex writeEnum(const EnumRecord &Record); TypeIndex writeBitField(const BitFieldRecord &Record); - TypeIndex writeVirtualTableShape(const VirtualTableShapeRecord &Record); + TypeIndex writeVFTableShape(const VFTableShapeRecord &Record); + TypeIndex writeStringId(const StringIdRecord &Record); + TypeIndex writeVFTable(const VFTableRecord &Record); + TypeIndex writeUdtSourceLine(const UdtSourceLineRecord &Record); + TypeIndex writeUdtModSourceLine(const UdtModSourceLineRecord &Record); + TypeIndex writeFuncId(const FuncIdRecord &Record); + TypeIndex writeMemberFuncId(const MemberFuncIdRecord &Record); + TypeIndex writeBuildInfo(const BuildInfoRecord &Record); + TypeIndex writeMethodOverloadList(const MethodOverloadListRecord &Record); + TypeIndex writeTypeServer2(const TypeServer2Record &Record); TypeIndex writeFieldList(FieldListRecordBuilder &FieldList); - TypeIndex writeMethodList(MethodListRecordBuilder &MethodList); -private: + TypeIndex writeRecord(TypeRecordBuilder &builder); + virtual TypeIndex writeRecord(llvm::StringRef record) = 0; }; } diff --git a/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h b/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h new file mode 100644 index 0000000000000000000000000000000000000000..310847ec5d2dca32acea4f2eb4d41fa64aabc9dc --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h @@ -0,0 +1,63 @@ +//===- TypeVisitorCallbacks.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEVISITORCALLBACKS_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPEVISITORCALLBACKS_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { +class TypeVisitorCallbacks { + friend class CVTypeVisitor; + +public: + virtual ~TypeVisitorCallbacks() {} + + /// Action to take on unknown types. By default, they are ignored. + virtual Error visitUnknownType(const CVRecord &Record) { + return Error::success(); + } + virtual Error visitUnknownMember(const CVRecord &Record) { + return Error::success(); + } + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + virtual Error visitTypeBegin(const CVRecord &Record) { + return Error::success(); + } + virtual Error visitTypeEnd(const CVRecord &Record) { + return Error::success(); + } + + virtual Error visitFieldListBegin(const CVRecord &Record) { + return Error::success(); + } + + virtual Error visitFieldListEnd(const CVRecord &Record) { + return Error::success(); + } + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + virtual Error visit##Name(Name##Record &Record) { return Error::success(); } +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "TypeRecords.def" +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/DIContext.h b/include/llvm/DebugInfo/DIContext.h index 769c45d4b20a0a33dc3b02404c1805c13930ffff..2f88371979ea880f28051e8e651957ff815ab39e 100644 --- a/include/llvm/DebugInfo/DIContext.h +++ b/include/llvm/DebugInfo/DIContext.h @@ -15,10 +15,8 @@ #ifndef LLVM_DEBUGINFO_DICONTEXT_H #define LLVM_DEBUGINFO_DICONTEXT_H -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Object/RelocVisitor.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DataTypes.h" #include diff --git a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h index bae3154b3b5f25ec80539fce8fd03186032a1999..bba3abe6e9e96ea30974004ad8075ad04649b330 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFCompileUnit.h @@ -19,10 +19,10 @@ public: DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, bool LE, - const DWARFUnitSectionBase &UnitSection, + bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, UnitSection, - Entry) {} + : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection, Entry) {} void dump(raw_ostream &OS); static const DWARFSectionKind Section = DW_SECT_INFO; // VTable anchor. diff --git a/include/llvm/DebugInfo/DWARF/DWARFContext.h b/include/llvm/DebugInfo/DWARF/DWARFContext.h index 5a363bc0f3266f29c0dc863539c20d132a879bfa..741a31cb582b4e78cc4f4eb96c6aae7c8ab4a37b 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -22,7 +22,6 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" -#include namespace llvm { @@ -40,7 +39,7 @@ typedef DenseMap > RelocAddrMap; class DWARFContext : public DIContext { DWARFUnitSection CUs; - std::vector> TUs; + std::deque> TUs; std::unique_ptr CUIndex; std::unique_ptr TUIndex; std::unique_ptr Abbrev; @@ -52,7 +51,7 @@ class DWARFContext : public DIContext { std::unique_ptr Macro; DWARFUnitSection DWOCUs; - std::vector> DWOTUs; + std::deque> DWOTUs; std::unique_ptr AbbrevDWO; std::unique_ptr LocDWO; @@ -87,7 +86,7 @@ public: typedef DWARFUnitSection::iterator_range cu_iterator_range; typedef DWARFUnitSection::iterator_range tu_iterator_range; - typedef iterator_range>::iterator> tu_section_iterator_range; + typedef iterator_range tu_section_iterator_range; /// Get compile units in this context. cu_iterator_range compile_units() { diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h b/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h index 21142089da6bb02c5acb62e96bc031206c1e31ec..67c4a2bb3e67383ce52099cbb41502ea2c908c82 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h @@ -11,7 +11,6 @@ #define LLVM_LIB_DEBUGINFO_DWARFDEBUGABBREV_H #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" -#include #include #include diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h b/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h index e17c993d275bc0908d501f7209ad71cc28eaf449..d13c7f553ba301cf58c6b761352d50f9eb218cc4 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h @@ -11,7 +11,6 @@ #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Dwarf.h" diff --git a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index 3c32a3e5b7949aeffd6b22f74a809f9336cd2d0f..b2f750dd7945b1a319cf007bc4a0d4f07b6e3418 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -10,12 +10,12 @@ #ifndef LLVM_DEBUGINFO_DWARFFORMVALUE_H #define LLVM_DEBUGINFO_DWARFFORMVALUE_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/DataExtractor.h" namespace llvm { +template class ArrayRef; class DWARFUnit; class raw_ostream; diff --git a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h index 894a88dce440ba1277cd67bb2cd60e14c120649c..a697edd320720beec723ceb0747f51f572a8baa8 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -21,11 +21,11 @@ private: public: DWARFTypeUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE, + StringRef SOS, StringRef AOS, StringRef LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *Entry) - : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, UnitSection, - Entry) {} + : DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, + UnitSection, Entry) {} uint32_t getHeaderSize() const override { return DWARFUnit::getHeaderSize() + 12; } diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/include/llvm/DebugInfo/DWARF/DWARFUnit.h index 681b2aa19a79d42427e717cd386c55c814a14a4f..9c3fe3be6aa6e12468bc239860bdc24094a4884a 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -47,7 +47,7 @@ protected: virtual void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, StringRef SOS, StringRef AOS, StringRef LS, - bool isLittleEndian) = 0; + bool isLittleEndian, bool isDWO) = 0; ~DWARFUnitSectionBase() = default; }; @@ -59,13 +59,9 @@ const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, template class DWARFUnitSection final : public SmallVector, 1>, public DWARFUnitSectionBase { - bool Parsed; + bool Parsed = false; public: - DWARFUnitSection() : Parsed(false) {} - DWARFUnitSection(DWARFUnitSection &&DUS) : - SmallVector, 1>(std::move(DUS)), Parsed(DUS.Parsed) {} - typedef llvm::SmallVectorImpl> UnitVector; typedef typename UnitVector::iterator iterator; typedef llvm::iterator_range iterator_range; @@ -84,7 +80,8 @@ public: private: void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE) override { + StringRef SOS, StringRef AOS, StringRef LS, bool LE, + bool IsDWO) override { if (Parsed) return; const auto &Index = getDWARFUnitIndex(Context, UnitType::Section); @@ -92,7 +89,7 @@ private: uint32_t Offset = 0; while (Data.isValidOffset(Offset)) { auto U = llvm::make_unique(Context, Section, DA, RS, SS, SOS, - AOS, LS, LE, *this, + AOS, LS, LE, IsDWO, *this, Index.getFromOffset(Offset)); if (!U->extract(Data, &Offset)) break; @@ -117,6 +114,7 @@ class DWARFUnit { StringRef AddrOffsetSection; uint32_t AddrOffsetSectionBase; bool isLittleEndian; + bool isDWO; const DWARFUnitSectionBase &UnitSection; uint32_t Offset; @@ -148,7 +146,7 @@ protected: public: DWARFUnit(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE, + StringRef SOS, StringRef AOS, StringRef LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *IndexEntry = nullptr); @@ -249,7 +247,7 @@ public: /// \brief Return the DIE object for a given offset inside the /// unit's DIE vector. /// - /// The unit needs to have his DIEs extracted for this method to work. + /// The unit needs to have its DIEs extracted for this method to work. const DWARFDebugInfoEntryMinimal *getDIEForOffset(uint32_t Offset) const { assert(!DieArray.empty()); auto it = std::lower_bound( diff --git a/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h b/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h index b5fa8c33414dbd2d0a9ad2bc3fe00ad737bef8c0..50f5c40bcac966c3445c7d4be11a23a5b4c43c33 100644 --- a/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h +++ b/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h @@ -15,6 +15,7 @@ #include namespace llvm { +namespace pdb { template class ConcreteSymbolEnumerator : public IPDBEnumChildren { @@ -55,5 +56,6 @@ private: std::unique_ptr Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h b/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h index 7b2bc146b32defdb5d2acc20f629802ba60d1fae..930bea6060b223fb34c301a2986bf9367f105d52 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIADataStream.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBDataStream.h" namespace llvm { +namespace pdb { class DIADataStream : public IPDBDataStream { public: explicit DIADataStream(CComPtr DiaStreamData); @@ -29,5 +30,6 @@ private: CComPtr StreamData; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h index 375bcdd7e3bd91725dee0b4eff6ce34fcb43052e..941e16a35fac2139d598af48e90c0677b99a326e 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { +namespace pdb { class IPDBDataStream; @@ -31,5 +32,6 @@ private: CComPtr Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h index 4cc85eda477fdb53a1475d177d50a182ce0867c0..106b84cecfffa7518a002a0cbb349b334086aef4 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { - +namespace pdb { class IPDBLineNumber; class DIAEnumLineNumbers : public IPDBEnumChildren { @@ -31,5 +31,6 @@ private: CComPtr Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h index 88625f64e49e05e4a68d98f780a6d0f00850335f..6c00d6a5e29d36a171fee437301d0ee0748397d5 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { - +namespace pdb { class DIASession; class DIAEnumSourceFiles : public IPDBEnumChildren { @@ -33,5 +33,6 @@ private: CComPtr Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h index fe343f778aad3573f57e7c1424e84a0078d4402f..b206ff59a6a49a6c185851bfe879599db5bdd028 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" namespace llvm { - +namespace pdb { class DIASession; class DIAEnumSymbols : public IPDBEnumChildren { @@ -33,5 +33,6 @@ private: CComPtr Enumerator; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAError.h b/include/llvm/DebugInfo/PDB/DIA/DIAError.h new file mode 100644 index 0000000000000000000000000000000000000000..f198d07e99d46c50faee841c6886a02cc89ec681 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/DIA/DIAError.h @@ -0,0 +1,46 @@ +//===- DIAError.h - Error extensions for PDB DIA implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_DIA_DIAERROR_H +#define LLVM_DEBUGINFO_PDB_DIA_DIAERROR_H + +#include "llvm/Support/Error.h" + +#include + +namespace llvm { +namespace pdb { +enum class dia_error_code { + unspecified = 1, + could_not_create_impl, + invalid_file_format, + invalid_parameter, + already_loaded, + debug_info_mismatch, +}; + +/// Base class for errors originating in DIA SDK, e.g. COM calls +class DIAError : public ErrorInfo { +public: + static char ID; + DIAError(dia_error_code C); + DIAError(const std::string &Context); + DIAError(dia_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + dia_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h b/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h index 5950a0d3835f6b128456ce1005a3d992ddd035f7..a59e3a19c8c22ee2251e5b02f4093b5ada121c1a 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIALineNumber.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" namespace llvm { +namespace pdb { class DIALineNumber : public IPDBLineNumber { public: explicit DIALineNumber(CComPtr DiaLineNumber); @@ -35,5 +36,5 @@ private: CComPtr LineNumber; }; } - +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h index 9308b8e82657949fc6d0f37b812524978666c0ee..1e40c46f8a27eb25e59a55174b6326ffdb48bf6c 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" namespace llvm { +namespace pdb { class DIASession; class DIARawSymbol : public IPDBRawSymbol { public: @@ -58,7 +59,7 @@ public: uint32_t getLiveRangeStartAddressOffset() const override; uint32_t getLiveRangeStartAddressSection() const override; uint32_t getLiveRangeStartRelativeVirtualAddress() const override; - PDB_RegisterId getLocalBasePointerRegisterId() const override; + codeview::RegisterId getLocalBasePointerRegisterId() const override; uint32_t getLowerBoundId() const override; uint32_t getMemorySpaceKind() const override; std::string getName() const override; @@ -73,7 +74,7 @@ public: uint32_t getOffsetInUdt() const override; PDB_Cpu getPlatform() const override; uint32_t getRank() const override; - PDB_RegisterId getRegisterId() const override; + codeview::RegisterId getRegisterId() const override; uint32_t getRegisterType() const override; uint32_t getRelativeVirtualAddress() const override; uint32_t getSamplerSlot() const override; @@ -109,7 +110,7 @@ public: int32_t getVirtualBasePointerOffset() const override; PDB_LocType getLocationType() const override; PDB_Machine getMachineType() const override; - PDB_ThunkOrdinal getThunkOrdinal() const override; + codeview::ThunkOrdinal getThunkOrdinal() const override; uint64_t getLength() const override; uint64_t getLiveRangeLength() const override; uint64_t getVirtualAddress() const override; @@ -202,5 +203,6 @@ private: CComPtr Symbol; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASession.h b/include/llvm/DebugInfo/PDB/DIA/DIASession.h index d887e9033f33f64bc16ce3d24f8125474cc69900..3f5818631e7bc1c9c1c56a868ab18fdf9da3b7a6 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASession.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASession.h @@ -11,18 +11,23 @@ #define LLVM_DEBUGINFO_PDB_DIA_DIASESSION_H #include "DIASupport.h" -#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/Support/Error.h" + +#include namespace llvm { +class StringRef; + +namespace pdb { class DIASession : public IPDBSession { public: explicit DIASession(CComPtr DiaSession); - static PDB_ErrorCode createFromPdb(StringRef Path, - std::unique_ptr &Session); - static PDB_ErrorCode createFromExe(StringRef Path, - std::unique_ptr &Session); + static Error createFromPdb(StringRef Path, + std::unique_ptr &Session); + static Error createFromExe(StringRef Path, + std::unique_ptr &Session); uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; @@ -63,5 +68,5 @@ private: CComPtr Session; }; } - +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h b/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h index 66b0c7db93f8e20f5b0b6811ae834ff8628fdf83..1088ea54981cfae65990c093fc5a55bc40c01d98 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASourceFile.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" namespace llvm { +namespace pdb { class DIASession; class DIASourceFile : public IPDBSourceFile { @@ -35,5 +36,6 @@ private: CComPtr SourceFile; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASupport.h b/include/llvm/DebugInfo/PDB/DIA/DIASupport.h index 407a34551cc74656801b1a404cd0203c4050193c..3b4a348289df94e4414e13af9027ecef23630376 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASupport.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASupport.h @@ -22,6 +22,14 @@ #define NOMINMAX #endif +// llvm/Support/Debug.h unconditionally #defines DEBUG as a macro. +// DIA headers #define it if it is not already defined, so we have +// an order of includes problem. The real fix is to make LLVM use +// something less generic than DEBUG, such as LLVM_DEBUG(), but it's +// fairly prevalent. So for now, we save the definition state and +// restore it. +#pragma push_macro("DEBUG") + // atlbase.h has to come before windows.h #include #include @@ -29,5 +37,8 @@ // DIA headers must come after windows headers. #include #include +#include + +#pragma pop_macro("DEBUG") #endif // LLVM_DEBUGINFO_PDB_DIA_DIASUPPORT_H diff --git a/include/llvm/DebugInfo/PDB/GenericError.h b/include/llvm/DebugInfo/PDB/GenericError.h new file mode 100644 index 0000000000000000000000000000000000000000..959c26161044273c0c65d9e411f44a43fc129ee1 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/GenericError.h @@ -0,0 +1,42 @@ +//===- Error.h - system_error extensions for PDB ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_ERROR_H +#define LLVM_DEBUGINFO_PDB_ERROR_H + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { + +enum class generic_error_code { + invalid_path = 1, + dia_sdk_not_present, + unspecified, +}; + +/// Base class for errors originating when parsing raw PDB files +class GenericError : public ErrorInfo { +public: + static char ID; + GenericError(generic_error_code C); + GenericError(const std::string &Context); + GenericError(generic_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + generic_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/PDB/IPDBDataStream.h b/include/llvm/DebugInfo/PDB/IPDBDataStream.h index 808a0f3ec3a9df111fd9fe551fb3e5a0d69c92bb..9594dc1591a76fa03c378188db772d4297b170d7 100644 --- a/include/llvm/DebugInfo/PDB/IPDBDataStream.h +++ b/include/llvm/DebugInfo/PDB/IPDBDataStream.h @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallVector.h" namespace llvm { +namespace pdb { /// IPDBDataStream defines an interface used to represent a stream consisting /// of a name and a series of records whose formats depend on the particular @@ -33,5 +34,6 @@ public: virtual IPDBDataStream *clone() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h b/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h index 645ac96e23a5e6916d74a03485ddb461e2ac12a8..8e9f6f883679dc456267085bc2e977f3c3a9bda9 100644 --- a/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h +++ b/include/llvm/DebugInfo/PDB/IPDBEnumChildren.h @@ -14,6 +14,7 @@ #include namespace llvm { +namespace pdb { template class IPDBEnumChildren { public: @@ -29,5 +30,6 @@ public: virtual MyType *clone() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBLineNumber.h b/include/llvm/DebugInfo/PDB/IPDBLineNumber.h index 92cd58d866490da40c70e186b6af4a551d2c10fd..e20080f2fbfcd3e8d5b3c126ad783f601f7903d3 100644 --- a/include/llvm/DebugInfo/PDB/IPDBLineNumber.h +++ b/include/llvm/DebugInfo/PDB/IPDBLineNumber.h @@ -13,7 +13,7 @@ #include "PDBTypes.h" namespace llvm { - +namespace pdb { class IPDBLineNumber { public: virtual ~IPDBLineNumber(); @@ -32,5 +32,6 @@ public: virtual bool isStatement() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h index 139bff56fd5deed43a27eba90660eff63b37261b..49866b8bb2f22eb5beef36881addb45bde430fca 100644 --- a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h +++ b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h @@ -13,12 +13,14 @@ #include "PDBTypes.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" #include namespace llvm { - class raw_ostream; +namespace pdb { + /// IPDBRawSymbol defines an interface used to represent an arbitrary symbol. /// It exposes a monolithic interface consisting of accessors for the union of /// all properties that are valid for any symbol type. This interface is then @@ -66,7 +68,7 @@ public: virtual uint32_t getLiveRangeStartAddressOffset() const = 0; virtual uint32_t getLiveRangeStartAddressSection() const = 0; virtual uint32_t getLiveRangeStartRelativeVirtualAddress() const = 0; - virtual PDB_RegisterId getLocalBasePointerRegisterId() const = 0; + virtual codeview::RegisterId getLocalBasePointerRegisterId() const = 0; virtual uint32_t getLowerBoundId() const = 0; virtual uint32_t getMemorySpaceKind() const = 0; virtual std::string getName() const = 0; @@ -81,7 +83,7 @@ public: virtual uint32_t getOffsetInUdt() const = 0; virtual PDB_Cpu getPlatform() const = 0; virtual uint32_t getRank() const = 0; - virtual PDB_RegisterId getRegisterId() const = 0; + virtual codeview::RegisterId getRegisterId() const = 0; virtual uint32_t getRegisterType() const = 0; virtual uint32_t getRelativeVirtualAddress() const = 0; virtual uint32_t getSamplerSlot() const = 0; @@ -117,7 +119,7 @@ public: virtual int32_t getVirtualBasePointerOffset() const = 0; virtual PDB_LocType getLocationType() const = 0; virtual PDB_Machine getMachineType() const = 0; - virtual PDB_ThunkOrdinal getThunkOrdinal() const = 0; + virtual codeview::ThunkOrdinal getThunkOrdinal() const = 0; virtual uint64_t getLength() const = 0; virtual uint64_t getLiveRangeLength() const = 0; virtual uint64_t getVirtualAddress() const = 0; @@ -206,6 +208,7 @@ public: virtual std::string getUnused() const = 0; }; +} // namespace pdb } // namespace llvm #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBSession.h b/include/llvm/DebugInfo/PDB/IPDBSession.h index b6bccbeb8842d77f3cf36a15b5761247df4fd635..3d2c37eff2e36c50573ae211ef6d31968c265824 100644 --- a/include/llvm/DebugInfo/PDB/IPDBSession.h +++ b/include/llvm/DebugInfo/PDB/IPDBSession.h @@ -11,11 +11,12 @@ #define LLVM_DEBUGINFO_PDB_IPDBSESSION_H #include "PDBTypes.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include namespace llvm { - +namespace pdb { class PDBSymbolCompiland; class PDBSymbolExe; @@ -75,5 +76,6 @@ public: virtual std::unique_ptr getDebugStreams() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/IPDBSourceFile.h b/include/llvm/DebugInfo/PDB/IPDBSourceFile.h index 3e4394387105ae58122c6055a2354c5f544f17fb..3676c4030b13f89385d9d4315647d0381e723f86 100644 --- a/include/llvm/DebugInfo/PDB/IPDBSourceFile.h +++ b/include/llvm/DebugInfo/PDB/IPDBSourceFile.h @@ -15,9 +15,10 @@ #include namespace llvm { - class raw_ostream; +namespace pdb { + /// IPDBSourceFile defines an interface used to represent source files whose /// information are stored in the PDB. class IPDBSourceFile { @@ -34,5 +35,6 @@ public: getCompilands() const = 0; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDB.h b/include/llvm/DebugInfo/PDB/PDB.h index 5df3be85e381b50ac1ebe1deedb98f6fa68095fc..1f5a066b9a1bdb187a07aeea581ab82c14b39c1a 100644 --- a/include/llvm/DebugInfo/PDB/PDB.h +++ b/include/llvm/DebugInfo/PDB/PDB.h @@ -11,16 +11,20 @@ #define LLVM_DEBUGINFO_PDB_PDB_H #include "PDBTypes.h" +#include "llvm/Support/Error.h" #include +#include namespace llvm { class StringRef; -PDB_ErrorCode loadDataForPDB(PDB_ReaderType Type, StringRef Path, - std::unique_ptr &Session); +namespace pdb { -PDB_ErrorCode loadDataForEXE(PDB_ReaderType Type, StringRef Path, - std::unique_ptr &Session); -} +Error loadDataForPDB(PDB_ReaderType Type, StringRef Path, + std::unique_ptr &Session); +Error loadDataForEXE(PDB_ReaderType Type, StringRef Path, + std::unique_ptr &Session); +} +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBContext.h b/include/llvm/DebugInfo/PDB/PDBContext.h index 2034e3b004b022521e69dd12dfdb532ccec2e692..836e3924843805925ccd2c8c94aed979a81967ed 100644 --- a/include/llvm/DebugInfo/PDB/PDBContext.h +++ b/include/llvm/DebugInfo/PDB/PDBContext.h @@ -17,44 +17,46 @@ namespace llvm { namespace object { class COFFObjectFile; -} - -/// PDBContext -/// This data structure is the top level entity that deals with PDB debug -/// information parsing. This data structure exists only when there is a -/// need for a transparent interface to different debug information formats -/// (e.g. PDB and DWARF). More control and power over the debug information -/// access can be had by using the PDB interfaces directly. -class PDBContext : public DIContext { - - PDBContext(PDBContext &) = delete; - PDBContext &operator=(PDBContext &) = delete; - -public: - PDBContext(const object::COFFObjectFile &Object, - std::unique_ptr PDBSession); - - static bool classof(const DIContext *DICtx) { - return DICtx->getKind() == CK_PDB; } - void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, - bool DumpEH = false) override; - - DILineInfo getLineInfoForAddress( - uint64_t Address, - DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; - DILineInfoTable getLineInfoForAddressRange( - uint64_t Address, uint64_t Size, - DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; - DIInliningInfo getInliningInfoForAddress( - uint64_t Address, - DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; - -private: - std::string getFunctionName(uint64_t Address, DINameKind NameKind) const; - std::unique_ptr Session; -}; + namespace pdb { + /// PDBContext + /// This data structure is the top level entity that deals with PDB debug + /// information parsing. This data structure exists only when there is a + /// need for a transparent interface to different debug information formats + /// (e.g. PDB and DWARF). More control and power over the debug information + /// access can be had by using the PDB interfaces directly. + class PDBContext : public DIContext { + + PDBContext(PDBContext &) = delete; + PDBContext &operator=(PDBContext &) = delete; + + public: + PDBContext(const object::COFFObjectFile &Object, + std::unique_ptr PDBSession); + + static bool classof(const DIContext *DICtx) { + return DICtx->getKind() == CK_PDB; + } + + void dump(raw_ostream &OS, DIDumpType DumpType = DIDT_All, + bool DumpEH = false) override; + + DILineInfo getLineInfoForAddress( + uint64_t Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + DILineInfoTable getLineInfoForAddressRange( + uint64_t Address, uint64_t Size, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + DIInliningInfo getInliningInfoForAddress( + uint64_t Address, + DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; + + private: + std::string getFunctionName(uint64_t Address, DINameKind NameKind) const; + std::unique_ptr Session; + }; + } } #endif diff --git a/include/llvm/DebugInfo/PDB/PDBExtras.h b/include/llvm/DebugInfo/PDB/PDBExtras.h index 48ce1c127196f4c2575d09b55788d5e8cdbae1b0..5a7422d9e9e4a529a8a46bf195cec74504fa6ba8 100644 --- a/include/llvm/DebugInfo/PDB/PDBExtras.h +++ b/include/llvm/DebugInfo/PDB/PDBExtras.h @@ -11,28 +11,33 @@ #define LLVM_DEBUGINFO_PDB_PDBEXTRAS_H #include "PDBTypes.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/Support/raw_ostream.h" #include namespace llvm { + +namespace pdb { typedef std::unordered_map TagStats; raw_ostream &operator<<(raw_ostream &OS, const PDB_VariantType &Value); raw_ostream &operator<<(raw_ostream &OS, const PDB_CallingConv &Conv); raw_ostream &operator<<(raw_ostream &OS, const PDB_DataKind &Data); -raw_ostream &operator<<(raw_ostream &OS, const PDB_RegisterId &Reg); +raw_ostream &operator<<(raw_ostream &OS, const codeview::RegisterId &Reg); raw_ostream &operator<<(raw_ostream &OS, const PDB_LocType &Loc); -raw_ostream &operator<<(raw_ostream &OS, const PDB_ThunkOrdinal &Thunk); +raw_ostream &operator<<(raw_ostream &OS, const codeview::ThunkOrdinal &Thunk); raw_ostream &operator<<(raw_ostream &OS, const PDB_Checksum &Checksum); raw_ostream &operator<<(raw_ostream &OS, const PDB_Lang &Lang); raw_ostream &operator<<(raw_ostream &OS, const PDB_SymType &Tag); raw_ostream &operator<<(raw_ostream &OS, const PDB_MemberAccess &Access); raw_ostream &operator<<(raw_ostream &OS, const PDB_UdtType &Type); raw_ostream &operator<<(raw_ostream &OS, const PDB_UniqueId &Id); +raw_ostream &operator<<(raw_ostream &OS, const PDB_Machine &Machine); raw_ostream &operator<<(raw_ostream &OS, const Variant &Value); raw_ostream &operator<<(raw_ostream &OS, const VersionInfo &Version); raw_ostream &operator<<(raw_ostream &OS, const TagStats &Stats); } +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBSymDumper.h b/include/llvm/DebugInfo/PDB/PDBSymDumper.h index 65110f39366f98a4009b2e1da51e110d0e145c05..095c33cfe8b5892e7b9b1fdbfd6b44a80f14926d 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymDumper.h +++ b/include/llvm/DebugInfo/PDB/PDBSymDumper.h @@ -15,6 +15,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymDumper { public: @@ -57,5 +58,6 @@ private: bool RequireImpl; }; } +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBSymbol.h b/include/llvm/DebugInfo/PDB/PDBSymbol.h index 943acd401c0981626962efd88a7b56906e86105a..bf51188065407cb0614b63df57c64ceb446d6f65 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbol.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbol.h @@ -15,9 +15,7 @@ #include "PDBExtras.h" #include "PDBTypes.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" -#include #define FORWARD_SYMBOL_METHOD(MethodName) \ auto MethodName() const->decltype(RawSymbol->MethodName()) { \ @@ -26,9 +24,12 @@ namespace llvm { -class IPDBRawSymbol; +class StringRef; class raw_ostream; +namespace pdb { +class IPDBRawSymbol; + #define DECLARE_PDB_SYMBOL_CONCRETE_TYPE(TagValue) \ static const PDB_SymType Tag = TagValue; \ static bool classof(const PDBSymbol *S) { return S->getSymTag() == Tag; } @@ -41,7 +42,8 @@ class raw_ostream; /// https://msdn.microsoft.com/en-us/library/370hs6k4.aspx class PDBSymbol { protected: - PDBSymbol(const IPDBSession &PDBSession, std::unique_ptr Symbol); + PDBSymbol(const IPDBSession &PDBSession, + std::unique_ptr Symbol); public: static std::unique_ptr @@ -94,5 +96,6 @@ protected: }; } // namespace llvm +} #endif diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h b/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h index f01d1db793a206fba6be60f376c5e60a2a47cf0f..3169146e5b126ae95215d4a3f6fa75af76e97c44 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolAnnotation.h @@ -11,11 +11,11 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolAnnotation : public PDBSymbol { public: @@ -34,5 +34,6 @@ public: FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLANNOTATION_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h b/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h index 563153a6aeb299433a569ffee86bf43cb0f5ed59..d0ff62ca7c3f50a20f5082a32da84c17bb8d62d3 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolBlock.h @@ -11,12 +11,13 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolBlock : public PDBSymbol { public: PDBSymbolBlock(const IPDBSession &PDBSession, @@ -36,5 +37,6 @@ public: FORWARD_SYMBOL_METHOD(getVirtualAddress) }; } +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLBLOCK_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h index ade807f64630665ecd7589cecbe8f35f0f1a1973..f1983b3f7bf5b689712acf1e9aefa0a95c46ceda 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompiland.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolCompiland : public PDBSymbol { public: PDBSymbolCompiland(const IPDBSession &PDBSession, @@ -34,5 +36,6 @@ public: std::string getSourceFileName() const; }; } +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLCOMPILAND_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h index 59d7eb310e1615edb32b59d3e325eaf524b0e800..bb4a78f68e2f7de925ca18cf6498f7195caeafc0 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolCompilandDetails : public PDBSymbol { public: @@ -51,5 +52,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBFUNCTION_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h index 4890f75eea30759851b5bbe643e76ed0f12fce1b..a71a0ba2df589f19006563d71aebb579940f7e20 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h @@ -16,7 +16,7 @@ namespace llvm { class raw_ostream; - +namespace pdb { class PDBSymbolCompilandEnv : public PDBSymbol { public: PDBSymbolCompilandEnv(const IPDBSession &PDBSession, @@ -32,5 +32,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLCOMPILANDENV_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h b/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h index 5a7b8096d9c6501f1d1066bd2b64ff54b2c65f29..54f089404262638e6854d1e8938fc643567d0c14 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolCustom.h @@ -18,6 +18,7 @@ namespace llvm { class raw_ostream; +namespace pdb { /// PDBSymbolCustom represents symbols that are compiler-specific and do not /// fit anywhere else in the lexical hierarchy. /// https://msdn.microsoft.com/en-us/library/d88sf09h.aspx @@ -34,5 +35,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLCUSTOM_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolData.h b/include/llvm/DebugInfo/PDB/PDBSymbolData.h index 6c42bcbe2b35ed8d13a7296806cbd043df0b1d38..36f32ab51c1108b675de3c6625677b3907bcf782 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolData.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolData.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolData : public PDBSymbol { public: PDBSymbolData(const IPDBSession &PDBSession, @@ -56,5 +58,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLDATA_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolExe.h b/include/llvm/DebugInfo/PDB/PDBSymbolExe.h index 19c3b651d3f32443a27bc795dbf6dbd847fd50db..5b3f50d153eb6078007570b1f497430c33403466 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolExe.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolExe.h @@ -12,12 +12,13 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolExe : public PDBSymbol { public: PDBSymbolExe(const IPDBSession &PDBSession, @@ -41,5 +42,6 @@ private: int Indent) const; }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLEXE_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h index 490a9754707db3855aa0759f2c989f4dcb1724d1..7170bcbe846c63a3a849a85106860dfc3b7f6c83 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolFunc : public PDBSymbol { public: PDBSymbolFunc(const IPDBSession &PDBSession, @@ -75,5 +77,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNC_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h index 7e6c2d634708894f358a8bd7b5eef9c860ff0b3a..464389503bef26e74de6709d38e14f321ecdb21c 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h @@ -17,6 +17,8 @@ namespace llvm { class raw_ostream; +namespace pdb { + class PDBSymbolFuncDebugEnd : public PDBSymbol { public: PDBSymbolFuncDebugEnd(const IPDBSession &PDBSession, @@ -44,5 +46,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNCDEBUGEND_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h index c1b1b59c211f556cc30cdf860a3b24b23041eeaa..c2e3dd39be6cf21c2764cf1a3573d10d28889cba 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolFuncDebugStart : public PDBSymbol { public: @@ -44,5 +45,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLFUNCDEBUGSTART_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h b/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h index 453bcdc969f1cd71e20e364b7a9075d58a345124..3aeae10b47bcd44060183df972067e41fd907d2d 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolLabel.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolLabel : public PDBSymbol { public: @@ -44,5 +45,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLLABEL_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h b/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h index 4a2efa282eb77e815b07568ca418b4fdcd279f9d..be0734445973ff2fca92a9a66eceeb2dbc62046a 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolPublicSymbol : public PDBSymbol { public: @@ -42,5 +43,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLPUBLICSYMBOL_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h b/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h index 1600cdf1008f3f778ae0619d229551edf4b14d79..63f7a09fc881d5213dc17e9b0c61977795458320 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolThunk.h @@ -12,11 +12,11 @@ #include "PDBSymbol.h" #include "PDBTypes.h" -#include namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolThunk : public PDBSymbol { public: @@ -52,5 +52,6 @@ public: FORWARD_SYMBOL_METHOD(isVolatileType) }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTHUNK_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h index 42aec6ae5951bc5fae8c2db45eff821a33de7995..57db03661fb7ebc0ab964e0c20e00234cbc0c827 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeArray.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeArray : public PDBSymbol { public: @@ -40,5 +41,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEARRAY_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h index 1563cc78977d718b7720f64a9c10ad54a61a4eb6..aaa3ab7988d71a6c20902dd3c845122ce6738c00 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeBaseClass : public PDBSymbol { public: @@ -55,5 +56,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEBASECLASS_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h index 5986a91531182e15e3e54fb03e9f3144bc3ea21c..c8f59f1f140a1a5420278d1ba7b778953cad1ca0 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeBuiltin : public PDBSymbol { public: @@ -35,5 +36,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEBUILTIN_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h index 7dca811201ebd580717c4a05201c56bfb49dd4e7..199b3f8b304e7dbc28dce0a9827d221c4c287957 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeCustom : public PDBSymbol { public: @@ -31,5 +32,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPECUSTOM_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h index 3c64a229c5977130e3cc76cd6f948f391badfd48..e635eb5bbf6f02642e8a34f381afee651cb8caab 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeDimension : public PDBSymbol { public: @@ -31,5 +32,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEDIMENSION_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h index 0bff97fa634e447e5d88e0dfa59fbcae07f4afc7..ade2887bac14be53059487f70e59886b19f0c088 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeEnum : public PDBSymbol { public: @@ -50,5 +51,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEENUM_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h index a23bb602cc5677c03773c89e57ba9bc18a4ba5c6..196d149ed2a2027acd3a8fc75e8eef17e3eb6efd 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeFriend : public PDBSymbol { public: @@ -32,5 +33,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEFRIEND_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h index ea451ae76ce440a12a0c0b1bcc80fe48e0f1d7f9..5561341d7e777d064723f1ba59cdaeb142b76db0 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeFunctionArg : public PDBSymbol { public: @@ -32,5 +33,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEFUNCTIONARG_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h index 0aba6d46766273749b34b79b9f3b70c4da9a57d1..516011ff8b3dc1f3daa4de1a77dbbc36f3cfaab1 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeFunctionSig : public PDBSymbol { public: @@ -45,5 +46,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEFUNCTIONSIG_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h index fdc951d9acc2f71960861ab2f345630670f9fe3e..31cf5363dde1d9658419f060d4ddaadd792dcc17 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeManaged : public PDBSymbol { public: @@ -30,5 +31,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEMANAGED_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h index 916beebcb512bc8e35bb59e6c142aad022affeaa..7a57272adb791e1420ba83e9d1f0e5a70712062d 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypePointer : public PDBSymbol { public: @@ -38,5 +39,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEPOINTER_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h index 1c535aa4251087f4ed2fccd0df810695b1764a24..5ed4f8d21d9029c2cc797d0361084aa44839e5d0 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeTypedef : public PDBSymbol { public: @@ -49,5 +50,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPETYPEDEF_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h index 396261ba23ceef57fabbaa5efda80650dd28a42e..1874dfef34f7fcd1bfd91f5d21cca5f984251716 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h @@ -17,6 +17,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeUDT : public PDBSymbol { public: PDBSymbolTypeUDT(const IPDBSession &PDBSession, @@ -45,7 +46,7 @@ public: FORWARD_SYMBOL_METHOD(getVirtualTableShapeId) FORWARD_SYMBOL_METHOD(isVolatileType) }; - +} } // namespace llvm #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h index a529ee985488cb6cf5dd8c96b2b7fe348ef39fbc..baf7ab79d60e6cbd19534048186143747499e913 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeVTable : public PDBSymbol { public: @@ -35,5 +36,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEVTABLE_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h index a1699498c42244ba120cc93739d18572cd180342..431fc1ac8625711d29c06a20b92c7ee5efde2979 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolTypeVTableShape : public PDBSymbol { public: @@ -34,5 +35,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEVTABLESHAPE_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h b/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h index 94bd2c14079f8edb9ac025e140aab8bdc5ed037e..de43e47badbdd4b94137c757444d1f00f024ed19 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolUnknown.h @@ -15,6 +15,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolUnknown : public PDBSymbol { public: @@ -30,5 +31,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLUNKNOWN_H diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h b/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h index 7b17b5bb902bce730714545bd4443dad226a89a6..a273fe159c12680e73b8f73e55bed2398858b05f 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h @@ -16,6 +16,7 @@ namespace llvm { class raw_ostream; +namespace pdb { class PDBSymbolUsingNamespace : public PDBSymbol { public: @@ -31,5 +32,6 @@ public: }; } // namespace llvm +} #endif // LLVM_DEBUGINFO_PDB_PDBSYMBOLUSINGNAMESPACE_H diff --git a/include/llvm/DebugInfo/PDB/PDBTypes.h b/include/llvm/DebugInfo/PDB/PDBTypes.h index 7e39bebf576847fb35148c5d1c8ddd044147a8b3..a9325a4343668d73c6c00100423f063cc2bcf397 100644 --- a/include/llvm/DebugInfo/PDB/PDBTypes.h +++ b/include/llvm/DebugInfo/PDB/PDBTypes.h @@ -12,12 +12,12 @@ #include "llvm/Config/llvm-config.h" #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/Support/Endian.h" #include #include #include namespace llvm { +namespace pdb { class PDBSymDumper; class PDBSymbol; @@ -70,14 +70,14 @@ class PDBSymbolUnknown; /// of PDB_ReaderType::DIA is supported. enum class PDB_ReaderType { DIA = 0, + Raw = 1, }; /// Defines a 128-bit unique identifier. This maps to a GUID on Windows, but /// is abstracted here for the purposes of non-Windows platforms that don't have /// the GUID structure defined. struct PDB_UniqueId { - uint64_t HighPart; - uint64_t LowPart; + char Guid[16]; }; /// An enumeration indicating the type of data contained in this table. @@ -217,18 +217,6 @@ enum class PDB_LocType { Max }; -/// These values correspond to the THUNK_ORDINAL enumeration, and are documented -/// here: https://msdn.microsoft.com/en-us/library/dh0k8hft.aspx -enum class PDB_ThunkOrdinal { - Standard, - ThisAdjustor, - Vcall, - Pcode, - UnknownLoad, - TrampIncremental, - BranchIsland -}; - /// These values correspond to the UdtKind enumeration, and are documented /// here: https://msdn.microsoft.com/en-us/library/wcstk66t.aspx enum class PDB_UdtType { Struct, Class, Union, Interface }; @@ -264,72 +252,8 @@ enum class PDB_BuiltinType { HResult = 31 }; -enum class PDB_RegisterId { - Unknown = 0, - VFrame = 30006, - AL = 1, - CL = 2, - DL = 3, - BL = 4, - AH = 5, - CH = 6, - DH = 7, - BH = 8, - AX = 9, - CX = 10, - DX = 11, - BX = 12, - SP = 13, - BP = 14, - SI = 15, - DI = 16, - EAX = 17, - ECX = 18, - EDX = 19, - EBX = 20, - ESP = 21, - EBP = 22, - ESI = 23, - EDI = 24, - ES = 25, - CS = 26, - SS = 27, - DS = 28, - FS = 29, - GS = 30, - IP = 31, - RAX = 328, - RBX = 329, - RCX = 330, - RDX = 331, - RSI = 332, - RDI = 333, - RBP = 334, - RSP = 335, - R8 = 336, - R9 = 337, - R10 = 338, - R11 = 339, - R12 = 340, - R13 = 341, - R14 = 342, - R15 = 343, -}; - enum class PDB_MemberAccess { Private = 1, Protected = 2, Public = 3 }; -enum class PDB_ErrorCode { - Success, - NoPdbImpl, - InvalidPath, - InvalidFileFormat, - InvalidParameter, - AlreadyLoaded, - UnknownError, - NoMemory, - DebugInfoMismatch -}; - struct VersionInfo { uint32_t Major; uint32_t Minor; @@ -355,9 +279,7 @@ enum PDB_VariantType { }; struct Variant { - Variant() - : Type(PDB_VariantType::Empty) { - } + Variant() : Type(PDB_VariantType::Empty) {} Variant(const Variant &Other) : Type(PDB_VariantType::Empty) { *this = Other; @@ -428,40 +350,12 @@ struct Variant { } }; -namespace PDB { -static const char Magic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', - 't', ' ', 'C', '/', 'C', '+', '+', ' ', - 'M', 'S', 'F', ' ', '7', '.', '0', '0', - '\r', '\n', '\x1a', 'D', 'S', '\0', '\0', '\0'}; - -// The superblock is overlaid at the beginning of the file (offset 0). -// It starts with a magic header and is followed by information which describes -// the layout of the file system. -struct SuperBlock { - char MagicBytes[sizeof(Magic)]; - // The file system is split into a variable number of fixed size elements. - // These elements are referred to as blocks. The size of a block may vary - // from system to system. - support::ulittle32_t BlockSize; - // This field's purpose is not yet known. - support::ulittle32_t Unknown0; - // This contains the number of blocks resident in the file system. In - // practice, NumBlocks * BlockSize is equivalent to the size of the PDB file. - support::ulittle32_t NumBlocks; - // This contains the number of bytes which make up the directory. - support::ulittle32_t NumDirectoryBytes; - // This field's purpose is not yet known. - support::ulittle32_t Unknown1; - // This contains the block # of the block map. - support::ulittle32_t BlockMapAddr; -}; -} // end namespace PDB - } // end namespace llvm +} namespace std { -template <> struct hash { - typedef llvm::PDB_SymType argument_type; +template <> struct hash { + typedef llvm::pdb::PDB_SymType argument_type; typedef std::size_t result_type; result_type operator()(const argument_type &Arg) const { diff --git a/include/llvm/DebugInfo/PDB/Raw/DbiStream.h b/include/llvm/DebugInfo/PDB/Raw/DbiStream.h new file mode 100644 index 0000000000000000000000000000000000000000..6ab3c80675585ab46d311c29496d5ea20447138b --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -0,0 +1,149 @@ +//===- DbiStream.h - PDB Dbi Stream (Stream 3) Access -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H + +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/ModInfo.h" +#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace object { +struct FpoData; +struct coff_section; +} + +namespace pdb { +class DbiStreamBuilder; +class PDBFile; +class ISectionContribVisitor; + +class DbiStream { + friend class DbiStreamBuilder; + + struct HeaderInfo { + support::little32_t VersionSignature; + support::ulittle32_t VersionHeader; + support::ulittle32_t Age; // Should match InfoStream. + support::ulittle16_t GlobalSymbolStreamIndex; // Global symbol stream # + support::ulittle16_t BuildNumber; // See DbiBuildNo structure. + support::ulittle16_t PublicSymbolStreamIndex; // Public symbols stream # + support::ulittle16_t PdbDllVersion; // version of mspdbNNN.dll + support::ulittle16_t SymRecordStreamIndex; // Symbol records stream # + support::ulittle16_t PdbDllRbld; // rbld number of mspdbNNN.dll + support::little32_t ModiSubstreamSize; // Size of module info stream + support::little32_t SecContrSubstreamSize; // Size of sec. contrib stream + support::little32_t SectionMapSize; // Size of sec. map substream + support::little32_t FileInfoSize; // Size of file info substream + support::little32_t TypeServerSize; // Size of type server map + support::ulittle32_t MFCTypeServerIndex; // Index of MFC Type Server + support::little32_t OptionalDbgHdrSize; // Size of DbgHeader info + support::little32_t ECSubstreamSize; // Size of EC stream (what is EC?) + support::ulittle16_t Flags; // See DbiFlags enum. + support::ulittle16_t MachineType; // See PDB_MachineType enum. + + support::ulittle32_t Reserved; // Pad to 64 bytes + }; + +public: + DbiStream(PDBFile &File, std::unique_ptr Stream); + ~DbiStream(); + Error reload(); + + PdbRaw_DbiVer getDbiVersion() const; + uint32_t getAge() const; + uint16_t getPublicSymbolStreamIndex() const; + uint16_t getGlobalSymbolStreamIndex() const; + + uint16_t getFlags() const; + bool isIncrementallyLinked() const; + bool hasCTypes() const; + bool isStripped() const; + + uint16_t getBuildNumber() const; + uint16_t getBuildMajorVersion() const; + uint16_t getBuildMinorVersion() const; + + uint16_t getPdbDllRbld() const; + uint32_t getPdbDllVersion() const; + + uint32_t getSymRecordStreamIndex() const; + + PDB_Machine getMachineType() const; + + enum { InvalidStreamIndex = 0xffff }; + + /// If the given stream type is present, returns its stream index. If it is + /// not present, returns InvalidStreamIndex. + uint32_t getDebugStreamIndex(DbgHeaderType Type) const; + + ArrayRef modules() const; + + Expected getFileNameForIndex(uint32_t Index) const; + + codeview::FixedStreamArray getSectionHeaders(); + + codeview::FixedStreamArray getFpoRecords(); + + codeview::FixedStreamArray getSectionMap() const; + void visitSectionContributions(ISectionContribVisitor &Visitor) const; + + Error commit(); + +private: + Error initializeSectionContributionData(); + Error initializeSectionHeadersData(); + Error initializeSectionMapData(); + Error initializeFileInfo(); + Error initializeFpoRecords(); + + PDBFile &Pdb; + std::unique_ptr Stream; + + std::vector ModuleInfos; + NameHashTable ECNames; + + codeview::StreamRef ModInfoSubstream; + codeview::StreamRef SecContrSubstream; + codeview::StreamRef SecMapSubstream; + codeview::StreamRef FileInfoSubstream; + codeview::StreamRef TypeServerMapSubstream; + codeview::StreamRef ECSubstream; + + codeview::StreamRef NamesBuffer; + + codeview::FixedStreamArray DbgStreams; + + PdbRaw_DbiSecContribVer SectionContribVersion; + codeview::FixedStreamArray SectionContribs; + codeview::FixedStreamArray SectionContribs2; + codeview::FixedStreamArray SectionMap; + codeview::FixedStreamArray FileNameOffsets; + + std::unique_ptr SectionHeaderStream; + codeview::FixedStreamArray SectionHeaders; + + std::unique_ptr FpoStream; + codeview::FixedStreamArray FpoRecords; + + const HeaderInfo *Header; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h b/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h new file mode 100644 index 0000000000000000000000000000000000000000..ab4300858cec20b4450c07638f418bb6ec265c42 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h @@ -0,0 +1,55 @@ +//===- DbiStreamBuilder.h - PDB Dbi Stream Creation -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAMBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAMBUILDER_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Error.h" + +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +namespace llvm { +namespace pdb { +class DbiStream; +class PDBFile; + +class DbiStreamBuilder { +public: + DbiStreamBuilder(PDBFile &File); + + DbiStreamBuilder(const DbiStreamBuilder &) = delete; + DbiStreamBuilder &operator=(const DbiStreamBuilder &) = delete; + + void setVersionHeader(PdbRaw_DbiVer V); + void setAge(uint32_t A); + void setBuildNumber(uint16_t B); + void setPdbDllVersion(uint16_t V); + void setPdbDllRbld(uint16_t R); + void setFlags(uint16_t F); + void setMachineType(PDB_Machine M); + + Expected> build(); + +private: + PDBFile &File; + Optional VerHeader; + uint32_t Age; + uint16_t BuildNumber; + uint16_t PdbDllVersion; + uint16_t PdbDllRbld; + uint16_t Flags; + PDB_Machine MachineType; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h b/include/llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h new file mode 100644 index 0000000000000000000000000000000000000000..0f354315122cfe44d80ff5d01451c11c658acfd3 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h @@ -0,0 +1,37 @@ +//===- DirectoryStreamData.h ---------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_DIRECTORYSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_DIRECTORYSTREAMDATA_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace pdb { +class IPDBFile; + +class DirectoryStreamData : public IPDBStreamData { +public: + DirectoryStreamData(const PDBFile &File) : File(File) {} + + virtual uint32_t getLength() { return File.getNumDirectoryBytes(); } + virtual llvm::ArrayRef getStreamBlocks() { + return File.getDirectoryBlockArray(); + } + +private: + const PDBFile &File; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/EnumTables.h b/include/llvm/DebugInfo/PDB/Raw/EnumTables.h new file mode 100644 index 0000000000000000000000000000000000000000..c018445630fed9f3fb79e16ac95458a98f185182 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/EnumTables.h @@ -0,0 +1,22 @@ +//===- EnumTables.h - Enum to string conversion tables ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_ENUMTABLES_H +#define LLVM_DEBUGINFO_PDB_RAW_ENUMTABLES_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/ScopedPrinter.h" + +namespace llvm { +namespace pdb { +ArrayRef> getOMFSegMapDescFlagNames(); +} +} + +#endif // LLVM_DEBUGINFO_PDB_RAW_ENUMTABLES_H diff --git a/include/llvm/DebugInfo/PDB/Raw/Hash.h b/include/llvm/DebugInfo/PDB/Raw/Hash.h new file mode 100644 index 0000000000000000000000000000000000000000..0340554d7b0b32c0e9a7fa7369a7fd8cd9608d60 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/Hash.h @@ -0,0 +1,25 @@ +//===- Hash.h - PDB hash functions ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_HASH_H +#define LLVM_DEBUGINFO_PDB_RAW_HASH_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace llvm { +namespace pdb { +uint32_t hashStringV1(StringRef Str); +uint32_t hashStringV2(StringRef Str); +uint32_t hashBufferV8(ArrayRef Data); +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h b/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h new file mode 100644 index 0000000000000000000000000000000000000000..fccea2ac2470dcece2de54079ccc6619a97676d0 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h @@ -0,0 +1,44 @@ +//===- IPDBFile.h - Abstract base class for a PDB file ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_IPDBFILE_H +#define LLVM_DEBUGINFO_PDB_RAW_IPDBFILE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include + +namespace llvm { +namespace pdb { + +class IPDBFile { +public: + virtual ~IPDBFile() {} + + virtual uint32_t getBlockSize() const = 0; + virtual uint32_t getBlockCount() const = 0; + + virtual uint32_t getNumStreams() const = 0; + virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const = 0; + virtual ArrayRef + getStreamBlockList(uint32_t StreamIndex) const = 0; + + virtual Expected> getBlockData(uint32_t BlockIndex, + uint32_t NumBytes) const = 0; + virtual Error setBlockData(uint32_t BlockIndex, uint32_t Offset, + ArrayRef Data) const = 0; +}; +} +} + +#endif // LLVM_DEBUGINFO_PDB_RAW_IPDBFILE_H diff --git a/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h b/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h new file mode 100644 index 0000000000000000000000000000000000000000..ab3c9f770755fa5a651be98e903c3796cc2ed71a --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h @@ -0,0 +1,38 @@ +//===- IPDBStreamData.h - Base interface for PDB Stream Data ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_IPDBSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_IPDBSTREAMDATA_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace pdb { +/// IPDBStream abstracts the notion of PDB stream data. Although we already +/// have another stream abstraction (namely in the form of StreamInterface +/// and MappedBlockStream), they assume that the stream data is referenced +/// the same way. Namely, by looking in the directory to get the list of +/// stream blocks, and by looking in the array of stream lengths to get the +/// length. This breaks down for the directory itself, however, since its +/// length and list of blocks are stored elsewhere. By abstracting the +/// notion of stream data further, we can use a MappedBlockStream to read +/// from the directory itself, or from an indexed stream which references +/// the directory. +class IPDBStreamData { +public: + virtual ~IPDBStreamData() {} + + virtual uint32_t getLength() = 0; + virtual ArrayRef getStreamBlocks() = 0; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h b/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..355a25a38ef811f7bcfd1db0688ef2bf76ef3914 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h @@ -0,0 +1,28 @@ +//===- ISectionContribVisitor.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_ISECTIONCONTRIBVISITOR_H +#define LLVM_DEBUGINFO_PDB_RAW_ISECTIONCONTRIBVISITOR_H + +namespace llvm { +namespace pdb { +struct SectionContrib; +struct SectionContrib2; + +class ISectionContribVisitor { +public: + virtual ~ISectionContribVisitor() {} + + virtual void visit(const SectionContrib &C) = 0; + virtual void visit(const SectionContrib2 &C) = 0; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_ISECTIONCONTRIBVISITOR_H diff --git a/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h b/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h new file mode 100644 index 0000000000000000000000000000000000000000..30563bc5b8983bc9276d6bc13f25a461fe4901be --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h @@ -0,0 +1,34 @@ +//===- IndexedStreamData.h - Standard PDB Stream Data -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_INDEXEDSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_INDEXEDSTREAMDATA_H + +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" + +namespace llvm { +namespace pdb { +class IPDBFile; + +class IndexedStreamData : public IPDBStreamData { +public: + IndexedStreamData(uint32_t StreamIdx, const IPDBFile &File); + virtual ~IndexedStreamData() {} + + uint32_t getLength() override; + ArrayRef getStreamBlocks() override; + +private: + uint32_t StreamIdx; + const IPDBFile &File; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/InfoStream.h b/include/llvm/DebugInfo/PDB/Raw/InfoStream.h new file mode 100644 index 0000000000000000000000000000000000000000..9cca487770974c2f091ee40b8b416e469f46fda9 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/InfoStream.h @@ -0,0 +1,77 @@ +//===- InfoStream.h - PDB Info Stream (Stream 1) Access ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAM_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/NameMap.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class InfoStreamBuilder; +class PDBFile; + +class InfoStream { + friend class InfoStreamBuilder; + + struct Header { + support::ulittle32_t Version; + support::ulittle32_t Signature; + support::ulittle32_t Age; + PDB_UniqueId Guid; + }; + +public: + InfoStream(std::unique_ptr Stream); + + Error reload(); + Error commit(); + + PdbRaw_ImplVer getVersion() const; + uint32_t getSignature() const; + uint32_t getAge() const; + PDB_UniqueId getGuid() const; + + uint32_t getNamedStreamIndex(llvm::StringRef Name) const; + iterator_range> named_streams() const; + +private: + std::unique_ptr Stream; + + // PDB file format version. We only support VC70. See the enumeration + // `PdbRaw_ImplVer` for the other possible values. + uint32_t Version; + + // A 32-bit signature unique across all PDBs. This is generated with + // a call to time() when the PDB is written, but obviously this is not + // universally unique. + uint32_t Signature; + + // The number of times the PDB has been written. Might also be used to + // ensure that the PDB matches the executable. + uint32_t Age; + + // Due to the aforementioned limitations with `Signature`, this is a new + // signature present on VC70 and higher PDBs which is guaranteed to be + // universally unique. + PDB_UniqueId Guid; + + NameMap NamedStreams; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h b/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h new file mode 100644 index 0000000000000000000000000000000000000000..e8ee572c1a05de9f84a148dbf5614bd9966aed81 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h @@ -0,0 +1,50 @@ +//===- InfoStreamBuilder.h - PDB Info Stream Creation -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAMBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBINFOSTREAMBUILDER_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Error.h" + +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/NameMap.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +namespace llvm { +namespace pdb { +class NameMap; +class PDBFile; + +class InfoStreamBuilder { +public: + InfoStreamBuilder(IPDBFile &File); + InfoStreamBuilder(const InfoStreamBuilder &) = delete; + InfoStreamBuilder &operator=(const InfoStreamBuilder &) = delete; + + void setVersion(PdbRaw_ImplVer V); + void setSignature(uint32_t S); + void setAge(uint32_t A); + void setGuid(PDB_UniqueId G); + + Expected> build(); + +private: + IPDBFile &File; + Optional Ver; + Optional Sig; + Optional Age; + Optional Guid; + Optional NamedStreams; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h b/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h new file mode 100644 index 0000000000000000000000000000000000000000..36424c0d16abbee6b2e9ede92d8d73c03dcbdb45 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h @@ -0,0 +1,68 @@ +//===- MappedBlockStream.h - Reads stream data from a PDBFile ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_MAPPEDBLOCKSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_MAPPEDBLOCKSTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include +#include + +namespace llvm { +namespace pdb { + +class IPDBFile; +class PDBFile; + +class MappedBlockStream : public codeview::StreamInterface { +public: + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) const override; + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) const override; + Error writeBytes(uint32_t Offset, ArrayRef Buffer) const override; + + uint32_t getLength() const override; + Error commit() const override; + + uint32_t getNumBytesCopied() const; + + static Expected> + createIndexedStream(uint32_t StreamIdx, const IPDBFile &File); + static Expected> + createDirectoryStream(const PDBFile &File); + + llvm::BumpPtrAllocator &getAllocator() { return Pool; } + +protected: + MappedBlockStream(std::unique_ptr Data, const IPDBFile &File); + + Error readBytes(uint32_t Offset, MutableArrayRef Buffer) const; + bool tryReadContiguously(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) const; + + const IPDBFile &Pdb; + std::unique_ptr Data; + + typedef MutableArrayRef CacheEntry; + mutable llvm::BumpPtrAllocator Pool; + mutable DenseMap> CacheMap; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_MAPPEDBLOCKSTREAM_H diff --git a/include/llvm/DebugInfo/PDB/Raw/ModInfo.h b/include/llvm/DebugInfo/PDB/Raw/ModInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..b8da0bfabf3863c9df5fb69ff59316d6581bf998 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/ModInfo.h @@ -0,0 +1,79 @@ +//===- ModInfo.h - PDB module information -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_MODINFO_H +#define LLVM_DEBUGINFO_PDB_RAW_MODINFO_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include +#include + +namespace llvm { +namespace pdb { + +class ModInfo { +private: + struct FileLayout; + +public: + ModInfo(); + ModInfo(const ModInfo &Info); + ~ModInfo(); + + static Error initialize(codeview::StreamRef Stream, ModInfo &Info); + + bool hasECInfo() const; + uint16_t getTypeServerIndex() const; + uint16_t getModuleStreamIndex() const; + uint32_t getSymbolDebugInfoByteSize() const; + uint32_t getLineInfoByteSize() const; + uint32_t getC13LineInfoByteSize() const; + uint32_t getNumberOfFiles() const; + uint32_t getSourceFileNameIndex() const; + uint32_t getPdbFilePathNameIndex() const; + + StringRef getModuleName() const; + StringRef getObjFileName() const; + + uint32_t getRecordLength() const; + +private: + StringRef ModuleName; + StringRef ObjFileName; + const FileLayout *Layout; +}; + +struct ModuleInfoEx { + ModuleInfoEx(const ModInfo &Info) : Info(Info) {} + ModuleInfoEx(const ModuleInfoEx &Ex) + : Info(Ex.Info), SourceFiles(Ex.SourceFiles) {} + + ModInfo Info; + std::vector SourceFiles; +}; + +} // end namespace pdb + +namespace codeview { +template <> struct VarStreamArrayExtractor { + Error operator()(StreamRef Stream, uint32_t &Length, + pdb::ModInfo &Info) const { + if (auto EC = pdb::ModInfo::initialize(Stream, Info)) + return EC; + Length = Info.getRecordLength(); + return Error::success(); + } +}; +} + +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_MODINFO_H diff --git a/include/llvm/DebugInfo/PDB/Raw/ModStream.h b/include/llvm/DebugInfo/PDB/Raw/ModStream.h new file mode 100644 index 0000000000000000000000000000000000000000..d22962cc1e28258b3ae15b96629e53c6efaa8b93 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/ModStream.h @@ -0,0 +1,57 @@ +//===- ModStream.h - PDB Module Info Stream Access ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_MODSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_MODSTREAM_H + +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/CVRecord.h" +#include "llvm/DebugInfo/CodeView/ModuleSubstream.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; +class ModInfo; + +class ModStream { +public: + ModStream(const ModInfo &Module, std::unique_ptr Stream); + ~ModStream(); + + Error reload(); + + iterator_range + symbols(bool *HadError) const; + + iterator_range + lines(bool *HadError) const; + + Error commit(); + +private: + const ModInfo &Mod; + + std::unique_ptr Stream; + + codeview::CVSymbolArray SymbolsSubstream; + codeview::StreamRef LinesSubstream; + codeview::StreamRef C13LinesSubstream; + codeview::StreamRef GlobalRefsSubstream; + + codeview::ModuleSubstreamArray LineInfo; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h b/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h new file mode 100644 index 0000000000000000000000000000000000000000..c9e060a3a70f6797e3789396ce661a9f1d441432 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/NameHashTable.h @@ -0,0 +1,54 @@ +//===- NameHashTable.h - PDB Name Hash Table --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H +#define LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include +#include + +namespace llvm { +namespace codeview { +class StreamReader; +} +namespace pdb { + +class NameHashTable { +public: + NameHashTable(); + + Error load(codeview::StreamReader &Stream); + + uint32_t getNameCount() const { return NameCount; } + uint32_t getHashVersion() const { return HashVersion; } + uint32_t getSignature() const { return Signature; } + + StringRef getStringForID(uint32_t ID) const; + uint32_t getIDForString(StringRef Str) const; + + codeview::FixedStreamArray name_ids() const; + +private: + codeview::StreamRef NamesBuffer; + codeview::FixedStreamArray IDs; + uint32_t Signature; + uint32_t HashVersion; + uint32_t NameCount; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_NAMEHASHTABLE_H diff --git a/include/llvm/DebugInfo/PDB/Raw/NameMap.h b/include/llvm/DebugInfo/PDB/Raw/NameMap.h new file mode 100644 index 0000000000000000000000000000000000000000..0bd34db0c82e2db1190c552729703e7a5de8a6d1 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/NameMap.h @@ -0,0 +1,43 @@ +//===- NameMap.h - PDB Name Map ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAP_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAP_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include + +namespace llvm { +namespace codeview { +class StreamReader; +class StreamWriter; +} +namespace pdb { + +class NameMap { +public: + NameMap(); + + Error load(codeview::StreamReader &Stream); + Error commit(codeview::StreamWriter &Writer); + + bool tryGetValue(StringRef Name, uint32_t &Value) const; + + iterator_range> entries() const; + +private: + StringMap Mapping; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAP_H diff --git a/include/llvm/DebugInfo/PDB/Raw/PDBFile.h b/include/llvm/DebugInfo/PDB/Raw/PDBFile.h new file mode 100644 index 0000000000000000000000000000000000000000..71d7c6144c3edd5dc6a067030aea2389931c9fc4 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/PDBFile.h @@ -0,0 +1,148 @@ +//===- PDBFile.h - Low level interface to a PDB file ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBFILE_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBFILE_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" + +#include + +namespace llvm { + +namespace codeview { +class StreamInterface; +} + +namespace pdb { +class DbiStream; +class InfoStream; +class MappedBlockStream; +class NameHashTable; +class PDBFileBuilder; +class PublicsStream; +class SymbolStream; +class TpiStream; + +static const char MsfMagic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', + 't', ' ', 'C', '/', 'C', '+', '+', ' ', + 'M', 'S', 'F', ' ', '7', '.', '0', '0', + '\r', '\n', '\x1a', 'D', 'S', '\0', '\0', '\0'}; + +class PDBFile : public IPDBFile { + friend PDBFileBuilder; + +public: + // The superblock is overlaid at the beginning of the file (offset 0). + // It starts with a magic header and is followed by information which + // describes the layout of the file system. + struct SuperBlock { + char MagicBytes[sizeof(MsfMagic)]; + // The file system is split into a variable number of fixed size elements. + // These elements are referred to as blocks. The size of a block may vary + // from system to system. + support::ulittle32_t BlockSize; + // This field's purpose is not yet known. + support::ulittle32_t Unknown0; + // This contains the number of blocks resident in the file system. In + // practice, NumBlocks * BlockSize is equivalent to the size of the PDB + // file. + support::ulittle32_t NumBlocks; + // This contains the number of bytes which make up the directory. + support::ulittle32_t NumDirectoryBytes; + // This field's purpose is not yet known. + support::ulittle32_t Unknown1; + // This contains the block # of the block map. + support::ulittle32_t BlockMapAddr; + }; + + explicit PDBFile(std::unique_ptr PdbFileBuffer); + ~PDBFile() override; + + uint32_t getUnknown0() const; + uint32_t getUnknown1() const; + + uint32_t getBlockSize() const override; + uint32_t getBlockCount() const override; + uint32_t getNumDirectoryBytes() const; + uint32_t getBlockMapIndex() const; + uint32_t getNumDirectoryBlocks() const; + uint64_t getBlockMapOffset() const; + + uint32_t getNumStreams() const override; + uint32_t getStreamByteSize(uint32_t StreamIndex) const override; + ArrayRef + getStreamBlockList(uint32_t StreamIndex) const override; + uint32_t getFileSize() const; + + Expected> getBlockData(uint32_t BlockIndex, + uint32_t NumBytes) const override; + Error setBlockData(uint32_t BlockIndex, uint32_t Offset, + ArrayRef Data) const override; + + ArrayRef getStreamSizes() const { return StreamSizes; } + ArrayRef> getStreamMap() const { + return StreamMap; + } + + ArrayRef getDirectoryBlockArray() const; + + Error parseFileHeaders(); + Error parseStreamData(); + + static uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) { + return alignTo(NumBytes, BlockSize) / BlockSize; + } + + static uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) { + return BlockNumber * BlockSize; + } + + Expected getPDBInfoStream(); + Expected getPDBDbiStream(); + Expected getPDBTpiStream(); + Expected getPDBIpiStream(); + Expected getPDBPublicsStream(); + Expected getPDBSymbolStream(); + Expected getStringTable(); + + Error commit(); + +private: + Error setSuperBlock(const SuperBlock *Block); + + BumpPtrAllocator Allocator; + + std::unique_ptr Buffer; + const PDBFile::SuperBlock *SB; + ArrayRef StreamSizes; + ArrayRef DirectoryBlocks; + std::vector> StreamMap; + + std::unique_ptr Info; + std::unique_ptr Dbi; + std::unique_ptr Tpi; + std::unique_ptr Ipi; + std::unique_ptr Publics; + std::unique_ptr Symbols; + std::unique_ptr DirectoryStream; + std::unique_ptr StringTableStream; + std::unique_ptr StringTable; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h b/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h new file mode 100644 index 0000000000000000000000000000000000000000..ba7ca935e5fa9247d3e64459794b6d07d72f331a --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h @@ -0,0 +1,60 @@ +//===- PDBFileBuilder.h - PDB File Creation ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBFILEBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBFILEBUILDER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" + +#include +#include + +namespace llvm { +namespace codeview { +class StreamInterface; +} +namespace pdb { +class DbiStreamBuilder; +class InfoStreamBuilder; +class PDBFile; + +class PDBFileBuilder { +public: + explicit PDBFileBuilder( + std::unique_ptr PdbFileBuffer); + PDBFileBuilder(const PDBFileBuilder &) = delete; + PDBFileBuilder &operator=(const PDBFileBuilder &) = delete; + + Error setSuperBlock(const PDBFile::SuperBlock &B); + void setStreamSizes(ArrayRef S); + void setDirectoryBlocks(ArrayRef D); + void setStreamMap(const std::vector> &S); + Error generateSimpleStreamMap(); + + InfoStreamBuilder &getInfoBuilder(); + DbiStreamBuilder &getDbiBuilder(); + + Expected> build(); + +private: + std::unique_ptr PdbFileBuffer; + std::unique_ptr Info; + std::unique_ptr Dbi; + + std::unique_ptr File; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h b/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h new file mode 100644 index 0000000000000000000000000000000000000000..f5bfb0ed60a9843272ee52050f2a53e26d65c565 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/PublicsStream.h @@ -0,0 +1,74 @@ +//===- PublicsStream.h - PDB Public Symbol Stream -------- ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PUBLICSSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PUBLICSSTREAM_H + +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class DbiStream; +class PDBFile; + +class PublicsStream { + struct GSIHashHeader; + struct HeaderInfo; + +public: + PublicsStream(PDBFile &File, std::unique_ptr Stream); + ~PublicsStream(); + Error reload(); + + uint32_t getSymHash() const; + uint32_t getAddrMap() const; + uint32_t getNumBuckets() const { return NumBuckets; } + iterator_range + getSymbols(bool *HadError) const; + codeview::FixedStreamArray getHashBuckets() const { + return HashBuckets; + } + codeview::FixedStreamArray getAddressMap() const { + return AddressMap; + } + codeview::FixedStreamArray getThunkMap() const { + return ThunkMap; + } + codeview::FixedStreamArray getSectionOffsets() const { + return SectionOffsets; + } + + Error commit(); + +private: + PDBFile &Pdb; + + std::unique_ptr Stream; + uint32_t NumBuckets = 0; + ArrayRef Bitmap; + codeview::FixedStreamArray HashRecords; + codeview::FixedStreamArray HashBuckets; + codeview::FixedStreamArray AddressMap; + codeview::FixedStreamArray ThunkMap; + codeview::FixedStreamArray SectionOffsets; + + const HeaderInfo *Header; + const GSIHashHeader *HashHdr; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/RawConstants.h b/include/llvm/DebugInfo/PDB/Raw/RawConstants.h new file mode 100644 index 0000000000000000000000000000000000000000..8daaf47882d87d6ee8b3f203368b399fa5613b36 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawConstants.h @@ -0,0 +1,94 @@ +//===- RawConstants.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" + +#include + +namespace llvm { +namespace pdb { + +enum PdbRaw_ImplVer : uint32_t { + PdbImplVC2 = 19941610, + PdbImplVC4 = 19950623, + PdbImplVC41 = 19950814, + PdbImplVC50 = 19960307, + PdbImplVC98 = 19970604, + PdbImplVC70Dep = 19990604, // deprecated + PdbImplVC70 = 20000404, + PdbImplVC80 = 20030901, + PdbImplVC110 = 20091201, + PdbImplVC140 = 20140508, +}; + +enum PdbRaw_DbiVer : uint32_t { + PdbDbiVC41 = 930803, + PdbDbiV50 = 19960307, + PdbDbiV60 = 19970606, + PdbDbiV70 = 19990903, + PdbDbiV110 = 20091201 +}; + +enum PdbRaw_TpiVer : uint32_t { + PdbTpiV40 = 19950410, + PdbTpiV41 = 19951122, + PdbTpiV50 = 19961031, + PdbTpiV70 = 19990903, + PdbTpiV80 = 20040203, +}; + +enum PdbRaw_DbiSecContribVer : uint32_t { + DbiSecContribVer60 = 0xeffe0000 + 19970605, + DbiSecContribV2 = 0xeffe0000 + 20140516 +}; + +enum SpecialStream : uint32_t { + // Stream 0 contains the copy of previous version of the MSF directory. + // We are not currently using it, but technically if we find the main + // MSF is corrupted, we could fallback to it. + OldMSFDirectory = 0, + + StreamPDB = 1, + StreamTPI = 2, + StreamDBI = 3, + StreamIPI = 4, +}; + +enum class DbgHeaderType : uint16_t { + FPO, + Exception, + Fixup, + OmapToSrc, + OmapFromSrc, + SectionHdr, + TokenRidMap, + Xdata, + Pdata, + NewFPO, + SectionHdrOrig, + Max +}; + +enum class OMFSegDescFlags : uint16_t { + Read = 1 << 0, // Segment is readable. + Write = 1 << 1, // Segment is writable. + Execute = 1 << 2, // Segment is executable. + AddressIs32Bit = 1 << 3, // Descriptor describes a 32-bit linear address. + IsSelector = 1 << 8, // Frame represents a selector. + IsAbsoluteAddress = 1 << 9, // Frame represents an absolute address. + IsGroup = 1 << 10 // If set, descriptor represents a group. +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_RAW_PDBRAWCONSTANTS_H diff --git a/include/llvm/DebugInfo/PDB/Raw/RawError.h b/include/llvm/DebugInfo/PDB/Raw/RawError.h new file mode 100644 index 0000000000000000000000000000000000000000..b0687cddbf48bbb875eabf7e9255c1808e8e6562 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawError.h @@ -0,0 +1,49 @@ +//===- RawError.h - Error extensions for raw PDB implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_RAWERROR_H +#define LLVM_DEBUGINFO_PDB_RAW_RAWERROR_H + +#include "llvm/Support/Error.h" + +#include + +namespace llvm { +namespace pdb { +enum class raw_error_code { + unspecified = 1, + feature_unsupported, + corrupt_file, + insufficient_buffer, + no_stream, + index_out_of_bounds, + invalid_block_address, + not_writable, + invalid_tpi_hash, +}; + +/// Base class for errors originating when parsing raw PDB files +class RawError : public ErrorInfo { +public: + static char ID; + RawError(raw_error_code C); + RawError(const std::string &Context); + RawError(raw_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + raw_error_code Code; +}; +} +} +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/RawSession.h b/include/llvm/DebugInfo/PDB/Raw/RawSession.h new file mode 100644 index 0000000000000000000000000000000000000000..73d281eab1a7a5d63b4ed9c59a8c0b6c03168153 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawSession.h @@ -0,0 +1,75 @@ +//===- RawSession.h - Native implementation of IPDBSession ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_RAWSESSION_H +#define LLVM_DEBUGINFO_PDB_RAW_RAWSESSION_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class RawSession : public IPDBSession { +public: + explicit RawSession(std::unique_ptr PdbFile); + ~RawSession() override; + + static Error createFromPdb(StringRef Path, + std::unique_ptr &Session); + static Error createFromExe(StringRef Path, + std::unique_ptr &Session); + + uint64_t getLoadAddress() const override; + void setLoadAddress(uint64_t Address) override; + std::unique_ptr getGlobalScope() const override; + std::unique_ptr getSymbolById(uint32_t SymbolId) const override; + + std::unique_ptr + findSymbolByAddress(uint64_t Address, PDB_SymType Type) const override; + + std::unique_ptr + findLineNumbers(const PDBSymbolCompiland &Compiland, + const IPDBSourceFile &File) const override; + std::unique_ptr + findLineNumbersByAddress(uint64_t Address, uint32_t Length) const override; + + std::unique_ptr + findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr + findOneSourceFile(const PDBSymbolCompiland *Compiland, + llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr> + findCompilandsForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr + findOneCompilandForSourceFile(llvm::StringRef Pattern, + PDB_NameSearchFlags Flags) const override; + std::unique_ptr getAllSourceFiles() const override; + std::unique_ptr getSourceFilesForCompiland( + const PDBSymbolCompiland &Compiland) const override; + std::unique_ptr + getSourceFileById(uint32_t FileId) const override; + + std::unique_ptr getDebugStreams() const override; + + PDBFile &getPDBFile() { return *Pdb; } + const PDBFile &getPDBFile() const { return *Pdb; } + +private: + std::unique_ptr Pdb; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/RawTypes.h b/include/llvm/DebugInfo/PDB/Raw/RawTypes.h new file mode 100644 index 0000000000000000000000000000000000000000..afcfe9405c0f46f1e407adfe6f9435307dc1ce9b --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/RawTypes.h @@ -0,0 +1,86 @@ +//===- RawTypes.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_RAWTYPES_H +#define LLVM_DEBUGINFO_PDB_RAW_RAWTYPES_H + +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace pdb { +// This struct is defined as "SO" in langapi/include/pdb.h. +struct SectionOffset { + support::ulittle32_t Off; + support::ulittle16_t Isect; + char Padding[2]; +}; + +// This is HRFile. +struct PSHashRecord { + support::ulittle32_t Off; // Offset in the symbol record stream + support::ulittle32_t CRef; +}; + +// This struct is defined as `SC` in include/dbicommon.h +struct SectionContrib { + support::ulittle16_t ISect; + char Padding[2]; + support::little32_t Off; + support::little32_t Size; + support::ulittle32_t Characteristics; + support::ulittle16_t Imod; + char Padding2[2]; + support::ulittle32_t DataCrc; + support::ulittle32_t RelocCrc; +}; + +// This struct is defined as `SC2` in include/dbicommon.h +struct SectionContrib2 { + // To guarantee SectionContrib2 is standard layout, we cannot use inheritance. + SectionContrib Base; + support::ulittle32_t ISectCoff; +}; + +// This corresponds to the `OMFSegMap` structure. +struct SecMapHeader { + support::ulittle16_t SecCount; // Number of segment descriptors in table + support::ulittle16_t SecCountLog; // Number of logical segment descriptors +}; + +// This corresponds to the `OMFSegMapDesc` structure. The definition is not +// present in the reference implementation, but the layout is derived from +// code that accesses the fields. +struct SecMapEntry { + support::ulittle16_t Flags; // Descriptor flags. See OMFSegDescFlags + support::ulittle16_t Ovl; // Logical overlay number. + support::ulittle16_t Group; // Group index into descriptor array. + support::ulittle16_t Frame; + support::ulittle16_t SecName; // Byte index of the segment or group name + // in the sstSegName table, or 0xFFFF. + support::ulittle16_t ClassName; // Byte index of the class name in the + // sstSegName table, or 0xFFFF. + support::ulittle32_t Offset; // Byte offset of the logical segment + // within the specified physical segment. + // If group is set in flags, offset is the + // offset of the group. + support::ulittle32_t SecByteLength; // Byte count of the segment or group. +}; + +// Used for serialized hash table in TPI stream. +// In the reference, it is an array of TI and cbOff pair. +struct TypeIndexOffset { + codeview::TypeIndex Type; + support::ulittle32_t Offset; +}; + +} // namespace pdb +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h b/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h new file mode 100644 index 0000000000000000000000000000000000000000..685a23411a3b63685b3b26e1aeb35562a90b52e2 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h @@ -0,0 +1,41 @@ +//===- SymbolStream.cpp - PDB Symbol Stream Access --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBSYMBOLSTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBSYMBOLSTREAM_H + +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class SymbolStream { +public: + SymbolStream(std::unique_ptr Stream); + ~SymbolStream(); + Error reload(); + + iterator_range + getSymbols(bool *HadError) const; + + Error commit(); + +private: + codeview::CVSymbolArray SymbolRecords; + std::unique_ptr Stream; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/PDB/Raw/TpiStream.h b/include/llvm/DebugInfo/PDB/Raw/TpiStream.h new file mode 100644 index 0000000000000000000000000000000000000000..4f36d70aabed333b408bd9a838b2363a3a503722 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Raw/TpiStream.h @@ -0,0 +1,72 @@ +//===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H + +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/Support/raw_ostream.h" + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class TpiStream { + struct HeaderInfo; + +public: + TpiStream(const PDBFile &File, std::unique_ptr Stream); + ~TpiStream(); + Error reload(); + + PdbRaw_TpiVer getTpiVersion() const; + + uint32_t TypeIndexBegin() const; + uint32_t TypeIndexEnd() const; + uint32_t NumTypeRecords() const; + uint16_t getTypeHashStreamIndex() const; + uint16_t getTypeHashStreamAuxIndex() const; + + uint32_t getHashKeySize() const; + uint32_t NumHashBuckets() const; + codeview::FixedStreamArray getHashValues() const; + codeview::FixedStreamArray getTypeIndexOffsets() const; + codeview::FixedStreamArray getHashAdjustments() const; + + iterator_range types(bool *HadError) const; + + Error commit(); + +private: + Error verifyHashValues(); + + const PDBFile &Pdb; + std::unique_ptr Stream; + + codeview::CVTypeArray TypeRecords; + + std::unique_ptr HashStream; + codeview::FixedStreamArray HashValues; + codeview::FixedStreamArray TypeIndexOffsets; + codeview::FixedStreamArray HashAdjustments; + + const HeaderInfo *Header; +}; +} +} + +#endif diff --git a/include/llvm/DebugInfo/Symbolize/DIPrinter.h b/include/llvm/DebugInfo/Symbolize/DIPrinter.h index 3098199bb4da6320b21fda32dd75737b773170e8..49f86eae01cf03273760f428185ef322168a8877 100644 --- a/include/llvm/DebugInfo/Symbolize/DIPrinter.h +++ b/include/llvm/DebugInfo/Symbolize/DIPrinter.h @@ -31,7 +31,7 @@ class DIPrinter { int PrintSourceContext; void print(const DILineInfo &Info, bool Inlined); - void printContext(std::string FileName, int64_t Line); + void printContext(const std::string &FileName, int64_t Line); public: DIPrinter(raw_ostream &OS, bool PrintFunctionNames = true, diff --git a/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h b/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h index ff9cc808875d4e8fa966492d52b6932b556dbb5f..e0bec6f6cf8598795035b2a868101b5a19171770 100644 --- a/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h +++ b/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h @@ -14,8 +14,6 @@ #define LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEMODULE_H #include "llvm/DebugInfo/DIContext.h" -#include -#include namespace llvm { namespace object { diff --git a/include/llvm/DebugInfo/Symbolize/Symbolize.h b/include/llvm/DebugInfo/Symbolize/Symbolize.h index ec3ae002659cd8dd979bd7f839a46f880738339b..9253adf7eedd491628c14b138c4fc48e6504d55b 100644 --- a/include/llvm/DebugInfo/Symbolize/Symbolize.h +++ b/include/llvm/DebugInfo/Symbolize/Symbolize.h @@ -19,6 +19,7 @@ #include #include #include +#include namespace llvm { namespace symbolize { @@ -40,7 +41,7 @@ public: bool RelativeAddresses = false, std::string DefaultArch = "") : PrintFunctions(PrintFunctions), UseSymbolTable(UseSymbolTable), Demangle(Demangle), RelativeAddresses(RelativeAddresses), - DefaultArch(DefaultArch) {} + DefaultArch(std::move(DefaultArch)) {} }; LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {} @@ -48,12 +49,12 @@ public: flush(); } - ErrorOr symbolizeCode(const std::string &ModuleName, - uint64_t ModuleOffset); - ErrorOr symbolizeInlinedCode(const std::string &ModuleName, - uint64_t ModuleOffset); - ErrorOr symbolizeData(const std::string &ModuleName, - uint64_t ModuleOffset); + Expected symbolizeCode(const std::string &ModuleName, + uint64_t ModuleOffset); + Expected symbolizeInlinedCode(const std::string &ModuleName, + uint64_t ModuleOffset); + Expected symbolizeData(const std::string &ModuleName, + uint64_t ModuleOffset); void flush(); static std::string DemangleName(const std::string &Name, const SymbolizableModule *ModInfo); @@ -63,8 +64,13 @@ private: // corresponding debug info. These objects can be the same. typedef std::pair ObjectPair; - ErrorOr + /// Returns a SymbolizableModule or an error if loading debug info failed. + /// Only one attempt is made to load a module, and errors during loading are + /// only reported once. Subsequent calls to get module info for a module that + /// failed to load will return nullptr. + Expected getOrCreateModuleInfo(const std::string &ModuleName); + ObjectFile *lookUpDsymFile(const std::string &Path, const MachOObjectFile *ExeObj, const std::string &ArchName); @@ -73,27 +79,27 @@ private: const std::string &ArchName); /// \brief Returns pair of pointers to object and debug object. - ErrorOr getOrCreateObjectPair(const std::string &Path, + Expected getOrCreateObjectPair(const std::string &Path, const std::string &ArchName); /// \brief Return a pointer to object file at specified path, for a specified /// architecture (e.g. if path refers to a Mach-O universal binary, only one /// object file from it will be returned). - ErrorOr getOrCreateObject(const std::string &Path, + Expected getOrCreateObject(const std::string &Path, const std::string &ArchName); - std::map>> Modules; + std::map> Modules; /// \brief Contains cached results of getOrCreateObjectPair(). - std::map, ErrorOr> + std::map, ObjectPair> ObjectPairForPathArch; /// \brief Contains parsed binary for each path, or parsing error. - std::map>> BinaryForPath; + std::map> BinaryForPath; /// \brief Parsed object file for path/architecture pair, where "path" refers /// to Mach-O universal binary. - std::map, ErrorOr>> + std::map, std::unique_ptr> ObjectForUBPathAndArch; Options Opts; diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h index a7302602dcd839da11813a2756d81ed6a2b81b67..ab13028b3ae04f8201cc478109111bbc1cb94d47 100644 --- a/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -22,7 +22,6 @@ #include "llvm/IR/Module.h" #include "llvm/IR/ValueHandle.h" #include "llvm/IR/ValueMap.h" -#include "llvm/MC/MCCodeGenInfo.h" #include "llvm/Object/Binary.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Mutex.h" @@ -290,7 +289,8 @@ public: /// at the specified location. This is used internally as functions are JIT'd /// and as global variables are laid out in memory. It can and should also be /// used by clients of the EE that want to have an LLVM global overlay - /// existing data in memory. Mappings are automatically removed when their + /// existing data in memory. Values to be mapped should be named, and have + /// external or weak linkage. Mappings are automatically removed when their /// GlobalValue is destroyed. void addGlobalMapping(const GlobalValue *GV, void *Addr); void addGlobalMapping(StringRef Name, uint64_t Addr); @@ -477,11 +477,11 @@ public: /// specified function pointer is invoked to create it. If it returns null, /// the JIT will abort. void InstallLazyFunctionCreator(FunctionCreator C) { - LazyFunctionCreator = C; + LazyFunctionCreator = std::move(C); } protected: - ExecutionEngine(const DataLayout DL) : DL(std::move(DL)){} + ExecutionEngine(DataLayout DL) : DL(std::move(DL)) {} explicit ExecutionEngine(DataLayout DL, std::unique_ptr M); explicit ExecutionEngine(std::unique_ptr M); @@ -518,7 +518,7 @@ private: std::shared_ptr MemMgr; std::shared_ptr Resolver; TargetOptions Options; - Reloc::Model RelocModel; + Optional RelocModel; CodeModel::Model CMModel; std::string MArch; std::string MCPU; diff --git a/include/llvm/ExecutionEngine/GenericValue.h b/include/llvm/ExecutionEngine/GenericValue.h index 0e92f79eba8f3c88d1cedc5b608c793913a854fb..537745519ddb6db6a679dd582b61a3dde61f052b 100644 --- a/include/llvm/ExecutionEngine/GenericValue.h +++ b/include/llvm/ExecutionEngine/GenericValue.h @@ -17,6 +17,7 @@ #include "llvm/ADT/APInt.h" #include "llvm/Support/DataTypes.h" +#include namespace llvm { diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index 84af4728b3504559b6a122bc125f4e99eadbaf8c..ef88dd03ad4fe1c4d913f3228b2883f96f3371ca 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -19,12 +19,12 @@ #include "LambdaResolver.h" #include "LogicalDylib.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Debug.h" #include "llvm/Transforms/Utils/Cloning.h" #include #include #include - -#include "llvm/Support/Debug.h" +#include namespace llvm { namespace orc { @@ -46,7 +46,7 @@ private: class LambdaMaterializer final : public ValueMaterializer { public: LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {} - Value *materializeDeclFor(Value *V) final { return M(V); } + Value *materialize(Value *V) final { return M(V); } private: MaterializerFtor M; @@ -145,7 +145,7 @@ private: return *this; } - SymbolResolverFtor ExternalSymbolResolver; + std::unique_ptr ExternalSymbolResolver; std::unique_ptr> MemMgr; ModuleAdderFtor ModuleAdder; }; @@ -173,7 +173,7 @@ public: CompileCallbackMgrT &CallbackMgr, IndirectStubsManagerBuilderT CreateIndirectStubsManager, bool CloneStubsIntoPartitions = true) - : BaseLayer(BaseLayer), Partition(Partition), + : BaseLayer(BaseLayer), Partition(std::move(Partition)), CompileCallbackMgr(CallbackMgr), CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)), CloneStubsIntoPartitions(CloneStubsIntoPartitions) {} @@ -188,10 +188,7 @@ public: LogicalDylibs.push_back(CODLogicalDylib(BaseLayer)); auto &LDResources = LogicalDylibs.back().getDylibResources(); - LDResources.ExternalSymbolResolver = - [Resolver](const std::string &Name) { - return Resolver->findSymbol(Name); - }; + LDResources.ExternalSymbolResolver = std::move(Resolver); auto &MemMgrRef = *MemMgr; LDResources.MemMgr = @@ -256,14 +253,8 @@ private: Module &SrcM = LMResources.SourceModule->getResource(); - // Create the GlobalValues module. + // Create stub functions. const DataLayout &DL = SrcM.getDataLayout(); - auto GVsM = llvm::make_unique((SrcM.getName() + ".globals").str(), - SrcM.getContext()); - GVsM->setDataLayout(DL); - - // Create function stubs. - ValueToValueMapTy VMap; { typename IndirectStubsMgrT::StubInitsMap StubInits; for (auto &F : SrcM) { @@ -295,6 +286,19 @@ private: assert(!EC && "Error generating stubs"); } + // If this module doesn't contain any globals or aliases we can bail out + // early and avoid the overhead of creating and managing an empty globals + // module. + if (SrcM.global_empty() && SrcM.alias_empty()) + return; + + // Create the GlobalValues module. + auto GVsM = llvm::make_unique((SrcM.getName() + ".globals").str(), + SrcM.getContext()); + GVsM->setDataLayout(DL); + + ValueToValueMapTy VMap; + // Clone global variable decls. for (auto &GV : SrcM.globals()) if (!GV.isDeclaration() && !VMap.count(&GV)) @@ -356,16 +360,17 @@ private: [&LD, LMH](const std::string &Name) { auto &LMResources = LD.getLogicalModuleResources(LMH); if (auto Sym = LMResources.StubsMgr->findStub(Name, false)) - return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); - return LD.getDylibResources().ExternalSymbolResolver(Name); + return Sym.toRuntimeDyldSymbol(); + auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver; + return LDResolver->findSymbolInLogicalDylib(Name); }, - [](const std::string &Name) { - return RuntimeDyld::SymbolInfo(nullptr); + [&LD](const std::string &Name) { + auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver; + return LDResolver->findSymbol(Name); }); - auto GVsH = - LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM), - std::move(GVsResolver)); + auto GVsH = LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM), + std::move(GVsResolver)); LD.addToLogicalModule(LMH, GVsH); } @@ -481,20 +486,18 @@ private: // Create memory manager and symbol resolver. auto Resolver = createLambdaResolver( [this, &LD, LMH](const std::string &Name) { - if (auto Symbol = LD.findSymbolInternally(LMH, Name)) - return RuntimeDyld::SymbolInfo(Symbol.getAddress(), - Symbol.getFlags()); - return LD.getDylibResources().ExternalSymbolResolver(Name); + if (auto Sym = LD.findSymbolInternally(LMH, Name)) + return Sym.toRuntimeDyldSymbol(); + auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver; + return LDResolver->findSymbolInLogicalDylib(Name); }, - [this, &LD, LMH](const std::string &Name) { - if (auto Symbol = LD.findSymbolInternally(LMH, Name)) - return RuntimeDyld::SymbolInfo(Symbol.getAddress(), - Symbol.getFlags()); - return RuntimeDyld::SymbolInfo(nullptr); + [this, &LD](const std::string &Name) { + auto &LDResolver = LD.getDylibResources().ExternalSymbolResolver; + return LDResolver->findSymbol(Name); }); return LD.getDylibResources().ModuleAdder(BaseLayer, std::move(M), - std::move(Resolver)); + std::move(Resolver)); } BaseLayerT &BaseLayer; diff --git a/include/llvm/ExecutionEngine/Orc/CompileUtils.h b/include/llvm/ExecutionEngine/Orc/CompileUtils.h index 1e7d211196f57203b8693576ed2b16de980d870f..ce0864fbd9c9a65a4c4d2065eb1fbc526151e7cf 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileUtils.h +++ b/include/llvm/ExecutionEngine/Orc/CompileUtils.h @@ -42,12 +42,13 @@ public: PM.run(M); std::unique_ptr ObjBuffer( new ObjectMemoryBuffer(std::move(ObjBufferSV))); - ErrorOr> Obj = + Expected> Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); - // TODO: Actually report errors helpfully. typedef object::OwningBinary OwningObj; if (Obj) return OwningObj(std::move(*Obj), std::move(ObjBuffer)); + // TODO: Actually report errors helpfully. + consumeError(Obj.takeError()); return OwningObj(nullptr, nullptr); } diff --git a/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h b/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h index 23ce7e24ad32ca1e088ec47d683abc611844b362..e6ce18a42b8bb54c8b1940ddc7f1a6d8622b5c88 100644 --- a/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h +++ b/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h @@ -124,10 +124,13 @@ private: if (!ObjBuffer) return object::OwningBinary(); - ErrorOr> Obj = + Expected> Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); - if (!Obj) + if (!Obj) { + // TODO: Actually report errors helpfully. + consumeError(Obj.takeError()); return object::OwningBinary(); + } return object::OwningBinary(std::move(*Obj), std::move(ObjBuffer)); diff --git a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h index e17630fa05ffbf229416dfde9077757432d53b96..51172c51e136029d5fd288dffae8e13dd4aa2e72 100644 --- a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h +++ b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h @@ -16,14 +16,12 @@ #include "JITSymbol.h" #include "LambdaResolver.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" -#include "llvm/Transforms/Utils/ValueMapper.h" #include "llvm/Support/Process.h" -#include +#include "llvm/Transforms/Utils/ValueMapper.h" namespace llvm { namespace orc { @@ -31,7 +29,6 @@ namespace orc { /// @brief Target-independent base class for compile callback management. class JITCompileCallbackManager { public: - typedef std::function CompileFtor; /// @brief Handle to a newly created compile callback. Can be used to get an @@ -40,12 +37,13 @@ public: class CompileCallbackInfo { public: CompileCallbackInfo(TargetAddress Addr, CompileFtor &Compile) - : Addr(Addr), Compile(Compile) {} + : Addr(Addr), Compile(Compile) {} TargetAddress getAddress() const { return Addr; } void setCompileAction(CompileFtor Compile) { this->Compile = std::move(Compile); } + private: TargetAddress Addr; CompileFtor &Compile; @@ -55,7 +53,7 @@ public: /// @param ErrorHandlerAddress The address of an error handler in the target /// process to be used if a compile callback fails. JITCompileCallbackManager(TargetAddress ErrorHandlerAddress) - : ErrorHandlerAddress(ErrorHandlerAddress) {} + : ErrorHandlerAddress(ErrorHandlerAddress) {} virtual ~JITCompileCallbackManager() {} @@ -71,8 +69,10 @@ public: // Found a callback handler. Yank this trampoline out of the active list and // put it back in the available trampolines list, then try to run the // handler's compile and update actions. - // Moving the trampoline ID back to the available list first means there's at - // least one available trampoline if the compile action triggers a request for + // Moving the trampoline ID back to the available list first means there's + // at + // least one available trampoline if the compile action triggers a request + // for // a new one. auto Compile = std::move(I->second); ActiveTrampolines.erase(I); @@ -118,7 +118,6 @@ protected: std::vector AvailableTrampolines; private: - TargetAddress getAvailableTrampolineAddr() { if (this->AvailableTrampolines.empty()) grow(); @@ -139,20 +138,17 @@ private: template class LocalJITCompileCallbackManager : public JITCompileCallbackManager { public: - /// @brief Construct a InProcessJITCompileCallbackManager. /// @param ErrorHandlerAddress The address of an error handler in the target /// process to be used if a compile callback fails. LocalJITCompileCallbackManager(TargetAddress ErrorHandlerAddress) - : JITCompileCallbackManager(ErrorHandlerAddress) { + : JITCompileCallbackManager(ErrorHandlerAddress) { /// Set up the resolver block. std::error_code EC; - ResolverBlock = - sys::OwningMemoryBlock( - sys::Memory::allocateMappedMemory(TargetT::ResolverCodeSize, nullptr, - sys::Memory::MF_READ | - sys::Memory::MF_WRITE, EC)); + ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( + TargetT::ResolverCodeSize, nullptr, + sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); assert(!EC && "Failed to allocate resolver block"); TargetT::writeResolverCode(static_cast(ResolverBlock.base()), @@ -165,13 +161,11 @@ public: } private: - static TargetAddress reenter(void *CCMgr, void *TrampolineId) { JITCompileCallbackManager *Mgr = - static_cast(CCMgr); + static_cast(CCMgr); return Mgr->executeCompileCallback( - static_cast( - reinterpret_cast(TrampolineId))); + static_cast(reinterpret_cast(TrampolineId))); } void grow() override { @@ -179,18 +173,16 @@ private: std::error_code EC; auto TrampolineBlock = - sys::OwningMemoryBlock( - sys::Memory::allocateMappedMemory(sys::Process::getPageSize(), nullptr, - sys::Memory::MF_READ | - sys::Memory::MF_WRITE, EC)); + sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( + sys::Process::getPageSize(), nullptr, + sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); assert(!EC && "Failed to allocate trampoline block"); - unsigned NumTrampolines = - (sys::Process::getPageSize() - TargetT::PointerSize) / + (sys::Process::getPageSize() - TargetT::PointerSize) / TargetT::TrampolineSize; - uint8_t *TrampolineMem = static_cast(TrampolineBlock.base()); + uint8_t *TrampolineMem = static_cast(TrampolineBlock.base()); TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(), NumTrampolines); @@ -214,19 +206,18 @@ private: /// @brief Base class for managing collections of named indirect stubs. class IndirectStubsManager { public: - /// @brief Map type for initializing the manager. See init. typedef StringMap> StubInitsMap; virtual ~IndirectStubsManager() {} /// @brief Create a single stub with the given name, target address and flags. - virtual std::error_code createStub(StringRef StubName, TargetAddress StubAddr, - JITSymbolFlags StubFlags) = 0; + virtual Error createStub(StringRef StubName, TargetAddress StubAddr, + JITSymbolFlags StubFlags) = 0; /// @brief Create StubInits.size() stubs with the given names, target /// addresses, and flags. - virtual std::error_code createStubs(const StubInitsMap &StubInits) = 0; + virtual Error createStubs(const StubInitsMap &StubInits) = 0; /// @brief Find the stub with the given name. If ExportedStubsOnly is true, /// this will only return a result if the stub's flags indicate that it @@ -237,7 +228,8 @@ public: virtual JITSymbol findPointer(StringRef Name) = 0; /// @brief Change the value of the implementation pointer for the stub. - virtual std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) = 0; + virtual Error updatePointer(StringRef Name, TargetAddress NewAddr) = 0; + private: virtual void anchor(); }; @@ -247,26 +239,25 @@ private: template class LocalIndirectStubsManager : public IndirectStubsManager { public: - - std::error_code createStub(StringRef StubName, TargetAddress StubAddr, - JITSymbolFlags StubFlags) override { - if (auto EC = reserveStubs(1)) - return EC; + Error createStub(StringRef StubName, TargetAddress StubAddr, + JITSymbolFlags StubFlags) override { + if (auto Err = reserveStubs(1)) + return Err; createStubInternal(StubName, StubAddr, StubFlags); - return std::error_code(); + return Error::success(); } - std::error_code createStubs(const StubInitsMap &StubInits) override { - if (auto EC = reserveStubs(StubInits.size())) - return EC; + Error createStubs(const StubInitsMap &StubInits) override { + if (auto Err = reserveStubs(StubInits.size())) + return Err; for (auto &Entry : StubInits) createStubInternal(Entry.first(), Entry.second.first, Entry.second.second); - return std::error_code(); + return Error::success(); } JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { @@ -277,7 +268,7 @@ public: void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second); assert(StubAddr && "Missing stub address"); auto StubTargetAddr = - static_cast(reinterpret_cast(StubAddr)); + static_cast(reinterpret_cast(StubAddr)); auto StubSymbol = JITSymbol(StubTargetAddr, I->second.second); if (ExportedStubsOnly && !StubSymbol.isExported()) return nullptr; @@ -292,35 +283,34 @@ public: void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second); assert(PtrAddr && "Missing pointer address"); auto PtrTargetAddr = - static_cast(reinterpret_cast(PtrAddr)); + static_cast(reinterpret_cast(PtrAddr)); return JITSymbol(PtrTargetAddr, I->second.second); } - std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) override { + Error updatePointer(StringRef Name, TargetAddress NewAddr) override { auto I = StubIndexes.find(Name); assert(I != StubIndexes.end() && "No stub pointer for symbol"); auto Key = I->second.first; *IndirectStubsInfos[Key.first].getPtr(Key.second) = - reinterpret_cast(static_cast(NewAddr)); - return std::error_code(); + reinterpret_cast(static_cast(NewAddr)); + return Error::success(); } private: - - std::error_code reserveStubs(unsigned NumStubs) { + Error reserveStubs(unsigned NumStubs) { if (NumStubs <= FreeStubs.size()) - return std::error_code(); + return Error::success(); unsigned NewStubsRequired = NumStubs - FreeStubs.size(); unsigned NewBlockId = IndirectStubsInfos.size(); typename TargetT::IndirectStubsInfo ISI; - if (auto EC = TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, - nullptr)) - return EC; + if (auto Err = + TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, nullptr)) + return Err; for (unsigned I = 0; I < ISI.getNumStubs(); ++I) FreeStubs.push_back(std::make_pair(NewBlockId, I)); IndirectStubsInfos.push_back(std::move(ISI)); - return std::error_code(); + return Error::success(); } void createStubInternal(StringRef StubName, TargetAddress InitAddr, @@ -328,7 +318,7 @@ private: auto Key = FreeStubs.back(); FreeStubs.pop_back(); *IndirectStubsInfos[Key.first].getPtr(Key.second) = - reinterpret_cast(static_cast(InitAddr)); + reinterpret_cast(static_cast(InitAddr)); StubIndexes[StubName] = std::make_pair(Key, StubFlags); } @@ -338,17 +328,32 @@ private: StringMap> StubIndexes; }; +/// @brief Create a local compile callback manager. +/// +/// The given target triple will determine the ABI, and the given +/// ErrorHandlerAddress will be used by the resulting compile callback +/// manager if a compile callback fails. +std::unique_ptr +createLocalCompileCallbackManager(const Triple &T, + TargetAddress ErrorHandlerAddress); + +/// @brief Create a local indriect stubs manager builder. +/// +/// The given target triple will determine the ABI. +std::function()> +createLocalIndirectStubsManagerBuilder(const Triple &T); + /// @brief Build a function pointer of FunctionType with the given constant /// address. /// /// Usage example: Turn a trampoline address into a function pointer constant /// for use in a stub. -Constant* createIRTypedAddress(FunctionType &FT, TargetAddress Addr); +Constant *createIRTypedAddress(FunctionType &FT, TargetAddress Addr); /// @brief Create a function pointer with the given type, name, and initializer /// in the given Module. -GlobalVariable* createImplPointer(PointerType &PT, Module &M, - const Twine &Name, Constant *Initializer); +GlobalVariable *createImplPointer(PointerType &PT, Module &M, const Twine &Name, + Constant *Initializer); /// @brief Turn a function declaration into a stub function that makes an /// indirect call using the given function pointer. @@ -373,7 +378,7 @@ void makeAllSymbolsExternallyAccessible(Module &M); /// modules with these utilities, all decls should be cloned (and added to a /// single VMap) before any bodies are moved. This will ensure that references /// between functions all refer to the versions in the new module. -Function* cloneFunctionDecl(Module &Dst, const Function &F, +Function *cloneFunctionDecl(Module &Dst, const Function &F, ValueToValueMapTy *VMap = nullptr); /// @brief Move the body of function 'F' to a cloned function declaration in a @@ -389,7 +394,7 @@ void moveFunctionBody(Function &OrigF, ValueToValueMapTy &VMap, Function *NewF = nullptr); /// @brief Clone a global variable declaration into a new module. -GlobalVariable* cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, +GlobalVariable *cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, ValueToValueMapTy *VMap = nullptr); /// @brief Move global variable GV from its parent module to cloned global @@ -406,7 +411,7 @@ void moveGlobalVariableInitializer(GlobalVariable &OrigGV, GlobalVariable *NewGV = nullptr); /// @brief Clone -GlobalAlias* cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, +GlobalAlias *cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, ValueToValueMapTy &VMap); } // End namespace orc. diff --git a/include/llvm/ExecutionEngine/Orc/JITSymbol.h b/include/llvm/ExecutionEngine/Orc/JITSymbol.h index 422a3761837c23ed965fe508de03ae722a726c67..464417e4e6d544bdae0ed1736db7ec0713eece70 100644 --- a/include/llvm/ExecutionEngine/Orc/JITSymbol.h +++ b/include/llvm/ExecutionEngine/Orc/JITSymbol.h @@ -15,6 +15,7 @@ #define LLVM_EXECUTIONENGINE_ORC_JITSYMBOL_H #include "llvm/ExecutionEngine/JITSymbolFlags.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/Support/DataTypes.h" #include #include @@ -52,6 +53,10 @@ public: JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags) : JITSymbolBase(Flags), GetAddress(std::move(GetAddress)), CachedAddr(0) {} + /// @brief Create a JITSymbol from a RuntimeDyld::SymbolInfo. + JITSymbol(const RuntimeDyld::SymbolInfo &Sym) + : JITSymbolBase(Sym.getFlags()), CachedAddr(Sym.getAddress()) {} + /// @brief Returns true if the symbol exists, false otherwise. explicit operator bool() const { return CachedAddr || GetAddress; } @@ -66,6 +71,11 @@ public: return CachedAddr; } + /// @brief Convert this JITSymbol to a RuntimeDyld::SymbolInfo. + RuntimeDyld::SymbolInfo toRuntimeDyldSymbol() { + return RuntimeDyld::SymbolInfo(getAddress(), getFlags()); + } + private: GetAddressFtor GetAddress; TargetAddress CachedAddr; diff --git a/include/llvm/ExecutionEngine/Orc/LambdaResolver.h b/include/llvm/ExecutionEngine/Orc/LambdaResolver.h index faa23658524fd6aea2913871b898eba34ed4c39f..a42b9d5c29d1e1e99cd1b2accbf52c4bd05ccd48 100644 --- a/include/llvm/ExecutionEngine/Orc/LambdaResolver.h +++ b/include/llvm/ExecutionEngine/Orc/LambdaResolver.h @@ -18,42 +18,41 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include -#include namespace llvm { namespace orc { -template +template class LambdaResolver : public RuntimeDyld::SymbolResolver { public: - LambdaResolver(ExternalLookupFtorT ExternalLookupFtor, - DylibLookupFtorT DylibLookupFtor) - : ExternalLookupFtor(ExternalLookupFtor), - DylibLookupFtor(DylibLookupFtor) {} - - RuntimeDyld::SymbolInfo findSymbol(const std::string &Name) final { - return ExternalLookupFtor(Name); - } + LambdaResolver(DylibLookupFtorT DylibLookupFtor, + ExternalLookupFtorT ExternalLookupFtor) + : DylibLookupFtor(DylibLookupFtor), + ExternalLookupFtor(ExternalLookupFtor) {} RuntimeDyld::SymbolInfo findSymbolInLogicalDylib(const std::string &Name) final { return DylibLookupFtor(Name); } + RuntimeDyld::SymbolInfo findSymbol(const std::string &Name) final { + return ExternalLookupFtor(Name); + } + private: - ExternalLookupFtorT ExternalLookupFtor; DylibLookupFtorT DylibLookupFtor; + ExternalLookupFtorT ExternalLookupFtor; }; -template -std::unique_ptr> -createLambdaResolver(ExternalLookupFtorT ExternalLookupFtor, - DylibLookupFtorT DylibLookupFtor) { - typedef LambdaResolver LR; - return make_unique(std::move(ExternalLookupFtor), - std::move(DylibLookupFtor)); +template +std::unique_ptr> +createLambdaResolver(DylibLookupFtorT DylibLookupFtor, + ExternalLookupFtorT ExternalLookupFtor) { + typedef LambdaResolver LR; + return make_unique(std::move(DylibLookupFtor), + std::move(ExternalLookupFtor)); } } // End namespace orc. diff --git a/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h b/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h index a5286ff9adde68fc46a502daf94fea5a6c1ccd79..c5fb6b847b3039f373ac2cc1ba156ddb75430ebb 100644 --- a/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h @@ -195,13 +195,8 @@ private: for (const auto &M : Ms) { Mangler Mang; - for (const auto &V : M->globals()) - if (auto GV = addGlobalValue(*Symbols, V, Mang, SearchName, - ExportedSymbolsOnly)) - return GV; - - for (const auto &F : *M) - if (auto GV = addGlobalValue(*Symbols, F, Mang, SearchName, + for (const auto &GO : M->global_objects()) + if (auto GV = addGlobalValue(*Symbols, GO, Mang, SearchName, ExportedSymbolsOnly)) return GV; } diff --git a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h index 85dfa849edc23a606534e1176ae85892f699fe99..a7798d8beb8d5f07ee12deda8648fa6ca601684d 100644 --- a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h @@ -57,8 +57,7 @@ protected: if (!Finalized) return JITSymbol(getSymbolMaterializer(Name), SymEntry->second.getFlags()); - return JITSymbol(SymEntry->second.getAddress(), - SymEntry->second.getFlags()); + return JITSymbol(SymEntry->second); } protected: StringMap SymbolTable; @@ -158,10 +157,12 @@ private: for (auto &Symbol : getObject(*Obj).symbols()) { if (Symbol.getFlags() & object::SymbolRef::SF_Undefined) continue; - ErrorOr SymbolName = Symbol.getName(); + Expected SymbolName = Symbol.getName(); // FIXME: Raise an error for bad symbols. - if (!SymbolName) + if (!SymbolName) { + consumeError(SymbolName.takeError()); continue; + } auto Flags = JITSymbol::flagsFromObjectSymbol(Symbol); SymbolTable.insert( std::make_pair(*SymbolName, RuntimeDyld::SymbolInfo(0, Flags))); diff --git a/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h b/include/llvm/ExecutionEngine/Orc/OrcABISupport.h similarity index 65% rename from include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h rename to include/llvm/ExecutionEngine/Orc/OrcABISupport.h index 7dd7bd353e32152d2319cd3f8c7e6660a1148f18..4a8d0b0b801c10d4db256f22eff3917f214e4889 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h +++ b/include/llvm/ExecutionEngine/Orc/OrcABISupport.h @@ -1,4 +1,4 @@ -//===-- OrcArchitectureSupport.h - Architecture support code ---*- C++ -*-===// +//===-------------- OrcABISupport.h - ABI support code ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,16 +7,16 @@ // //===----------------------------------------------------------------------===// // -// Architecture specific code for Orc, e.g. callback assembly. +// ABI specific code for Orc, e.g. callback assembly. // -// Architecture classes should be part of the JIT *target* process, not the host +// ABI classes should be part of the JIT *target* process, not the host // process (except where you're doing hosted JITing and the two are one and the // same). // //===----------------------------------------------------------------------===// -#ifndef LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H -#define LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H +#ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H +#define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H #include "IndirectionUtils.h" #include "llvm/Support/Memory.h" @@ -25,13 +25,13 @@ namespace llvm { namespace orc { -/// Generic ORC Architecture support. +/// Generic ORC ABI support. /// /// This class can be substituted as the target architecure support class for /// ORC templates that require one (e.g. IndirectStubsManagers). It does not /// support lazy JITing however, and any attempt to use that functionality /// will result in execution of an llvm_unreachable. -class OrcGenericArchitecture { +class OrcGenericABI { public: static const unsigned PointerSize = sizeof(uintptr_t); static const unsigned TrampolineSize = 1; @@ -59,9 +59,8 @@ public: void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); } }; - static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, - unsigned MinStubs, - void *InitialPtrVal) { + static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, + unsigned MinStubs, void *InitialPtrVal) { llvm_unreachable("emitIndirectStubsBlock is not supported by the generic " "host support class"); } @@ -69,8 +68,7 @@ public: /// @brief Provide information about stub blocks generated by the /// makeIndirectStubsBlock function. -template -class GenericIndirectStubsInfo { +template class GenericIndirectStubsInfo { public: const static unsigned StubSize = StubSizeVal; @@ -100,8 +98,7 @@ public: /// @brief Get a pointer to the implementation-pointer at the given index, /// which must be in the range 0 .. getNumStubs() - 1. void **getPtr(unsigned Idx) const { - char *PtrsBase = - static_cast(StubsMem.base()) + NumStubs * StubSize; + char *PtrsBase = static_cast(StubsMem.base()) + NumStubs * StubSize; return reinterpret_cast(PtrsBase) + Idx; } @@ -110,14 +107,11 @@ private: sys::OwningMemoryBlock StubsMem; }; -/// @brief X86_64 support. -/// -/// X86_64 supports lazy JITing. -class OrcX86_64 { +class OrcAArch64 { public: static const unsigned PointerSize = 8; - static const unsigned TrampolineSize = 8; - static const unsigned ResolverCodeSize = 0x6C; + static const unsigned TrampolineSize = 12; + static const unsigned ResolverCodeSize = 0x120; typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; @@ -140,9 +134,62 @@ public: /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 /// will return a block of 1024 (2-pages worth). - static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, - unsigned MinStubs, - void *InitialPtrVal); + static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, + unsigned MinStubs, void *InitialPtrVal); +}; + +/// @brief X86_64 code that's common to all ABIs. +/// +/// X86_64 supports lazy JITing. +class OrcX86_64_Base { +public: + static const unsigned PointerSize = 8; + static const unsigned TrampolineSize = 8; + + typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; + + /// @brief Write the requsted number of trampolines into the given memory, + /// which must be big enough to hold 1 pointer, plus NumTrampolines + /// trampolines. + static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, + unsigned NumTrampolines); + + /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to + /// the nearest page size. + /// + /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k + /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 + /// will return a block of 1024 (2-pages worth). + static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, + unsigned MinStubs, void *InitialPtrVal); +}; + +/// @brief X86_64 support for SysV ABI (Linux, MacOSX). +/// +/// X86_64_SysV supports lazy JITing. +class OrcX86_64_SysV : public OrcX86_64_Base { +public: + static const unsigned ResolverCodeSize = 0x6C; + typedef TargetAddress(*JITReentryFn)(void *CallbackMgr, void *TrampolineId); + + /// @brief Write the resolver code into the given memory. The user is be + /// responsible for allocating the memory and setting permissions. + static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, + void *CallbackMgr); +}; + +/// @brief X86_64 support for Win32. +/// +/// X86_64_Win32 supports lazy JITing. +class OrcX86_64_Win32 : public OrcX86_64_Base { +public: + static const unsigned ResolverCodeSize = 0x74; + typedef TargetAddress(*JITReentryFn)(void *CallbackMgr, void *TrampolineId); + + /// @brief Write the resolver code into the given memory. The user is be + /// responsible for allocating the memory and setting permissions. + static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, + void *CallbackMgr); }; /// @brief I386 support. @@ -175,13 +222,11 @@ public: /// E.g. Asking for 4 stubs on i386, where stubs are 8-bytes, with 4k /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 /// will return a block of 1024 (2-pages worth). - static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, - unsigned MinStubs, - void *InitialPtrVal); + static Error emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, + unsigned MinStubs, void *InitialPtrVal); }; - } // End namespace orc. } // End namespace llvm. -#endif // LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H +#endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H diff --git a/include/llvm/ExecutionEngine/Orc/OrcError.h b/include/llvm/ExecutionEngine/Orc/OrcError.h index 48f35d6b39bedd085fe3bbc6f85f877c0cb0c545..1b3f25fae162564b083b1035796b94a9f9c75c82 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcError.h +++ b/include/llvm/ExecutionEngine/Orc/OrcError.h @@ -14,6 +14,7 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_ORCERROR_H #define LLVM_EXECUTIONENGINE_ORC_ORCERROR_H +#include "llvm/Support/Error.h" #include namespace llvm { @@ -26,10 +27,11 @@ enum class OrcErrorCode : int { RemoteMProtectAddrUnrecognized, RemoteIndirectStubsOwnerDoesNotExist, RemoteIndirectStubsOwnerIdAlreadyInUse, - UnexpectedRPCCall + UnexpectedRPCCall, + UnexpectedRPCResponse, }; -std::error_code orcError(OrcErrorCode ErrCode); +Error orcError(OrcErrorCode ErrCode); } // End namespace orc. } // End namespace llvm. diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h index 8068733dcdd6fd8c6e56246c169689dc6c024980..5c867e7e7fd43a663f5662cc6aac0fefd4fc1860 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h @@ -36,6 +36,23 @@ namespace remote { template class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI { public: + // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops. + + OrcRemoteTargetClient(const OrcRemoteTargetClient &) = delete; + OrcRemoteTargetClient &operator=(const OrcRemoteTargetClient &) = delete; + + OrcRemoteTargetClient(OrcRemoteTargetClient &&Other) + : Channel(Other.Channel), ExistingError(std::move(Other.ExistingError)), + RemoteTargetTriple(std::move(Other.RemoteTargetTriple)), + RemotePointerSize(std::move(Other.RemotePointerSize)), + RemotePageSize(std::move(Other.RemotePageSize)), + RemoteTrampolineSize(std::move(Other.RemoteTrampolineSize)), + RemoteIndirectStubSize(std::move(Other.RemoteIndirectStubSize)), + AllocatorIds(std::move(Other.AllocatorIds)), + IndirectStubOwnerIds(std::move(Other.IndirectStubOwnerIds)) {} + + OrcRemoteTargetClient &operator=(OrcRemoteTargetClient &&) = delete; + /// Remote memory manager. class RCMemoryManager : public RuntimeDyld::MemoryManager { public: @@ -105,11 +122,13 @@ public: DEBUG(dbgs() << "Allocator " << Id << " reserved:\n"); if (CodeSize != 0) { - std::error_code EC = Client.reserveMem(Unmapped.back().RemoteCodeAddr, - Id, CodeSize, CodeAlign); - // FIXME; Add error to poll. - assert(!EC && "Failed reserving remote memory."); - (void)EC; + if (auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign)) + Unmapped.back().RemoteCodeAddr = *AddrOrErr; + else { + // FIXME; Add error to poll. + assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); + } + DEBUG(dbgs() << " code: " << format("0x%016x", Unmapped.back().RemoteCodeAddr) << " (" << CodeSize << " bytes, alignment " << CodeAlign @@ -117,11 +136,13 @@ public: } if (RODataSize != 0) { - std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRODataAddr, - Id, RODataSize, RODataAlign); - // FIXME; Add error to poll. - assert(!EC && "Failed reserving remote memory."); - (void)EC; + if (auto AddrOrErr = Client.reserveMem(Id, RODataSize, RODataAlign)) + Unmapped.back().RemoteRODataAddr = *AddrOrErr; + else { + // FIXME; Add error to poll. + assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); + } + DEBUG(dbgs() << " ro-data: " << format("0x%016x", Unmapped.back().RemoteRODataAddr) << " (" << RODataSize << " bytes, alignment " @@ -129,11 +150,13 @@ public: } if (RWDataSize != 0) { - std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRWDataAddr, - Id, RWDataSize, RWDataAlign); - // FIXME; Add error to poll. - assert(!EC && "Failed reserving remote memory."); - (void)EC; + if (auto AddrOrErr = Client.reserveMem(Id, RWDataSize, RWDataAlign)) + Unmapped.back().RemoteRWDataAddr = *AddrOrErr; + else { + // FIXME; Add error to poll. + assert(!AddrOrErr.takeError() && "Failed reserving remote memory."); + } + DEBUG(dbgs() << " rw-data: " << format("0x%016x", Unmapped.back().RemoteRWDataAddr) << " (" << RWDataSize << " bytes, alignment " @@ -151,10 +174,10 @@ public: void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override { - auto EC = Client.deregisterEHFrames(LoadAddr, Size); + auto Err = Client.deregisterEHFrames(LoadAddr, Size); // FIXME: Add error poll. - assert(!EC && "Failed to register remote EH frames."); - (void)EC; + assert(!Err && "Failed to register remote EH frames."); + (void)Err; } void notifyObjectLoaded(RuntimeDyld &Dyld, @@ -214,15 +237,35 @@ public: << static_cast(Alloc.getLocalAddress()) << " -> " << format("0x%016x", Alloc.getRemoteAddress()) << " (" << Alloc.getSize() << " bytes)\n"); - Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), - Alloc.getSize()); + if (auto Err = + Client.writeMem(Alloc.getRemoteAddress(), + Alloc.getLocalAddress(), Alloc.getSize())) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return true; + } } if (ObjAllocs.RemoteCodeAddr) { DEBUG(dbgs() << " setting R-X permissions on code block: " << format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n"); - Client.setProtections(Id, ObjAllocs.RemoteCodeAddr, - sys::Memory::MF_READ | sys::Memory::MF_EXEC); + if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteCodeAddr, + sys::Memory::MF_READ | + sys::Memory::MF_EXEC)) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return true; + } } for (auto &Alloc : ObjAllocs.RODataAllocs) { @@ -230,16 +273,35 @@ public: << static_cast(Alloc.getLocalAddress()) << " -> " << format("0x%016x", Alloc.getRemoteAddress()) << " (" << Alloc.getSize() << " bytes)\n"); - Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), - Alloc.getSize()); + if (auto Err = + Client.writeMem(Alloc.getRemoteAddress(), + Alloc.getLocalAddress(), Alloc.getSize())) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return true; + } } if (ObjAllocs.RemoteRODataAddr) { DEBUG(dbgs() << " setting R-- permissions on ro-data block: " << format("0x%016x", ObjAllocs.RemoteRODataAddr) << "\n"); - Client.setProtections(Id, ObjAllocs.RemoteRODataAddr, - sys::Memory::MF_READ); + if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRODataAddr, + sys::Memory::MF_READ)) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return false; + } } for (auto &Alloc : ObjAllocs.RWDataAllocs) { @@ -247,25 +309,51 @@ public: << static_cast(Alloc.getLocalAddress()) << " -> " << format("0x%016x", Alloc.getRemoteAddress()) << " (" << Alloc.getSize() << " bytes)\n"); - Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), - Alloc.getSize()); + if (auto Err = + Client.writeMem(Alloc.getRemoteAddress(), + Alloc.getLocalAddress(), Alloc.getSize())) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return false; + } } if (ObjAllocs.RemoteRWDataAddr) { DEBUG(dbgs() << " setting RW- permissions on rw-data block: " << format("0x%016x", ObjAllocs.RemoteRWDataAddr) << "\n"); - Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr, - sys::Memory::MF_READ | sys::Memory::MF_WRITE); + if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr, + sys::Memory::MF_READ | + sys::Memory::MF_WRITE)) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return false; + } } } Unfinalized.clear(); for (auto &EHFrame : UnfinalizedEHFrames) { - auto EC = Client.registerEHFrames(EHFrame.first, EHFrame.second); - // FIXME: Add error poll. - assert(!EC && "Failed to register remote EH frames."); - (void)EC; + if (auto Err = Client.registerEHFrames(EHFrame.first, EHFrame.second)) { + // FIXME: Replace this once finalizeMemory can return an Error. + handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { + if (ErrMsg) { + raw_string_ostream ErrOut(*ErrMsg); + EIB.log(ErrOut); + } + }); + return false; + } } UnfinalizedEHFrames.clear(); @@ -356,27 +444,30 @@ public: : Remote(Remote), Id(Id) {} ~RCIndirectStubsManager() override { - Remote.destroyIndirectStubsManager(Id); + if (auto Err = Remote.destroyIndirectStubsManager(Id)) { + // FIXME: Thread this error back to clients. + consumeError(std::move(Err)); + } } - std::error_code createStub(StringRef StubName, TargetAddress StubAddr, - JITSymbolFlags StubFlags) override { - if (auto EC = reserveStubs(1)) - return EC; + Error createStub(StringRef StubName, TargetAddress StubAddr, + JITSymbolFlags StubFlags) override { + if (auto Err = reserveStubs(1)) + return Err; return createStubInternal(StubName, StubAddr, StubFlags); } - std::error_code createStubs(const StubInitsMap &StubInits) override { - if (auto EC = reserveStubs(StubInits.size())) - return EC; + Error createStubs(const StubInitsMap &StubInits) override { + if (auto Err = reserveStubs(StubInits.size())) + return Err; for (auto &Entry : StubInits) - if (auto EC = createStubInternal(Entry.first(), Entry.second.first, - Entry.second.second)) - return EC; + if (auto Err = createStubInternal(Entry.first(), Entry.second.first, + Entry.second.second)) + return Err; - return std::error_code(); + return Error::success(); } JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { @@ -400,8 +491,7 @@ public: return JITSymbol(getPtrAddr(Key), Flags); } - std::error_code updatePointer(StringRef Name, - TargetAddress NewAddr) override { + Error updatePointer(StringRef Name, TargetAddress NewAddr) override { auto I = StubIndexes.find(Name); assert(I != StubIndexes.end() && "No stub pointer for symbol"); auto Key = I->second.first; @@ -422,17 +512,19 @@ public: std::vector FreeStubs; StringMap> StubIndexes; - std::error_code reserveStubs(unsigned NumStubs) { + Error reserveStubs(unsigned NumStubs) { if (NumStubs <= FreeStubs.size()) - return std::error_code(); + return Error::success(); unsigned NewStubsRequired = NumStubs - FreeStubs.size(); TargetAddress StubBase; TargetAddress PtrBase; unsigned NumStubsEmitted; - Remote.emitIndirectStubs(StubBase, PtrBase, NumStubsEmitted, Id, - NewStubsRequired); + if (auto StubInfoOrErr = Remote.emitIndirectStubs(Id, NewStubsRequired)) + std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr; + else + return StubInfoOrErr.takeError(); unsigned NewBlockId = RemoteIndirectStubsInfos.size(); RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted}); @@ -440,12 +532,11 @@ public: for (unsigned I = 0; I < NumStubsEmitted; ++I) FreeStubs.push_back(std::make_pair(NewBlockId, I)); - return std::error_code(); + return Error::success(); } - std::error_code createStubInternal(StringRef StubName, - TargetAddress InitAddr, - JITSymbolFlags StubFlags) { + Error createStubInternal(StringRef StubName, TargetAddress InitAddr, + JITSymbolFlags StubFlags) { auto Key = FreeStubs.back(); FreeStubs.pop_back(); StubIndexes[StubName] = std::make_pair(Key, StubFlags); @@ -472,20 +563,18 @@ public: public: RCCompileCallbackManager(TargetAddress ErrorHandlerAddress, OrcRemoteTargetClient &Remote) - : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) { - assert(!Remote.CompileCallback && "Compile callback already set"); - Remote.CompileCallback = [this](TargetAddress TrampolineAddr) { - return executeCompileCallback(TrampolineAddr); - }; - Remote.emitResolverBlock(); - } + : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {} private: void grow() override { TargetAddress BlockAddr = 0; uint32_t NumTrampolines = 0; - auto EC = Remote.emitTrampolineBlock(BlockAddr, NumTrampolines); - assert(!EC && "Failed to create trampolines"); + if (auto TrampolineInfoOrErr = Remote.emitTrampolineBlock()) + std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr; + else { + // FIXME: Return error. + llvm_unreachable("Failed to create trampolines"); + } uint32_t TrampolineSize = Remote.getTrampolineSize(); for (unsigned I = 0; I < NumTrampolines; ++I) @@ -498,146 +587,123 @@ public: /// Create an OrcRemoteTargetClient. /// Channel is the ChannelT instance to communicate on. It is assumed that /// the channel is ready to be read from and written to. - static ErrorOr Create(ChannelT &Channel) { - std::error_code EC; - OrcRemoteTargetClient H(Channel, EC); - if (EC) - return EC; - return H; + static Expected Create(ChannelT &Channel) { + Error Err; + OrcRemoteTargetClient H(Channel, Err); + if (Err) + return std::move(Err); + return Expected(std::move(H)); } /// Call the int(void) function at the given address in the target and return /// its result. - std::error_code callIntVoid(int &Result, TargetAddress Addr) { + Expected callIntVoid(TargetAddress Addr) { DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n"); - if (auto EC = call(Channel, Addr)) - return EC; - - unsigned NextProcId; - if (auto EC = listenForCompileRequests(NextProcId)) - return EC; - - if (NextProcId != CallIntVoidResponseId) - return orcError(OrcErrorCode::UnexpectedRPCCall); - - return handle(Channel, [&](int R) { - Result = R; - DEBUG(dbgs() << "Result: " << R << "\n"); - return std::error_code(); - }); + auto Listen = [&](RPCChannel &C, uint32_t Id) { + return listenForCompileRequests(C, Id); + }; + return callSTHandling(Channel, Listen, Addr); } /// Call the int(int, char*[]) function at the given address in the target and /// return its result. - std::error_code callMain(int &Result, TargetAddress Addr, - const std::vector &Args) { + Expected callMain(TargetAddress Addr, + const std::vector &Args) { DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr) << "\n"); - if (auto EC = call(Channel, Addr, Args)) - return EC; - - unsigned NextProcId; - if (auto EC = listenForCompileRequests(NextProcId)) - return EC; - - if (NextProcId != CallMainResponseId) - return orcError(OrcErrorCode::UnexpectedRPCCall); - - return handle(Channel, [&](int R) { - Result = R; - DEBUG(dbgs() << "Result: " << R << "\n"); - return std::error_code(); - }); + auto Listen = [&](RPCChannel &C, uint32_t Id) { + return listenForCompileRequests(C, Id); + }; + return callSTHandling(Channel, Listen, Addr, Args); } /// Call the void() function at the given address in the target and wait for /// it to finish. - std::error_code callVoidVoid(TargetAddress Addr) { + Error callVoidVoid(TargetAddress Addr) { DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr) << "\n"); - if (auto EC = call(Channel, Addr)) - return EC; - - unsigned NextProcId; - if (auto EC = listenForCompileRequests(NextProcId)) - return EC; - - if (NextProcId != CallVoidVoidResponseId) - return orcError(OrcErrorCode::UnexpectedRPCCall); - - return handle(Channel, doNothing); + auto Listen = [&](RPCChannel &C, uint32_t Id) { + return listenForCompileRequests(C, Id); + }; + return callSTHandling(Channel, Listen, Addr); } /// Create an RCMemoryManager which will allocate its memory on the remote /// target. - std::error_code - createRemoteMemoryManager(std::unique_ptr &MM) { + Error createRemoteMemoryManager(std::unique_ptr &MM) { assert(!MM && "MemoryManager should be null before creation."); auto Id = AllocatorIds.getNext(); - if (auto EC = call(Channel, Id)) - return EC; + if (auto Err = callST(Channel, Id)) + return Err; MM = llvm::make_unique(*this, Id); - return std::error_code(); + return Error::success(); } /// Create an RCIndirectStubsManager that will allocate stubs on the remote /// target. - std::error_code - createIndirectStubsManager(std::unique_ptr &I) { + Error createIndirectStubsManager(std::unique_ptr &I) { assert(!I && "Indirect stubs manager should be null before creation."); auto Id = IndirectStubOwnerIds.getNext(); - if (auto EC = call(Channel, Id)) - return EC; + if (auto Err = callST(Channel, Id)) + return Err; I = llvm::make_unique(*this, Id); - return std::error_code(); + return Error::success(); + } + + Expected + enableCompileCallbacks(TargetAddress ErrorHandlerAddress) { + // Check for an 'out-of-band' error, e.g. from an MM destructor. + if (ExistingError) + return std::move(ExistingError); + + // Emit the resolver block on the JIT server. + if (auto Err = callST(Channel)) + return std::move(Err); + + // Create the callback manager. + CallbackManager.emplace(ErrorHandlerAddress, *this); + RCCompileCallbackManager &Mgr = *CallbackManager; + return Mgr; } /// Search for symbols in the remote process. Note: This should be used by /// symbol resolvers *after* they've searched the local symbol table in the /// JIT stack. - std::error_code getSymbolAddress(TargetAddress &Addr, StringRef Name) { + Expected getSymbolAddress(StringRef Name) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; - - // Request remote symbol address. - if (auto EC = call(Channel, Name)) - return EC; - - return expect(Channel, [&](TargetAddress &A) { - Addr = A; - DEBUG(dbgs() << "Remote address lookup " << Name << " = " - << format("0x%016x", Addr) << "\n"); - return std::error_code(); - }); + return std::move(ExistingError); + + return callST(Channel, Name); } /// Get the triple for the remote target. const std::string &getTargetTriple() const { return RemoteTargetTriple; } - std::error_code terminateSession() { return call(Channel); } + Error terminateSession() { return callST(Channel); } private: - OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC) - : Channel(Channel) { - if ((EC = call(Channel))) - return; - - EC = expect( - Channel, readArgs(RemoteTargetTriple, RemotePointerSize, RemotePageSize, - RemoteTrampolineSize, RemoteIndirectStubSize)); + OrcRemoteTargetClient(ChannelT &Channel, Error &Err) : Channel(Channel) { + ErrorAsOutParameter EAO(Err); + if (auto RIOrErr = callST(Channel)) { + std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize, + RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr; + Err = Error::success(); + } else { + Err = joinErrors(RIOrErr.takeError(), std::move(ExistingError)); + } } - std::error_code deregisterEHFrames(TargetAddress Addr, uint32_t Size) { - return call(Channel, Addr, Size); + Error deregisterEHFrames(TargetAddress Addr, uint32_t Size) { + return callST(Channel, Addr, Size); } void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { - if (auto EC = call(Channel, Id)) { + if (auto Err = callST(Channel, Id)) { // FIXME: This will be triggered by a removeModuleSet call: Propagate // error return up through that. llvm_unreachable("Failed to destroy remote allocator."); @@ -645,46 +711,22 @@ private: } } - std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) { + Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) { IndirectStubOwnerIds.release(Id); - return call(Channel, Id); + return callST(Channel, Id); } - std::error_code emitIndirectStubs(TargetAddress &StubBase, - TargetAddress &PtrBase, - uint32_t &NumStubsEmitted, - ResourceIdMgr::ResourceId Id, - uint32_t NumStubsRequired) { - if (auto EC = call(Channel, Id, NumStubsRequired)) - return EC; - - return expect( - Channel, readArgs(StubBase, PtrBase, NumStubsEmitted)); + Expected> + emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) { + return callST(Channel, Id, NumStubsRequired); } - std::error_code emitResolverBlock() { + Expected> emitTrampolineBlock() { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; + return std::move(ExistingError); - return call(Channel); - } - - std::error_code emitTrampolineBlock(TargetAddress &BlockAddr, - uint32_t &NumTrampolines) { - // Check for an 'out-of-band' error, e.g. from an MM destructor. - if (ExistingError) - return ExistingError; - - if (auto EC = call(Channel)) - return EC; - - return expect( - Channel, [&](TargetAddress BAddr, uint32_t NTrampolines) { - BlockAddr = BAddr; - NumTrampolines = NTrampolines; - return std::error_code(); - }); + return callST(Channel); } uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; } @@ -693,104 +735,86 @@ private: uint32_t getTrampolineSize() const { return RemoteTrampolineSize; } - std::error_code listenForCompileRequests(uint32_t &NextId) { + Error listenForCompileRequests(RPCChannel &C, uint32_t &Id) { + assert(CallbackManager && + "No calback manager. enableCompileCallbacks must be called first"); + // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; - - if (auto EC = getNextProcId(Channel, NextId)) - return EC; - - while (NextId == RequestCompileId) { - TargetAddress TrampolineAddr = 0; - if (auto EC = handle(Channel, readArgs(TrampolineAddr))) - return EC; - - TargetAddress ImplAddr = CompileCallback(TrampolineAddr); - if (auto EC = call(Channel, ImplAddr)) - return EC; + return std::move(ExistingError); + + // FIXME: CompileCallback could be an anonymous lambda defined at the use + // site below, but that triggers a GCC 4.7 ICE. When we move off + // GCC 4.7, tidy this up. + auto CompileCallback = + [this](TargetAddress Addr) -> Expected { + return this->CallbackManager->executeCompileCallback(Addr); + }; - if (auto EC = getNextProcId(Channel, NextId)) - return EC; + if (Id == RequestCompileId) { + if (auto Err = handle(C, CompileCallback)) + return Err; + return Error::success(); } - - return std::error_code(); + // else + return orcError(OrcErrorCode::UnexpectedRPCCall); } - std::error_code readMem(char *Dst, TargetAddress Src, uint64_t Size) { + Expected> readMem(char *Dst, TargetAddress Src, + uint64_t Size) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; - - if (auto EC = call(Channel, Src, Size)) - return EC; - - if (auto EC = expect( - Channel, [&]() { return Channel.readBytes(Dst, Size); })) - return EC; + return std::move(ExistingError); - return std::error_code(); + return callST(Channel, Src, Size); } - std::error_code registerEHFrames(TargetAddress &RAddr, uint32_t Size) { - return call(Channel, RAddr, Size); + Error registerEHFrames(TargetAddress &RAddr, uint32_t Size) { + return callST(Channel, RAddr, Size); } - std::error_code reserveMem(TargetAddress &RemoteAddr, - ResourceIdMgr::ResourceId Id, uint64_t Size, - uint32_t Align) { + Expected reserveMem(ResourceIdMgr::ResourceId Id, + uint64_t Size, uint32_t Align) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; + return std::move(ExistingError); - if (std::error_code EC = call(Channel, Id, Size, Align)) - return EC; - - return expect(Channel, readArgs(RemoteAddr)); + return callST(Channel, Id, Size, Align); } - std::error_code setProtections(ResourceIdMgr::ResourceId Id, - TargetAddress RemoteSegAddr, - unsigned ProtFlags) { - return call(Channel, Id, RemoteSegAddr, ProtFlags); + Error setProtections(ResourceIdMgr::ResourceId Id, + TargetAddress RemoteSegAddr, unsigned ProtFlags) { + return callST(Channel, Id, RemoteSegAddr, ProtFlags); } - std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) { + Error writeMem(TargetAddress Addr, const char *Src, uint64_t Size) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; - - // Make the send call. - if (auto EC = call(Channel, Addr, Size)) - return EC; - - // Follow this up with the section contents. - if (auto EC = Channel.appendBytes(Src, Size)) - return EC; + return std::move(ExistingError); - return Channel.send(); + return callST(Channel, DirectBufferWriter(Src, Addr, Size)); } - std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) { + Error writePointer(TargetAddress Addr, TargetAddress PtrVal) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) - return ExistingError; + return std::move(ExistingError); - return call(Channel, Addr, PtrVal); + return callST(Channel, Addr, PtrVal); } - static std::error_code doNothing() { return std::error_code(); } + static Error doNothing() { return Error::success(); } ChannelT &Channel; - std::error_code ExistingError; + Error ExistingError; std::string RemoteTargetTriple; uint32_t RemotePointerSize = 0; uint32_t RemotePageSize = 0; uint32_t RemoteTrampolineSize = 0; uint32_t RemoteIndirectStubSize = 0; ResourceIdMgr AllocatorIds, IndirectStubOwnerIds; - std::function CompileCallback; + Optional CallbackManager; }; } // end namespace remote diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h index 94327d0e32071b4a0986034e9b80bfa78928521a..74d851522f79340ce52055ce69d23189e142f7a7 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h @@ -24,11 +24,51 @@ namespace llvm { namespace orc { namespace remote { +class DirectBufferWriter { +public: + DirectBufferWriter() = default; + DirectBufferWriter(const char *Src, TargetAddress Dst, uint64_t Size) + : Src(Src), Dst(Dst), Size(Size) {} + + const char *getSrc() const { return Src; } + TargetAddress getDst() const { return Dst; } + uint64_t getSize() const { return Size; } + +private: + const char *Src; + TargetAddress Dst; + uint64_t Size; +}; + +inline Error serialize(RPCChannel &C, const DirectBufferWriter &DBW) { + if (auto EC = serialize(C, DBW.getDst())) + return EC; + if (auto EC = serialize(C, DBW.getSize())) + return EC; + return C.appendBytes(DBW.getSrc(), DBW.getSize()); +} + +inline Error deserialize(RPCChannel &C, DirectBufferWriter &DBW) { + TargetAddress Dst; + if (auto EC = deserialize(C, Dst)) + return EC; + uint64_t Size; + if (auto EC = deserialize(C, Size)) + return EC; + char *Addr = reinterpret_cast(static_cast(Dst)); + + DBW = DirectBufferWriter(0, Dst, Size); + + return C.readBytes(Addr, Size); +} + class OrcRemoteTargetRPCAPI : public RPC { protected: class ResourceIdMgr { public: typedef uint64_t ResourceId; + static const ResourceId InvalidId = ~0U; + ResourceId getNext() { if (!FreeIds.empty()) { ResourceId I = FreeIds.back(); @@ -45,146 +85,117 @@ protected: }; public: - enum JITProcId : uint32_t { - InvalidId = 0, - CallIntVoidId, - CallIntVoidResponseId, + // FIXME: Remove constructors once MSVC supports synthesizing move-ops. + OrcRemoteTargetRPCAPI() = default; + OrcRemoteTargetRPCAPI(const OrcRemoteTargetRPCAPI &) = delete; + OrcRemoteTargetRPCAPI &operator=(const OrcRemoteTargetRPCAPI &) = delete; + + OrcRemoteTargetRPCAPI(OrcRemoteTargetRPCAPI &&) {} + OrcRemoteTargetRPCAPI &operator=(OrcRemoteTargetRPCAPI &&) { return *this; } + + enum JITFuncId : uint32_t { + InvalidId = RPCFunctionIdTraits::InvalidId, + CallIntVoidId = RPCFunctionIdTraits::FirstValidId, CallMainId, - CallMainResponseId, CallVoidVoidId, - CallVoidVoidResponseId, CreateRemoteAllocatorId, CreateIndirectStubsOwnerId, DeregisterEHFramesId, DestroyRemoteAllocatorId, DestroyIndirectStubsOwnerId, EmitIndirectStubsId, - EmitIndirectStubsResponseId, EmitResolverBlockId, EmitTrampolineBlockId, - EmitTrampolineBlockResponseId, GetSymbolAddressId, - GetSymbolAddressResponseId, GetRemoteInfoId, - GetRemoteInfoResponseId, ReadMemId, - ReadMemResponseId, RegisterEHFramesId, ReserveMemId, - ReserveMemResponseId, RequestCompileId, - RequestCompileResponseId, SetProtectionsId, TerminateSessionId, WriteMemId, WritePtrId }; - static const char *getJITProcIdName(JITProcId Id); + static const char *getJITFuncIdName(JITFuncId Id); - typedef Procedure CallIntVoid; + typedef Function CallIntVoid; - typedef Procedure - CallIntVoidResponse; - - typedef Procedure Args)> + typedef Function Args)> CallMain; - typedef Procedure CallMainResponse; - - typedef Procedure CallVoidVoid; - - typedef Procedure CallVoidVoidResponse; + typedef Function CallVoidVoid; - typedef Procedure + typedef Function CreateRemoteAllocator; - typedef Procedure - CreateIndirectStubsOwner; + typedef Function + CreateIndirectStubsOwner; - typedef Procedure + typedef Function DeregisterEHFrames; - typedef Procedure + typedef Function DestroyRemoteAllocator; - typedef Procedure + typedef Function DestroyIndirectStubsOwner; - typedef Procedure + /// EmitIndirectStubs result is (StubsBase, PtrsBase, NumStubsEmitted). + typedef Function( + ResourceIdMgr::ResourceId StubsOwnerID, + uint32_t NumStubsRequired)> EmitIndirectStubs; - typedef Procedure - EmitIndirectStubsResponse; - - typedef Procedure EmitResolverBlock; - - typedef Procedure EmitTrampolineBlock; + typedef Function EmitResolverBlock; - typedef Procedure - EmitTrampolineBlockResponse; + /// EmitTrampolineBlock result is (BlockAddr, NumTrampolines). + typedef Function()> + EmitTrampolineBlock; - typedef Procedure + typedef Function GetSymbolAddress; - typedef Procedure - GetSymbolAddressResponse; + /// GetRemoteInfo result is (Triple, PointerSize, PageSize, TrampolineSize, + /// IndirectStubsSize). + typedef Function()> + GetRemoteInfo; - typedef Procedure GetRemoteInfo; - - typedef Procedure - GetRemoteInfoResponse; - - typedef Procedure + typedef Function(TargetAddress Src, uint64_t Size)> ReadMem; - typedef Procedure ReadMemResponse; - - typedef Procedure + typedef Function RegisterEHFrames; - typedef Procedure + typedef Function ReserveMem; - typedef Procedure - ReserveMemResponse; - - typedef Procedure + typedef Function RequestCompile; - typedef Procedure - RequestCompileResponse; - - typedef Procedure + typedef Function SetProtections; - typedef Procedure TerminateSession; + typedef Function TerminateSession; - typedef Procedure - WriteMem; + typedef Function WriteMem; - typedef Procedure + typedef Function WritePtr; }; diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h index a6afd3183aa75eddaec671e42ccac1a5d6a7cb75..bf4299c69b24b63f85f02bd8a62a4e3cc1d110f1 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h @@ -45,14 +45,21 @@ public: EHFramesRegister(std::move(EHFramesRegister)), EHFramesDeregister(std::move(EHFramesDeregister)) {} - std::error_code getNextProcId(JITProcId &Id) { - return deserialize(Channel, Id); - } + // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops. + OrcRemoteTargetServer(const OrcRemoteTargetServer &) = delete; + OrcRemoteTargetServer &operator=(const OrcRemoteTargetServer &) = delete; + + OrcRemoteTargetServer(OrcRemoteTargetServer &&Other) + : Channel(Other.Channel), SymbolLookup(std::move(Other.SymbolLookup)), + EHFramesRegister(std::move(Other.EHFramesRegister)), + EHFramesDeregister(std::move(Other.EHFramesDeregister)) {} + + OrcRemoteTargetServer &operator=(OrcRemoteTargetServer &&) = delete; - std::error_code handleKnownProcedure(JITProcId Id) { + Error handleKnownFunction(JITFuncId Id) { typedef OrcRemoteTargetServer ThisT; - DEBUG(dbgs() << "Handling known proc: " << getJITProcIdName(Id) << "\n"); + DEBUG(dbgs() << "Handling known proc: " << getJITFuncIdName(Id) << "\n"); switch (Id) { case CallIntVoidId: @@ -111,27 +118,16 @@ public: llvm_unreachable("Unhandled JIT RPC procedure Id."); } - std::error_code requestCompile(TargetAddress &CompiledFnAddr, - TargetAddress TrampolineAddr) { - if (auto EC = call(Channel, TrampolineAddr)) - return EC; - - while (1) { - JITProcId Id = InvalidId; - if (auto EC = getNextProcId(Id)) - return EC; - - switch (Id) { - case RequestCompileResponseId: - return handle(Channel, - readArgs(CompiledFnAddr)); - default: - if (auto EC = handleKnownProcedure(Id)) - return EC; - } - } + Expected requestCompile(TargetAddress TrampolineAddr) { + auto Listen = [&](RPCChannel &C, uint32_t Id) { + return handleKnownFunction(static_cast(Id)); + }; - llvm_unreachable("Fell through request-compile command loop."); + return callSTHandling(Channel, Listen, TrampolineAddr); + } + + Error handleTerminateSession() { + return handle(Channel, []() { return Error::success(); }); } private: @@ -148,45 +144,43 @@ private: sys::Memory::releaseMappedMemory(Alloc.second); } - std::error_code allocate(void *&Addr, size_t Size, uint32_t Align) { + Error allocate(void *&Addr, size_t Size, uint32_t Align) { std::error_code EC; sys::MemoryBlock MB = sys::Memory::allocateMappedMemory( Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); if (EC) - return EC; + return errorCodeToError(EC); Addr = MB.base(); assert(Allocs.find(MB.base()) == Allocs.end() && "Duplicate alloc"); Allocs[MB.base()] = std::move(MB); - return std::error_code(); + return Error::success(); } - std::error_code setProtections(void *block, unsigned Flags) { + Error setProtections(void *block, unsigned Flags) { auto I = Allocs.find(block); if (I == Allocs.end()) return orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized); - return sys::Memory::protectMappedMemory(I->second, Flags); + return errorCodeToError( + sys::Memory::protectMappedMemory(I->second, Flags)); } private: std::map Allocs; }; - static std::error_code doNothing() { return std::error_code(); } + static Error doNothing() { return Error::success(); } static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) { - TargetAddress CompiledFnAddr = 0; - auto T = static_cast(JITTargetAddr); - auto EC = T->requestCompile( - CompiledFnAddr, static_cast( - reinterpret_cast(TrampolineAddr))); - assert(!EC && "Compile request failed"); - (void)EC; - return CompiledFnAddr; + auto AddrOrErr = T->requestCompile(static_cast( + reinterpret_cast(TrampolineAddr))); + // FIXME: Allow customizable failure substitution functions. + assert(AddrOrErr && "Compile request failed"); + return *AddrOrErr; } - std::error_code handleCallIntVoid(TargetAddress Addr) { + Expected handleCallIntVoid(TargetAddress Addr) { typedef int (*IntVoidFnTy)(); IntVoidFnTy Fn = reinterpret_cast(static_cast(Addr)); @@ -195,11 +189,11 @@ private: int Result = Fn(); DEBUG(dbgs() << " Result = " << Result << "\n"); - return call(Channel, Result); + return Result; } - std::error_code handleCallMain(TargetAddress Addr, - std::vector Args) { + Expected handleCallMain(TargetAddress Addr, + std::vector Args) { typedef int (*MainFnTy)(int, const char *[]); MainFnTy Fn = reinterpret_cast(static_cast(Addr)); @@ -214,10 +208,10 @@ private: int Result = Fn(ArgC, ArgV.get()); DEBUG(dbgs() << " Result = " << Result << "\n"); - return call(Channel, Result); + return Result; } - std::error_code handleCallVoidVoid(TargetAddress Addr) { + Error handleCallVoidVoid(TargetAddress Addr) { typedef void (*VoidVoidFnTy)(); VoidVoidFnTy Fn = reinterpret_cast(static_cast(Addr)); @@ -226,55 +220,55 @@ private: Fn(); DEBUG(dbgs() << " Complete.\n"); - return call(Channel); + return Error::success(); } - std::error_code handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) { + Error handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) { auto I = Allocators.find(Id); if (I != Allocators.end()) return orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse); DEBUG(dbgs() << " Created allocator " << Id << "\n"); Allocators[Id] = Allocator(); - return std::error_code(); + return Error::success(); } - std::error_code handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) { + Error handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) { auto I = IndirectStubsOwners.find(Id); if (I != IndirectStubsOwners.end()) return orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse); DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n"); IndirectStubsOwners[Id] = ISBlockOwnerList(); - return std::error_code(); + return Error::success(); } - std::error_code handleDeregisterEHFrames(TargetAddress TAddr, uint32_t Size) { + Error handleDeregisterEHFrames(TargetAddress TAddr, uint32_t Size) { uint8_t *Addr = reinterpret_cast(static_cast(TAddr)); DEBUG(dbgs() << " Registering EH frames at " << format("0x%016x", TAddr) << ", Size = " << Size << " bytes\n"); EHFramesDeregister(Addr, Size); - return std::error_code(); + return Error::success(); } - std::error_code handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { + Error handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { auto I = Allocators.find(Id); if (I == Allocators.end()) return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist); Allocators.erase(I); DEBUG(dbgs() << " Destroyed allocator " << Id << "\n"); - return std::error_code(); + return Error::success(); } - std::error_code - handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) { + Error handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) { auto I = IndirectStubsOwners.find(Id); if (I == IndirectStubsOwners.end()) return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist); IndirectStubsOwners.erase(I); - return std::error_code(); + return Error::success(); } - std::error_code handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id, - uint32_t NumStubsRequired) { + Expected> + handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id, + uint32_t NumStubsRequired) { DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired << " stubs.\n"); @@ -283,9 +277,9 @@ private: return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist); typename TargetT::IndirectStubsInfo IS; - if (auto EC = + if (auto Err = TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr)) - return EC; + return std::move(Err); TargetAddress StubsBase = static_cast(reinterpret_cast(IS.getStub(0))); @@ -296,36 +290,35 @@ private: auto &BlockList = StubOwnerItr->second; BlockList.push_back(std::move(IS)); - return call(Channel, StubsBase, PtrsBase, - NumStubsEmitted); + return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted); } - std::error_code handleEmitResolverBlock() { + Error handleEmitResolverBlock() { std::error_code EC; ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( TargetT::ResolverCodeSize, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); if (EC) - return EC; + return errorCodeToError(EC); TargetT::writeResolverCode(static_cast(ResolverBlock.base()), &reenter, this); - return sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(), - sys::Memory::MF_READ | - sys::Memory::MF_EXEC); + return errorCodeToError(sys::Memory::protectMappedMemory( + ResolverBlock.getMemoryBlock(), + sys::Memory::MF_READ | sys::Memory::MF_EXEC)); } - std::error_code handleEmitTrampolineBlock() { + Expected> handleEmitTrampolineBlock() { std::error_code EC; auto TrampolineBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( sys::Process::getPageSize(), nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); if (EC) - return EC; + return errorCodeToError(EC); - unsigned NumTrampolines = + uint32_t NumTrampolines = (sys::Process::getPageSize() - TargetT::PointerSize) / TargetT::TrampolineSize; @@ -339,20 +332,21 @@ private: TrampolineBlocks.push_back(std::move(TrampolineBlock)); - return call( - Channel, - static_cast(reinterpret_cast(TrampolineMem)), - NumTrampolines); + auto TrampolineBaseAddr = + static_cast(reinterpret_cast(TrampolineMem)); + + return std::make_tuple(TrampolineBaseAddr, NumTrampolines); } - std::error_code handleGetSymbolAddress(const std::string &Name) { + Expected handleGetSymbolAddress(const std::string &Name) { TargetAddress Addr = SymbolLookup(Name); DEBUG(dbgs() << " Symbol '" << Name << "' = " << format("0x%016x", Addr) << "\n"); - return call(Channel, Addr); + return Addr; } - std::error_code handleGetRemoteInfo() { + Expected> + handleGetRemoteInfo() { std::string ProcessTriple = sys::getProcessTriple(); uint32_t PointerSize = TargetT::PointerSize; uint32_t PageSize = sys::Process::getPageSize(); @@ -364,43 +358,41 @@ private: << " page size = " << PageSize << "\n" << " trampoline size = " << TrampolineSize << "\n" << " indirect stub size = " << IndirectStubSize << "\n"); - return call(Channel, ProcessTriple, PointerSize, - PageSize, TrampolineSize, - IndirectStubSize); + return std::make_tuple(ProcessTriple, PointerSize, PageSize, TrampolineSize, + IndirectStubSize); } - std::error_code handleReadMem(TargetAddress RSrc, uint64_t Size) { + Expected> handleReadMem(TargetAddress RSrc, uint64_t Size) { char *Src = reinterpret_cast(static_cast(RSrc)); DEBUG(dbgs() << " Reading " << Size << " bytes from " << format("0x%016x", RSrc) << "\n"); - if (auto EC = call(Channel)) - return EC; - - if (auto EC = Channel.appendBytes(Src, Size)) - return EC; + std::vector Buffer; + Buffer.resize(Size); + for (char *P = Src; Size != 0; --Size) + Buffer.push_back(*P++); - return Channel.send(); + return Buffer; } - std::error_code handleRegisterEHFrames(TargetAddress TAddr, uint32_t Size) { + Error handleRegisterEHFrames(TargetAddress TAddr, uint32_t Size) { uint8_t *Addr = reinterpret_cast(static_cast(TAddr)); DEBUG(dbgs() << " Registering EH frames at " << format("0x%016x", TAddr) << ", Size = " << Size << " bytes\n"); EHFramesRegister(Addr, Size); - return std::error_code(); + return Error::success(); } - std::error_code handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size, - uint32_t Align) { + Expected handleReserveMem(ResourceIdMgr::ResourceId Id, + uint64_t Size, uint32_t Align) { auto I = Allocators.find(Id); if (I == Allocators.end()) return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist); auto &Allocator = I->second; void *LocalAllocAddr = nullptr; - if (auto EC = Allocator.allocate(LocalAllocAddr, Size, Align)) - return EC; + if (auto Err = Allocator.allocate(LocalAllocAddr, Size, Align)) + return std::move(Err); DEBUG(dbgs() << " Allocator " << Id << " reserved " << LocalAllocAddr << " (" << Size << " bytes, alignment " << Align << ")\n"); @@ -408,11 +400,11 @@ private: TargetAddress AllocAddr = static_cast(reinterpret_cast(LocalAllocAddr)); - return call(Channel, AllocAddr); + return AllocAddr; } - std::error_code handleSetProtections(ResourceIdMgr::ResourceId Id, - TargetAddress Addr, uint32_t Flags) { + Error handleSetProtections(ResourceIdMgr::ResourceId Id, TargetAddress Addr, + uint32_t Flags) { auto I = Allocators.find(Id); if (I == Allocators.end()) return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist); @@ -425,20 +417,19 @@ private: return Allocator.setProtections(LocalAddr, Flags); } - std::error_code handleWriteMem(TargetAddress RDst, uint64_t Size) { - char *Dst = reinterpret_cast(static_cast(RDst)); - DEBUG(dbgs() << " Writing " << Size << " bytes to " - << format("0x%016x", RDst) << "\n"); - return Channel.readBytes(Dst, Size); + Error handleWriteMem(DirectBufferWriter DBW) { + DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to " + << format("0x%016x", DBW.getDst()) << "\n"); + return Error::success(); } - std::error_code handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) { + Error handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) { DEBUG(dbgs() << " Writing pointer *" << format("0x%016x", Addr) << " = " << format("0x%016x", PtrVal) << "\n"); uintptr_t *Ptr = reinterpret_cast(static_cast(Addr)); *Ptr = static_cast(PtrVal); - return std::error_code(); + return Error::success(); } ChannelT &Channel; diff --git a/include/llvm/ExecutionEngine/Orc/RPCChannel.h b/include/llvm/ExecutionEngine/Orc/RPCChannel.h index b97b6daf5864fcfe7bb5da325fc6c2e8f8a32414..c569e3cf05b411243854942fb0464e8ffcf727a9 100644 --- a/include/llvm/ExecutionEngine/Orc/RPCChannel.h +++ b/include/llvm/ExecutionEngine/Orc/RPCChannel.h @@ -1,13 +1,27 @@ -// -*- c++ -*- +//===- llvm/ExecutionEngine/Orc/RPCChannel.h --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// #ifndef LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H #define LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H #include "OrcError.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Endian.h" - -#include +#include "llvm/Support/Error.h" +#include +#include +#include +#include +#include +#include namespace llvm { namespace orc { @@ -19,40 +33,73 @@ public: virtual ~RPCChannel() {} /// Read Size bytes from the stream into *Dst. - virtual std::error_code readBytes(char *Dst, unsigned Size) = 0; + virtual Error readBytes(char *Dst, unsigned Size) = 0; /// Read size bytes from *Src and append them to the stream. - virtual std::error_code appendBytes(const char *Src, unsigned Size) = 0; + virtual Error appendBytes(const char *Src, unsigned Size) = 0; /// Flush the stream if possible. - virtual std::error_code send() = 0; + virtual Error send() = 0; + + /// Get the lock for stream reading. + std::mutex &getReadLock() { return readLock; } + + /// Get the lock for stream writing. + std::mutex &getWriteLock() { return writeLock; } + +private: + std::mutex readLock, writeLock; }; +/// Notify the channel that we're starting a message send. +/// Locks the channel for writing. +inline Error startSendMessage(RPCChannel &C) { + C.getWriteLock().lock(); + return Error::success(); +} + +/// Notify the channel that we're ending a message send. +/// Unlocks the channel for writing. +inline Error endSendMessage(RPCChannel &C) { + C.getWriteLock().unlock(); + return Error::success(); +} + +/// Notify the channel that we're starting a message receive. +/// Locks the channel for reading. +inline Error startReceiveMessage(RPCChannel &C) { + C.getReadLock().lock(); + return Error::success(); +} + +/// Notify the channel that we're ending a message receive. +/// Unlocks the channel for reading. +inline Error endReceiveMessage(RPCChannel &C) { + C.getReadLock().unlock(); + return Error::success(); +} + /// RPC channel serialization for a variadic list of arguments. template -std::error_code serialize_seq(RPCChannel &C, const T &Arg, const Ts &... Args) { - if (auto EC = serialize(C, Arg)) - return EC; - return serialize_seq(C, Args...); +Error serializeSeq(RPCChannel &C, const T &Arg, const Ts &... Args) { + if (auto Err = serialize(C, Arg)) + return Err; + return serializeSeq(C, Args...); } /// RPC channel serialization for an (empty) variadic list of arguments. -inline std::error_code serialize_seq(RPCChannel &C) { - return std::error_code(); -} +inline Error serializeSeq(RPCChannel &C) { return Error::success(); } /// RPC channel deserialization for a variadic list of arguments. template -std::error_code deserialize_seq(RPCChannel &C, T &Arg, Ts &... Args) { - if (auto EC = deserialize(C, Arg)) - return EC; - return deserialize_seq(C, Args...); +Error deserializeSeq(RPCChannel &C, T &Arg, Ts &... Args) { + if (auto Err = deserialize(C, Arg)) + return Err; + return deserializeSeq(C, Args...); } /// RPC channel serialization for an (empty) variadic list of arguments. -inline std::error_code deserialize_seq(RPCChannel &C) { - return std::error_code(); -} +inline Error deserializeSeq(RPCChannel &C) { return Error::success(); } /// RPC channel serialization for integer primitives. template @@ -61,7 +108,7 @@ typename std::enable_if< std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value, - std::error_code>::type + Error>::type serialize(RPCChannel &C, T V) { support::endian::byte_swap(V); return C.appendBytes(reinterpret_cast(&V), sizeof(T)); @@ -74,106 +121,129 @@ typename std::enable_if< std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value, - std::error_code>::type + Error>::type deserialize(RPCChannel &C, T &V) { - if (auto EC = C.readBytes(reinterpret_cast(&V), sizeof(T))) - return EC; + if (auto Err = C.readBytes(reinterpret_cast(&V), sizeof(T))) + return Err; support::endian::byte_swap(V); - return std::error_code(); + return Error::success(); } /// RPC channel serialization for enums. template -typename std::enable_if::value, std::error_code>::type +typename std::enable_if::value, Error>::type serialize(RPCChannel &C, T V) { return serialize(C, static_cast::type>(V)); } /// RPC channel deserialization for enums. template -typename std::enable_if::value, std::error_code>::type +typename std::enable_if::value, Error>::type deserialize(RPCChannel &C, T &V) { typename std::underlying_type::type Tmp; - std::error_code EC = deserialize(C, Tmp); + Error Err = deserialize(C, Tmp); V = static_cast(Tmp); - return EC; + return Err; } /// RPC channel serialization for bools. -inline std::error_code serialize(RPCChannel &C, bool V) { +inline Error serialize(RPCChannel &C, bool V) { uint8_t VN = V ? 1 : 0; return C.appendBytes(reinterpret_cast(&VN), 1); } /// RPC channel deserialization for bools. -inline std::error_code deserialize(RPCChannel &C, bool &V) { +inline Error deserialize(RPCChannel &C, bool &V) { uint8_t VN = 0; - if (auto EC = C.readBytes(reinterpret_cast(&VN), 1)) - return EC; + if (auto Err = C.readBytes(reinterpret_cast(&VN), 1)) + return Err; - V = (VN != 0) ? true : false; - return std::error_code(); + V = (VN != 0); + return Error::success(); } /// RPC channel serialization for StringRefs. /// Note: There is no corresponding deseralization for this, as StringRef /// doesn't own its memory and so can't hold the deserialized data. -inline std::error_code serialize(RPCChannel &C, StringRef S) { - if (auto EC = serialize(C, static_cast(S.size()))) - return EC; +inline Error serialize(RPCChannel &C, StringRef S) { + if (auto Err = serialize(C, static_cast(S.size()))) + return Err; return C.appendBytes((const char *)S.bytes_begin(), S.size()); } /// RPC channel serialization for std::strings. -inline std::error_code serialize(RPCChannel &C, const std::string &S) { +inline Error serialize(RPCChannel &C, const std::string &S) { return serialize(C, StringRef(S)); } /// RPC channel deserialization for std::strings. -inline std::error_code deserialize(RPCChannel &C, std::string &S) { +inline Error deserialize(RPCChannel &C, std::string &S) { uint64_t Count; - if (auto EC = deserialize(C, Count)) - return EC; + if (auto Err = deserialize(C, Count)) + return Err; S.resize(Count); return C.readBytes(&S[0], Count); } +// Serialization helper for std::tuple. +template +inline Error serializeTupleHelper(RPCChannel &C, const TupleT &V, + llvm::index_sequence _) { + return serializeSeq(C, std::get(V)...); +} + +/// RPC channel serialization for std::tuple. +template +inline Error serialize(RPCChannel &C, const std::tuple &V) { + return serializeTupleHelper(C, V, llvm::index_sequence_for()); +} + +// Serialization helper for std::tuple. +template +inline Error deserializeTupleHelper(RPCChannel &C, TupleT &V, + llvm::index_sequence _) { + return deserializeSeq(C, std::get(V)...); +} + +/// RPC channel deserialization for std::tuple. +template +inline Error deserialize(RPCChannel &C, std::tuple &V) { + return deserializeTupleHelper(C, V, llvm::index_sequence_for()); +} + /// RPC channel serialization for ArrayRef. -template -std::error_code serialize(RPCChannel &C, const ArrayRef &A) { - if (auto EC = serialize(C, static_cast(A.size()))) - return EC; +template Error serialize(RPCChannel &C, const ArrayRef &A) { + if (auto Err = serialize(C, static_cast(A.size()))) + return Err; for (const auto &E : A) - if (auto EC = serialize(C, E)) - return EC; + if (auto Err = serialize(C, E)) + return Err; - return std::error_code(); + return Error::success(); } /// RPC channel serialization for std::array. -template -std::error_code serialize(RPCChannel &C, const std::vector &V) { +template Error serialize(RPCChannel &C, const std::vector &V) { return serialize(C, ArrayRef(V)); } /// RPC channel deserialization for std::array. -template -std::error_code deserialize(RPCChannel &C, std::vector &V) { +template Error deserialize(RPCChannel &C, std::vector &V) { uint64_t Count = 0; - if (auto EC = deserialize(C, Count)) - return EC; + if (auto Err = deserialize(C, Count)) + return Err; V.resize(Count); for (auto &E : V) - if (auto EC = deserialize(C, E)) - return EC; + if (auto Err = deserialize(C, E)) + return Err; - return std::error_code(); + return Error::success(); } } // end namespace remote } // end namespace orc } // end namespace llvm -#endif +#endif // LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H diff --git a/include/llvm/ExecutionEngine/Orc/RPCUtils.h b/include/llvm/ExecutionEngine/Orc/RPCUtils.h index d1b8546268fcac246695136500bd66165d5bce58..966a49684348ef96652c22c16f66ca76a54ecfa0 100644 --- a/include/llvm/ExecutionEngine/Orc/RPCUtils.h +++ b/include/llvm/ExecutionEngine/Orc/RPCUtils.h @@ -14,84 +14,256 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H +#include +#include + +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/Orc/OrcError.h" +#ifdef _MSC_VER +// concrt.h depends on eh.h for __uncaught_exception declaration +// even if we disable exceptions. +#include + +// Disable warnings from ppltasks.h transitively included by . +#pragma warning(push) +#pragma warning(disable : 4530) +#pragma warning(disable : 4062) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + namespace llvm { namespace orc { namespace remote { +/// Describes reserved RPC Function Ids. +/// +/// The default implementation will serve for integer and enum function id +/// types. If you want to use a custom type as your FunctionId you can +/// specialize this class and provide unique values for InvalidId, +/// ResponseId and FirstValidId. + +template class RPCFunctionIdTraits { +public: + static const T InvalidId = static_cast(0); + static const T ResponseId = static_cast(1); + static const T FirstValidId = static_cast(2); +}; + // Base class containing utilities that require partial specialization. // These cannot be included in RPC, as template class members cannot be // partially specialized. class RPCBase { protected: - template - class ProcedureHelper { + // RPC Function description type. + // + // This class provides the information and operations needed to support the + // RPC primitive operations (call, expect, etc) for a given function. It + // is specialized for void and non-void functions to deal with the differences + // betwen the two. Both specializations have the same interface: + // + // Id - The function's unique identifier. + // OptionalReturn - The return type for asyncronous calls. + // ErrorReturn - The return type for synchronous calls. + // optionalToErrorReturn - Conversion from a valid OptionalReturn to an + // ErrorReturn. + // readResult - Deserialize a result from a channel. + // abandon - Abandon a promised (asynchronous) result. + // respond - Retun a result on the channel. + template + class FunctionHelper {}; + + // RPC Function description specialization for non-void functions. + template + class FunctionHelper { public: - static const ProcedureIdT Id = ProcId; + static_assert(FuncId != RPCFunctionIdTraits::InvalidId && + FuncId != RPCFunctionIdTraits::ResponseId, + "Cannot define custom function with InvalidId or ResponseId. " + "Please use RPCFunctionTraits::FirstValidId."); + + static const FunctionIdT Id = FuncId; + + typedef Optional OptionalReturn; + + typedef Expected ErrorReturn; + + static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) { + assert(V && "Return value not available"); + return std::move(*V); + } + + template + static Error readResult(ChannelT &C, std::promise &P) { + RetT Val; + auto Err = deserialize(C, Val); + auto Err2 = endReceiveMessage(C); + Err = joinErrors(std::move(Err), std::move(Err2)); + + if (Err) { + P.set_value(OptionalReturn()); + return Err; + } + P.set_value(std::move(Val)); + return Error::success(); + } + + static void abandon(std::promise &P) { + P.set_value(OptionalReturn()); + } + + template + static Error respond(ChannelT &C, SequenceNumberT SeqNo, + ErrorReturn &Result) { + FunctionIdT ResponseId = RPCFunctionIdTraits::ResponseId; + + // If the handler returned an error then bail out with that. + if (!Result) + return Result.takeError(); + + // Otherwise open a new message on the channel and send the result. + if (auto Err = startSendMessage(C)) + return Err; + if (auto Err = serializeSeq(C, ResponseId, SeqNo, *Result)) + return Err; + return endSendMessage(C); + } }; - template class CallHelper; + // RPC Function description specialization for void functions. + template + class FunctionHelper { + public: + static_assert(FuncId != RPCFunctionIdTraits::InvalidId && + FuncId != RPCFunctionIdTraits::ResponseId, + "Cannot define custom function with InvalidId or ResponseId. " + "Please use RPCFunctionTraits::FirstValidId."); - template - class CallHelper> { + static const FunctionIdT Id = FuncId; + + typedef bool OptionalReturn; + typedef Error ErrorReturn; + + static ErrorReturn optionalToErrorReturn(OptionalReturn &&V) { + assert(V && "Return value not available"); + return Error::success(); + } + + template + static Error readResult(ChannelT &C, std::promise &P) { + // Void functions don't have anything to deserialize, so we're good. + P.set_value(true); + return endReceiveMessage(C); + } + + static void abandon(std::promise &P) { P.set_value(false); } + + template + static Error respond(ChannelT &C, SequenceNumberT SeqNo, + ErrorReturn &Result) { + const FunctionIdT ResponseId = + RPCFunctionIdTraits::ResponseId; + + // If the handler returned an error then bail out with that. + if (Result) + return std::move(Result); + + // Otherwise open a new message on the channel and send the result. + if (auto Err = startSendMessage(C)) + return Err; + if (auto Err = serializeSeq(C, ResponseId, SeqNo)) + return Err; + return endSendMessage(C); + } + }; + + // Helper for the call primitive. + template + class CallHelper; + + template + class CallHelper> { public: - static std::error_code call(ChannelT &C, const ArgTs &... Args) { - if (auto EC = serialize(C, ProcId)) - return EC; - // If you see a compile-error on this line you're probably calling a - // function with the wrong signature. - return serialize_seq(C, Args...); + static Error call(ChannelT &C, SequenceNumberT SeqNo, + const ArgTs &... Args) { + if (auto Err = startSendMessage(C)) + return Err; + if (auto Err = serializeSeq(C, FuncId, SeqNo, Args...)) + return Err; + return endSendMessage(C); } }; - template class HandlerHelper; + // Helper for handle primitive. + template + class HandlerHelper; - template - class HandlerHelper> { + template + class HandlerHelper> { public: template - static std::error_code handle(ChannelT &C, HandlerT Handler) { + static Error handle(ChannelT &C, HandlerT Handler) { return readAndHandle(C, Handler, llvm::index_sequence_for()); } private: + typedef FunctionHelper Func; + template - static std::error_code readAndHandle(ChannelT &C, HandlerT Handler, - llvm::index_sequence _) { + static Error readAndHandle(ChannelT &C, HandlerT Handler, + llvm::index_sequence _) { std::tuple RPCArgs; + SequenceNumberT SeqNo; // GCC 4.7 and 4.8 incorrectly issue a -Wunused-but-set-variable warning // for RPCArgs. Void cast RPCArgs to work around this for now. // FIXME: Remove this workaround once we can assume a working GCC version. (void)RPCArgs; - if (auto EC = deserialize_seq(C, std::get(RPCArgs)...)) - return EC; - return Handler(std::get(RPCArgs)...); + if (auto Err = deserializeSeq(C, SeqNo, std::get(RPCArgs)...)) + return Err; + + // We've deserialized the arguments, so unlock the channel for reading + // before we call the handler. This allows recursive RPC calls. + if (auto Err = endReceiveMessage(C)) + return Err; + + // Run the handler and get the result. + auto Result = Handler(std::get(RPCArgs)...); + + // Return the result to the client. + return Func::template respond(C, SeqNo, + Result); } }; - template class MemberFnWrapper { + // Helper for wrapping member functions up as functors. + template + class MemberFnWrapper { public: - typedef std::error_code (ClassT::*MethodT)(ArgTs...); + typedef RetT (ClassT::*MethodT)(ArgTs...); MemberFnWrapper(ClassT &Instance, MethodT Method) : Instance(Instance), Method(Method) {} - std::error_code operator()(ArgTs &... Args) { - return (Instance.*Method)(Args...); - } + RetT operator()(ArgTs &... Args) { return (Instance.*Method)(Args...); } private: ClassT &Instance; MethodT Method; }; + // Helper that provides a Functor for deserializing arguments. template class ReadArgs { public: - std::error_code operator()() { return std::error_code(); } + Error operator()() { return Error::success(); } }; template @@ -100,7 +272,7 @@ protected: ReadArgs(ArgT &Arg, ArgTs &... Args) : ReadArgs(Args...), Arg(Arg) {} - std::error_code operator()(ArgT &ArgVal, ArgTs &... ArgVals) { + Error operator()(ArgT &ArgVal, ArgTs &... ArgVals) { this->Arg = std::move(ArgVal); return ReadArgs::operator()(ArgVals...); } @@ -112,7 +284,7 @@ protected: /// Contains primitive utilities for defining, calling and handling calls to /// remote procedures. ChannelT is a bidirectional stream conforming to the -/// RPCChannel interface (see RPCChannel.h), and ProcedureIdT is a procedure +/// RPCChannel interface (see RPCChannel.h), and FunctionIdT is a procedure /// identifier type that must be serializable on ChannelT. /// /// These utilities support the construction of very primitive RPC utilities. @@ -129,120 +301,223 @@ protected: /// /// Overview (see comments individual types/methods for details): /// -/// Procedure : +/// Function : /// /// associates a unique serializable id with an argument list. /// /// -/// call(Channel, Args...) : +/// call(Channel, Args...) : /// -/// Calls the remote procedure 'Proc' by serializing Proc's id followed by its +/// Calls the remote procedure 'Func' by serializing Func's id followed by its /// arguments and sending the resulting bytes to 'Channel'. /// /// -/// handle(Channel, : +/// handle(Channel, : /// -/// Handles a call to 'Proc' by deserializing its arguments and calling the -/// given functor. This assumes that the id for 'Proc' has already been +/// Handles a call to 'Func' by deserializing its arguments and calling the +/// given functor. This assumes that the id for 'Func' has already been /// deserialized. /// -/// expect(Channel, : +/// expect(Channel, : /// /// The same as 'handle', except that the procedure id should not have been -/// read yet. Expect will deserialize the id and assert that it matches Proc's +/// read yet. Expect will deserialize the id and assert that it matches Func's /// id. If it does not, and unexpected RPC call error is returned. - -template +template class RPC : public RPCBase { public: + /// RPC default constructor. + RPC() = default; + + /// RPC instances cannot be copied. + RPC(const RPC &) = delete; + + /// RPC instances cannot be copied. + RPC &operator=(const RPC &) = delete; + + /// RPC move constructor. + // FIXME: Remove once MSVC can synthesize move ops. + RPC(RPC &&Other) + : SequenceNumberMgr(std::move(Other.SequenceNumberMgr)), + OutstandingResults(std::move(Other.OutstandingResults)) {} + + /// RPC move assignment. + // FIXME: Remove once MSVC can synthesize move ops. + RPC &operator=(RPC &&Other) { + SequenceNumberMgr = std::move(Other.SequenceNumberMgr); + OutstandingResults = std::move(Other.OutstandingResults); + return *this; + } + /// Utility class for defining/referring to RPC procedures. /// /// Typedefs of this utility are used when calling/handling remote procedures. /// - /// ProcId should be a unique value of ProcedureIdT (i.e. not used with any - /// other Procedure typedef in the RPC API being defined. + /// FuncId should be a unique value of FunctionIdT (i.e. not used with any + /// other Function typedef in the RPC API being defined. /// /// the template argument Ts... gives the argument list for the remote /// procedure. /// /// E.g. /// - /// typedef Procedure<0, bool> Proc1; - /// typedef Procedure<1, std::string, std::vector> Proc2; + /// typedef Function<0, bool> Func1; + /// typedef Function<1, std::string, std::vector> Func2; /// - /// if (auto EC = call(Channel, true)) - /// /* handle EC */; + /// if (auto Err = call(Channel, true)) + /// /* handle Err */; /// - /// if (auto EC = expect(Channel, + /// if (auto Err = expect(Channel, /// [](std::string &S, std::vector &V) { /// // Stuff. - /// return std::error_code(); + /// return Error::success(); /// }) - /// /* handle EC */; + /// /* handle Err */; /// - template - using Procedure = ProcedureHelper; + template + using Function = FunctionHelper; + + /// Return type for asynchronous call primitives. + template + using AsyncCallResult = std::future; + + /// Return type for asynchronous call-with-seq primitives. + template + using AsyncCallWithSeqResult = + std::pair, SequenceNumberT>; /// Serialize Args... to channel C, but do not call C.send(). /// - /// For buffered channels, this can be used to queue up several calls before - /// flushing the channel. - template - static std::error_code appendCall(ChannelT &C, const ArgTs &... Args) { - return CallHelper::call(C, Args...); + /// Returns an error (on serialization failure) or a pair of: + /// (1) A future Optional (or future for void functions), and + /// (2) A sequence number. + /// + /// This utility function is primarily used for single-threaded mode support, + /// where the sequence number can be used to wait for the corresponding + /// result. In multi-threaded mode the appendCallAsync method, which does not + /// return the sequence numeber, should be preferred. + template + Expected> + appendCallAsyncWithSeq(ChannelT &C, const ArgTs &... Args) { + auto SeqNo = SequenceNumberMgr.getSequenceNumber(); + std::promise Promise; + auto Result = Promise.get_future(); + OutstandingResults[SeqNo] = + createOutstandingResult(std::move(Promise)); + + if (auto Err = CallHelper::call(C, SeqNo, + Args...)) { + abandonOutstandingResults(); + return std::move(Err); + } else + return AsyncCallWithSeqResult(std::move(Result), SeqNo); } - /// Serialize Args... to channel C and call C.send(). - template - static std::error_code call(ChannelT &C, const ArgTs &... Args) { - if (auto EC = appendCall(C, Args...)) - return EC; - return C.send(); + /// The same as appendCallAsyncWithSeq, except that it calls C.send() to + /// flush the channel after serializing the call. + template + Expected> + callAsyncWithSeq(ChannelT &C, const ArgTs &... Args) { + auto Result = appendCallAsyncWithSeq(C, Args...); + if (!Result) + return Result; + if (auto Err = C.send()) { + abandonOutstandingResults(); + return std::move(Err); + } + return Result; + } + + /// Serialize Args... to channel C, but do not call send. + /// Returns an error if serialization fails, otherwise returns a + /// std::future> (or a future for void functions). + template + Expected> appendCallAsync(ChannelT &C, + const ArgTs &... Args) { + auto ResAndSeqOrErr = appendCallAsyncWithSeq(C, Args...); + if (ResAndSeqOrErr) + return std::move(ResAndSeqOrErr->first); + return ResAndSeqOrErr.getError(); + } + + /// The same as appendCallAsync, except that it calls C.send to flush the + /// channel after serializing the call. + template + Expected> callAsync(ChannelT &C, + const ArgTs &... Args) { + auto ResAndSeqOrErr = callAsyncWithSeq(C, Args...); + if (ResAndSeqOrErr) + return std::move(ResAndSeqOrErr->first); + return ResAndSeqOrErr.getError(); + } + + /// This can be used in single-threaded mode. + template + typename Func::ErrorReturn + callSTHandling(ChannelT &C, HandleFtor &HandleOther, const ArgTs &... Args) { + if (auto ResultAndSeqNoOrErr = callAsyncWithSeq(C, Args...)) { + auto &ResultAndSeqNo = *ResultAndSeqNoOrErr; + if (auto Err = waitForResult(C, ResultAndSeqNo.second, HandleOther)) + return std::move(Err); + return Func::optionalToErrorReturn(ResultAndSeqNo.first.get()); + } else + return ResultAndSeqNoOrErr.takeError(); } - /// Deserialize and return an enum whose underlying type is ProcedureIdT. - static std::error_code getNextProcId(ChannelT &C, ProcedureIdT &Id) { + // This can be used in single-threaded mode. + template + typename Func::ErrorReturn callST(ChannelT &C, const ArgTs &... Args) { + return callSTHandling(C, handleNone, Args...); + } + + /// Start receiving a new function call. + /// + /// Calls startReceiveMessage on the channel, then deserializes a FunctionId + /// into Id. + Error startReceivingFunction(ChannelT &C, FunctionIdT &Id) { + if (auto Err = startReceiveMessage(C)) + return Err; + return deserialize(C, Id); } - /// Deserialize args for Proc from C and call Handler. The signature of - /// handler must conform to 'std::error_code(Args...)' where Args... matches - /// the arguments used in the Proc typedef. - template - static std::error_code handle(ChannelT &C, HandlerT Handler) { - return HandlerHelper::handle(C, Handler); + /// Deserialize args for Func from C and call Handler. The signature of + /// handler must conform to 'Error(Args...)' where Args... matches + /// the arguments used in the Func typedef. + template + static Error handle(ChannelT &C, HandlerT Handler) { + return HandlerHelper::handle(C, Handler); } /// Helper version of 'handle' for calling member functions. - template - static std::error_code - handle(ChannelT &C, ClassT &Instance, - std::error_code (ClassT::*HandlerMethod)(ArgTs...)) { - return handle( - C, MemberFnWrapper(Instance, HandlerMethod)); + template + static Error handle(ChannelT &C, ClassT &Instance, + RetT (ClassT::*HandlerMethod)(ArgTs...)) { + return handle( + C, MemberFnWrapper(Instance, HandlerMethod)); } - /// Deserialize a ProcedureIdT from C and verify it matches the id for Proc. + /// Deserialize a FunctionIdT from C and verify it matches the id for Func. /// If the id does match, deserialize the arguments and call the handler /// (similarly to handle). /// If the id does not match, return an unexpect RPC call error and do not /// deserialize any further bytes. - template - static std::error_code expect(ChannelT &C, HandlerT Handler) { - ProcedureIdT ProcId; - if (auto EC = getNextProcId(C, ProcId)) - return EC; - if (ProcId != Proc::Id) + template + Error expect(ChannelT &C, HandlerT Handler) { + FunctionIdT FuncId; + if (auto Err = startReceivingFunction(C, FuncId)) + return std::move(Err); + if (FuncId != Func::Id) return orcError(OrcErrorCode::UnexpectedRPCCall); - return handle(C, Handler); + return handle(C, Handler); } /// Helper version of expect for calling member functions. - template - static std::error_code - expect(ChannelT &C, ClassT &Instance, - std::error_code (ClassT::*HandlerMethod)(ArgTs...)) { - return expect( + template + static Error expect(ChannelT &C, ClassT &Instance, + Error (ClassT::*HandlerMethod)(ArgTs...)) { + return expect( C, MemberFnWrapper(Instance, HandlerMethod)); } @@ -251,18 +526,165 @@ public: /// channel. /// E.g. /// - /// typedef Procedure<0, bool, int> Proc1; + /// typedef Function<0, bool, int> Func1; /// /// ... /// bool B; /// int I; - /// if (auto EC = expect(Channel, readArgs(B, I))) + /// if (auto Err = expect(Channel, readArgs(B, I))) /// /* Handle Args */ ; /// template static ReadArgs readArgs(ArgTs &... Args) { return ReadArgs(Args...); } + + /// Read a response from Channel. + /// This should be called from the receive loop to retrieve results. + Error handleResponse(ChannelT &C, SequenceNumberT *SeqNoRet = nullptr) { + SequenceNumberT SeqNo; + if (auto Err = deserialize(C, SeqNo)) { + abandonOutstandingResults(); + return Err; + } + + if (SeqNoRet) + *SeqNoRet = SeqNo; + + auto I = OutstandingResults.find(SeqNo); + if (I == OutstandingResults.end()) { + abandonOutstandingResults(); + return orcError(OrcErrorCode::UnexpectedRPCResponse); + } + + if (auto Err = I->second->readResult(C)) { + abandonOutstandingResults(); + // FIXME: Release sequence numbers? + return Err; + } + + OutstandingResults.erase(I); + SequenceNumberMgr.releaseSequenceNumber(SeqNo); + + return Error::success(); + } + + // Loop waiting for a result with the given sequence number. + // This can be used as a receive loop if the user doesn't have a default. + template + Error waitForResult(ChannelT &C, SequenceNumberT TgtSeqNo, + HandleOtherFtor &HandleOther = handleNone) { + bool GotTgtResult = false; + + while (!GotTgtResult) { + FunctionIdT Id = RPCFunctionIdTraits::InvalidId; + if (auto Err = startReceivingFunction(C, Id)) + return Err; + if (Id == RPCFunctionIdTraits::ResponseId) { + SequenceNumberT SeqNo; + if (auto Err = handleResponse(C, &SeqNo)) + return Err; + GotTgtResult = (SeqNo == TgtSeqNo); + } else if (auto Err = HandleOther(C, Id)) + return Err; + } + + return Error::success(); + } + + // Default handler for 'other' (non-response) functions when waiting for a + // result from the channel. + static Error handleNone(ChannelT &, FunctionIdT) { + return orcError(OrcErrorCode::UnexpectedRPCCall); + }; + +private: + // Manage sequence numbers. + class SequenceNumberManager { + public: + SequenceNumberManager() = default; + + SequenceNumberManager(const SequenceNumberManager &) = delete; + SequenceNumberManager &operator=(const SequenceNumberManager &) = delete; + + SequenceNumberManager(SequenceNumberManager &&Other) + : NextSequenceNumber(std::move(Other.NextSequenceNumber)), + FreeSequenceNumbers(std::move(Other.FreeSequenceNumbers)) {} + + SequenceNumberManager &operator=(SequenceNumberManager &&Other) { + NextSequenceNumber = std::move(Other.NextSequenceNumber); + FreeSequenceNumbers = std::move(Other.FreeSequenceNumbers); + } + + void reset() { + std::lock_guard Lock(SeqNoLock); + NextSequenceNumber = 0; + FreeSequenceNumbers.clear(); + } + + SequenceNumberT getSequenceNumber() { + std::lock_guard Lock(SeqNoLock); + if (FreeSequenceNumbers.empty()) + return NextSequenceNumber++; + auto SequenceNumber = FreeSequenceNumbers.back(); + FreeSequenceNumbers.pop_back(); + return SequenceNumber; + } + + void releaseSequenceNumber(SequenceNumberT SequenceNumber) { + std::lock_guard Lock(SeqNoLock); + FreeSequenceNumbers.push_back(SequenceNumber); + } + + private: + std::mutex SeqNoLock; + SequenceNumberT NextSequenceNumber = 0; + std::vector FreeSequenceNumbers; + }; + + // Base class for results that haven't been returned from the other end of the + // RPC connection yet. + class OutstandingResult { + public: + virtual ~OutstandingResult() {} + virtual Error readResult(ChannelT &C) = 0; + virtual void abandon() = 0; + }; + + // Outstanding results for a specific function. + template + class OutstandingResultImpl : public OutstandingResult { + private: + public: + OutstandingResultImpl(std::promise &&P) + : P(std::move(P)) {} + + Error readResult(ChannelT &C) override { return Func::readResult(C, P); } + + void abandon() override { Func::abandon(P); } + + private: + std::promise P; + }; + + // Create an outstanding result for the given function. + template + std::unique_ptr + createOutstandingResult(std::promise &&P) { + return llvm::make_unique>(std::move(P)); + } + + // Abandon all outstanding results. + void abandonOutstandingResults() { + for (auto &KV : OutstandingResults) + KV.second->abandon(); + OutstandingResults.clear(); + SequenceNumberMgr.reset(); + } + + SequenceNumberManager SequenceNumberMgr; + std::map> + OutstandingResults; }; } // end namespace remote diff --git a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h index a68716636578ba5f5344a74525f6a60b3f66b7b9..adcb063f45440c7a80de6674ab28c40caf5d1383 100644 --- a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h +++ b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h @@ -16,7 +16,6 @@ #include "RuntimeDyld.h" #include "llvm-c/ExecutionEngine.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Memory.h" diff --git a/include/llvm/ExecutionEngine/RuntimeDyld.h b/include/llvm/ExecutionEngine/RuntimeDyld.h index 100e97b8b3d9f6ee4c7b49b2f01f987cb02d3be8..bd485de91bd453de7ebab43935b8fff7ef4f6477 100644 --- a/include/llvm/ExecutionEngine/RuntimeDyld.h +++ b/include/llvm/ExecutionEngine/RuntimeDyld.h @@ -16,20 +16,35 @@ #include "JITSymbolFlags.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DIContext.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Memory.h" -#include "llvm/DebugInfo/DIContext.h" #include #include +#include namespace llvm { +class StringRef; + namespace object { class ObjectFile; template class OwningBinary; } +/// Base class for errors originating in RuntimeDyld, e.g. missing relocation +/// support. +class RuntimeDyldError : public ErrorInfo { +public: + static char ID; + RuntimeDyldError(std::string ErrMsg) : ErrMsg(std::move(ErrMsg)) {} + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const { return ErrMsg; } + std::error_code convertToErrorCode() const override; +private: + std::string ErrMsg; +}; + class RuntimeDyldImpl; class RuntimeDyldCheckerImpl; @@ -64,7 +79,7 @@ public: typedef std::map ObjSectionToIDMap; LoadedObjectInfo(RuntimeDyldImpl &RTDyld, ObjSectionToIDMap ObjSecToIDMap) - : RTDyld(RTDyld), ObjSecToIDMap(ObjSecToIDMap) { } + : RTDyld(RTDyld), ObjSecToIDMap(std::move(ObjSecToIDMap)) {} virtual object::OwningBinary getObjectForDebug(const object::ObjectFile &Obj) const = 0; @@ -179,17 +194,9 @@ public: public: virtual ~SymbolResolver() {} - /// This method returns the address of the specified function or variable. - /// It is used to resolve symbols during module linking. - /// - /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will - /// skip all relocations for that symbol, and the client will be responsible - /// for handling them manually. - virtual SymbolInfo findSymbol(const std::string &Name) = 0; - /// This method returns the address of the specified symbol if it exists /// within the logical dynamic library represented by this - /// RTDyldMemoryManager. Unlike getSymbolAddress, queries through this + /// RTDyldMemoryManager. Unlike findSymbol, queries through this /// interface should return addresses for hidden symbols. /// /// This is of particular importance for the Orc JIT APIs, which support lazy @@ -198,13 +205,17 @@ public: /// writing memory managers for MCJIT can usually ignore this method. /// /// This method will be queried by RuntimeDyld when checking for previous - /// definitions of common symbols. It will *not* be queried by default when - /// resolving external symbols (this minimises the link-time overhead for - /// MCJIT clients who don't care about Orc features). If you are writing a - /// RTDyldMemoryManager for Orc and want "external" symbol resolution to - /// search the logical dylib, you should override your getSymbolAddress - /// method call this method directly. + /// definitions of common symbols. virtual SymbolInfo findSymbolInLogicalDylib(const std::string &Name) = 0; + + /// This method returns the address of the specified function or variable. + /// It is used to resolve symbols during module linking. + /// + /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will + /// skip all relocations for that symbol, and the client will be responsible + /// for handling them manually. + virtual SymbolInfo findSymbol(const std::string &Name) = 0; + private: virtual void anchor(); }; diff --git a/include/llvm/ExecutionEngine/RuntimeDyldChecker.h b/include/llvm/ExecutionEngine/RuntimeDyldChecker.h index dacb34a779fcb4539f1f66f1c6b5690c5b420300..f5f52b5d2f9226e9aa96208d43bc44090f92b1c7 100644 --- a/include/llvm/ExecutionEngine/RuntimeDyldChecker.h +++ b/include/llvm/ExecutionEngine/RuntimeDyldChecker.h @@ -10,11 +10,14 @@ #ifndef LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H #define LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H -#include "llvm/ADT/StringRef.h" +#include #include +#include +#include namespace llvm { +class StringRef; class MCDisassembler; class MemoryBuffer; class MCInstPrinter; diff --git a/include/llvm/IR/Argument.h b/include/llvm/IR/Argument.h index 33dc1b7dcda32e2241c6e23fac50c3efcfaf47ed..d8b280a66f1847fd433988dfa232395c6d2f4489 100644 --- a/include/llvm/IR/Argument.h +++ b/include/llvm/IR/Argument.h @@ -73,6 +73,12 @@ public: /// containing function. bool hasByValAttr() const; + /// \brief Return true if this argument has the swiftself attribute. + bool hasSwiftSelfAttr() const; + + /// \brief Return true if this argument has the swifterror attribute. + bool hasSwiftErrorAttr() const; + /// \brief Return true if this argument has the byval attribute or inalloca /// attribute on it in its containing function. These attributes both /// represent arguments being passed by value. diff --git a/include/llvm/IR/Attributes.h b/include/llvm/IR/Attributes.h index 8b17862f1fe9bb5b091a587fea61693a03326d3b..af1bf0a354ec86b2399db45f01205fa2af677aac 100644 --- a/include/llvm/IR/Attributes.h +++ b/include/llvm/IR/Attributes.h @@ -18,8 +18,10 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm-c/Types.h" #include #include #include @@ -94,6 +96,9 @@ public: uint64_t Bytes); static Attribute getWithDereferenceableOrNullBytes(LLVMContext &Context, uint64_t Bytes); + static Attribute getWithAllocSizeArgs(LLVMContext &Context, + unsigned ElemSizeArg, + const Optional &NumElemsArg); //===--------------------------------------------------------------------===// // Attribute Accessors @@ -147,6 +152,10 @@ public: /// dereferenceable_or_null attribute. uint64_t getDereferenceableOrNullBytes() const; + /// Returns the argument numbers for the allocsize attribute (or pair(0, 0) + /// if not known). + std::pair> getAllocSizeArgs() const; + /// \brief The Attribute is converted to a string of equivalent mnemonic. This /// is, presumably, for writing out the mnemonics for the assembly writer. std::string getAsString(bool InAttrGrp = false) const; @@ -161,8 +170,28 @@ public: void Profile(FoldingSetNodeID &ID) const { ID.AddPointer(pImpl); } + + /// \brief Return a raw pointer that uniquely identifies this attribute. + void *getRawPointer() const { + return pImpl; + } + + /// \brief Get an attribute from a raw pointer created by getRawPointer. + static Attribute fromRawPointer(void *RawPtr) { + return Attribute(reinterpret_cast(RawPtr)); + } }; +// Specialized opaque value conversions. +inline LLVMAttributeRef wrap(Attribute Attr) { + return reinterpret_cast(Attr.getRawPointer()); +} + +// Specialized opaque value conversions. +inline Attribute unwrap(LLVMAttributeRef Attr) { + return Attribute::fromRawPointer(Attr); +} + //===----------------------------------------------------------------------===// /// \class /// \brief This class holds the attributes for a function, its return value, and @@ -213,20 +242,20 @@ public: /// \brief Return an AttributeSet with the specified parameters in it. static AttributeSet get(LLVMContext &C, ArrayRef Attrs); static AttributeSet get(LLVMContext &C, unsigned Index, - ArrayRef Kind); + ArrayRef Kinds); + static AttributeSet get(LLVMContext &C, unsigned Index, + ArrayRef Kind); static AttributeSet get(LLVMContext &C, unsigned Index, const AttrBuilder &B); /// \brief Add an attribute to the attribute set at the given index. Because /// attribute sets are immutable, this returns a new set. AttributeSet addAttribute(LLVMContext &C, unsigned Index, - Attribute::AttrKind Attr) const; + Attribute::AttrKind Kind) const; /// \brief Add an attribute to the attribute set at the given index. Because /// attribute sets are immutable, this returns a new set. - AttributeSet addAttribute(LLVMContext &C, unsigned Index, - StringRef Kind) const; - AttributeSet addAttribute(LLVMContext &C, unsigned Index, - StringRef Kind, StringRef Value) const; + AttributeSet addAttribute(LLVMContext &C, unsigned Index, StringRef Kind, + StringRef Value = StringRef()) const; /// Add an attribute to the attribute set at the given indices. Because /// attribute sets are immutable, this returns a new set. @@ -242,7 +271,13 @@ public: /// attribute list. Because attribute lists are immutable, this returns the /// new list. AttributeSet removeAttribute(LLVMContext &C, unsigned Index, - Attribute::AttrKind Attr) const; + Attribute::AttrKind Kind) const; + + /// \brief Remove the specified attribute at the specified index from this + /// attribute list. Because attribute lists are immutable, this returns the + /// new list. + AttributeSet removeAttribute(LLVMContext &C, unsigned Index, + StringRef Kind) const; /// \brief Remove the specified attributes at the specified index from this /// attribute list. Because attribute lists are immutable, this returns the @@ -267,6 +302,12 @@ public: AttributeSet addDereferenceableOrNullAttr(LLVMContext &C, unsigned Index, uint64_t Bytes) const; + /// Add the allocsize attribute to the attribute set at the given index. + /// Because attribute sets are immutable, this returns a new set. + AttributeSet addAllocSizeAttr(LLVMContext &C, unsigned Index, + unsigned ElemSizeArg, + const Optional &NumElemsArg); + //===--------------------------------------------------------------------===// // AttributeSet Accessors //===--------------------------------------------------------------------===// @@ -297,8 +338,10 @@ public: bool hasFnAttribute(Attribute::AttrKind Kind) const; /// \brief Return true if the specified attribute is set for at least one - /// parameter or for the return value. - bool hasAttrSomewhere(Attribute::AttrKind Attr) const; + /// parameter or for the return value. If Index is not nullptr, the index + /// of a parameter with the specified attribute is provided. + bool hasAttrSomewhere(Attribute::AttrKind Kind, + unsigned *Index = nullptr) const; /// \brief Return the attribute object that exists at the given index. Attribute getAttribute(unsigned Index, Attribute::AttrKind Kind) const; @@ -319,6 +362,10 @@ public: /// unknown). uint64_t getDereferenceableOrNullBytes(unsigned Index) const; + /// Get the allocsize argument numbers (or pair(0, 0) if unknown). + std::pair> + getAllocSizeArgs(unsigned Index) const; + /// \brief Return the attributes at the index as a string. std::string getAsString(unsigned Index, bool InAttrGrp = false) const; @@ -400,19 +447,20 @@ class AttrBuilder { uint64_t StackAlignment; uint64_t DerefBytes; uint64_t DerefOrNullBytes; + uint64_t AllocSizeArgs; public: AttrBuilder() : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), - DerefOrNullBytes(0) {} + DerefOrNullBytes(0), AllocSizeArgs(0) {} explicit AttrBuilder(uint64_t Val) : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), - DerefOrNullBytes(0) { + DerefOrNullBytes(0), AllocSizeArgs(0) { addRawValue(Val); } AttrBuilder(const Attribute &A) : Attrs(0), Alignment(0), StackAlignment(0), DerefBytes(0), - DerefOrNullBytes(0) { + DerefOrNullBytes(0), AllocSizeArgs(0) { addAttribute(A); } AttrBuilder(AttributeSet AS, unsigned Idx); @@ -481,6 +529,10 @@ public: /// dereferenceable_or_null attribute exists (zero is returned otherwise). uint64_t getDereferenceableOrNullBytes() const { return DerefOrNullBytes; } + /// Retrieve the allocsize args, if the allocsize attribute exists. If it + /// doesn't exist, pair(0, 0) is returned. + std::pair> getAllocSizeArgs() const; + /// \brief This turns an int alignment (which must be a power of 2) into the /// form used internally in Attribute. AttrBuilder &addAlignmentAttr(unsigned Align); @@ -497,6 +549,14 @@ public: /// form used internally in Attribute. AttrBuilder &addDereferenceableOrNullAttr(uint64_t Bytes); + /// This turns one (or two) ints into the form used internally in Attribute. + AttrBuilder &addAllocSizeAttr(unsigned ElemSizeArg, + const Optional &NumElemsArg); + + /// Add an allocsize attribute, using the representation returned by + /// Attribute.getIntValue(). + AttrBuilder &addAllocSizeAttrFromRawRepr(uint64_t RawAllocSizeRepr); + /// \brief Return true if the builder contains no target-independent /// attributes. bool empty() const { return Attrs.none(); } diff --git a/include/llvm/IR/Attributes.td b/include/llvm/IR/Attributes.td index 30249bbd8fab188608b2dd9510bff0a221ae5bac..7b63638a3f6acd015df70770b6474512bfe10805 100644 --- a/include/llvm/IR/Attributes.td +++ b/include/llvm/IR/Attributes.td @@ -16,6 +16,10 @@ class StrBoolAttr : Attr; /// 0 means unaligned (different from align(1)). def Alignment : EnumAttr<"align">; +/// The result of the function is guaranteed to point to a number of bytes that +/// we can determine if we know the value of the function's arguments. +def AllocSize : EnumAttr<"allocsize">; + /// inline=always. def AlwaysInline : EnumAttr<"alwaysinline">; @@ -154,9 +158,18 @@ def SanitizeThread : EnumAttr<"sanitize_thread">; /// MemorySanitizer is on. def SanitizeMemory : EnumAttr<"sanitize_memory">; +/// Argument is swift error. +def SwiftError : EnumAttr<"swifterror">; + +/// Argument is swift self/context. +def SwiftSelf : EnumAttr<"swiftself">; + /// Function must be in a unwind table. def UWTable : EnumAttr<"uwtable">; +/// Function only writes to memory. +def WriteOnly : EnumAttr<"writeonly">; + /// Zero extended before/after call. def ZExt : EnumAttr<"zeroext">; @@ -165,6 +178,7 @@ def LessPreciseFPMAD : StrBoolAttr<"less-precise-fpmad">; def NoInfsFPMath : StrBoolAttr<"no-infs-fp-math">; def NoNansFPMath : StrBoolAttr<"no-nans-fp-math">; def UnsafeFPMath : StrBoolAttr<"unsafe-fp-math">; +def NoJumpTables : StrBoolAttr<"no-jump-tables">; class CompatRule { // The name of the function called to check the attribute of the caller and @@ -179,6 +193,7 @@ class CompatRule { def : CompatRule<"isEqual">; def : CompatRule<"isEqual">; def : CompatRule<"isEqual">; +def : CompatRule<"isEqual">; class MergeRule { // The name of the function called to merge the attributes of the caller and @@ -194,4 +209,5 @@ def : MergeRule<"setAND">; def : MergeRule<"setAND">; def : MergeRule<"setAND">; def : MergeRule<"setOR">; +def : MergeRule<"setOR">; def : MergeRule<"adjustCallerSSPLevel">; diff --git a/include/llvm/IR/AutoUpgrade.h b/include/llvm/IR/AutoUpgrade.h index 24665c4e3676f48c5450bb65453233cc0443c103..9eb358682c655dd317712a83494b2096615d4f1f 100644 --- a/include/llvm/IR/AutoUpgrade.h +++ b/include/llvm/IR/AutoUpgrade.h @@ -47,6 +47,10 @@ namespace llvm { /// if it requires upgrading. bool UpgradeGlobalVariable(GlobalVariable *GV); + /// This checks for module flags which should be upgraded. It returns true if + /// module is modified. + bool UpgradeModuleFlags(Module &M); + /// If the TBAA tag for the given instruction uses the scalar TBAA format, /// we upgrade it to the struct-path aware TBAA format. void UpgradeInstWithTBAATag(Instruction *I); diff --git a/include/llvm/IR/CallSite.h b/include/llvm/IR/CallSite.h index 2bd836fd794c7d150313f0e23e44169e7e311088..9c977aef941ad3e6842f16219844392b1b240c67 100644 --- a/include/llvm/IR/CallSite.h +++ b/include/llvm/IR/CallSite.h @@ -273,6 +273,10 @@ public: CALLSITE_DELEGATE_GETTER(getArgOperand(i)); } + ValTy *getReturnedArgOperand() const { + CALLSITE_DELEGATE_GETTER(getReturnedArgOperand()); + } + bool isInlineAsm() const { if (isCall()) return cast(getInstruction())->isInlineAsm(); @@ -305,19 +309,51 @@ public: CALLSITE_DELEGATE_SETTER(setAttributes(PAL)); } + void addAttribute(unsigned i, Attribute::AttrKind Kind) { + CALLSITE_DELEGATE_SETTER(addAttribute(i, Kind)); + } + + void addAttribute(unsigned i, StringRef Kind, StringRef Value) { + CALLSITE_DELEGATE_SETTER(addAttribute(i, Kind, Value)); + } + + void addAttribute(unsigned i, Attribute Attr) { + CALLSITE_DELEGATE_SETTER(addAttribute(i, Attr)); + } + + void removeAttribute(unsigned i, Attribute::AttrKind Kind) { + CALLSITE_DELEGATE_SETTER(removeAttribute(i, Kind)); + } + + void removeAttribute(unsigned i, StringRef Kind) { + CALLSITE_DELEGATE_SETTER(removeAttribute(i, Kind)); + } + + void removeAttribute(unsigned i, Attribute Attr) { + CALLSITE_DELEGATE_SETTER(removeAttribute(i, Attr)); + } + /// \brief Return true if this function has the given attribute. - bool hasFnAttr(Attribute::AttrKind A) const { - CALLSITE_DELEGATE_GETTER(hasFnAttr(A)); + bool hasFnAttr(Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(hasFnAttr(Kind)); } /// \brief Return true if this function has the given attribute. - bool hasFnAttr(StringRef A) const { - CALLSITE_DELEGATE_GETTER(hasFnAttr(A)); + bool hasFnAttr(StringRef Kind) const { + CALLSITE_DELEGATE_GETTER(hasFnAttr(Kind)); } /// \brief Return true if the call or the callee has the given attribute. - bool paramHasAttr(unsigned i, Attribute::AttrKind A) const { - CALLSITE_DELEGATE_GETTER(paramHasAttr(i, A)); + bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(paramHasAttr(i, Kind)); + } + + Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(getAttribute(i, Kind)); + } + + Attribute getAttribute(unsigned i, StringRef Kind) const { + CALLSITE_DELEGATE_GETTER(getAttribute(i, Kind)); } /// \brief Return true if the data operand at index \p i directly or @@ -327,8 +363,8 @@ public: /// in the attribute set attached to this instruction, while operand bundle /// operands may have some attributes implied by the type of its containing /// operand bundle. - bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const { - CALLSITE_DELEGATE_GETTER(dataOperandHasImpliedAttr(i, A)); + bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind Kind) const { + CALLSITE_DELEGATE_GETTER(dataOperandHasImpliedAttr(i, Kind)); } /// @brief Extract the alignment for a call or parameter (0=unknown). @@ -385,6 +421,14 @@ public: CALLSITE_DELEGATE_SETTER(setOnlyReadsMemory()); } + /// @brief Determine if the call does not access or only writes memory. + bool doesNotReadMemory() const { + CALLSITE_DELEGATE_GETTER(doesNotReadMemory()); + } + void setDoesNotReadMemory() { + CALLSITE_DELEGATE_SETTER(setDoesNotReadMemory()); + } + /// @brief Determine if the call can access memmory only using pointers based /// on its arguments. bool onlyAccessesArgMemory() const { @@ -410,6 +454,14 @@ public: CALLSITE_DELEGATE_SETTER(setDoesNotThrow()); } + /// @brief Determine if the call can be duplicated. + bool cannotDuplicate() const { + CALLSITE_DELEGATE_GETTER(cannotDuplicate()); + } + void setCannotDuplicate() { + CALLSITE_DELEGATE_GETTER(setCannotDuplicate()); + } + /// @brief Determine if the call is convergent. bool isConvergent() const { CALLSITE_DELEGATE_GETTER(isConvergent()); diff --git a/include/llvm/IR/CallingConv.h b/include/llvm/IR/CallingConv.h index 9797a163434d6cae59fc2c188d6cab4d8ac84eee..4987b7e943f2311d395a9cb964c2cf45017d197d 100644 --- a/include/llvm/IR/CallingConv.h +++ b/include/llvm/IR/CallingConv.h @@ -178,6 +178,21 @@ namespace CallingConv { /// which have an "optimized" convention to preserve registers. AVR_BUILTIN = 86, + /// Calling convention used for Mesa vertex shaders. + AMDGPU_VS = 87, + + /// Calling convention used for Mesa geometry shaders. + AMDGPU_GS = 88, + + /// Calling convention used for Mesa pixel shaders. + AMDGPU_PS = 89, + + /// Calling convention used for Mesa compute shaders. + AMDGPU_CS = 90, + + /// Calling convention for AMDGPU code object kernels. + AMDGPU_KERNEL = 91, + /// The highest possible calling convention ID. Must be some 2^k - 1. MaxID = 1023 }; diff --git a/include/llvm/IR/Comdat.h b/include/llvm/IR/Comdat.h index fb79e13af3a509185704d795aa409ee0a185a224..577247f27e2076862f5a0e34b4d0a4309c094a2d 100644 --- a/include/llvm/IR/Comdat.h +++ b/include/llvm/IR/Comdat.h @@ -16,12 +16,10 @@ #ifndef LLVM_IR_COMDAT_H #define LLVM_IR_COMDAT_H -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Compiler.h" - namespace llvm { class raw_ostream; +class StringRef; template class StringMapEntry; // This is a Name X SelectionKind pair. The reason for having this be an @@ -48,7 +46,6 @@ public: private: friend class Module; Comdat(); - Comdat(SelectionKind SK, StringMapEntry *Name); Comdat(const Comdat &) = delete; // Points to the map in Module. diff --git a/include/llvm/IR/ConstantRange.h b/include/llvm/IR/ConstantRange.h index 89af6bb235e49ca7fde6f723518121a06a381b73..9458fa9f5c8612d3101bd45297faaf70aa51c531 100644 --- a/include/llvm/IR/ConstantRange.h +++ b/include/llvm/IR/ConstantRange.h @@ -82,6 +82,16 @@ public: static ConstantRange makeSatisfyingICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other); + /// Produce the exact range such that all values in the returned range satisfy + /// the given predicate with any value contained within Other. Formally, this + /// returns the exact answer when the superset of 'union over all y in Other + /// is exactly same as the subset of intersection over all y in Other. + /// { x : icmp op x y is true}'. + /// + /// Example: Pred = ult and Other = i8 3 returns [0, 3) + static ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred, + const APInt &Other); + /// Return the largest range containing all X such that "X BinOpC Y" is /// guaranteed not to wrap (overflow) for all Y in Other. /// @@ -104,6 +114,11 @@ public: const ConstantRange &Other, unsigned NoWrapKind); + /// Set up \p Pred and \p RHS such that + /// ConstantRange::makeExactICmpRegion(Pred, RHS) == *this. Return true if + /// successful. + bool getEquivalentICmp(CmpInst::Predicate &Pred, APInt &RHS) const; + /// Return the lower value for this range. /// const APInt &getLower() const { return Lower; } diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h index 03b800efabed20afcced8522cde437e23f74e87e..2a5d14d94646768a03393654e66bf95c14ce7660 100644 --- a/include/llvm/IR/Constants.h +++ b/include/llvm/IR/Constants.h @@ -44,7 +44,7 @@ template struct ConstantAggrKeyType; /// /// These constants have no operands; they represent their data directly. /// Since they can be in use by unrelated modules (and are never based on -/// GlobalValues), it never makes sensee to RAUW them. +/// GlobalValues), it never makes sense to RAUW them. class ConstantData : public Constant { void anchor() override; void *operator new(size_t, unsigned) = delete; @@ -72,7 +72,7 @@ public: /// This is the shared class of boolean and integer constants. This class /// represents both boolean and integral constants. /// @brief Class for constant integers. -class ConstantInt : public ConstantData { +class ConstantInt final : public ConstantData { void anchor() override; ConstantInt(const ConstantInt &) = delete; ConstantInt(IntegerType *Ty, const APInt& V); @@ -251,7 +251,7 @@ public: //===----------------------------------------------------------------------===// /// ConstantFP - Floating Point Values [float, double] /// -class ConstantFP : public ConstantData { +class ConstantFP final : public ConstantData { APFloat Val; void anchor() override; ConstantFP(const ConstantFP &) = delete; @@ -259,7 +259,6 @@ class ConstantFP : public ConstantData { friend class Constant; void destroyConstantImpl(); -protected: ConstantFP(Type *Ty, const APFloat& V); public: @@ -318,13 +317,12 @@ public: //===----------------------------------------------------------------------===// /// All zero aggregate value /// -class ConstantAggregateZero : public ConstantData { +class ConstantAggregateZero final : public ConstantData { ConstantAggregateZero(const ConstantAggregateZero &) = delete; friend class Constant; void destroyConstantImpl(); -protected: explicit ConstantAggregateZero(Type *Ty) : ConstantData(Ty, ConstantAggregateZeroVal) {} @@ -339,7 +337,8 @@ public: /// the specified element. Constant *getStructElement(unsigned Elt) const; - /// Return a zero of the right value for the specified GEP index. + /// Return a zero of the right value for the specified GEP index if we can, + /// otherwise return null (e.g. if C is a ConstantExpr). Constant *getElementValue(Constant *C) const; /// Return a zero of the right value for the specified GEP index. @@ -355,20 +354,49 @@ public: } }; +/// Base class for aggregate constants (with operands). +/// +/// These constants are aggregates of other constants, which are stored as +/// operands. +/// +/// Subclasses are \a ConstantStruct, \a ConstantArray, and \a +/// ConstantVector. +/// +/// \note Some subclasses of \a ConstantData are semantically aggregates -- +/// such as \a ConstantDataArray -- but are not subclasses of this because they +/// use operands. +class ConstantAggregate : public Constant { +protected: + ConstantAggregate(CompositeType *T, ValueTy VT, ArrayRef V); + +public: + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static bool classof(const Value *V) { + return V->getValueID() >= ConstantAggregateFirstVal && + V->getValueID() <= ConstantAggregateLastVal; + } +}; + +template <> +struct OperandTraits + : public VariadicOperandTraits {}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantAggregate, Constant) //===----------------------------------------------------------------------===// /// ConstantArray - Constant Array Declarations /// -class ConstantArray : public Constant { +class ConstantArray final : public ConstantAggregate { friend struct ConstantAggrKeyType; - ConstantArray(const ConstantArray &) = delete; - friend class Constant; void destroyConstantImpl(); Value *handleOperandChangeImpl(Value *From, Value *To); -protected: ConstantArray(ArrayType *T, ArrayRef Val); + public: // ConstantArray accessors static Constant *get(ArrayType *T, ArrayRef V); @@ -377,9 +405,6 @@ private: static Constant *getImpl(ArrayType *T, ArrayRef V); public: - /// Transparently provide more efficient getOperand methods. - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); - /// Specialize the getType() method to always return an ArrayType, /// which reduces the amount of casting needed in parts of the compiler. inline ArrayType *getType() const { @@ -392,26 +417,17 @@ public: } }; -template <> -struct OperandTraits : - public VariadicOperandTraits { -}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantArray, Constant) - //===----------------------------------------------------------------------===// // Constant Struct Declarations // -class ConstantStruct : public Constant { +class ConstantStruct final : public ConstantAggregate { friend struct ConstantAggrKeyType; - ConstantStruct(const ConstantStruct &) = delete; - friend class Constant; void destroyConstantImpl(); Value *handleOperandChangeImpl(Value *From, Value *To); -protected: ConstantStruct(StructType *T, ArrayRef Val); + public: // ConstantStruct accessors static Constant *get(StructType *T, ArrayRef V); @@ -436,9 +452,6 @@ public: ArrayRef V, bool Packed = false); - /// Transparently provide more efficient getOperand methods. - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); - /// Specialization - reduce amount of casting. inline StructType *getType() const { return cast(Value::getType()); @@ -450,27 +463,18 @@ public: } }; -template <> -struct OperandTraits : - public VariadicOperandTraits { -}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantStruct, Constant) - //===----------------------------------------------------------------------===// /// Constant Vector Declarations /// -class ConstantVector : public Constant { +class ConstantVector final : public ConstantAggregate { friend struct ConstantAggrKeyType; - ConstantVector(const ConstantVector &) = delete; - friend class Constant; void destroyConstantImpl(); Value *handleOperandChangeImpl(Value *From, Value *To); -protected: ConstantVector(VectorType *T, ArrayRef Val); + public: // ConstantVector accessors static Constant *get(ArrayRef V); @@ -482,9 +486,6 @@ public: /// Return a ConstantVector with the specified constant in each element. static Constant *getSplat(unsigned NumElts, Constant *Elt); - /// Transparently provide more efficient getOperand methods. - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); - /// Specialize the getType() method to always return a VectorType, /// which reduces the amount of casting needed in parts of the compiler. inline VectorType *getType() const { @@ -501,23 +502,15 @@ public: } }; -template <> -struct OperandTraits : - public VariadicOperandTraits { -}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantVector, Constant) - //===----------------------------------------------------------------------===// /// A constant pointer value that points to null /// -class ConstantPointerNull : public ConstantData { +class ConstantPointerNull final : public ConstantData { ConstantPointerNull(const ConstantPointerNull &) = delete; friend class Constant; void destroyConstantImpl(); -protected: explicit ConstantPointerNull(PointerType *T) : ConstantData(T, Value::ConstantPointerNullVal) {} @@ -655,20 +648,19 @@ private: /// (i.e. ConstantInt/ConstantFP). This Constant node has no operands because it /// stores all of the elements of the constant as densely packed data, instead /// of as Value*'s. -class ConstantDataArray : public ConstantDataSequential { +class ConstantDataArray final : public ConstantDataSequential { void *operator new(size_t, unsigned) = delete; ConstantDataArray(const ConstantDataArray &) = delete; void anchor() override; friend class ConstantDataSequential; explicit ConstantDataArray(Type *ty, const char *Data) - : ConstantDataSequential(ty, ConstantDataArrayVal, Data) {} -protected: + : ConstantDataSequential(ty, ConstantDataArrayVal, Data) {} /// Allocate space for exactly zero operands. void *operator new(size_t s) { return User::operator new(s, 0); } -public: +public: /// get() constructors - Return a constant with array type with an element /// count and element type matching the ArrayRef passed in. Note that this /// can return a ConstantAggregateZero object. @@ -714,20 +706,19 @@ public: /// (i.e. ConstantInt/ConstantFP). This Constant node has no operands because it /// stores all of the elements of the constant as densely packed data, instead /// of as Value*'s. -class ConstantDataVector : public ConstantDataSequential { +class ConstantDataVector final : public ConstantDataSequential { void *operator new(size_t, unsigned) = delete; ConstantDataVector(const ConstantDataVector &) = delete; void anchor() override; friend class ConstantDataSequential; explicit ConstantDataVector(Type *ty, const char *Data) - : ConstantDataSequential(ty, ConstantDataVectorVal, Data) {} -protected: + : ConstantDataSequential(ty, ConstantDataVectorVal, Data) {} // allocate space for exactly zero operands. void *operator new(size_t s) { return User::operator new(s, 0); } -public: +public: /// get() constructors - Return a constant with vector type with an element /// count and element type matching the ArrayRef passed in. Note that this /// can return a ConstantAggregateZero object. @@ -771,13 +762,12 @@ public: //===----------------------------------------------------------------------===// /// A constant token which is empty /// -class ConstantTokenNone : public ConstantData { +class ConstantTokenNone final : public ConstantData { ConstantTokenNone(const ConstantTokenNone &) = delete; friend class Constant; void destroyConstantImpl(); -protected: explicit ConstantTokenNone(LLVMContext &Context) : ConstantData(Type::getTokenTy(Context), ConstantTokenNoneVal) {} @@ -793,7 +783,7 @@ public: /// The address of a basic block. /// -class BlockAddress : public Constant { +class BlockAddress final : public Constant { void *operator new(size_t, unsigned) = delete; void *operator new(size_t s) { return User::operator new(s, 2); } BlockAddress(Function *F, BasicBlock *BB); @@ -851,7 +841,7 @@ class ConstantExpr : public Constant { protected: ConstantExpr(Type *ty, unsigned Opcode, Use *Ops, unsigned NumOps) - : Constant(ty, ConstantExprVal, Ops, NumOps) { + : Constant(ty, ConstantExprVal, Ops, NumOps) { // Operation type (an Instruction opcode) is stored as the SubclassData. setValueSubclassData(Opcode); } @@ -1210,13 +1200,12 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantExpr, Constant) /// can appear to have different bit patterns at each use. See /// LangRef.html#undefvalues for details. /// -class UndefValue : public ConstantData { +class UndefValue final : public ConstantData { UndefValue(const UndefValue &) = delete; friend class Constant; void destroyConstantImpl(); -protected: explicit UndefValue(Type *T) : ConstantData(T, UndefValueVal) {} public: @@ -1231,7 +1220,8 @@ public: /// for the specified element. UndefValue *getStructElement(unsigned Elt) const; - /// Return an undef of the right value for the specified GEP index. + /// Return an undef of the right value for the specified GEP index if we can, + /// otherwise return null (e.g. if C is a ConstantExpr). UndefValue *getElementValue(Constant *C) const; /// Return an undef of the right value for the specified GEP index. diff --git a/include/llvm/IR/DIBuilder.h b/include/llvm/IR/DIBuilder.h index 98bef39ac9908a324f8c12af048a6da141fe4b23..0f2f67f5feaf6bec15b655ce4049ee6892d8474d 100644 --- a/include/llvm/IR/DIBuilder.h +++ b/include/llvm/IR/DIBuilder.h @@ -15,8 +15,6 @@ #ifndef LLVM_IR_DIBUILDER_H #define LLVM_IR_DIBUILDER_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/TrackingMDRef.h" #include "llvm/IR/ValueHandle.h" @@ -31,6 +29,7 @@ namespace llvm { class Constant; class LLVMContext; class StringRef; + template class ArrayRef; class DIBuilder { Module &M; @@ -52,7 +51,11 @@ namespace llvm { bool AllowUnresolvedNodes; /// Each subprogram's preserved local variables. - DenseMap> PreservedVariables; + /// + /// Do not use a std::vector. Some versions of libc++ apparently copy + /// instead of move on grow operations, and TrackingMDRef is expensive to + /// copy. + DenseMap> PreservedVariables; DIBuilder(const DIBuilder &) = delete; void operator=(const DIBuilder &) = delete; @@ -68,7 +71,6 @@ namespace llvm { /// If \c AllowUnresolved, collect unresolved nodes attached to the module /// in order to resolve cycles during \a finalize(). explicit DIBuilder(Module &M, bool AllowUnresolved = true); - enum DebugEmissionKind { FullDebug=1, LineTablesOnly }; /// Construct any deferred debug info descriptors. void finalize(); @@ -93,22 +95,13 @@ namespace llvm { /// out into. /// \param Kind The kind of debug information to generate. /// \param DWOId The DWOId if this is a split skeleton compile unit. - /// \param EmitDebugInfo A boolean flag which indicates whether - /// debug information should be written to - /// the final output or not. When this is - /// false, debug information annotations will - /// be present in the IL but they are not - /// written to the final assembly or object - /// file. This supports tracking source - /// location information in the back end - /// without actually changing the output - /// (e.g., when using optimization remarks). DICompileUnit * createCompileUnit(unsigned Lang, StringRef File, StringRef Dir, StringRef Producer, bool isOptimized, StringRef Flags, unsigned RV, StringRef SplitName = StringRef(), - DebugEmissionKind Kind = FullDebug, uint64_t DWOId = 0, - bool EmitDebugInfo = true); + DICompileUnit::DebugEmissionKind Kind = + DICompileUnit::DebugEmissionKind::FullDebug, + uint64_t DWOId = 0); /// Create a file descriptor to hold debugging information /// for a file. @@ -154,7 +147,8 @@ namespace llvm { /// \param Class Type for which this pointer points to members of. DIDerivedType *createMemberPointerType(DIType *PointeeTy, DIType *Class, uint64_t SizeInBits, - uint64_t AlignInBits = 0); + uint64_t AlignInBits = 0, + unsigned Flags = 0); /// Create debugging information entry for a c++ /// style reference or rvalue reference type. @@ -200,6 +194,22 @@ namespace llvm { uint64_t OffsetInBits, unsigned Flags, DIType *Ty); + /// Create debugging information entry for a bit field member. + /// \param Scope Member scope. + /// \param Name Member name. + /// \param File File where this member is defined. + /// \param LineNo Line number. + /// \param SizeInBits Member size. + /// \param AlignInBits Member alignment. + /// \param OffsetInBits Member offset. + /// \param StorageOffsetInBits Member storage offset. + /// \param Flags Flags to encode member attribute. + /// \param Ty Parent type. + DIDerivedType *createBitFieldMemberType( + DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, + uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, + uint64_t StorageOffsetInBits, unsigned Flags, DIType *Ty); + /// Create debugging information entry for a /// C++ static data member. /// \param Scope Member scope. @@ -381,8 +391,9 @@ namespace llvm { /// includes return type at 0th index. /// \param Flags E.g.: LValueReference. /// These flags are used to emit dwarf attributes. + /// \param CC Calling convention, e.g. dwarf::DW_CC_normal DISubroutineType *createSubroutineType(DITypeRefArray ParameterTypes, - unsigned Flags = 0); + unsigned Flags = 0, unsigned CC = 0); /// Create an external type reference. /// \param Tag Dwarf TAG. @@ -413,9 +424,9 @@ namespace llvm { uint64_t AlignInBits = 0, unsigned Flags = DINode::FlagFwdDecl, StringRef UniqueIdentifier = ""); - /// Retain DIType* in a module even if it is not referenced + /// Retain DIScope* in a module even if it is not referenced /// through debug info anchors. - void retainType(DIType *T); + void retainType(DIScope *T); /// Create unspecified parameter type /// for a subroutine type. @@ -535,17 +546,6 @@ namespace llvm { bool isOptimized = false, DITemplateParameterArray TParams = nullptr, DISubprogram *Decl = nullptr); - /// FIXME: this is added for dragonegg. Once we update dragonegg - /// to call resolve function, this will be removed. - DISubprogram *createFunction(DIScopeRef Scope, StringRef Name, - StringRef LinkageName, DIFile *File, - unsigned LineNo, DISubroutineType *Ty, - bool isLocalToUnit, bool isDefinition, - unsigned ScopeLine, unsigned Flags = 0, - bool isOptimized = false, - DITemplateParameterArray TParams = nullptr, - DISubprogram *Decl = nullptr); - /// Create a new descriptor for the specified C++ method. /// See comments in \a DISubprogram* for descriptions of these fields. /// \param Scope Function scope. @@ -560,6 +560,9 @@ namespace llvm { /// virtual function. /// \param VTableIndex Index no of this method in virtual table, or -1u if /// unrepresentable. + /// \param ThisAdjustment + /// MS ABI-specific adjustment of 'this' that occurs + /// in the prologue. /// \param VTableHolder Type that holds vtable. /// \param Flags e.g. is this function prototyped or not. /// This flags are used to emit dwarf attributes. @@ -569,8 +572,9 @@ namespace llvm { createMethod(DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DISubroutineType *Ty, bool isLocalToUnit, bool isDefinition, unsigned Virtuality = 0, - unsigned VTableIndex = 0, DIType *VTableHolder = nullptr, - unsigned Flags = 0, bool isOptimized = false, + unsigned VTableIndex = 0, int ThisAdjustment = 0, + DIType *VTableHolder = nullptr, unsigned Flags = 0, + bool isOptimized = false, DITemplateParameterArray TParams = nullptr); /// This creates new descriptor for a namespace with the specified diff --git a/include/llvm/IR/DataLayout.h b/include/llvm/IR/DataLayout.h index 6caa968ae4dd66413e4e1ac7ddaf2f51e3594fea..173121b72ffd6bdc0fd34f9873e5b3fb0d839ba2 100644 --- a/include/llvm/IR/DataLayout.h +++ b/include/llvm/IR/DataLayout.h @@ -20,7 +20,6 @@ #ifndef LLVM_IR_DATALAYOUT_H #define LLVM_IR_DATALAYOUT_H -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Type.h" @@ -34,8 +33,6 @@ typedef struct LLVMOpaqueTargetData *LLVMTargetDataRef; namespace llvm { class Value; -class Type; -class IntegerType; class StructType; class StructLayout; class Triple; @@ -430,20 +427,20 @@ public: /// \brief Returns the largest legal integer type, or null if none are set. Type *getLargestLegalIntType(LLVMContext &C) const { - unsigned LargestSize = getLargestLegalIntTypeSize(); + unsigned LargestSize = getLargestLegalIntTypeSizeInBits(); return (LargestSize == 0) ? nullptr : Type::getIntNTy(C, LargestSize); } /// \brief Returns the size of largest legal integer type size, or 0 if none /// are set. - unsigned getLargestLegalIntTypeSize() const; + unsigned getLargestLegalIntTypeSizeInBits() const; /// \brief Returns the offset from the beginning of the type for the specified /// indices. /// /// Note that this takes the element type, not the pointer type. /// This is used to implement getelementptr. - uint64_t getIndexedOffsetInType(Type *ElemTy, ArrayRef Indices) const; + int64_t getIndexedOffsetInType(Type *ElemTy, ArrayRef Indices) const; /// \brief Returns a StructLayout object, indicating the alignment of the /// struct, its size, and the offsets of its fields. diff --git a/include/llvm/IR/DebugInfo.h b/include/llvm/IR/DebugInfo.h index 82227930403113057f8561f093df2cc585550936..972042432b7b491976fea1a04fc44fe5047dfbff 100644 --- a/include/llvm/IR/DebugInfo.h +++ b/include/llvm/IR/DebugInfo.h @@ -17,10 +17,8 @@ #ifndef LLVM_IR_DEBUGINFO_H #define LLVM_IR_DEBUGINFO_H -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/Support/Casting.h" @@ -32,16 +30,12 @@ namespace llvm { class Module; class DbgDeclareInst; class DbgValueInst; - -/// \brief Maps from type identifier to the actual MDNode. -typedef DenseMap DITypeIdentifierMap; +template +class DenseMap; /// \brief Find subprogram that is enclosing this scope. DISubprogram *getDISubprogram(const MDNode *Scope); -/// \brief Generate map by visiting all retained types. -DITypeIdentifierMap generateDITypeIdentifierMap(const NamedMDNode *CU_Nodes); - /// \brief Strip debug info in the module if it exists. /// /// To do this, we remove all calls to the debugger intrinsics and any named @@ -63,8 +57,6 @@ unsigned getDebugMetadataVersionFromModule(const Module &M); /// used by the CUs. class DebugInfoFinder { public: - DebugInfoFinder() : TypeMapInitialized(false) {} - /// \brief Process entire module and collect debug info anchors. void processModule(const Module &M); @@ -132,10 +124,6 @@ private: SmallVector TYs; SmallVector Scopes; SmallPtrSet NodesSeen; - DITypeIdentifierMap TypeIdentifierMap; - - /// \brief Specify if TypeIdentifierMap is initialized. - bool TypeMapInitialized; }; } // end namespace llvm diff --git a/include/llvm/IR/DebugInfoFlags.def b/include/llvm/IR/DebugInfoFlags.def index 9756c12264b442d826c6701fc51ce682093a9537..26238c349e7e3f0e72c4b4e493ef03d8f2874fba 100644 --- a/include/llvm/IR/DebugInfoFlags.def +++ b/include/llvm/IR/DebugInfoFlags.def @@ -33,5 +33,10 @@ HANDLE_DI_FLAG((1 << 12), StaticMember) HANDLE_DI_FLAG((1 << 13), LValueReference) HANDLE_DI_FLAG((1 << 14), RValueReference) HANDLE_DI_FLAG((1 << 15), ExternalTypeRef) +HANDLE_DI_FLAG((1 << 16), SingleInheritance) +HANDLE_DI_FLAG((2 << 16), MultipleInheritance) +HANDLE_DI_FLAG((3 << 16), VirtualInheritance) +HANDLE_DI_FLAG((1 << 18), IntroducedVirtual) +HANDLE_DI_FLAG((1 << 19), BitField) #undef HANDLE_DI_FLAG diff --git a/include/llvm/IR/DebugInfoMetadata.h b/include/llvm/IR/DebugInfoMetadata.h index ce23cf35f9a8d9f702391322d17b2cb8c54e1276..853a94afd9d98e03c0e827c147bc97bb42b3ca86 100644 --- a/include/llvm/IR/DebugInfoMetadata.h +++ b/include/llvm/IR/DebugInfoMetadata.h @@ -43,21 +43,25 @@ namespace llvm { -/// \brief Pointer union between a subclass of DINode and MDString. +template class Optional; + +/// Holds a subclass of DINode. /// -/// \a DICompositeType can be referenced via an \a MDString unique identifier. -/// This class allows some type safety in the face of that, requiring either a -/// node of a particular type or an \a MDString. +/// FIXME: This class doesn't currently make much sense. Previously it was a +/// union beteen MDString (for ODR-uniqued types) and things like DIType. To +/// support CodeView work, it wasn't deleted outright when MDString-based type +/// references were deleted; we'll soon need a similar concept for CodeView +/// DITypeIndex. template class TypedDINodeRef { const Metadata *MD = nullptr; public: TypedDINodeRef() = default; TypedDINodeRef(std::nullptr_t) {} + TypedDINodeRef(const T *MD) : MD(MD) {} - /// \brief Construct from a raw pointer. explicit TypedDINodeRef(const Metadata *MD) : MD(MD) { - assert((!MD || isa(MD) || isa(MD)) && "Expected valid ref"); + assert((!MD || isa(MD)) && "Expected valid type ref"); } template @@ -69,26 +73,10 @@ public: operator Metadata *() const { return const_cast(MD); } + T *resolve() const { return const_cast(cast_or_null(MD)); } + bool operator==(const TypedDINodeRef &X) const { return MD == X.MD; } bool operator!=(const TypedDINodeRef &X) const { return MD != X.MD; } - - /// \brief Create a reference. - /// - /// Get a reference to \c N, using an \a MDString reference if available. - static TypedDINodeRef get(const T *N); - - template T *resolve(const MapTy &Map) const { - if (!MD) - return nullptr; - - if (auto *Typed = dyn_cast(MD)) - return const_cast(Typed); - - auto *S = cast(MD); - auto I = Map.find(S); - assert(I != Map.end() && "Missing identifier in type map"); - return cast(I->second); - } }; typedef TypedDINodeRef DINodeRef; @@ -173,6 +161,9 @@ protected: return MDString::get(Context, S); } + /// Allow subclasses to mutate the tag. + void setTag(unsigned Tag) { SubclassData16 = Tag; } + public: unsigned getTag() const { return SubclassData16; } @@ -183,7 +174,9 @@ public: enum DIFlags { #define HANDLE_DI_FLAG(ID, NAME) Flag##NAME = ID, #include "llvm/IR/DebugInfoFlags.def" - FlagAccessibility = FlagPrivate | FlagProtected | FlagPublic + FlagAccessibility = FlagPrivate | FlagProtected | FlagPublic, + FlagPtrToMemberRep = FlagSingleInheritance | FlagMultipleInheritance | + FlagVirtualInheritance, }; static unsigned getFlag(StringRef Flag); @@ -196,8 +189,6 @@ public: static unsigned splitFlags(unsigned Flags, SmallVectorImpl &SplitFlags); - DINodeRef getRef() const { return DINodeRef::get(this); } - static bool classof(const Metadata *MD) { switch (MD->getMetadataID()) { default: @@ -432,8 +423,6 @@ public: : static_cast(getOperand(0)); } - DIScopeRef getRef() const { return DIScopeRef::get(this); } - static bool classof(const Metadata *MD) { switch (MD->getMetadataID()) { default: @@ -528,11 +517,28 @@ protected: DIType(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, unsigned Line, uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, unsigned Flags, ArrayRef Ops) - : DIScope(C, ID, Storage, Tag, Ops), Line(Line), Flags(Flags), - SizeInBits(SizeInBits), AlignInBits(AlignInBits), - OffsetInBits(OffsetInBits) {} + : DIScope(C, ID, Storage, Tag, Ops) { + init(Line, SizeInBits, AlignInBits, OffsetInBits, Flags); + } ~DIType() = default; + void init(unsigned Line, uint64_t SizeInBits, uint64_t AlignInBits, + uint64_t OffsetInBits, unsigned Flags) { + this->Line = Line; + this->Flags = Flags; + this->SizeInBits = SizeInBits; + this->AlignInBits = AlignInBits; + this->OffsetInBits = OffsetInBits; + } + + /// Change fields in place. + void mutate(unsigned Tag, unsigned Line, uint64_t SizeInBits, + uint64_t AlignInBits, uint64_t OffsetInBits, unsigned Flags) { + assert(isDistinct() && "Only distinct nodes can mutate"); + setTag(Tag); + init(Line, SizeInBits, AlignInBits, OffsetInBits, Flags); + } + public: TempDIType clone() const { return TempDIType(cast(MDNode::clone().release())); @@ -575,13 +581,12 @@ public: return getFlags() & FlagObjcClassComplete; } bool isVector() const { return getFlags() & FlagVector; } + bool isBitField() const { return getFlags() & FlagBitField; } bool isStaticMember() const { return getFlags() & FlagStaticMember; } bool isLValueReference() const { return getFlags() & FlagLValueReference; } bool isRValueReference() const { return getFlags() & FlagRValueReference; } bool isExternalTypeRef() const { return getFlags() & FlagExternalTypeRef; } - DITypeRef getRef() const { return DITypeRef::get(this); } - static bool classof(const Metadata *MD) { switch (MD->getMetadataID()) { default: @@ -736,6 +741,12 @@ public: DIObjCProperty *getObjCProperty() const { return dyn_cast_or_null(getExtraData()); } + Constant *getStorageOffsetInBits() const { + assert(getTag() == dwarf::DW_TAG_member && isBitField()); + if (auto *C = cast_or_null(getExtraData())) + return C->getValue(); + return nullptr; + } Constant *getConstant() const { assert(getTag() == dwarf::DW_TAG_member && isStaticMember()); if (auto *C = cast_or_null(getExtraData())) @@ -768,6 +779,16 @@ class DICompositeType : public DIType { RuntimeLang(RuntimeLang) {} ~DICompositeType() = default; + /// Change fields in place. + void mutate(unsigned Tag, unsigned Line, unsigned RuntimeLang, + uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, + unsigned Flags) { + assert(isDistinct() && "Only distinct nodes can mutate"); + assert(getRawIdentifier() && "Only ODR-uniqued nodes should mutate"); + this->RuntimeLang = RuntimeLang; + DIType::mutate(Tag, Line, SizeInBits, AlignInBits, OffsetInBits, Flags); + } + static DICompositeType * getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, Metadata *File, unsigned Line, DIScopeRef Scope, DITypeRef BaseType, @@ -823,6 +844,40 @@ public: TempDICompositeType clone() const { return cloneImpl(); } + /// Get a DICompositeType with the given ODR identifier. + /// + /// If \a LLVMContext::isODRUniquingDebugTypes(), gets the mapped + /// DICompositeType for the given ODR \c Identifier. If none exists, creates + /// a new node. + /// + /// Else, returns \c nullptr. + static DICompositeType * + getODRType(LLVMContext &Context, MDString &Identifier, unsigned Tag, + MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, uint64_t AlignInBits, + uint64_t OffsetInBits, unsigned Flags, Metadata *Elements, + unsigned RuntimeLang, Metadata *VTableHolder, + Metadata *TemplateParams); + static DICompositeType *getODRTypeIfExists(LLVMContext &Context, + MDString &Identifier); + + /// Build a DICompositeType with the given ODR identifier. + /// + /// Looks up the mapped DICompositeType for the given ODR \c Identifier. If + /// it doesn't exist, creates a new one. If it does exist and \a + /// isForwardDecl(), and the new arguments would be a definition, mutates the + /// the type in place. In either case, returns the type. + /// + /// If not \a LLVMContext::isODRUniquingDebugTypes(), this function returns + /// nullptr. + static DICompositeType * + buildODRType(LLVMContext &Context, MDString &Identifier, unsigned Tag, + MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, uint64_t AlignInBits, + uint64_t OffsetInBits, unsigned Flags, Metadata *Elements, + unsigned RuntimeLang, Metadata *VTableHolder, + Metadata *TemplateParams); + DITypeRef getBaseType() const { return DITypeRef(getRawBaseType()); } DINodeArray getElements() const { return cast_or_null(getRawElements()); @@ -867,14 +922,6 @@ public: } }; -template TypedDINodeRef TypedDINodeRef::get(const T *N) { - if (N) - if (auto *Composite = dyn_cast(N)) - if (auto *S = Composite->getRawIdentifier()) - return TypedDINodeRef(S); - return TypedDINodeRef(N); -} - /// \brief Type array for a subprogram. /// /// TODO: Fold the array of types in directly as operands. @@ -882,35 +929,44 @@ class DISubroutineType : public DIType { friend class LLVMContextImpl; friend class MDNode; + /// The calling convention used with DW_AT_calling_convention. Actually of + /// type dwarf::CallingConvention. + uint8_t CC; + DISubroutineType(LLVMContext &C, StorageType Storage, unsigned Flags, - ArrayRef Ops) + uint8_t CC, ArrayRef Ops) : DIType(C, DISubroutineTypeKind, Storage, dwarf::DW_TAG_subroutine_type, - 0, 0, 0, 0, Flags, Ops) {} + 0, 0, 0, 0, Flags, Ops), + CC(CC) {} ~DISubroutineType() = default; static DISubroutineType *getImpl(LLVMContext &Context, unsigned Flags, - DITypeRefArray TypeArray, + uint8_t CC, DITypeRefArray TypeArray, StorageType Storage, bool ShouldCreate = true) { - return getImpl(Context, Flags, TypeArray.get(), Storage, ShouldCreate); + return getImpl(Context, Flags, CC, TypeArray.get(), Storage, ShouldCreate); } static DISubroutineType *getImpl(LLVMContext &Context, unsigned Flags, - Metadata *TypeArray, StorageType Storage, + uint8_t CC, Metadata *TypeArray, + StorageType Storage, bool ShouldCreate = true); TempDISubroutineType cloneImpl() const { - return getTemporary(getContext(), getFlags(), getTypeArray()); + return getTemporary(getContext(), getFlags(), getCC(), getTypeArray()); } public: DEFINE_MDNODE_GET(DISubroutineType, - (unsigned Flags, DITypeRefArray TypeArray), - (Flags, TypeArray)) - DEFINE_MDNODE_GET(DISubroutineType, (unsigned Flags, Metadata *TypeArray), - (Flags, TypeArray)) + (unsigned Flags, uint8_t CC, DITypeRefArray TypeArray), + (Flags, CC, TypeArray)) + DEFINE_MDNODE_GET(DISubroutineType, + (unsigned Flags, uint8_t CC, Metadata *TypeArray), + (Flags, CC, TypeArray)) TempDISubroutineType clone() const { return cloneImpl(); } + uint8_t getCC() const { return CC; } + DITypeRefArray getTypeArray() const { return cast_or_null(getRawTypeArray()); } @@ -925,7 +981,17 @@ public: class DICompileUnit : public DIScope { friend class LLVMContextImpl; friend class MDNode; +public: + enum DebugEmissionKind : unsigned { + NoDebug = 0, + FullDebug, + LineTablesOnly, + LastEmissionKind = LineTablesOnly + }; + static Optional getEmissionKind(StringRef Str); + static const char *EmissionKindString(DebugEmissionKind EK); +private: unsigned SourceLanguage; bool IsOptimized; unsigned RuntimeVersion; @@ -948,33 +1014,30 @@ class DICompileUnit : public DIScope { StringRef Producer, bool IsOptimized, StringRef Flags, unsigned RuntimeVersion, StringRef SplitDebugFilename, unsigned EmissionKind, DICompositeTypeArray EnumTypes, - DITypeArray RetainedTypes, DISubprogramArray Subprograms, - DIGlobalVariableArray GlobalVariables, + DIScopeArray RetainedTypes, DIGlobalVariableArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, uint64_t DWOId, StorageType Storage, bool ShouldCreate = true) { - return getImpl(Context, SourceLanguage, File, - getCanonicalMDString(Context, Producer), IsOptimized, - getCanonicalMDString(Context, Flags), RuntimeVersion, - getCanonicalMDString(Context, SplitDebugFilename), - EmissionKind, EnumTypes.get(), RetainedTypes.get(), - Subprograms.get(), GlobalVariables.get(), - ImportedEntities.get(), Macros.get(), DWOId, Storage, - ShouldCreate); + return getImpl( + Context, SourceLanguage, File, getCanonicalMDString(Context, Producer), + IsOptimized, getCanonicalMDString(Context, Flags), RuntimeVersion, + getCanonicalMDString(Context, SplitDebugFilename), EmissionKind, + EnumTypes.get(), RetainedTypes.get(), GlobalVariables.get(), + ImportedEntities.get(), Macros.get(), DWOId, Storage, ShouldCreate); } static DICompileUnit * getImpl(LLVMContext &Context, unsigned SourceLanguage, Metadata *File, MDString *Producer, bool IsOptimized, MDString *Flags, unsigned RuntimeVersion, MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, - Metadata *Subprograms, Metadata *GlobalVariables, - Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, - StorageType Storage, bool ShouldCreate = true); + Metadata *GlobalVariables, Metadata *ImportedEntities, + Metadata *Macros, uint64_t DWOId, StorageType Storage, + bool ShouldCreate = true); TempDICompileUnit cloneImpl() const { return getTemporary( getContext(), getSourceLanguage(), getFile(), getProducer(), isOptimized(), getFlags(), getRuntimeVersion(), getSplitDebugFilename(), - getEmissionKind(), getEnumTypes(), getRetainedTypes(), getSubprograms(), + getEmissionKind(), getEnumTypes(), getRetainedTypes(), getGlobalVariables(), getImportedEntities(), getMacros(), DWOId); } @@ -986,24 +1049,23 @@ public: DICompileUnit, (unsigned SourceLanguage, DIFile *File, StringRef Producer, bool IsOptimized, StringRef Flags, unsigned RuntimeVersion, - StringRef SplitDebugFilename, unsigned EmissionKind, - DICompositeTypeArray EnumTypes, DITypeArray RetainedTypes, - DISubprogramArray Subprograms, DIGlobalVariableArray GlobalVariables, + StringRef SplitDebugFilename, DebugEmissionKind EmissionKind, + DICompositeTypeArray EnumTypes, DIScopeArray RetainedTypes, + DIGlobalVariableArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, uint64_t DWOId), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, - SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, + SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId)) DEFINE_MDNODE_GET_DISTINCT_TEMPORARY( DICompileUnit, (unsigned SourceLanguage, Metadata *File, MDString *Producer, bool IsOptimized, MDString *Flags, unsigned RuntimeVersion, MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, - Metadata *RetainedTypes, Metadata *Subprograms, - Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, - uint64_t DWOId), + Metadata *RetainedTypes, Metadata *GlobalVariables, + Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, - SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, + SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId)) TempDICompileUnit clone() const { return cloneImpl(); } @@ -1011,19 +1073,18 @@ public: unsigned getSourceLanguage() const { return SourceLanguage; } bool isOptimized() const { return IsOptimized; } unsigned getRuntimeVersion() const { return RuntimeVersion; } - unsigned getEmissionKind() const { return EmissionKind; } + DebugEmissionKind getEmissionKind() const { + return (DebugEmissionKind)EmissionKind; + } StringRef getProducer() const { return getStringOperand(1); } StringRef getFlags() const { return getStringOperand(2); } StringRef getSplitDebugFilename() const { return getStringOperand(3); } DICompositeTypeArray getEnumTypes() const { return cast_or_null(getRawEnumTypes()); } - DITypeArray getRetainedTypes() const { + DIScopeArray getRetainedTypes() const { return cast_or_null(getRawRetainedTypes()); } - DISubprogramArray getSubprograms() const { - return cast_or_null(getRawSubprograms()); - } DIGlobalVariableArray getGlobalVariables() const { return cast_or_null(getRawGlobalVariables()); } @@ -1043,10 +1104,9 @@ public: } Metadata *getRawEnumTypes() const { return getOperand(4); } Metadata *getRawRetainedTypes() const { return getOperand(5); } - Metadata *getRawSubprograms() const { return getOperand(6); } - Metadata *getRawGlobalVariables() const { return getOperand(7); } - Metadata *getRawImportedEntities() const { return getOperand(8); } - Metadata *getRawMacros() const { return getOperand(9); } + Metadata *getRawGlobalVariables() const { return getOperand(6); } + Metadata *getRawImportedEntities() const { return getOperand(7); } + Metadata *getRawMacros() const { return getOperand(8); } /// \brief Replace arrays. /// @@ -1060,16 +1120,13 @@ public: void replaceRetainedTypes(DITypeArray N) { replaceOperandWith(5, N.get()); } - void replaceSubprograms(DISubprogramArray N) { - replaceOperandWith(6, N.get()); - } void replaceGlobalVariables(DIGlobalVariableArray N) { - replaceOperandWith(7, N.get()); + replaceOperandWith(6, N.get()); } void replaceImportedEntities(DIImportedEntityArray N) { - replaceOperandWith(8, N.get()); + replaceOperandWith(7, N.get()); } - void replaceMacros(DIMacroNodeArray N) { replaceOperandWith(9, N.get()); } + void replaceMacros(DIMacroNodeArray N) { replaceOperandWith(8, N.get()); } /// @} static bool classof(const Metadata *MD) { @@ -1096,6 +1153,12 @@ public: /// chain. DISubprogram *getSubprogram() const; + /// Get the first non DILexicalBlockFile scope of this scope. + /// + /// Return this if it's not a \a DILexicalBlockFIle; otherwise, look up the + /// scope chain. + DILocalScope *getNonLexicalBlockFileScope() const; + static bool classof(const Metadata *MD) { return MD->getMetadataID() == DISubprogramKind || MD->getMetadataID() == DILexicalBlockKind || @@ -1215,22 +1278,41 @@ class DISubprogram : public DILocalScope { unsigned Line; unsigned ScopeLine; - unsigned Virtuality; unsigned VirtualIndex; - unsigned Flags; - bool IsLocalToUnit; - bool IsDefinition; - bool IsOptimized; + + /// In the MS ABI, the implicit 'this' parameter is adjusted in the prologue + /// of method overrides from secondary bases by this amount. It may be + /// negative. + int ThisAdjustment; + + // Virtuality can only assume three values, so we can pack + // in 2 bits (none/pure/pure_virtual). + unsigned Virtuality : 2; + + unsigned Flags : 27; + + // These are boolean flags so one bit is enough. + // MSVC starts a new container field every time the base + // type changes so we can't use 'bool' to ensure these bits + // are packed. + unsigned IsLocalToUnit : 1; + unsigned IsDefinition : 1; + unsigned IsOptimized : 1; DISubprogram(LLVMContext &C, StorageType Storage, unsigned Line, unsigned ScopeLine, unsigned Virtuality, unsigned VirtualIndex, - unsigned Flags, bool IsLocalToUnit, bool IsDefinition, - bool IsOptimized, ArrayRef Ops) + int ThisAdjustment, unsigned Flags, bool IsLocalToUnit, + bool IsDefinition, bool IsOptimized, ArrayRef Ops) : DILocalScope(C, DISubprogramKind, Storage, dwarf::DW_TAG_subprogram, Ops), - Line(Line), ScopeLine(ScopeLine), Virtuality(Virtuality), - VirtualIndex(VirtualIndex), Flags(Flags), IsLocalToUnit(IsLocalToUnit), - IsDefinition(IsDefinition), IsOptimized(IsOptimized) {} + Line(Line), ScopeLine(ScopeLine), VirtualIndex(VirtualIndex), + ThisAdjustment(ThisAdjustment), Virtuality(Virtuality), Flags(Flags), + IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition), + IsOptimized(IsOptimized) { + static_assert(dwarf::DW_VIRTUALITY_max < 4, "Virtuality out of range"); + assert(Virtuality < 4 && "Virtuality out of range"); + assert((Flags < (1 << 27)) && "Flags out of range"); + } ~DISubprogram() = default; static DISubprogram * @@ -1238,32 +1320,34 @@ class DISubprogram : public DILocalScope { StringRef LinkageName, DIFile *File, unsigned Line, DISubroutineType *Type, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, DITypeRef ContainingType, unsigned Virtuality, - unsigned VirtualIndex, unsigned Flags, bool IsOptimized, + unsigned VirtualIndex, int ThisAdjustment, unsigned Flags, + bool IsOptimized, DICompileUnit *Unit, DITemplateParameterArray TemplateParams, DISubprogram *Declaration, DILocalVariableArray Variables, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), getCanonicalMDString(Context, LinkageName), File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, - Virtuality, VirtualIndex, Flags, IsOptimized, - TemplateParams.get(), Declaration, Variables.get(), Storage, - ShouldCreate); + Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized, + Unit, TemplateParams.get(), Declaration, Variables.get(), + Storage, ShouldCreate); } static DISubprogram * getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, Metadata *ContainingType, unsigned Virtuality, unsigned VirtualIndex, - unsigned Flags, bool IsOptimized, Metadata *TemplateParams, - Metadata *Declaration, Metadata *Variables, StorageType Storage, - bool ShouldCreate = true); + int ThisAdjustment, unsigned Flags, bool IsOptimized, Metadata *Unit, + Metadata *TemplateParams, Metadata *Declaration, Metadata *Variables, + StorageType Storage, bool ShouldCreate = true); TempDISubprogram cloneImpl() const { return getTemporary( getContext(), getScope(), getName(), getLinkageName(), getFile(), getLine(), getType(), isLocalToUnit(), isDefinition(), getScopeLine(), - getContainingType(), getVirtuality(), getVirtualIndex(), getFlags(), - isOptimized(), getTemplateParams(), getDeclaration(), getVariables()); + getContainingType(), getVirtuality(), getVirtualIndex(), + getThisAdjustment(), getFlags(), isOptimized(), getUnit(), + getTemplateParams(), getDeclaration(), getVariables()); } public: @@ -1272,25 +1356,26 @@ public: DIFile *File, unsigned Line, DISubroutineType *Type, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, DITypeRef ContainingType, unsigned Virtuality, - unsigned VirtualIndex, unsigned Flags, bool IsOptimized, + unsigned VirtualIndex, int ThisAdjustment, unsigned Flags, + bool IsOptimized, DICompileUnit *Unit, DITemplateParameterArray TemplateParams = nullptr, DISubprogram *Declaration = nullptr, DILocalVariableArray Variables = nullptr), (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, - VirtualIndex, Flags, IsOptimized, TemplateParams, - Declaration, Variables)) + VirtualIndex, ThisAdjustment, Flags, IsOptimized, Unit, + TemplateParams, Declaration, Variables)) DEFINE_MDNODE_GET( DISubprogram, (Metadata * Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, Metadata *ContainingType, unsigned Virtuality, - unsigned VirtualIndex, unsigned Flags, bool IsOptimized, - Metadata *TemplateParams = nullptr, Metadata *Declaration = nullptr, - Metadata *Variables = nullptr), + unsigned VirtualIndex, int ThisAdjustment, unsigned Flags, + bool IsOptimized, Metadata *Unit, Metadata *TemplateParams = nullptr, + Metadata *Declaration = nullptr, Metadata *Variables = nullptr), (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, - TemplateParams, Declaration, Variables)) + ScopeLine, ContainingType, Virtuality, VirtualIndex, ThisAdjustment, + Flags, IsOptimized, Unit, TemplateParams, Declaration, Variables)) TempDISubprogram clone() const { return cloneImpl(); } @@ -1298,6 +1383,7 @@ public: unsigned getLine() const { return Line; } unsigned getVirtuality() const { return Virtuality; } unsigned getVirtualIndex() const { return VirtualIndex; } + int getThisAdjustment() const { return ThisAdjustment; } unsigned getScopeLine() const { return ScopeLine; } unsigned getFlags() const { return Flags; } bool isLocalToUnit() const { return IsLocalToUnit; } @@ -1349,6 +1435,12 @@ public: return DITypeRef(getRawContainingType()); } + DICompileUnit *getUnit() const { + return cast_or_null(getRawUnit()); + } + void replaceUnit(DICompileUnit *CU) { + replaceOperandWith(7, CU); + } DITemplateParameterArray getTemplateParams() const { return cast_or_null(getRawTemplateParams()); } @@ -1362,9 +1454,10 @@ public: Metadata *getRawScope() const { return getOperand(1); } Metadata *getRawType() const { return getOperand(5); } Metadata *getRawContainingType() const { return getOperand(6); } - Metadata *getRawTemplateParams() const { return getOperand(7); } - Metadata *getRawDeclaration() const { return getOperand(8); } - Metadata *getRawVariables() const { return getOperand(9); } + Metadata *getRawUnit() const { return getOperand(7); } + Metadata *getRawTemplateParams() const { return getOperand(8); } + Metadata *getRawDeclaration() const { return getOperand(9); } + Metadata *getRawVariables() const { return getOperand(10); } /// \brief Check if this subprogram describes the given function. /// @@ -1844,13 +1937,16 @@ class DILocalVariable : public DIVariable { friend class LLVMContextImpl; friend class MDNode; - unsigned Arg; - unsigned Flags; + unsigned Arg : 16; + unsigned Flags : 16; DILocalVariable(LLVMContext &C, StorageType Storage, unsigned Line, unsigned Arg, unsigned Flags, ArrayRef Ops) : DIVariable(C, DILocalVariableKind, Storage, Line, Ops), Arg(Arg), - Flags(Flags) {} + Flags(Flags) { + assert(Flags < (1 << 16) && "DILocalVariable: Flags out of range"); + assert(Arg < (1 << 16) && "DILocalVariable: Arg out of range"); + } ~DILocalVariable() = default; static DILocalVariable *getImpl(LLVMContext &Context, DIScope *Scope, diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h index 256e15eeb4200ef185a14cdfd2fbdbb3d39a12c5..02265cff9ce8468ff03ad9e247a6070dbc645631 100644 --- a/include/llvm/IR/DiagnosticInfo.h +++ b/include/llvm/IR/DiagnosticInfo.h @@ -1,4 +1,4 @@ -//===- llvm/Support/DiagnosticInfo.h - Diagnostic Declaration ---*- C++ -*-===// +//===- llvm/IR/DiagnosticInfo.h - Diagnostic Declaration --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,12 +15,13 @@ #ifndef LLVM_IR_DIAGNOSTICINFO_H #define LLVM_IR_DIAGNOSTICINFO_H -#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DebugLoc.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/Casting.h" +#include "llvm/Support/CBindingWrapping.h" +#include "llvm-c/Types.h" #include +#include namespace llvm { @@ -28,13 +29,12 @@ namespace llvm { class DiagnosticPrinter; class Function; class Instruction; -class LLVMContextImpl; -class Value; -class DebugLoc; +class LLVMContext; +class Module; class SMDiagnostic; /// \brief Defines the different supported severity of a diagnostic. -enum DiagnosticSeverity { +enum DiagnosticSeverity : char { DS_Error, DS_Warning, DS_Remark, @@ -48,9 +48,11 @@ enum DiagnosticSeverity { enum DiagnosticKind { DK_Bitcode, DK_InlineAsm, + DK_ResourceLimit, DK_StackSize, DK_Linker, DK_DebugMetadataVersion, + DK_DebugMetadataInvalid, DK_SampleProfile, DK_OptimizationRemark, DK_OptimizationRemarkMissed, @@ -58,6 +60,8 @@ enum DiagnosticKind { DK_OptimizationRemarkAnalysisFPCommute, DK_OptimizationRemarkAnalysisAliasing, DK_OptimizationFailure, + DK_FirstRemark = DK_OptimizationRemark, + DK_LastRemark = DK_OptimizationFailure, DK_MIRParser, DK_PGOProfile, DK_Unsupported, @@ -102,8 +106,6 @@ public: /// The printed message must not end with '.' nor start with a severity /// keyword. virtual void print(DiagnosticPrinter &DP) const = 0; - - static const char *AlwaysPrint; }; typedef std::function DiagnosticHandlerFunction; @@ -157,28 +159,63 @@ public: } }; -/// Diagnostic information for stack size reporting. +/// Diagnostic information for stack size etc. reporting. /// This is basically a function and a size. -class DiagnosticInfoStackSize : public DiagnosticInfo { +class DiagnosticInfoResourceLimit : public DiagnosticInfo { private: - /// The function that is concerned by this stack size diagnostic. + /// The function that is concerned by this resource limit diagnostic. const Function &Fn; - /// The computed stack size. - unsigned StackSize; + + /// Description of the resource type (e.g. stack size) + const char *ResourceName; + + /// The computed size usage + uint64_t ResourceSize; + + // Threshould passed + uint64_t ResourceLimit; public: /// \p The function that is concerned by this stack size diagnostic. /// \p The computed stack size. - DiagnosticInfoStackSize(const Function &Fn, unsigned StackSize, - DiagnosticSeverity Severity = DS_Warning) - : DiagnosticInfo(DK_StackSize, Severity), Fn(Fn), StackSize(StackSize) {} + DiagnosticInfoResourceLimit(const Function &Fn, + const char *ResourceName, + uint64_t ResourceSize, + DiagnosticSeverity Severity = DS_Warning, + DiagnosticKind Kind = DK_ResourceLimit, + uint64_t ResourceLimit = 0) + : DiagnosticInfo(Kind, Severity), + Fn(Fn), + ResourceName(ResourceName), + ResourceSize(ResourceSize), + ResourceLimit(ResourceLimit) {} const Function &getFunction() const { return Fn; } - unsigned getStackSize() const { return StackSize; } + const char *getResourceName() const { return ResourceName; } + uint64_t getResourceSize() const { return ResourceSize; } + uint64_t getResourceLimit() const { return ResourceLimit; } /// \see DiagnosticInfo::print. void print(DiagnosticPrinter &DP) const override; + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_ResourceLimit || + DI->getKind() == DK_StackSize; + } +}; + +class DiagnosticInfoStackSize : public DiagnosticInfoResourceLimit { +public: + DiagnosticInfoStackSize(const Function &Fn, + uint64_t StackSize, + DiagnosticSeverity Severity = DS_Warning, + uint64_t StackLimit = 0) + : DiagnosticInfoResourceLimit(Fn, "stack size", StackSize, + Severity, DK_StackSize, StackLimit) {} + + uint64_t getStackSize() const { return getResourceSize(); } + uint64_t getStackLimit() const { return getResourceLimit(); } + static bool classof(const DiagnosticInfo *DI) { return DI->getKind() == DK_StackSize; } @@ -212,6 +249,29 @@ public: } }; +/// Diagnostic information for stripping invalid debug metadata. +class DiagnosticInfoIgnoringInvalidDebugMetadata : public DiagnosticInfo { +private: + /// The module that is concerned by this debug metadata version diagnostic. + const Module &M; + +public: + /// \p The module that is concerned by this debug metadata version diagnostic. + DiagnosticInfoIgnoringInvalidDebugMetadata( + const Module &M, DiagnosticSeverity Severity = DS_Warning) + : DiagnosticInfo(DK_DebugMetadataVersion, Severity), M(M) {} + + const Module &getModule() const { return M; } + + /// \see DiagnosticInfo::print. + void print(DiagnosticPrinter &DP) const override; + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_DebugMetadataInvalid; + } +}; + + /// Diagnostic information for the sample profiler. class DiagnosticInfoSampleProfile : public DiagnosticInfo { public: @@ -340,6 +400,11 @@ public: const char *getPassName() const { return PassName; } const Twine &getMsg() const { return Msg; } + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() >= DK_FirstRemark && + DI->getKind() <= DK_LastRemark; + } + private: /// Name of the pass that triggers this report. If this matches the /// regular expression given in -Rpass=regexp, then the remark will @@ -426,6 +491,10 @@ public: /// \see DiagnosticInfoOptimizationBase::isEnabled. bool isEnabled() const override; + static const char *AlwaysPrint; + + bool shouldAlwaysPrint() const { return getPassName() == AlwaysPrint; } + protected: DiagnosticInfoOptimizationRemarkAnalysis(enum DiagnosticKind Kind, const char *PassName, @@ -601,8 +670,9 @@ public: /// copy this message, so this reference must be valid for the whole life time /// of the diagnostic. DiagnosticInfoUnsupported(const Function &Fn, const Twine &Msg, - DebugLoc DLoc = DebugLoc()) - : DiagnosticInfoWithDebugLocBase(DK_Unsupported, DS_Error, Fn, DLoc), + DebugLoc DLoc = DebugLoc(), + DiagnosticSeverity Severity = DS_Error) + : DiagnosticInfoWithDebugLocBase(DK_Unsupported, Severity, Fn, DLoc), Msg(Msg) {} static bool classof(const DiagnosticInfo *DI) { @@ -611,7 +681,7 @@ public: const Twine &getMessage() const { return Msg; } - void print(DiagnosticPrinter &DP) const; + void print(DiagnosticPrinter &DP) const override; }; /// Emit a warning when loop vectorization is specified but fails. \p Fn is the @@ -626,6 +696,6 @@ void emitLoopVectorizeWarning(LLVMContext &Ctx, const Function &Fn, void emitLoopInterleaveWarning(LLVMContext &Ctx, const Function &Fn, const DebugLoc &DLoc, const Twine &Msg); -} // End namespace llvm +} // end namespace llvm -#endif +#endif // LLVM_IR_DIAGNOSTICINFO_H diff --git a/include/llvm/IR/Dominators.h b/include/llvm/IR/Dominators.h index f4990b0557e517a2537d708afffad21bb6ce03e6..f445a49b67b82f2e1eaffe027805bc7da701df84 100644 --- a/include/llvm/IR/Dominators.h +++ b/include/llvm/IR/Dominators.h @@ -15,23 +15,20 @@ #ifndef LLVM_IR_DOMINATORS_H #define LLVM_IR_DOMINATORS_H -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" -#include "llvm/IR/Function.h" #include "llvm/IR/PassManager.h" #include "llvm/Pass.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/GenericDomTree.h" -#include "llvm/Support/raw_ostream.h" -#include namespace llvm { +class Function; +class BasicBlock; +class raw_ostream; + extern template class DomTreeNodeBase; extern template class DominatorTreeBase; @@ -58,6 +55,26 @@ public: bool isSingleEdge() const; }; +template <> struct DenseMapInfo { + static unsigned getHashValue(const BasicBlockEdge *V); + typedef DenseMapInfo BBInfo; + static inline BasicBlockEdge getEmptyKey() { + return BasicBlockEdge(BBInfo::getEmptyKey(), BBInfo::getEmptyKey()); + } + static inline BasicBlockEdge getTombstoneKey() { + return BasicBlockEdge(BBInfo::getTombstoneKey(), BBInfo::getTombstoneKey()); + } + + static unsigned getHashValue(const BasicBlockEdge &Edge) { + return hash_combine(BBInfo::getHashValue(Edge.getStart()), + BBInfo::getHashValue(Edge.getEnd())); + } + static bool isEqual(const BasicBlockEdge &LHS, const BasicBlockEdge &RHS) { + return BBInfo::isEqual(LHS.getStart(), RHS.getStart()) && + BBInfo::isEqual(LHS.getEnd(), RHS.getEnd()); + } +}; + /// \brief Concrete subclass of DominatorTreeBase that is used to compute a /// normal dominator tree. /// @@ -191,7 +208,7 @@ public: typedef DominatorTree Result; /// \brief Run the analysis pass over a function and produce a dominator tree. - DominatorTree run(Function &F); + DominatorTree run(Function &F, AnalysisManager &); }; /// \brief Printer pass for the \c DominatorTree. diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index 70eb29f7a6a287bcb76e823e65e6eaa68ca56be2..d7d27e7585c1cc9935270c57201f39d7efdeda34 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -19,7 +19,6 @@ #define LLVM_IR_FUNCTION_H #include "llvm/ADT/iterator_range.h" -#include "llvm/ADT/Optional.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" @@ -30,6 +29,7 @@ namespace llvm { +template class Optional; class FunctionType; class LLVMContext; class DISubprogram; @@ -72,13 +72,8 @@ private: /// Bits from GlobalObject::GlobalObjectSubclassData. enum { /// Whether this function is materializable. - IsMaterializableBit = 1 << 0, - HasMetadataHashEntryBit = 1 << 1 + IsMaterializableBit = 0, }; - void setGlobalObjectBit(unsigned Mask, bool Value) { - setGlobalObjectSubClassData((~Mask & getGlobalObjectSubClassData()) | - (Value ? Mask : 0u)); - } friend class SymbolTableListTraits; @@ -88,9 +83,12 @@ private: /// built on demand, so that the list isn't allocated until the first client /// needs it. The hasLazyArguments predicate returns true if the arg list /// hasn't been set up yet. +public: bool hasLazyArguments() const { return getSubclassDataFromValue() & (1<<0); } + +private: void CheckLazyArguments() const { if (hasLazyArguments()) BuildLazyArguments(); @@ -165,7 +163,7 @@ public: AttributeSet getAttributes() const { return AttributeSets; } /// @brief Set the attribute list for this Function. - void setAttributes(AttributeSet attrs) { AttributeSets = attrs; } + void setAttributes(AttributeSet Attrs) { AttributeSets = Attrs; } /// @brief Add function attributes to this function. void addFnAttr(Attribute::AttrKind N) { @@ -174,9 +172,9 @@ public: } /// @brief Remove function attributes from this function. - void removeFnAttr(Attribute::AttrKind N) { + void removeFnAttr(Attribute::AttrKind Kind) { setAttributes(AttributeSets.removeAttribute( - getContext(), AttributeSet::FunctionIndex, N)); + getContext(), AttributeSet::FunctionIndex, Kind)); } /// @brief Add function attributes to this function. @@ -207,12 +205,10 @@ public: /// @brief Return the attribute for the given attribute kind. Attribute getFnAttribute(Attribute::AttrKind Kind) const { - if (!hasFnAttribute(Kind)) - return Attribute(); - return AttributeSets.getAttribute(AttributeSet::FunctionIndex, Kind); + return getAttribute(AttributeSet::FunctionIndex, Kind); } Attribute getFnAttribute(StringRef Kind) const { - return AttributeSets.getAttribute(AttributeSet::FunctionIndex, Kind); + return getAttribute(AttributeSet::FunctionIndex, Kind); } /// \brief Return the stack alignment for the function. @@ -228,24 +224,38 @@ public: return getSubclassDataFromValue() & (1<<14); } const std::string &getGC() const; - void setGC(const std::string Str); + void setGC(std::string Str); void clearGC(); /// @brief adds the attribute to the list of attributes. - void addAttribute(unsigned i, Attribute::AttrKind attr); + void addAttribute(unsigned i, Attribute::AttrKind Kind); + + /// @brief adds the attribute to the list of attributes. + void addAttribute(unsigned i, Attribute Attr); /// @brief adds the attributes to the list of attributes. - void addAttributes(unsigned i, AttributeSet attrs); + void addAttributes(unsigned i, AttributeSet Attrs); + + /// @brief removes the attribute from the list of attributes. + void removeAttribute(unsigned i, Attribute::AttrKind Kind); /// @brief removes the attribute from the list of attributes. - void removeAttribute(unsigned i, Attribute::AttrKind attr); + void removeAttribute(unsigned i, StringRef Kind); /// @brief removes the attributes from the list of attributes. - void removeAttributes(unsigned i, AttributeSet attr); + void removeAttributes(unsigned i, AttributeSet Attrs); /// @brief check if an attributes is in the list of attributes. - bool hasAttribute(unsigned i, Attribute::AttrKind attr) const { - return getAttributes().hasAttribute(i, attr); + bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const { + return getAttributes().hasAttribute(i, Kind); + } + + Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { + return AttributeSets.getAttribute(i, Kind); + } + + Attribute getAttribute(unsigned i, StringRef Kind) const { + return AttributeSets.getAttribute(i, Kind); } /// @brief adds the dereferenceable attribute to the list of attributes. @@ -288,6 +298,14 @@ public: addFnAttr(Attribute::ReadOnly); } + /// @brief Determine if the function does not access or only writes memory. + bool doesNotReadMemory() const { + return doesNotAccessMemory() || hasFnAttribute(Attribute::WriteOnly); + } + void setDoesNotReadMemory() { + addFnAttr(Attribute::WriteOnly); + } + /// @brief Determine if the call can access memmory only using pointers based /// on its arguments. bool onlyAccessesArgMemory() const { @@ -442,6 +460,12 @@ public: /// void eraseFromParent() override; + /// Steal arguments from another function. + /// + /// Drop this function's arguments and splice in the ones from \c Src. + /// Requires that this has no function body. + void stealArgumentListFrom(Function &Src); + /// Get the underlying elements of the Function... the basic block list is /// empty for external functions. /// @@ -605,35 +629,6 @@ public: /// setjmp or other function that gcc recognizes as "returning twice". bool callsFunctionThatReturnsTwice() const; - /// \brief Check if this has any metadata. - bool hasMetadata() const { return hasMetadataHashEntry(); } - - /// \brief Get the current metadata attachment, if any. - /// - /// Returns \c nullptr if such an attachment is missing. - /// @{ - MDNode *getMetadata(unsigned KindID) const; - MDNode *getMetadata(StringRef Kind) const; - /// @} - - /// \brief Set a particular kind of metadata attachment. - /// - /// Sets the given attachment to \c MD, erasing it if \c MD is \c nullptr or - /// replacing it if it already exists. - /// @{ - void setMetadata(unsigned KindID, MDNode *MD); - void setMetadata(StringRef Kind, MDNode *MD); - /// @} - - /// \brief Get all current metadata attachments. - void - getAllMetadata(SmallVectorImpl> &MDs) const; - - /// \brief Drop metadata not in the given list. - /// - /// Drop all metadata from \c this not included in \c KnownIDs. - void dropUnknownMetadata(ArrayRef KnownIDs); - /// \brief Set the attached subprogram. /// /// Calls \a setMetadata() with \a LLVMContext::MD_dbg. @@ -655,15 +650,6 @@ private: Value::setValueSubclassData(D); } void setValueSubclassDataBit(unsigned Bit, bool On); - - bool hasMetadataHashEntry() const { - return getGlobalObjectSubClassData() & HasMetadataHashEntryBit; - } - void setHasMetadataHashEntry(bool HasEntry) { - setGlobalObjectBit(HasMetadataHashEntryBit, HasEntry); - } - - void clearMetadata(); }; template <> diff --git a/include/llvm/IR/GVMaterializer.h b/include/llvm/IR/GVMaterializer.h index 6cb593c7a3dab790b28ee169e216ca523c4d855b..9e47722c892b5f4bdd28dba44170bd709d3f4d6d 100644 --- a/include/llvm/IR/GVMaterializer.h +++ b/include/llvm/IR/GVMaterializer.h @@ -18,14 +18,12 @@ #ifndef LLVM_IR_GVMATERIALIZER_H #define LLVM_IR_GVMATERIALIZER_H -#include "llvm/ADT/DenseMap.h" #include #include namespace llvm { class Function; class GlobalValue; -class Metadata; class Module; class StructType; @@ -47,14 +45,6 @@ public: virtual std::error_code materializeMetadata() = 0; virtual void setStripDebugInfo() = 0; - /// Client should define this interface if the mapping between metadata - /// values and value ids needs to be preserved, e.g. across materializer - /// instantiations. If OnlyTempMD is true, only those that have remained - /// temporary metadata are recorded in the map. - virtual void - saveMetadataList(DenseMap &MetadataToIDs, - bool OnlyTempMD) {} - virtual std::vector getIdentifiedStructTypes() const = 0; }; diff --git a/include/llvm/IR/GlobalAlias.h b/include/llvm/IR/GlobalAlias.h index b0772143309f6f70098bc1f9aff435d7affb36ba..3ae3e4a001e1f5f464416ef4e7a67feb1f94cdef 100644 --- a/include/llvm/IR/GlobalAlias.h +++ b/include/llvm/IR/GlobalAlias.h @@ -15,17 +15,17 @@ #ifndef LLVM_IR_GLOBALALIAS_H #define LLVM_IR_GLOBALALIAS_H -#include "llvm/ADT/Twine.h" #include "llvm/ADT/ilist_node.h" -#include "llvm/IR/GlobalValue.h" -#include "llvm/IR/OperandTraits.h" +#include "llvm/IR/GlobalIndirectSymbol.h" namespace llvm { +class Twine; class Module; template class SymbolTableListTraits; -class GlobalAlias : public GlobalValue, public ilist_node { +class GlobalAlias : public GlobalIndirectSymbol, + public ilist_node { friend class SymbolTableListTraits; void operator=(const GlobalAlias &) = delete; GlobalAlias(const GlobalAlias &) = delete; @@ -36,11 +36,6 @@ class GlobalAlias : public GlobalValue, public ilist_node { const Twine &Name, Constant *Aliasee, Module *Parent); public: - // allocate space for exactly one operand - void *operator new(size_t s) { - return User::operator new(s, 1); - } - /// If a parent module is specified, the alias is automatically inserted into /// the end of the specified module's alias list. static GlobalAlias *create(Type *Ty, unsigned AddressSpace, @@ -64,9 +59,6 @@ public: // Linkage, Type, Parent and AddressSpace taken from the Aliasee. static GlobalAlias *create(const Twine &Name, GlobalValue *Aliasee); - /// Provide fast operand accessors - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); - /// removeFromParent - This method unlinks 'this' from the containing module, /// but does not delete it. /// @@ -77,28 +69,13 @@ public: /// void eraseFromParent() override; - /// These methods retrive and set alias target. + /// These methods retrieve and set alias target. void setAliasee(Constant *Aliasee); const Constant *getAliasee() const { - return const_cast(this)->getAliasee(); + return getIndirectSymbol(); } Constant *getAliasee() { - return getOperand(0); - } - - const GlobalObject *getBaseObject() const { - return const_cast(this)->getBaseObject(); - } - GlobalObject *getBaseObject() { - return dyn_cast(getAliasee()->stripInBoundsOffsets()); - } - - const GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) const { - return const_cast(this)->getBaseObject(DL, Offset); - } - GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) { - return dyn_cast( - getAliasee()->stripAndAccumulateInBoundsConstantOffsets(DL, Offset)); + return getIndirectSymbol(); } static bool isValidLinkage(LinkageTypes L) { @@ -112,13 +89,6 @@ public: } }; -template <> -struct OperandTraits : - public FixedNumOperandTraits { -}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalAlias, Constant) - } // End llvm namespace #endif diff --git a/include/llvm/IR/GlobalIFunc.h b/include/llvm/IR/GlobalIFunc.h new file mode 100644 index 0000000000000000000000000000000000000000..0cbe882c58d8b697ac1918bcac3023de3d29d20c --- /dev/null +++ b/include/llvm/IR/GlobalIFunc.h @@ -0,0 +1,76 @@ +//===-------- llvm/GlobalIFunc.h - GlobalIFunc class ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \brief +/// This file contains the declaration of the GlobalIFunc class, which +/// represents a single indirect function in the IR. Indirect function uses +/// ELF symbol type extension to mark that the address of a declaration should +/// be resolved at runtime by calling a resolver function. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_GLOBALIFUNC_H +#define LLVM_IR_GLOBALIFUNC_H + +#include "llvm/ADT/ilist_node.h" +#include "llvm/IR/GlobalIndirectSymbol.h" + +namespace llvm { + +class Twine; +class Module; + +// Traits class for using GlobalIFunc in symbol table in Module. +template class SymbolTableListTraits; + +class GlobalIFunc final : public GlobalIndirectSymbol, + public ilist_node { + friend class SymbolTableListTraits; + void operator=(const GlobalIFunc &) = delete; + GlobalIFunc(const GlobalIFunc &) = delete; + + void setParent(Module *parent); + + GlobalIFunc(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, + const Twine &Name, Constant *Resolver, Module *Parent); + +public: + /// If a parent module is specified, the ifunc is automatically inserted into + /// the end of the specified module's ifunc list. + static GlobalIFunc *create(Type *Ty, unsigned AddressSpace, + LinkageTypes Linkage, const Twine &Name, + Constant *Resolver, Module *Parent); + + /// This method unlinks 'this' from the containing module, but does not + /// delete it. + void removeFromParent() final; + + /// This method unlinks 'this' from the containing module and deletes it. + void eraseFromParent() final; + + /// These methods retrieve and set ifunc resolver function. + void setResolver(Constant *Resolver) { + setIndirectSymbol(Resolver); + } + const Constant *getResolver() const { + return getIndirectSymbol(); + } + Constant *getResolver() { + return getIndirectSymbol(); + } + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const Value *V) { + return V->getValueID() == Value::GlobalIFuncVal; + } +}; + +} // End llvm namespace + +#endif diff --git a/include/llvm/IR/GlobalIndirectSymbol.h b/include/llvm/IR/GlobalIndirectSymbol.h new file mode 100644 index 0000000000000000000000000000000000000000..8edb3d1dbf4b31efb2f26016ed53d49be1483c4e --- /dev/null +++ b/include/llvm/IR/GlobalIndirectSymbol.h @@ -0,0 +1,84 @@ +//===- llvm/GlobalIndirectSymbol.h - GlobalIndirectSymbol class -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the GlobalIndirectSymbol class, which +// is a base class for GlobalAlias and GlobalIFunc. It contains all common code +// for aliases and ifuncs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_GLOBALINDIRECTSYMBOL_H +#define LLVM_IR_GLOBALINDIRECTSYMBOL_H + +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/OperandTraits.h" + +namespace llvm { + +class GlobalIndirectSymbol : public GlobalValue { + void operator=(const GlobalIndirectSymbol &) = delete; + GlobalIndirectSymbol(const GlobalIndirectSymbol &) = delete; + +protected: + GlobalIndirectSymbol(Type *Ty, ValueTy VTy, unsigned AddressSpace, + LinkageTypes Linkage, const Twine &Name, Constant *Symbol); + +public: + // allocate space for exactly one operand + void *operator new(size_t s) { + return User::operator new(s, 1); + } + + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + + /// These methods set and retrieve indirect symbol. + void setIndirectSymbol(Constant *Symbol) { + setOperand(0, Symbol); + } + const Constant *getIndirectSymbol() const { + return const_cast(this)->getIndirectSymbol(); + } + Constant *getIndirectSymbol() { + return getOperand(0); + } + + const GlobalObject *getBaseObject() const { + return const_cast(this)->getBaseObject(); + } + GlobalObject *getBaseObject() { + return dyn_cast(getIndirectSymbol()->stripInBoundsOffsets()); + } + + const GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) const { + return const_cast(this)->getBaseObject(DL, Offset); + } + GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) { + return dyn_cast( + getIndirectSymbol()->stripAndAccumulateInBoundsConstantOffsets(DL, + Offset)); + } + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const Value *V) { + return V->getValueID() == Value::GlobalAliasVal || + V->getValueID() == Value::GlobalIFuncVal; + } +}; + +template <> +struct OperandTraits : + public FixedNumOperandTraits { +}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalIndirectSymbol, Constant) + +} // End llvm namespace + +#endif diff --git a/include/llvm/IR/GlobalObject.h b/include/llvm/IR/GlobalObject.h index ee111a046d7373d847ecf7e7bef148ddee4d85ed..04737a045ae579e07109417f45fcb8af0bfdc051 100644 --- a/include/llvm/IR/GlobalObject.h +++ b/include/llvm/IR/GlobalObject.h @@ -15,12 +15,13 @@ #ifndef LLVM_IR_GLOBALOBJECT_H #define LLVM_IR_GLOBALOBJECT_H -#include "llvm/IR/Constant.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalValue.h" namespace llvm { class Comdat; +class MDNode; +class Metadata; class Module; class GlobalObject : public GlobalValue { @@ -37,12 +38,19 @@ protected: std::string Section; // Section to emit this into, empty means default Comdat *ObjComdat; - static const unsigned AlignmentBits = 5; + enum { + LastAlignmentBit = 4, + HasMetadataHashEntryBit, + + GlobalObjectBits, + }; static const unsigned GlobalObjectSubClassDataBits = - GlobalValueSubClassDataBits - AlignmentBits; + GlobalValueSubClassDataBits - GlobalObjectBits; private: + static const unsigned AlignmentBits = LastAlignmentBit + 1; static const unsigned AlignmentMask = (1 << AlignmentBits) - 1; + static const unsigned GlobalObjectMask = (1 << GlobalObjectBits) - 1; public: unsigned getAlignment() const { @@ -55,8 +63,8 @@ public: unsigned getGlobalObjectSubClassData() const; void setGlobalObjectSubClassData(unsigned Val); - bool hasSection() const { return !StringRef(getSection()).empty(); } - const char *getSection() const { return Section.c_str(); } + bool hasSection() const { return !getSection().empty(); } + StringRef getSection() const { return Section; } void setSection(StringRef S); bool hasComdat() const { return getComdat() != nullptr; } @@ -64,6 +72,54 @@ public: Comdat *getComdat() { return ObjComdat; } void setComdat(Comdat *C) { ObjComdat = C; } + /// Check if this has any metadata. + bool hasMetadata() const { return hasMetadataHashEntry(); } + + /// Get the current metadata attachments for the given kind, if any. + /// + /// These functions require that the function have at most a single attachment + /// of the given kind, and return \c nullptr if such an attachment is missing. + /// @{ + MDNode *getMetadata(unsigned KindID) const; + MDNode *getMetadata(StringRef Kind) const; + /// @} + + /// Appends all attachments with the given ID to \c MDs in insertion order. + /// If the global has no attachments with the given ID, or if ID is invalid, + /// leaves MDs unchanged. + /// @{ + void getMetadata(unsigned KindID, SmallVectorImpl &MDs) const; + void getMetadata(StringRef Kind, SmallVectorImpl &MDs) const; + /// @} + + /// Set a particular kind of metadata attachment. + /// + /// Sets the given attachment to \c MD, erasing it if \c MD is \c nullptr or + /// replacing it if it already exists. + /// @{ + void setMetadata(unsigned KindID, MDNode *MD); + void setMetadata(StringRef Kind, MDNode *MD); + /// @} + + /// Add a metadata attachment. + /// @{ + void addMetadata(unsigned KindID, MDNode &MD); + void addMetadata(StringRef Kind, MDNode &MD); + /// @} + + /// Appends all attachments for the global to \c MDs, sorting by attachment + /// ID. Attachments with the same ID appear in insertion order. + void + getAllMetadata(SmallVectorImpl> &MDs) const; + + /// Erase all metadata attachments with the given kind. + void eraseMetadata(unsigned KindID); + + /// Copy metadata from Src, adjusting offsets by Offset. + void copyMetadata(const GlobalObject *Src, unsigned Offset); + + void addTypeMetadata(unsigned Offset, Metadata *TypeID); + void copyAttributesFrom(const GlobalValue *Src) override; // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -71,6 +127,18 @@ public: return V->getValueID() == Value::FunctionVal || V->getValueID() == Value::GlobalVariableVal; } + + void clearMetadata(); + +private: + bool hasMetadataHashEntry() const { + return getGlobalValueSubClassData() & (1 << HasMetadataHashEntryBit); + } + void setHasMetadataHashEntry(bool HasEntry) { + unsigned Mask = 1 << HasMetadataHashEntryBit; + setGlobalValueSubClassData((~Mask & getGlobalValueSubClassData()) | + (HasEntry ? Mask : 0u)); + } }; } // End llvm namespace diff --git a/include/llvm/IR/GlobalValue.h b/include/llvm/IR/GlobalValue.h index c6a88e4d167deb78b1076009e00c0838cba09e8b..09682f7aa349abf2330235581d4eef4344b027d3 100644 --- a/include/llvm/IR/GlobalValue.h +++ b/include/llvm/IR/GlobalValue.h @@ -70,8 +70,9 @@ protected: LinkageTypes Linkage, const Twine &Name, unsigned AddressSpace) : Constant(PointerType::get(Ty, AddressSpace), VTy, Ops, NumOps), ValueType(Ty), Linkage(Linkage), Visibility(DefaultVisibility), - UnnamedAddr(0), DllStorageClass(DefaultStorageClass), - ThreadLocal(NotThreadLocal), IntID((Intrinsic::ID)0U), Parent(nullptr) { + UnnamedAddrVal(unsigned(UnnamedAddr::None)), + DllStorageClass(DefaultStorageClass), ThreadLocal(NotThreadLocal), + IntID((Intrinsic::ID)0U), Parent(nullptr) { setName(Name); } @@ -80,7 +81,7 @@ protected: // them. unsigned Linkage : 4; // The linkage of this global unsigned Visibility : 2; // The visibility style of this global - unsigned UnnamedAddr : 1; // This value's address is not significant + unsigned UnnamedAddrVal : 2; // This value's address is not significant unsigned DllStorageClass : 2; // DLL storage class unsigned ThreadLocal : 3; // Is this symbol "Thread Local", if so, what is @@ -89,13 +90,37 @@ protected: private: // Give subclasses access to what otherwise would be wasted padding. - // (19 + 3 + 2 + 1 + 2 + 5) == 32. + // (19 + 4 + 2 + 2 + 2 + 3) == 32. unsigned SubClassData : GlobalValueSubClassDataBits; friend class Constant; void destroyConstantImpl(); Value *handleOperandChangeImpl(Value *From, Value *To); + /// Returns true if the definition of this global may be replaced by a + /// differently optimized variant of the same source level function at link + /// time. + bool mayBeDerefined() const { + switch (getLinkage()) { + case WeakODRLinkage: + case LinkOnceODRLinkage: + case AvailableExternallyLinkage: + return true; + + case WeakAnyLinkage: + case LinkOnceAnyLinkage: + case CommonLinkage: + case ExternalWeakLinkage: + case ExternalLinkage: + case AppendingLinkage: + case InternalLinkage: + case PrivateLinkage: + return isInterposable(); + } + + llvm_unreachable("Fully covered switch above!"); + } + protected: /// \brief The intrinsic ID for this subclass (which must be a Function). /// @@ -129,8 +154,37 @@ public: unsigned getAlignment() const; - bool hasUnnamedAddr() const { return UnnamedAddr; } - void setUnnamedAddr(bool Val) { UnnamedAddr = Val; } + enum class UnnamedAddr { + None, + Local, + Global, + }; + + bool hasGlobalUnnamedAddr() const { + return getUnnamedAddr() == UnnamedAddr::Global; + } + + /// Returns true if this value's address is not significant in this module. + /// This attribute is intended to be used only by the code generator and LTO + /// to allow the linker to decide whether the global needs to be in the symbol + /// table. It should probably not be used in optimizations, as the value may + /// have uses outside the module; use hasGlobalUnnamedAddr() instead. + bool hasAtLeastLocalUnnamedAddr() const { + return getUnnamedAddr() != UnnamedAddr::None; + } + + UnnamedAddr getUnnamedAddr() const { + return UnnamedAddr(UnnamedAddrVal); + } + void setUnnamedAddr(UnnamedAddr Val) { UnnamedAddrVal = unsigned(Val); } + + static UnnamedAddr getMinUnnamedAddr(UnnamedAddr A, UnnamedAddr B) { + if (A == UnnamedAddr::None || B == UnnamedAddr::None) + return UnnamedAddr::None; + if (A == UnnamedAddr::Local || B == UnnamedAddr::Local) + return UnnamedAddr::Local; + return UnnamedAddr::Global; + } bool hasComdat() const { return getComdat() != nullptr; } Comdat *getComdat(); @@ -174,14 +228,8 @@ public: } void setDLLStorageClass(DLLStorageClassTypes C) { DllStorageClass = C; } - bool hasSection() const { return !StringRef(getSection()).empty(); } - // It is unfortunate that we have to use "char *" in here since this is - // always non NULL, but: - // * The C API expects a null terminated string, so we cannot use StringRef. - // * The C API expects us to own it, so we cannot use a std:string. - // * For GlobalAliases we can fail to find the section and we have to - // return "", so we cannot use a "const std::string &". - const char *getSection() const; + bool hasSection() const { return !getSection().empty(); } + StringRef getSection() const; /// Global values are always pointers. PointerType *getType() const { return cast(User::getType()); } @@ -234,6 +282,34 @@ public: static bool isCommonLinkage(LinkageTypes Linkage) { return Linkage == CommonLinkage; } + static bool isValidDeclarationLinkage(LinkageTypes Linkage) { + return isExternalWeakLinkage(Linkage) || isExternalLinkage(Linkage); + } + + /// Whether the definition of this global may be replaced by something + /// non-equivalent at link time. For example, if a function has weak linkage + /// then the code defining it may be replaced by different code. + static bool isInterposableLinkage(LinkageTypes Linkage) { + switch (Linkage) { + case WeakAnyLinkage: + case LinkOnceAnyLinkage: + case CommonLinkage: + case ExternalWeakLinkage: + return true; + + case AvailableExternallyLinkage: + case LinkOnceODRLinkage: + case WeakODRLinkage: + // The above three cannot be overridden but can be de-refined. + + case ExternalLinkage: + case AppendingLinkage: + case InternalLinkage: + case PrivateLinkage: + return false; + } + llvm_unreachable("Fully covered switch above!"); + } /// Whether the definition of this global may be discarded if it is not used /// in its compilation unit. @@ -242,17 +318,9 @@ public: isAvailableExternallyLinkage(Linkage); } - /// Whether the definition of this global may be replaced by something - /// non-equivalent at link time. For example, if a function has weak linkage - /// then the code defining it may be replaced by different code. - static bool mayBeOverridden(LinkageTypes Linkage) { - return Linkage == WeakAnyLinkage || Linkage == LinkOnceAnyLinkage || - Linkage == CommonLinkage || Linkage == ExternalWeakLinkage; - } - /// Whether the definition of this global may be replaced at link time. NB: /// Using this method outside of the code generators is almost always a - /// mistake: when working at the IR level use mayBeOverridden instead as it + /// mistake: when working at the IR level use isInterposable instead as it /// knows about ODR semantics. static bool isWeakForLinker(LinkageTypes Linkage) { return Linkage == WeakAnyLinkage || Linkage == WeakODRLinkage || @@ -260,6 +328,52 @@ public: Linkage == CommonLinkage || Linkage == ExternalWeakLinkage; } + /// Return true if the currently visible definition of this global (if any) is + /// exactly the definition we will see at runtime. + /// + /// Non-exact linkage types inhibits most non-inlining IPO, since a + /// differently optimized variant of the same function can have different + /// observable or undefined behavior than in the variant currently visible. + /// For instance, we could have started with + /// + /// void foo(int *v) { + /// int t = 5 / v[0]; + /// (void) t; + /// } + /// + /// and "refined" it to + /// + /// void foo(int *v) { } + /// + /// However, we cannot infer readnone for `foo`, since that would justify + /// DSE'ing a store to `v[0]` across a call to `foo`, which can cause + /// undefined behavior if the linker replaces the actual call destination with + /// the unoptimized `foo`. + /// + /// Inlining is okay across non-exact linkage types as long as they're not + /// interposable (see \c isInterposable), since in such cases the currently + /// visible variant is *a* correct implementation of the original source + /// function; it just isn't the *only* correct implementation. + bool isDefinitionExact() const { + return !mayBeDerefined(); + } + + /// Return true if this global has an exact defintion. + bool hasExactDefinition() const { + // While this computes exactly the same thing as + // isStrongDefinitionForLinker, the intended uses are different. This + // function is intended to help decide if specific inter-procedural + // transforms are correct, while isStrongDefinitionForLinker's intended use + // is in low level code generation. + return !isDeclaration() && isDefinitionExact(); + } + + /// Return true if this global's definition can be substituted with an + /// *arbitrary* definition at link time. We cannot do any IPO or inlinining + /// across interposable call edges, since the callee can be replaced with + /// something arbitrary at link time. + bool isInterposable() const { return isInterposableLinkage(getLinkage()); } + bool hasExternalLinkage() const { return isExternalLinkage(getLinkage()); } bool hasAvailableExternallyLinkage() const { return isAvailableExternallyLinkage(getLinkage()); @@ -279,6 +393,9 @@ public: return isExternalWeakLinkage(getLinkage()); } bool hasCommonLinkage() const { return isCommonLinkage(getLinkage()); } + bool hasValidDeclarationLinkage() const { + return isValidDeclarationLinkage(getLinkage()); + } void setLinkage(LinkageTypes LT) { if (isLocalLinkage(LT)) @@ -291,8 +408,6 @@ public: return isDiscardableIfUnused(getLinkage()); } - bool mayBeOverridden() const { return mayBeOverridden(getLinkage()); } - bool isWeakForLinker() const { return isWeakForLinker(getLinkage()); } /// Copy all additional attributes (those not needed to create a GlobalValue) @@ -318,15 +433,20 @@ public: /// Return the modified name for this global value suitable to be /// used as the key for a global lookup (e.g. profile or ThinLTO). - std::string getGlobalIdentifier(); + std::string getGlobalIdentifier() const; + + /// Declare a type to represent a global unique identifier for a global value. + /// This is a 64 bits hash that is used by PGO and ThinLTO to have a compact + /// unique way to identify a symbol. + using GUID = uint64_t; /// Return a 64-bit global unique ID constructed from global value name /// (i.e. returned by getGlobalIdentifier()). - static uint64_t getGUID(StringRef GlobalName) { return MD5Hash(GlobalName); } + static GUID getGUID(StringRef GlobalName) { return MD5Hash(GlobalName); } /// Return a 64-bit global unique ID constructed from global value name /// (i.e. returned by getGlobalIdentifier()). - uint64_t getGUID() { return getGUID(getGlobalIdentifier()); } + GUID getGUID() const { return getGUID(getGlobalIdentifier()); } /// @name Materialization /// Materialization is used to construct functions only as they're needed. @@ -360,6 +480,10 @@ public: /// Returns true if this global's definition will be the one chosen by the /// linker. + /// + /// NB! Ideally this should not be used at the IR level at all. If you're + /// interested in optimization constraints implied by the linker's ability to + /// choose an implementation, prefer using \c hasExactDefinition. bool isStrongDefinitionForLinker() const { return !(isDeclarationForLinker() || isWeakForLinker()); } @@ -383,7 +507,8 @@ public: static bool classof(const Value *V) { return V->getValueID() == Value::FunctionVal || V->getValueID() == Value::GlobalVariableVal || - V->getValueID() == Value::GlobalAliasVal; + V->getValueID() == Value::GlobalAliasVal || + V->getValueID() == Value::GlobalIFuncVal; } }; diff --git a/include/llvm/IR/GlobalVariable.h b/include/llvm/IR/GlobalVariable.h index 342bdc01bfbdca7f46edec7851abd855ae071941..ebeb635468d06cf69327a34b41c6d6f41759553e 100644 --- a/include/llvm/IR/GlobalVariable.h +++ b/include/llvm/IR/GlobalVariable.h @@ -65,6 +65,8 @@ public: bool isExternallyInitialized = false); ~GlobalVariable() override { + dropAllReferences(); + // FIXME: needed by operator delete setGlobalVariableNumOperands(1); } @@ -94,9 +96,9 @@ public: /// unique. inline bool hasDefinitiveInitializer() const { return hasInitializer() && - // The initializer of a global variable with weak linkage may change at - // link time. - !mayBeOverridden() && + // The initializer of a global variable may change to something arbitrary + // at link time. + !isInterposable() && // The initializer of a global variable with the externally_initialized // marker may change at runtime before C++ initializers are evaluated. !isExternallyInitialized(); @@ -159,6 +161,10 @@ public: /// void eraseFromParent() override; + /// Drop all references in preparation to destroy the GlobalVariable. This + /// drops not only the reference to the initializer but also to any metadata. + void dropAllReferences(); + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Value *V) { return V->getValueID() == Value::GlobalVariableVal; diff --git a/include/llvm/IR/IRBuilder.h b/include/llvm/IR/IRBuilder.h index 3049259b31a4b6371be600d61f797840c42ef68f..016e9e1d2c50f2519d942dc3cc6e1acfeabfe462 100644 --- a/include/llvm/IR/IRBuilder.h +++ b/include/llvm/IR/IRBuilder.h @@ -16,22 +16,42 @@ #define LLVM_IR_IRBUILDER_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constant.h" #include "llvm/IR/ConstantFolder.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" #include "llvm/IR/ValueHandle.h" +#include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/CBindingWrapping.h" +#include "llvm/Support/Casting.h" +#include "llvm-c/Types.h" +#include +#include +#include namespace llvm { + +class APInt; class MDNode; +class Module; +class Use; /// \brief This provides the default implementation of the IRBuilder /// 'InsertHelper' method that is called whenever an instruction is created by @@ -435,12 +455,14 @@ public: Value *Mask); /// \brief Create a call to Masked Gather intrinsic - CallInst *CreateMaskedGather(Value *Ptrs, unsigned Align, Value *Mask = 0, - Value *PassThru = 0, const Twine& Name = ""); + CallInst *CreateMaskedGather(Value *Ptrs, unsigned Align, + Value *Mask = nullptr, + Value *PassThru = nullptr, + const Twine& Name = ""); /// \brief Create a call to Masked Scatter intrinsic CallInst *CreateMaskedScatter(Value *Val, Value *Ptrs, unsigned Align, - Value *Mask = 0); + Value *Mask = nullptr); /// \brief Create an assume intrinsic call that allows the optimizer to /// assume that the provided condition will be true. @@ -518,9 +540,9 @@ public: private: /// \brief Create a call to a masked intrinsic with given Id. - /// Masked intrinsic has only one overloaded type - data type. CallInst *CreateMaskedIntrinsic(Intrinsic::ID Id, ArrayRef Ops, - Type *DataTy, const Twine &Name = ""); + ArrayRef OverloadedTypes, + const Twine &Name = ""); Value *getCastedInt8PtrValue(Value *Ptr); }; @@ -676,28 +698,10 @@ public: return Insert(IndirectBrInst::Create(Addr, NumDests)); } - InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, - BasicBlock *UnwindDest, const Twine &Name = "") { - return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, None), - Name); - } - InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, - BasicBlock *UnwindDest, Value *Arg1, - const Twine &Name = "") { - return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, Arg1), - Name); - } - InvokeInst *CreateInvoke3(Value *Callee, BasicBlock *NormalDest, - BasicBlock *UnwindDest, Value *Arg1, - Value *Arg2, Value *Arg3, - const Twine &Name = "") { - Value *Args[] = { Arg1, Arg2, Arg3 }; - return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, Args), - Name); - } /// \brief Create an invoke instruction. InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, - BasicBlock *UnwindDest, ArrayRef Args, + BasicBlock *UnwindDest, + ArrayRef Args = None, const Twine &Name = "") { return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, Args), Name); @@ -1624,13 +1628,9 @@ public: return Insert(new ShuffleVectorInst(V1, V2, Mask), Name); } - Value *CreateShuffleVector(Value *V1, Value *V2, ArrayRef IntMask, + Value *CreateShuffleVector(Value *V1, Value *V2, ArrayRef IntMask, const Twine &Name = "") { - size_t MaskSize = IntMask.size(); - SmallVector MaskVec(MaskSize); - for (size_t i = 0; i != MaskSize; ++i) - MaskVec[i] = getInt32(IntMask[i]); - Value *Mask = ConstantVector::get(MaskVec); + Value *Mask = ConstantDataVector::get(Context, IntMask); return CreateShuffleVector(V1, V2, Mask, Name); } diff --git a/include/llvm/IR/IRPrintingPasses.h b/include/llvm/IR/IRPrintingPasses.h index 88b18e826dafa6fb0164b869b3ac44b3a3b0aa0c..bc6de19a6c3a49a2a64a25fb86b30f5afd7b9521 100644 --- a/include/llvm/IR/IRPrintingPasses.h +++ b/include/llvm/IR/IRPrintingPasses.h @@ -30,6 +30,7 @@ class Module; class ModulePass; class PreservedAnalyses; class raw_ostream; +template class AnalysisManager; /// \brief Create and return a pass that writes the module to the specified /// \c raw_ostream. @@ -67,7 +68,7 @@ public: PrintModulePass(raw_ostream &OS, const std::string &Banner = "", bool ShouldPreserveUseListOrder = false); - PreservedAnalyses run(Module &M); + PreservedAnalyses run(Module &M, AnalysisManager &); static StringRef name() { return "PrintModulePass"; } }; @@ -84,7 +85,7 @@ public: PrintFunctionPass(); PrintFunctionPass(raw_ostream &OS, const std::string &Banner = ""); - PreservedAnalyses run(Function &F); + PreservedAnalyses run(Function &F, AnalysisManager &); static StringRef name() { return "PrintFunctionPass"; } }; diff --git a/include/llvm/IR/InlineAsm.h b/include/llvm/IR/InlineAsm.h index d2e9e48539ceb430d393fb50946299f4ef994f06..d8f515e570adec2c052d8e1440ebd2f349ca05a0 100644 --- a/include/llvm/IR/InlineAsm.h +++ b/include/llvm/IR/InlineAsm.h @@ -223,6 +223,7 @@ public: Extra_AsmDialect = 4, Extra_MayLoad = 8, Extra_MayStore = 16, + Extra_IsConvergent = 32, // Inline asm operands map to multiple SDNode / MachineInstr operands. // The first operand is an immediate describing the asm operand, the low diff --git a/include/llvm/IR/InstrTypes.h b/include/llvm/IR/InstrTypes.h index e52fa5b7738648464b55c35689147e223a8d90d8..39514c5675a7a5bfd789c8d2180e50ef9dee4672 100644 --- a/include/llvm/IR/InstrTypes.h +++ b/include/llvm/IR/InstrTypes.h @@ -535,35 +535,6 @@ public: /// bool swapOperands(); - /// Set or clear the nsw flag on this instruction, which must be an operator - /// which supports this flag. See LangRef.html for the meaning of this flag. - void setHasNoUnsignedWrap(bool b = true); - - /// Set or clear the nsw flag on this instruction, which must be an operator - /// which supports this flag. See LangRef.html for the meaning of this flag. - void setHasNoSignedWrap(bool b = true); - - /// Set or clear the exact flag on this instruction, which must be an operator - /// which supports this flag. See LangRef.html for the meaning of this flag. - void setIsExact(bool b = true); - - /// Determine whether the no unsigned wrap flag is set. - bool hasNoUnsignedWrap() const; - - /// Determine whether the no signed wrap flag is set. - bool hasNoSignedWrap() const; - - /// Determine whether the exact flag is set. - bool isExact() const; - - /// Convenience method to copy supported wrapping, exact, and fast-math flags - /// from V to this instruction. - void copyIRFlags(const Value *V); - - /// Logical 'and' of any supported wrapping, exact, and fast-math flags of - /// V and this instruction. - void andIRFlags(const Value *V); - // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->isBinaryOp(); @@ -888,6 +859,10 @@ public: /// Values in the range 0-31 are reserved for FCmpInst, while values in the /// range 32-64 are reserved for ICmpInst. This is necessary to ensure the /// predicate values are not overlapping between the classes. + /// + /// Some passes (e.g. InstCombine) depend on the bit-wise characteristics of + /// FCMP_* values. Changing the bit patterns requires a potential change to + /// those passes. enum Predicate { // Opcode U L G E Intuitive operation FCMP_FALSE = 0, ///< 0 0 0 0 Always false (always folded) @@ -1067,6 +1042,18 @@ public: return isFalseWhenEqual(getPredicate()); } + /// @brief Determine if Pred1 implies Pred2 is true when two compares have + /// matching operands. + bool isImpliedTrueByMatchingCmp(Predicate Pred2) { + return isImpliedTrueByMatchingCmp(getPredicate(), Pred2); + } + + /// @brief Determine if Pred1 implies Pred2 is false when two compares have + /// matching operands. + bool isImpliedFalseByMatchingCmp(Predicate Pred2) { + return isImpliedFalseByMatchingCmp(getPredicate(), Pred2); + } + /// @returns true if the predicate is unsigned, false otherwise. /// @brief Determine if the predicate is an unsigned operation. static bool isUnsigned(Predicate predicate); @@ -1087,6 +1074,14 @@ public: /// Determine if the predicate is false when comparing a value with itself. static bool isFalseWhenEqual(Predicate predicate); + /// Determine if Pred1 implies Pred2 is true when two compares have matching + /// operands. + static bool isImpliedTrueByMatchingCmp(Predicate Pred1, Predicate Pred2); + + /// Determine if Pred1 implies Pred2 is false when two compares have matching + /// operands. + static bool isImpliedFalseByMatchingCmp(Predicate Pred1, Predicate Pred2); + /// @brief Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::ICmp || diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h index 12cbcce4c09cb4fa3d736495378ca2a3740ace4b..748bb946775d7ee1d8b1c1780de693c9031d72f7 100644 --- a/include/llvm/IR/Instruction.h +++ b/include/llvm/IR/Instruction.h @@ -217,12 +217,43 @@ public: /// Sets the metadata on this instruction from the AAMDNodes structure. void setAAMetadata(const AAMDNodes &N); + /// Retrieve the raw weight values of a conditional branch or select. + /// Returns true on success with profile weights filled in. + /// Returns false if no metadata or invalid metadata was found. + bool extractProfMetadata(uint64_t &TrueVal, uint64_t &FalseVal); + + /// Retrieve total raw weight values of a branch. + /// Returns true on success with profile total weights filled in. + /// Returns false if no metadata was found. + bool extractProfTotalWeight(uint64_t &TotalVal); + /// Set the debug location information for this instruction. void setDebugLoc(DebugLoc Loc) { DbgLoc = std::move(Loc); } /// Return the debug location for this node as a DebugLoc. const DebugLoc &getDebugLoc() const { return DbgLoc; } + /// Set or clear the nsw flag on this instruction, which must be an operator + /// which supports this flag. See LangRef.html for the meaning of this flag. + void setHasNoUnsignedWrap(bool b = true); + + /// Set or clear the nsw flag on this instruction, which must be an operator + /// which supports this flag. See LangRef.html for the meaning of this flag. + void setHasNoSignedWrap(bool b = true); + + /// Set or clear the exact flag on this instruction, which must be an operator + /// which supports this flag. See LangRef.html for the meaning of this flag. + void setIsExact(bool b = true); + + /// Determine whether the no unsigned wrap flag is set. + bool hasNoUnsignedWrap() const; + + /// Determine whether the no signed wrap flag is set. + bool hasNoSignedWrap() const; + + /// Determine whether the exact flag is set. + bool isExact() const; + /// Set or clear the unsafe-algebra flag on this instruction, which must be an /// operator which supports this flag. See LangRef.html for the meaning of /// this flag. @@ -281,6 +312,14 @@ public: /// Copy I's fast-math flags void copyFastMathFlags(const Instruction *I); + /// Convenience method to copy supported wrapping, exact, and fast-math flags + /// from V to this instruction. + void copyIRFlags(const Value *V); + + /// Logical 'and' of any supported wrapping, exact, and fast-math flags of + /// V and this instruction. + void andIRFlags(const Value *V); + private: /// Return true if we have an entry in the on-the-side metadata hash. bool hasMetadataHashEntry() const { @@ -360,21 +399,13 @@ public: /// Return true if this instruction may throw an exception. bool mayThrow() const; - /// Return true if this is a function that may return. - /// This is true for all normal instructions. The only exception - /// is functions that are marked with the 'noreturn' attribute. - /// - bool mayReturn() const; - /// Return true if the instruction may have side effects. /// /// Note that this does not consider malloc and alloca to have side /// effects because the newly allocated memory is completely invisible to /// instructions which don't use the returned value. For cases where this /// matters, isSafeToSpeculativelyExecute may be more appropriate. - bool mayHaveSideEffects() const { - return mayWriteToMemory() || mayThrow() || !mayReturn(); - } + bool mayHaveSideEffects() const { return mayWriteToMemory() || mayThrow(); } /// Return true if the instruction is a variety of EH-block. bool isEHPad() const { diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index 5a32b7bdec544b67a82a3f8b71c455e7de2d82c8..be077725f7bc30ca53b653d21d1c1f642a52af51 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -25,6 +25,7 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstrTypes.h" +#include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/ErrorHandling.h" #include @@ -36,38 +37,11 @@ class ConstantRange; class DataLayout; class LLVMContext; -enum AtomicOrdering { - NotAtomic = 0, - Unordered = 1, - Monotonic = 2, - // Consume = 3, // Not specified yet. - Acquire = 4, - Release = 5, - AcquireRelease = 6, - SequentiallyConsistent = 7 -}; - enum SynchronizationScope { SingleThread = 0, CrossThread = 1 }; -/// Returns true if the ordering is at least as strong as acquire -/// (i.e. acquire, acq_rel or seq_cst) -inline bool isAtLeastAcquire(AtomicOrdering Ord) { - return (Ord == Acquire || - Ord == AcquireRelease || - Ord == SequentiallyConsistent); -} - -/// Returns true if the ordering is at least as strong as release -/// (i.e. release, acq_rel or seq_cst) -inline bool isAtLeastRelease(AtomicOrdering Ord) { -return (Ord == Release || - Ord == AcquireRelease || - Ord == SequentiallyConsistent); -} - //===----------------------------------------------------------------------===// // AllocaInst Class //===----------------------------------------------------------------------===// @@ -152,6 +126,18 @@ public: (V ? 32 : 0)); } + /// \brief Return true if this alloca is used as a swifterror argument to a + /// call. + bool isSwiftError() const { + return getSubclassDataFromInstruction() & 64; + } + + /// \brief Specify whether this alloca is used to represent a swifterror. + void setSwiftError(bool V) { + setInstructionSubclassData((getSubclassDataFromInstruction() & ~64) | + (V ? 64 : 0)); + } + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return (I->getOpcode() == Instruction::Alloca); @@ -257,7 +243,7 @@ public: /// AcquireRelease. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) | - (Ordering << 7)); + ((unsigned)Ordering << 7)); } SynchronizationScope getSynchScope() const { @@ -280,7 +266,9 @@ public: bool isSimple() const { return !isAtomic() && !isVolatile(); } bool isUnordered() const { - return getOrdering() <= Unordered && !isVolatile(); + return (getOrdering() == AtomicOrdering::NotAtomic || + getOrdering() == AtomicOrdering::Unordered) && + !isVolatile(); } Value *getPointerOperand() { return getOperand(0); } @@ -378,7 +366,7 @@ public: /// AcquireRelease. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) | - (Ordering << 7)); + ((unsigned)Ordering << 7)); } SynchronizationScope getSynchScope() const { @@ -401,7 +389,9 @@ public: bool isSimple() const { return !isAtomic() && !isVolatile(); } bool isUnordered() const { - return getOrdering() <= Unordered && !isVolatile(); + return (getOrdering() == AtomicOrdering::NotAtomic || + getOrdering() == AtomicOrdering::Unordered) && + !isVolatile(); } Value *getValueOperand() { return getOperand(0); } @@ -477,7 +467,7 @@ public: /// AcquireRelease, or SequentiallyConsistent. void setOrdering(AtomicOrdering Ordering) { setInstructionSubclassData((getSubclassDataFromInstruction() & 1) | - (Ordering << 1)); + ((unsigned)Ordering << 1)); } SynchronizationScope getSynchScope() const { @@ -572,17 +562,17 @@ public: /// Set the ordering constraint on this cmpxchg. void setSuccessOrdering(AtomicOrdering Ordering) { - assert(Ordering != NotAtomic && + assert(Ordering != AtomicOrdering::NotAtomic && "CmpXchg instructions can only be atomic."); setInstructionSubclassData((getSubclassDataFromInstruction() & ~0x1c) | - (Ordering << 2)); + ((unsigned)Ordering << 2)); } void setFailureOrdering(AtomicOrdering Ordering) { - assert(Ordering != NotAtomic && + assert(Ordering != AtomicOrdering::NotAtomic && "CmpXchg instructions can only be atomic."); setInstructionSubclassData((getSubclassDataFromInstruction() & ~0xe0) | - (Ordering << 5)); + ((unsigned)Ordering << 5)); } /// Specify whether this cmpxchg is atomic and orders other operations with @@ -634,15 +624,16 @@ public: static AtomicOrdering getStrongestFailureOrdering(AtomicOrdering SuccessOrdering) { switch (SuccessOrdering) { - default: llvm_unreachable("invalid cmpxchg success ordering"); - case Release: - case Monotonic: - return Monotonic; - case AcquireRelease: - case Acquire: - return Acquire; - case SequentiallyConsistent: - return SequentiallyConsistent; + default: + llvm_unreachable("invalid cmpxchg success ordering"); + case AtomicOrdering::Release: + case AtomicOrdering::Monotonic: + return AtomicOrdering::Monotonic; + case AtomicOrdering::AcquireRelease: + case AtomicOrdering::Acquire: + return AtomicOrdering::Acquire; + case AtomicOrdering::SequentiallyConsistent: + return AtomicOrdering::SequentiallyConsistent; } } @@ -758,10 +749,10 @@ public: /// Set the ordering constraint on this RMW. void setOrdering(AtomicOrdering Ordering) { - assert(Ordering != NotAtomic && + assert(Ordering != AtomicOrdering::NotAtomic && "atomicrmw instructions can only be atomic."); setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 2)) | - (Ordering << 2)); + ((unsigned)Ordering << 2)); } /// Specify whether this RMW orders other operations with respect to all @@ -1490,9 +1481,29 @@ public: Value *AllocSize, Value *ArraySize = nullptr, Function* MallocF = nullptr, const Twine &Name = ""); + static Instruction *CreateMalloc(Instruction *InsertBefore, + Type *IntPtrTy, Type *AllocTy, + Value *AllocSize, Value *ArraySize = nullptr, + ArrayRef Bundles = None, + Function* MallocF = nullptr, + const Twine &Name = ""); + static Instruction *CreateMalloc(BasicBlock *InsertAtEnd, + Type *IntPtrTy, Type *AllocTy, + Value *AllocSize, Value *ArraySize = nullptr, + ArrayRef Bundles = None, + Function* MallocF = nullptr, + const Twine &Name = ""); /// CreateFree - Generate the IR for a call to the builtin free function. - static Instruction* CreateFree(Value* Source, Instruction *InsertBefore); - static Instruction* CreateFree(Value* Source, BasicBlock *InsertAtEnd); + static Instruction *CreateFree(Value *Source, + Instruction *InsertBefore); + static Instruction *CreateFree(Value *Source, + BasicBlock *InsertAtEnd); + static Instruction *CreateFree(Value *Source, + ArrayRef Bundles, + Instruction *InsertBefore); + static Instruction *CreateFree(Value *Source, + ArrayRef Bundles, + BasicBlock *InsertAtEnd); ~CallInst() override; @@ -1586,6 +1597,10 @@ public: return getOperandUse(i); } + /// If one of the arguments has the 'returned' attribute, return its + /// operand value. Otherwise, return nullptr. + Value *getReturnedArgOperand() const; + /// getCallingConv/setCallingConv - Get or set the calling convention of this /// function call. CallingConv::ID getCallingConv() const { @@ -1607,13 +1622,22 @@ public: void setAttributes(const AttributeSet &Attrs) { AttributeList = Attrs; } /// addAttribute - adds the attribute to the list of attributes. - void addAttribute(unsigned i, Attribute::AttrKind attr); + void addAttribute(unsigned i, Attribute::AttrKind Kind); /// addAttribute - adds the attribute to the list of attributes. void addAttribute(unsigned i, StringRef Kind, StringRef Value); + /// addAttribute - adds the attribute to the list of attributes. + void addAttribute(unsigned i, Attribute Attr); + + /// removeAttribute - removes the attribute from the list of attributes. + void removeAttribute(unsigned i, Attribute::AttrKind Kind); + /// removeAttribute - removes the attribute from the list of attributes. - void removeAttribute(unsigned i, Attribute attr); + void removeAttribute(unsigned i, StringRef Kind); + + /// removeAttribute - removes the attribute from the list of attributes. + void removeAttribute(unsigned i, Attribute Attr); /// \brief adds the dereferenceable attribute to the list of attributes. void addDereferenceableAttr(unsigned i, uint64_t Bytes); @@ -1623,19 +1647,25 @@ public: void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes); /// \brief Determine whether this call has the given attribute. - bool hasFnAttr(Attribute::AttrKind A) const { - assert(A != Attribute::NoBuiltin && + bool hasFnAttr(Attribute::AttrKind Kind) const { + assert(Kind != Attribute::NoBuiltin && "Use CallInst::isNoBuiltin() to check for Attribute::NoBuiltin"); - return hasFnAttrImpl(A); + return hasFnAttrImpl(Kind); } /// \brief Determine whether this call has the given attribute. - bool hasFnAttr(StringRef A) const { - return hasFnAttrImpl(A); + bool hasFnAttr(StringRef Kind) const { + return hasFnAttrImpl(Kind); } /// \brief Determine whether the call or the callee has the given attributes. - bool paramHasAttr(unsigned i, Attribute::AttrKind A) const; + bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const; + + /// \brief Get the attribute of a given kind at a position. + Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const; + + /// \brief Get the attribute of a given kind at a position. + Attribute getAttribute(unsigned i, StringRef Kind) const; /// \brief Return true if the data operand at index \p i has the attribute \p /// A. @@ -1650,7 +1680,7 @@ public: /// \p i in [1, arg_size + 1) -> argument number (\p i - 1) /// \p i in [arg_size + 1, data_operand_size + 1) -> bundle operand at index /// (\p i - 1) in the operand list. - bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const; + bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind Kind) const; /// \brief Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { @@ -1713,6 +1743,14 @@ public: addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly); } + /// \brief Determine if the call does not access or only writes memory. + bool doesNotReadMemory() const { + return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly); + } + void setDoesNotReadMemory() { + addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly); + } + /// @brief Determine if the call can access memmory only using pointers based /// on its arguments. bool onlyAccessesArgMemory() const { @@ -1910,6 +1948,10 @@ public: Value *getTrueValue() { return Op<1>(); } Value *getFalseValue() { return Op<2>(); } + void setCondition(Value *V) { Op<0>() = V; } + void setTrueValue(Value *V) { Op<1>() = V; } + void setFalseValue(Value *V) { Op<2>() = V; } + /// areInvalidOperands - Return a string if the specified operands are invalid /// for a select operation, otherwise return null. static const char *areInvalidOperands(Value *Cond, Value *True, Value *False); @@ -2623,6 +2665,11 @@ public: /// same value, return the value, otherwise return null. Value *hasConstantValue() const; + /// hasConstantOrUndefValue - Whether the specified PHI node always merges + /// together the same value, assuming undefs are equal to a unique + /// non-undef value. + bool hasConstantOrUndefValue() const; + /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::PHI; @@ -2932,7 +2979,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BranchInst, Value) //===----------------------------------------------------------------------===// //===--------------------------------------------------------------------------- -/// SwitchInst - Multiway switch +/// Multiway switch /// class SwitchInst : public TerminatorInst { void *operator new(size_t, unsigned) = delete; @@ -2948,17 +2995,17 @@ class SwitchInst : public TerminatorInst { void *operator new(size_t s) { return User::operator new(s); } - /// SwitchInst ctor - Create a new switch instruction, specifying a value to - /// switch on and a default destination. The number of additional cases can - /// be specified here to make memory allocation more efficient. This - /// constructor can also autoinsert before another instruction. + /// Create a new switch instruction, specifying a value to switch on and a + /// default destination. The number of additional cases can be specified here + /// to make memory allocation more efficient. This constructor can also + /// auto-insert before another instruction. SwitchInst(Value *Value, BasicBlock *Default, unsigned NumCases, Instruction *InsertBefore); - /// SwitchInst ctor - Create a new switch instruction, specifying a value to - /// switch on and a default destination. The number of additional cases can - /// be specified here to make memory allocation more efficient. This - /// constructor also autoinserts at the end of the specified BasicBlock. + /// Create a new switch instruction, specifying a value to switch on and a + /// default destination. The number of additional cases can be specified here + /// to make memory allocation more efficient. This constructor also + /// auto-inserts at the end of the specified BasicBlock. SwitchInst(Value *Value, BasicBlock *Default, unsigned NumCases, BasicBlock *InsertAtEnd); @@ -3108,40 +3155,40 @@ public: setOperand(1, reinterpret_cast(DefaultCase)); } - /// getNumCases - return the number of 'cases' in this switch instruction, - /// except the default case + /// Return the number of 'cases' in this switch instruction, excluding the + /// default case. unsigned getNumCases() const { return getNumOperands()/2 - 1; } - /// Returns a read/write iterator that points to the first - /// case in SwitchInst. + /// Returns a read/write iterator that points to the first case in the + /// SwitchInst. CaseIt case_begin() { return CaseIt(this, 0); } - /// Returns a read-only iterator that points to the first - /// case in the SwitchInst. + /// Returns a read-only iterator that points to the first case in the + /// SwitchInst. ConstCaseIt case_begin() const { return ConstCaseIt(this, 0); } - /// Returns a read/write iterator that points one past the last - /// in the SwitchInst. + /// Returns a read/write iterator that points one past the last in the + /// SwitchInst. CaseIt case_end() { return CaseIt(this, getNumCases()); } - /// Returns a read-only iterator that points one past the last - /// in the SwitchInst. + /// Returns a read-only iterator that points one past the last in the + /// SwitchInst. ConstCaseIt case_end() const { return ConstCaseIt(this, getNumCases()); } - /// cases - iteration adapter for range-for loops. + /// Iteration adapter for range-for loops. iterator_range cases() { return make_range(case_begin(), case_end()); } - /// cases - iteration adapter for range-for loops. + /// Constant iteration adapter for range-for loops. iterator_range cases() const { return make_range(case_begin(), case_end()); } @@ -3158,10 +3205,10 @@ public: return ConstCaseIt(this, DefaultPseudoIndex); } - /// findCaseValue - Search all of the case values for the specified constant. - /// If it is explicitly handled, return the case iterator of it, otherwise - /// return default case iterator to indicate - /// that it is handled by the default handler. + /// Search all of the case values for the specified constant. If it is + /// explicitly handled, return the case iterator of it, otherwise return + /// default case iterator to indicate that it is handled by the default + /// handler. CaseIt findCaseValue(const ConstantInt *C) { for (CaseIt i = case_begin(), e = case_end(); i != e; ++i) if (i.getCaseValue() == C) @@ -3175,8 +3222,8 @@ public: return case_default(); } - /// findCaseDest - Finds the unique case value for a given successor. Returns - /// null if the successor is not found, not unique, or is the default case. + /// Finds the unique case value for a given successor. Returns null if the + /// successor is not found, not unique, or is the default case. ConstantInt *findCaseDest(BasicBlock *BB) { if (BB == getDefaultDest()) return nullptr; @@ -3190,15 +3237,15 @@ public: return CI; } - /// addCase - Add an entry to the switch instruction... + /// Add an entry to the switch instruction. /// Note: /// This action invalidates case_end(). Old case_end() iterator will /// point to the added case. void addCase(ConstantInt *OnVal, BasicBlock *Dest); - /// removeCase - This method removes the specified case and its successor - /// from the switch instruction. Note that this operation may reorder the - /// remaining cases at index idx and above. + /// This method removes the specified case and its successor from the switch + /// instruction. Note that this operation may reorder the remaining cases at + /// index idx and above. /// Note: /// This action invalidates iterators for all cases following the one removed, /// including the case_end() iterator. @@ -3523,6 +3570,10 @@ public: return getOperandUse(i); } + /// If one of the arguments has the 'returned' attribute, return its + /// operand value. Otherwise, return nullptr. + Value *getReturnedArgOperand() const; + /// getCallingConv/setCallingConv - Get or set the calling convention of this /// function call. CallingConv::ID getCallingConv() const { @@ -3543,10 +3594,19 @@ public: void setAttributes(const AttributeSet &Attrs) { AttributeList = Attrs; } /// addAttribute - adds the attribute to the list of attributes. - void addAttribute(unsigned i, Attribute::AttrKind attr); + void addAttribute(unsigned i, Attribute::AttrKind Kind); + + /// addAttribute - adds the attribute to the list of attributes. + void addAttribute(unsigned i, Attribute Attr); /// removeAttribute - removes the attribute from the list of attributes. - void removeAttribute(unsigned i, Attribute attr); + void removeAttribute(unsigned i, Attribute::AttrKind Kind); + + /// removeAttribute - removes the attribute from the list of attributes. + void removeAttribute(unsigned i, StringRef Kind); + + /// removeAttribute - removes the attribute from the list of attributes. + void removeAttribute(unsigned i, Attribute Attr); /// \brief adds the dereferenceable attribute to the list of attributes. void addDereferenceableAttr(unsigned i, uint64_t Bytes); @@ -3556,19 +3616,25 @@ public: void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes); /// \brief Determine whether this call has the given attribute. - bool hasFnAttr(Attribute::AttrKind A) const { - assert(A != Attribute::NoBuiltin && + bool hasFnAttr(Attribute::AttrKind Kind) const { + assert(Kind != Attribute::NoBuiltin && "Use CallInst::isNoBuiltin() to check for Attribute::NoBuiltin"); - return hasFnAttrImpl(A); + return hasFnAttrImpl(Kind); } /// \brief Determine whether this call has the given attribute. - bool hasFnAttr(StringRef A) const { - return hasFnAttrImpl(A); + bool hasFnAttr(StringRef Kind) const { + return hasFnAttrImpl(Kind); } /// \brief Determine whether the call or the callee has the given attributes. - bool paramHasAttr(unsigned i, Attribute::AttrKind A) const; + bool paramHasAttr(unsigned i, Attribute::AttrKind Kind) const; + + /// \brief Get the attribute of a given kind at a position. + Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const; + + /// \brief Get the attribute of a given kind at a position. + Attribute getAttribute(unsigned i, StringRef Kind) const; /// \brief Return true if the data operand at index \p i has the attribute \p /// A. @@ -3584,7 +3650,7 @@ public: /// \p i in [1, arg_size + 1) -> argument number (\p i - 1) /// \p i in [arg_size + 1, data_operand_size + 1) -> bundle operand at index /// (\p i - 1) in the operand list. - bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind A) const; + bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind Kind) const; /// \brief Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned i) const { @@ -3641,6 +3707,14 @@ public: addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly); } + /// \brief Determine if the call does not access or only writes memory. + bool doesNotReadMemory() const { + return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly); + } + void setDoesNotReadMemory() { + addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly); + } + /// @brief Determine if the call access memmory only using it's pointer /// arguments. bool onlyAccessesArgMemory() const { @@ -4842,6 +4916,31 @@ public: static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } + + /// \brief Gets the pointer operand. + Value *getPointerOperand() { + return getOperand(0); + } + + /// \brief Gets the pointer operand. + const Value *getPointerOperand() const { + return getOperand(0); + } + + /// \brief Gets the operand index of the pointer operand. + static unsigned getPointerOperandIndex() { + return 0U; + } + + /// \brief Returns the address space of the pointer operand. + unsigned getSrcAddressSpace() const { + return getPointerOperand()->getType()->getPointerAddressSpace(); + } + + /// \brief Returns the address space of the result. + unsigned getDestAddressSpace() const { + return getType()->getPointerAddressSpace(); + } }; } // End llvm namespace diff --git a/include/llvm/IR/IntrinsicInst.h b/include/llvm/IR/IntrinsicInst.h index af61c8fac08ba5f2c12a42fc2ebbba671bbbc4cf..52044e0a0cc89c1c2c2bb86a55a60ecac8bdc72d 100644 --- a/include/llvm/IR/IntrinsicInst.h +++ b/include/llvm/IR/IntrinsicInst.h @@ -58,6 +58,10 @@ namespace llvm { /// This is the common base class for debug info intrinsics. class DbgInfoIntrinsic : public IntrinsicInst { public: + /// Get the location corresponding to the variable referenced by the debug + /// info intrinsic. Depending on the intrinsic, this could be the + /// variable's value or its address. + Value *getVariableLocation(bool AllowNullOp = true) const; // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const IntrinsicInst *I) { @@ -71,14 +75,12 @@ namespace llvm { static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); } - - static Value *StripCast(Value *C); }; /// This represents the llvm.dbg.declare instruction. class DbgDeclareInst : public DbgInfoIntrinsic { public: - Value *getAddress() const; + Value *getAddress() const { return getVariableLocation(); } DILocalVariable *getVariable() const { return cast(getRawVariable()); } @@ -105,8 +107,9 @@ namespace llvm { /// This represents the llvm.dbg.value instruction. class DbgValueInst : public DbgInfoIntrinsic { public: - const Value *getValue() const; - Value *getValue(); + Value *getValue() const { + return getVariableLocation(/* AllowNullOp = */ false); + } uint64_t getOffset() const { return cast( const_cast(getArgOperand(1)))->getZExtValue(); diff --git a/include/llvm/IR/Intrinsics.h b/include/llvm/IR/Intrinsics.h index 40a800e17ba4d59610936dc13421109736c1057b..7a87c2167710eb6a3177eaa193ea052d4ba32896 100644 --- a/include/llvm/IR/Intrinsics.h +++ b/include/llvm/IR/Intrinsics.h @@ -17,6 +17,8 @@ #define LLVM_IR_INTRINSICS_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include namespace llvm { @@ -133,6 +135,25 @@ namespace Intrinsic { /// of IITDescriptors. void getIntrinsicInfoTableEntries(ID id, SmallVectorImpl &T); + /// Match the specified type (which comes from an intrinsic argument or return + /// value) with the type constraints specified by the .td file. If the given + /// type is an overloaded type it is pushed to the ArgTys vector. + /// + /// Returns false if the given type matches with the constraints, true + /// otherwise. + bool matchIntrinsicType(Type *Ty, ArrayRef &Infos, + SmallVectorImpl &ArgTys); + + /// Verify if the intrinsic has variable arguments. This method is intended to + /// be called after all the fixed arguments have been matched first. + /// + /// This method returns true on error. + bool matchIntrinsicVarArg(bool isVarArg, ArrayRef &Infos); + + // Checks if the intrinsic name matches with its signature and if not + // returns the declaration with the same signature and remangled name. + llvm::Optional remangleIntrinsicFunction(Function *F); + } // End Intrinsic namespace } // End llvm namespace diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index 5f3c7e3ef401d8caf8553d4f8d4b112fe8604666..5ece731fa143ee83ff4531283ca56cdc490d2f0b 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -19,9 +19,7 @@ include "llvm/CodeGen/ValueTypes.td" class IntrinsicProperty; -// Intr*Mem - Memory properties. An intrinsic is allowed to have at most one of -// these properties set. They are listed from the most aggressive (best to use -// if correct) to the least aggressive. If no property is set, the worst case +// Intr*Mem - Memory properties. If no property is set, the worst case // is assumed (it may read and write any memory it can get access to and it may // have other side effects). @@ -29,20 +27,21 @@ class IntrinsicProperty; // effects. It may be CSE'd deleted if dead, etc. def IntrNoMem : IntrinsicProperty; -// IntrReadArgMem - This intrinsic reads only from memory that one of its -// pointer-typed arguments points to, but may read an unspecified amount. -def IntrReadArgMem : IntrinsicProperty; - -// IntrReadMem - This intrinsic reads from unspecified memory, so it cannot be -// moved across stores. However, it can be reordered otherwise and can be -// deleted if dead. +// IntrReadMem - This intrinsic only reads from memory. It does not write to +// memory and has no other side effects. Therefore, it cannot be moved across +// potentially aliasing stores. However, it can be reordered otherwise and can +// be deleted if dead. def IntrReadMem : IntrinsicProperty; -// IntrReadWriteArgMem - This intrinsic reads and writes only from memory that -// one of its arguments points to, but may access an unspecified amount. The -// reads and writes may be volatile, but except for this it has no other side -// effects. -def IntrReadWriteArgMem : IntrinsicProperty; +// IntrWriteMem - This intrinsic only writes to memory, but does not read from +// memory, and has no other side effects. This means dead stores before calls +// to this intrinsics may be removed. +def IntrWriteMem : IntrinsicProperty; + +// IntrArgMemOnly - This intrinsic only accesses memory that its pointer-typed +// argument(s) points to, but may access an unspecified amount. Other than +// reads from and (possibly volatile) writes to memory, it has no side effects. +def IntrArgMemOnly : IntrinsicProperty; // Commutative - This intrinsic is commutative: X op Y == Y op X. def Commutative : IntrinsicProperty; @@ -55,12 +54,24 @@ class NoCapture : IntrinsicProperty { int ArgNo = argNo; } +// Returned - The specified argument is always the return value of the +// intrinsic. +class Returned : IntrinsicProperty { + int ArgNo = argNo; +} + // ReadOnly - The specified argument pointer is not written to through the // pointer by the intrinsic. class ReadOnly : IntrinsicProperty { int ArgNo = argNo; } +// WriteOnly - The intrinsic does not read memory through the specified +// argument pointer. +class WriteOnly : IntrinsicProperty { + int ArgNo = argNo; +} + // ReadNone - The specified argument pointer is not dereferenced by the // intrinsic. class ReadNone : IntrinsicProperty { @@ -271,10 +282,10 @@ def int_gcroot : Intrinsic<[], [llvm_ptrptr_ty, llvm_ptr_ty]>; def int_gcread : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_ptrptr_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_gcwrite : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_ptrptr_ty], - [IntrReadWriteArgMem, NoCapture<1>, NoCapture<2>]>; + [IntrArgMemOnly, NoCapture<1>, NoCapture<2>]>; //===--------------------- Code Generator Intrinsics ----------------------===// // @@ -306,13 +317,16 @@ def int_stackrestore : Intrinsic<[], [llvm_ptr_ty]>, def int_get_dynamic_area_offset : Intrinsic<[llvm_anyint_ty]>; -// IntrReadWriteArgMem is more pessimistic than strictly necessary for prefetch, +def int_thread_pointer : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>, + GCCBuiltin<"__builtin_thread_pointer">; + +// IntrArgMemOnly is more pessimistic than strictly necessary for prefetch, // however it does conveniently prevent the prefetch from being reordered // with respect to nearby accesses to the same memory. def int_prefetch : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_pcmarker : Intrinsic<[], [llvm_i32_ty]>; def int_readcyclecounter : Intrinsic<[llvm_i64_ty]>; @@ -324,8 +338,7 @@ def int_assume : Intrinsic<[], [llvm_i1_ty], []>; // Stack Protector Intrinsic - The stackprotector intrinsic writes the stack // guard to the correct place on the stack frame. def int_stackprotector : Intrinsic<[], [llvm_ptr_ty, llvm_ptrptr_ty], []>; -def int_stackprotectorcheck : Intrinsic<[], [llvm_ptrptr_ty], - [IntrReadWriteArgMem]>; +def int_stackguard : Intrinsic<[llvm_ptr_ty], [], []>; // A counter increment for instrumentation based profiling. def int_instrprof_increment : Intrinsic<[], @@ -347,17 +360,17 @@ def int_instrprof_value_profile : Intrinsic<[], def int_memcpy : Intrinsic<[], [llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty, llvm_i32_ty, llvm_i1_ty], - [IntrReadWriteArgMem, NoCapture<0>, NoCapture<1>, - ReadOnly<1>]>; + [IntrArgMemOnly, NoCapture<0>, NoCapture<1>, + WriteOnly<0>, ReadOnly<1>]>; def int_memmove : Intrinsic<[], [llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty, llvm_i32_ty, llvm_i1_ty], - [IntrReadWriteArgMem, NoCapture<0>, NoCapture<1>, + [IntrArgMemOnly, NoCapture<0>, NoCapture<1>, ReadOnly<1>]>; def int_memset : Intrinsic<[], [llvm_anyptr_ty, llvm_i8_ty, llvm_anyint_ty, llvm_i32_ty, llvm_i1_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>, WriteOnly<0>]>; let IntrProperties = [IntrNoMem] in { def int_fma : Intrinsic<[llvm_anyfloat_ty], @@ -500,11 +513,11 @@ def int_annotation : Intrinsic<[llvm_anyint_ty], // def int_init_trampoline : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<0>]>, + [IntrArgMemOnly, NoCapture<0>]>, GCCBuiltin<"__builtin_init_trampoline">; def int_adjust_trampoline : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], - [IntrReadArgMem]>, + [IntrReadMem, IntrArgMemOnly]>, GCCBuiltin<"__builtin_adjust_trampoline">; //===------------------------ Overflow Intrinsics -------------------------===// @@ -536,17 +549,17 @@ def int_umul_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty], // def int_lifetime_start : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<1>]>; + [IntrArgMemOnly, NoCapture<1>]>; def int_lifetime_end : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<1>]>; + [IntrArgMemOnly, NoCapture<1>]>; def int_invariant_start : Intrinsic<[llvm_descriptor_ty], [llvm_i64_ty, llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<1>]>; + [IntrArgMemOnly, NoCapture<1>]>; def int_invariant_end : Intrinsic<[], [llvm_descriptor_ty, llvm_i64_ty, llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<2>]>; + [IntrArgMemOnly, NoCapture<2>]>; def int_invariant_group_barrier : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], @@ -597,6 +610,10 @@ def int_debugtrap : Intrinsic<[]>, def int_experimental_deoptimize : Intrinsic<[llvm_any_ty], [llvm_vararg_ty], [Throws]>; +// Support for speculative runtime guards +def int_experimental_guard : Intrinsic<[], [llvm_i1_ty, llvm_vararg_ty], + [Throws]>; + // NOP: calls/invokes to this intrinsic are removed by codegen def int_donothing : Intrinsic<[], [], [IntrNoMem]>; @@ -636,31 +653,40 @@ def int_clear_cache : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty], //===-------------------------- Masked Intrinsics -------------------------===// // -def int_masked_store : Intrinsic<[], [llvm_anyvector_ty, LLVMPointerTo<0>, +def int_masked_store : Intrinsic<[], [llvm_anyvector_ty, + LLVMAnyPointerType>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_masked_load : Intrinsic<[llvm_anyvector_ty], - [LLVMPointerTo<0>, llvm_i32_ty, + [LLVMAnyPointerType>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>, LLVMMatchType<0>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_masked_gather: Intrinsic<[llvm_anyvector_ty], [LLVMVectorOfPointersToElt<0>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>, LLVMMatchType<0>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_masked_scatter: Intrinsic<[], [llvm_anyvector_ty, LLVMVectorOfPointersToElt<0>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; + +// Test whether a pointer is associated with a type metadata identifier. +def int_type_test : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_metadata_ty], + [IntrNoMem]>; + +// Safely loads a function pointer from a virtual table pointer using type metadata. +def int_type_checked_load : Intrinsic<[llvm_ptr_ty, llvm_i1_ty], + [llvm_ptr_ty, llvm_i32_ty, llvm_metadata_ty], + [IntrNoMem]>; -// Intrinsics to support bit sets. -def int_bitset_test : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_metadata_ty], - [IntrNoMem]>; +def int_load_relative: Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_anyint_ty], + [IntrReadMem, IntrArgMemOnly]>; //===----------------------------------------------------------------------===// // Target-specific intrinsics diff --git a/include/llvm/IR/IntrinsicsAArch64.td b/include/llvm/IR/IntrinsicsAArch64.td index 5489604565ad95216fd8cd90f2b5347ca5c980f7..d1e331775b7bf5f48b4c6db225f06c534f8b53ac 100644 --- a/include/llvm/IR/IntrinsicsAArch64.td +++ b/include/llvm/IR/IntrinsicsAArch64.td @@ -13,9 +13,6 @@ let TargetPrefix = "aarch64" in { -def int_aarch64_thread_pointer : GCCBuiltin<"__builtin_thread_pointer">, - Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; - def int_aarch64_ldxr : Intrinsic<[llvm_i64_ty], [llvm_anyptr_ty]>; def int_aarch64_ldaxr : Intrinsic<[llvm_i64_ty], [llvm_anyptr_ty]>; def int_aarch64_stxr : Intrinsic<[llvm_i32_ty], [llvm_i64_ty, llvm_anyptr_ty]>; @@ -159,7 +156,7 @@ let TargetPrefix = "aarch64" in { // All intrinsics start with "llvm.aarch64.". // Arithmetic ops -let IntrProperties = [IntrNoMem] in { +let TargetPrefix = "aarch64", IntrProperties = [IntrNoMem] in { // Vector Add Across Lanes def int_aarch64_neon_saddv : AdvSIMD_1VectorArg_Int_Across_Intrinsic; def int_aarch64_neon_uaddv : AdvSIMD_1VectorArg_Int_Across_Intrinsic; @@ -436,70 +433,70 @@ def int_aarch64_neon_vcopy_lane: AdvSIMD_2Vector2Index_Intrinsic; let TargetPrefix = "aarch64" in { // All intrinsics start with "llvm.aarch64.". class AdvSIMD_1Vec_Load_Intrinsic : Intrinsic<[llvm_anyvector_ty], [LLVMAnyPointerType>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_1Vec_Store_Lane_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadWriteArgMem, NoCapture<2>]>; + [IntrArgMemOnly, NoCapture<2>]>; class AdvSIMD_2Vec_Load_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>], [LLVMAnyPointerType>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_2Vec_Load_Lane_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>], [LLVMMatchType<0>, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_2Vec_Store_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, LLVMAnyPointerType>], - [IntrReadWriteArgMem, NoCapture<2>]>; + [IntrArgMemOnly, NoCapture<2>]>; class AdvSIMD_2Vec_Store_Lane_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadWriteArgMem, NoCapture<3>]>; + [IntrArgMemOnly, NoCapture<3>]>; class AdvSIMD_3Vec_Load_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>], [LLVMAnyPointerType>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_3Vec_Load_Lane_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_3Vec_Store_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMAnyPointerType>], - [IntrReadWriteArgMem, NoCapture<3>]>; + [IntrArgMemOnly, NoCapture<3>]>; class AdvSIMD_3Vec_Store_Lane_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadWriteArgMem, NoCapture<4>]>; + [IntrArgMemOnly, NoCapture<4>]>; class AdvSIMD_4Vec_Load_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [LLVMAnyPointerType>], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_4Vec_Load_Lane_Intrinsic : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; class AdvSIMD_4Vec_Store_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, LLVMAnyPointerType>], - [IntrReadWriteArgMem, NoCapture<4>]>; + [IntrArgMemOnly, NoCapture<4>]>; class AdvSIMD_4Vec_Store_Lane_Intrinsic : Intrinsic<[], [llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i64_ty, llvm_anyptr_ty], - [IntrReadWriteArgMem, NoCapture<5>]>; + [IntrArgMemOnly, NoCapture<5>]>; } // Memory ops diff --git a/include/llvm/IR/IntrinsicsAMDGPU.td b/include/llvm/IR/IntrinsicsAMDGPU.td index 89ea798d96e2aa1dfb6d448ecbfd7d0aef96ed10..1473146cd929d1e28936c81f995c5f38ff076d13 100644 --- a/include/llvm/IR/IntrinsicsAMDGPU.td +++ b/include/llvm/IR/IntrinsicsAMDGPU.td @@ -11,28 +11,43 @@ // //===----------------------------------------------------------------------===// -class AMDGPUReadPreloadRegisterIntrinsic - : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin; +class AMDGPUReadPreloadRegisterIntrinsic + : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>; + +class AMDGPUReadPreloadRegisterIntrinsicNamed + : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, GCCBuiltin; let TargetPrefix = "r600" in { -multiclass AMDGPUReadPreloadRegisterIntrinsic_xyz { - def _x : AMDGPUReadPreloadRegisterIntrinsic; - def _y : AMDGPUReadPreloadRegisterIntrinsic; - def _z : AMDGPUReadPreloadRegisterIntrinsic; +multiclass AMDGPUReadPreloadRegisterIntrinsic_xyz { + def _x : AMDGPUReadPreloadRegisterIntrinsic; + def _y : AMDGPUReadPreloadRegisterIntrinsic; + def _z : AMDGPUReadPreloadRegisterIntrinsic; +} + +multiclass AMDGPUReadPreloadRegisterIntrinsic_xyz_named { + def _x : AMDGPUReadPreloadRegisterIntrinsicNamed; + def _y : AMDGPUReadPreloadRegisterIntrinsicNamed; + def _z : AMDGPUReadPreloadRegisterIntrinsicNamed; } -defm int_r600_read_global_size : AMDGPUReadPreloadRegisterIntrinsic_xyz < - "__builtin_r600_read_global_size">; -defm int_r600_read_local_size : AMDGPUReadPreloadRegisterIntrinsic_xyz < - "__builtin_r600_read_local_size">; -defm int_r600_read_ngroups : AMDGPUReadPreloadRegisterIntrinsic_xyz < - "__builtin_r600_read_ngroups">; -defm int_r600_read_tgid : AMDGPUReadPreloadRegisterIntrinsic_xyz < - "__builtin_r600_read_tgid">; -defm int_r600_read_tidig : AMDGPUReadPreloadRegisterIntrinsic_xyz < - "__builtin_r600_read_tidig">; +defm int_r600_read_global_size : AMDGPUReadPreloadRegisterIntrinsic_xyz_named + <"__builtin_r600_read_global_size">; +defm int_r600_read_ngroups : AMDGPUReadPreloadRegisterIntrinsic_xyz_named + <"__builtin_r600_read_ngroups">; +defm int_r600_read_tgid : AMDGPUReadPreloadRegisterIntrinsic_xyz_named + <"__builtin_r600_read_tgid">; + +defm int_r600_read_local_size : AMDGPUReadPreloadRegisterIntrinsic_xyz; +defm int_r600_read_tidig : AMDGPUReadPreloadRegisterIntrinsic_xyz; + +def int_r600_read_workdim : AMDGPUReadPreloadRegisterIntrinsic; + + +// AS 7 is PARAM_I_ADDRESS, used for kernel arguments +def int_r600_implicitarg_ptr : + GCCBuiltin<"__builtin_r600_implicitarg_ptr">, + Intrinsic<[LLVMQualPointerType], [], [IntrNoMem]>; def int_r600_rat_store_typed : // 1st parameter: Data @@ -45,9 +60,6 @@ def int_r600_rsq : Intrinsic< [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] >; -def int_r600_read_workdim : AMDGPUReadPreloadRegisterIntrinsic < - "__builtin_r600_read_workdim" ->; } // End TargetPrefix = "r600" @@ -60,14 +72,15 @@ def int_AMDGPU_ldexp : Intrinsic< let TargetPrefix = "amdgcn" in { -defm int_amdgcn_workitem_id : AMDGPUReadPreloadRegisterIntrinsic_xyz < - "__builtin_amdgcn_workitem_id">; -defm int_amdgcn_workgroup_id : AMDGPUReadPreloadRegisterIntrinsic_xyz < - "__builtin_amdgcn_workgroup_id">; +defm int_amdgcn_workitem_id : AMDGPUReadPreloadRegisterIntrinsic_xyz; +defm int_amdgcn_workgroup_id : AMDGPUReadPreloadRegisterIntrinsic_xyz_named + <"__builtin_amdgcn_workgroup_id">; def int_amdgcn_s_barrier : GCCBuiltin<"__builtin_amdgcn_s_barrier">, Intrinsic<[], [], [IntrConvergent]>; +def int_amdgcn_s_waitcnt : Intrinsic<[], [llvm_i32_ty], []>; + def int_amdgcn_div_scale : Intrinsic< // 1st parameter: Numerator // 2nd parameter: Denominator @@ -112,6 +125,11 @@ def int_amdgcn_rsq : Intrinsic< [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] >; +def int_amdgcn_rsq_legacy : GCCBuiltin<"__builtin_amdgcn_rsq_legacy">, + Intrinsic< + [llvm_float_ty], [llvm_float_ty], [IntrNoMem] +>; + def int_amdgcn_rsq_clamp : Intrinsic< [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; @@ -123,6 +141,17 @@ def int_amdgcn_frexp_mant : Intrinsic< [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] >; +def int_amdgcn_frexp_exp : Intrinsic< + [llvm_i32_ty], [llvm_anyfloat_ty], [IntrNoMem] +>; + +// v_fract is buggy on SI/CI. It mishandles infinities, may return 1.0 +// and always uses rtz, so is not suitable for implementing the OpenCL +// fract function. It should be ok on VI. +def int_amdgcn_fract : Intrinsic< + [llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem] +>; + def int_amdgcn_class : Intrinsic< [llvm_i1_ty], [llvm_anyfloat_ty, llvm_i32_ty], [IntrNoMem] >; @@ -147,6 +176,17 @@ def int_amdgcn_cubetc : GCCBuiltin<"__builtin_amdgcn_cubetc">, [llvm_float_ty, llvm_float_ty, llvm_float_ty], [IntrNoMem] >; +// TODO: Do we want an ordering for these? +def int_amdgcn_atomic_inc : Intrinsic<[llvm_anyint_ty], + [llvm_anyptr_ty, LLVMMatchType<0>], + [IntrArgMemOnly, NoCapture<0>] +>; + +def int_amdgcn_atomic_dec : Intrinsic<[llvm_anyint_ty], + [llvm_anyptr_ty, LLVMMatchType<0>], + [IntrArgMemOnly, NoCapture<0>] +>; + class AMDGPUImageLoad : Intrinsic < [llvm_v4f32_ty], // vdata(VGPR) [llvm_anyint_ty, // vaddr(VGPR) @@ -209,7 +249,7 @@ def int_amdgcn_image_atomic_cmpswap : Intrinsic < llvm_i1_ty], // slc(imm) []>; -def int_amdgcn_buffer_load_format : Intrinsic < +class AMDGPUBufferLoad : Intrinsic < [llvm_anyfloat_ty], [llvm_v4i32_ty, // rsrc(SGPR) llvm_i32_ty, // vindex(VGPR) @@ -217,16 +257,20 @@ def int_amdgcn_buffer_load_format : Intrinsic < llvm_i1_ty, // glc(imm) llvm_i1_ty], // slc(imm) [IntrReadMem]>; +def int_amdgcn_buffer_load_format : AMDGPUBufferLoad; +def int_amdgcn_buffer_load : AMDGPUBufferLoad; -def int_amdgcn_buffer_store_format : Intrinsic < +class AMDGPUBufferStore : Intrinsic < [], - [llvm_anyfloat_ty, // vdata(VGPR) -- can currently only select v4f32 + [llvm_anyfloat_ty, // vdata(VGPR) -- can currently only select f32, v2f32, v4f32 llvm_v4i32_ty, // rsrc(SGPR) llvm_i32_ty, // vindex(VGPR) llvm_i32_ty, // offset(SGPR/VGPR/imm) llvm_i1_ty, // glc(imm) llvm_i1_ty], // slc(imm) - []>; + [IntrWriteMem]>; +def int_amdgcn_buffer_store_format : AMDGPUBufferStore; +def int_amdgcn_buffer_store : AMDGPUBufferStore; class AMDGPUBufferAtomic : Intrinsic < [llvm_i32_ty], @@ -256,8 +300,7 @@ def int_amdgcn_buffer_atomic_cmpswap : Intrinsic< llvm_i1_ty], // slc(imm) []>; -def int_amdgcn_read_workdim : AMDGPUReadPreloadRegisterIntrinsic < - "__builtin_amdgcn_read_workdim">; +def int_amdgcn_read_workdim : AMDGPUReadPreloadRegisterIntrinsic; def int_amdgcn_buffer_wbinvl1_sc : @@ -293,6 +336,18 @@ def int_amdgcn_dispatch_ptr : GCCBuiltin<"__builtin_amdgcn_dispatch_ptr">, Intrinsic<[LLVMQualPointerType], [], [IntrNoMem]>; +def int_amdgcn_queue_ptr : + GCCBuiltin<"__builtin_amdgcn_queue_ptr">, + Intrinsic<[LLVMQualPointerType], [], [IntrNoMem]>; + +def int_amdgcn_kernarg_segment_ptr : + GCCBuiltin<"__builtin_amdgcn_kernarg_segment_ptr">, + Intrinsic<[LLVMQualPointerType], [], [IntrNoMem]>; + +def int_amdgcn_implicitarg_ptr : + GCCBuiltin<"__builtin_amdgcn_implicitarg_ptr">, + Intrinsic<[LLVMQualPointerType], [], [IntrNoMem]>; + // __builtin_amdgcn_interp_p1 , , , def int_amdgcn_interp_p1 : GCCBuiltin<"__builtin_amdgcn_interp_p1">, @@ -309,6 +364,13 @@ def int_amdgcn_interp_p2 : [IntrNoMem]>; // See int_amdgcn_v_interp_p1 for why this is // IntrNoMem. +// Pixel shaders only: whether the current pixel is live (i.e. not a helper +// invocation for derivative computation). +def int_amdgcn_ps_live : Intrinsic < + [llvm_i1_ty], + [], + [IntrNoMem]>; + def int_amdgcn_mbcnt_lo : GCCBuiltin<"__builtin_amdgcn_mbcnt_lo">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; @@ -317,6 +379,16 @@ def int_amdgcn_mbcnt_hi : GCCBuiltin<"__builtin_amdgcn_mbcnt_hi">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; +// llvm.amdgcn.ds.swizzle src offset +def int_amdgcn_ds_swizzle : + GCCBuiltin<"__builtin_amdgcn_ds_swizzle">, + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrConvergent]>; + +// llvm.amdgcn.lerp +def int_amdgcn_lerp : + GCCBuiltin<"__builtin_amdgcn_lerp">, + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; + //===----------------------------------------------------------------------===// // CI+ Intrinsics //===----------------------------------------------------------------------===// diff --git a/include/llvm/IR/IntrinsicsARM.td b/include/llvm/IR/IntrinsicsARM.td index 626d99be9c45fb3a21e96ecc4971fbbb9ea93725..0995985968853982a994868ce0fe94f4e546b611 100644 --- a/include/llvm/IR/IntrinsicsARM.td +++ b/include/llvm/IR/IntrinsicsARM.td @@ -17,9 +17,6 @@ let TargetPrefix = "arm" in { // All intrinsics start with "llvm.arm.". -def int_arm_thread_pointer : GCCBuiltin<"__builtin_thread_pointer">, - Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; - // A space-consuming intrinsic primarily for testing ARMConstantIslands. The // first argument is the number of bytes this "instruction" takes up, the second // and return value are essentially chains, used to force ordering during ISel. @@ -81,6 +78,24 @@ def int_arm_vcvtru : Intrinsic<[llvm_float_ty], [llvm_anyfloat_ty], //===----------------------------------------------------------------------===// // Coprocessor +def int_arm_ldc : GCCBuiltin<"__builtin_arm_ldc">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_ldcl : GCCBuiltin<"__builtin_arm_ldcl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_ldc2 : GCCBuiltin<"__builtin_arm_ldc2">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_ldc2l : GCCBuiltin<"__builtin_arm_ldc2l">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; + +def int_arm_stc : GCCBuiltin<"__builtin_arm_stc">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_stcl : GCCBuiltin<"__builtin_arm_stcl">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_stc2 : GCCBuiltin<"__builtin_arm_stc2">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; +def int_arm_stc2l : GCCBuiltin<"__builtin_arm_stc2l">, + Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty], []>; + // Move to coprocessor def int_arm_mcr : GCCBuiltin<"__builtin_arm_mcr">, Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, @@ -108,12 +123,15 @@ def int_arm_cdp2 : GCCBuiltin<"__builtin_arm_cdp2">, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], []>; // Move from two registers to coprocessor -def int_arm_mcrr : GCCBuiltin<"__builtin_arm_mcrr">, - Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, - llvm_i32_ty, llvm_i32_ty], []>; -def int_arm_mcrr2 : GCCBuiltin<"__builtin_arm_mcrr2">, - Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, - llvm_i32_ty, llvm_i32_ty], []>; +def int_arm_mcrr : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, + llvm_i32_ty, llvm_i32_ty], []>; +def int_arm_mcrr2 : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, + llvm_i32_ty, llvm_i32_ty], []>; + +def int_arm_mrrc : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [llvm_i32_ty, + llvm_i32_ty, llvm_i32_ty], []>; +def int_arm_mrrc2 : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [llvm_i32_ty, + llvm_i32_ty, llvm_i32_ty], []>; //===----------------------------------------------------------------------===// // CRC32 @@ -406,18 +424,18 @@ def int_arm_neon_vrintp : Neon_1Arg_Intrinsic; // Source operands are the address and alignment. def int_arm_neon_vld1 : Intrinsic<[llvm_anyvector_ty], [llvm_anyptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_arm_neon_vld2 : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>], [llvm_anyptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_arm_neon_vld3 : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>], [llvm_anyptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_arm_neon_vld4 : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [llvm_anyptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; // Vector load N-element structure to one lane. // Source operands are: the address, the N input vectors (since only one @@ -425,38 +443,38 @@ def int_arm_neon_vld4 : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, def int_arm_neon_vld2lane : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>], [llvm_anyptr_ty, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i32_ty, - llvm_i32_ty], [IntrReadArgMem]>; + llvm_i32_ty], [IntrReadMem, IntrArgMemOnly]>; def int_arm_neon_vld3lane : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>], [llvm_anyptr_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i32_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_arm_neon_vld4lane : Intrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [llvm_anyptr_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, llvm_i32_ty, - llvm_i32_ty], [IntrReadArgMem]>; + llvm_i32_ty], [IntrReadMem, IntrArgMemOnly]>; // Interleaving vector stores from N-element structures. // Source operands are: the address, the N vectors, and the alignment. def int_arm_neon_vst1 : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, - llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty], [IntrArgMemOnly]>; def int_arm_neon_vst2 : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_arm_neon_vst3 : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, LLVMMatchType<1>, - llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty], [IntrArgMemOnly]>; def int_arm_neon_vst4 : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, LLVMMatchType<1>, LLVMMatchType<1>, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; // Vector store N-element structure from one lane. // Source operands are: the address, the N vectors, the lane number, and @@ -464,17 +482,17 @@ def int_arm_neon_vst4 : Intrinsic<[], def int_arm_neon_vst2lane : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, llvm_i32_ty, - llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty], [IntrArgMemOnly]>; def int_arm_neon_vst3lane : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, LLVMMatchType<1>, llvm_i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_arm_neon_vst4lane : Intrinsic<[], [llvm_anyptr_ty, llvm_anyvector_ty, LLVMMatchType<1>, LLVMMatchType<1>, LLVMMatchType<1>, llvm_i32_ty, - llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty], [IntrArgMemOnly]>; // Vector bitwise select. def int_arm_neon_vbsl : Intrinsic<[llvm_anyvector_ty], diff --git a/include/llvm/IR/IntrinsicsHexagon.td b/include/llvm/IR/IntrinsicsHexagon.td index ca6fcbd4433725e68949ef9caded0651721936e1..6519f051deeb7c8cbc11cf7d2638ba30762fa11b 100644 --- a/include/llvm/IR/IntrinsicsHexagon.td +++ b/include/llvm/IR/IntrinsicsHexagon.td @@ -428,42 +428,42 @@ class Hexagon_mem_memmemsi_Intrinsic : Hexagon_Intrinsic; + [IntrArgMemOnly]>; class Hexagon_mem_memsisi_Intrinsic : Hexagon_Intrinsic; + [IntrArgMemOnly]>; class Hexagon_mem_memdisi_Intrinsic : Hexagon_Intrinsic; + [IntrArgMemOnly]>; class Hexagon_mem_memmemsisi_Intrinsic : Hexagon_Intrinsic; + [IntrArgMemOnly]>; class Hexagon_mem_memsisisi_Intrinsic : Hexagon_Intrinsic; + [IntrArgMemOnly]>; class Hexagon_mem_memdisisi_Intrinsic : Hexagon_Intrinsic; + [IntrArgMemOnly]>; class Hexagon_v256_v256v256_Intrinsic : Hexagon_Intrinsic; + [IntrArgMemOnly]>; // // Hexagon_sf_df_Intrinsic @@ -2998,7 +2998,7 @@ Hexagon_di_di_Intrinsic<"HEXAGON_A2_tfrp">; // BUILTIN_INFO(HEXAGON.A2_tfrpi,DI_ftype_SI,1) // def int_hexagon_A2_tfrpi : -Hexagon_di_di_Intrinsic<"HEXAGON_A2_tfrpi">; +Hexagon_di_si_Intrinsic<"HEXAGON_A2_tfrpi">; // // BUILTIN_INFO(HEXAGON.A2_zxtb,SI_ftype_SI,1) // @@ -4971,17 +4971,17 @@ def llvm_ptr64_ty : LLVMPointerType; // Mark locked loads as read/write to prevent any accidental reordering. def int_hexagon_L2_loadw_locked : Hexagon_Intrinsic<"HEXAGON_L2_loadw_locked", [llvm_i32_ty], [llvm_ptr32_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_hexagon_L4_loadd_locked : Hexagon_Intrinsic<"HEXAGON_L4_loadd_locked", [llvm_i64_ty], [llvm_ptr64_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_hexagon_S2_storew_locked : Hexagon_Intrinsic<"HEXAGON_S2_storew_locked", [llvm_i32_ty], - [llvm_ptr32_ty, llvm_i32_ty], [IntrReadWriteArgMem, NoCapture<0>]>; + [llvm_ptr32_ty, llvm_i32_ty], [IntrArgMemOnly, NoCapture<0>]>; def int_hexagon_S4_stored_locked : Hexagon_Intrinsic<"HEXAGON_S4_stored_locked", [llvm_i32_ty], - [llvm_ptr64_ty, llvm_i64_ty], [IntrReadWriteArgMem, NoCapture<0>]>; + [llvm_ptr64_ty, llvm_i64_ty], [IntrArgMemOnly, NoCapture<0>]>; // V60 diff --git a/include/llvm/IR/IntrinsicsMips.td b/include/llvm/IR/IntrinsicsMips.td index 34557612cb96edbe806c0c8e74a04128c2b1e5df..421a79be4ebc22881230d1e835bc8f7cc8676d2d 100644 --- a/include/llvm/IR/IntrinsicsMips.td +++ b/include/llvm/IR/IntrinsicsMips.td @@ -264,11 +264,11 @@ def int_mips_bposge32: GCCBuiltin<"__builtin_mips_bposge32">, Intrinsic<[llvm_i32_ty], [], [IntrReadMem]>; def int_mips_lbux: GCCBuiltin<"__builtin_mips_lbux">, - Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadMem, IntrArgMemOnly]>; def int_mips_lhx: GCCBuiltin<"__builtin_mips_lhx">, - Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadMem, IntrArgMemOnly]>; def int_mips_lwx: GCCBuiltin<"__builtin_mips_lwx">, - Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty], [IntrReadMem, IntrArgMemOnly]>; //===----------------------------------------------------------------------===// // MIPS DSP Rev 2 @@ -1261,16 +1261,16 @@ def int_mips_insve_d : GCCBuiltin<"__builtin_msa_insve_d">, def int_mips_ld_b : GCCBuiltin<"__builtin_msa_ld_b">, Intrinsic<[llvm_v16i8_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ld_h : GCCBuiltin<"__builtin_msa_ld_h">, Intrinsic<[llvm_v8i16_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ld_w : GCCBuiltin<"__builtin_msa_ld_w">, Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ld_d : GCCBuiltin<"__builtin_msa_ld_d">, Intrinsic<[llvm_v2i64_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ldi_b : GCCBuiltin<"__builtin_msa_ldi_b">, Intrinsic<[llvm_v16i8_ty], [llvm_i32_ty], [IntrNoMem]>; @@ -1685,16 +1685,16 @@ def int_mips_srlri_d : GCCBuiltin<"__builtin_msa_srlri_d">, def int_mips_st_b : GCCBuiltin<"__builtin_msa_st_b">, Intrinsic<[], [llvm_v16i8_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_mips_st_h : GCCBuiltin<"__builtin_msa_st_h">, Intrinsic<[], [llvm_v8i16_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_mips_st_w : GCCBuiltin<"__builtin_msa_st_w">, Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_mips_st_d : GCCBuiltin<"__builtin_msa_st_d">, Intrinsic<[], [llvm_v2i64_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_mips_subs_s_b : GCCBuiltin<"__builtin_msa_subs_s_b">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>; diff --git a/include/llvm/IR/IntrinsicsNVVM.td b/include/llvm/IR/IntrinsicsNVVM.td index e3c69703497de588f4b78bb9f5c3534d2931029c..6919ec47eb9ab51fbccba1f1e5355a644ba3a669 100644 --- a/include/llvm/IR/IntrinsicsNVVM.td +++ b/include/llvm/IR/IntrinsicsNVVM.td @@ -17,6 +17,7 @@ def llvm_anyi64ptr_ty : LLVMAnyPointerType; // (space)i64* // MISC // +let TargetPrefix = "nvvm" in { def int_nvvm_clz_i : GCCBuiltin<"__nvvm_clz_i">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>; def int_nvvm_clz_ll : GCCBuiltin<"__nvvm_clz_ll">, @@ -720,18 +721,19 @@ def llvm_anyi64ptr_ty : LLVMAnyPointerType; // (space)i64* // Atomic not available as an llvm intrinsic. def int_nvvm_atomic_load_add_f32 : Intrinsic<[llvm_float_ty], [LLVMAnyPointerType, llvm_float_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_nvvm_atomic_load_inc_32 : Intrinsic<[llvm_i32_ty], [LLVMAnyPointerType, llvm_i32_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_nvvm_atomic_load_dec_32 : Intrinsic<[llvm_i32_ty], [LLVMAnyPointerType, llvm_i32_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; // Bar.Sync - def int_cuda_syncthreads : GCCBuiltin<"__syncthreads">, - Intrinsic<[], [], [IntrConvergent]>; - def int_nvvm_barrier0 : GCCBuiltin<"__nvvm_bar0">, + + // The builtin for "bar.sync 0" is called __syncthreads. Unlike most of the + // intrinsics in this file, this one is a user-facing API. + def int_nvvm_barrier0 : GCCBuiltin<"__syncthreads">, Intrinsic<[], [], [IntrConvergent]>; def int_nvvm_barrier0_popc : GCCBuiltin<"__nvvm_bar0_popc">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent]>; @@ -740,6 +742,10 @@ def llvm_anyi64ptr_ty : LLVMAnyPointerType; // (space)i64* def int_nvvm_barrier0_or : GCCBuiltin<"__nvvm_bar0_or">, Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent]>; + def int_nvvm_bar_sync : + Intrinsic<[], [llvm_i32_ty], [IntrConvergent]>, + GCCBuiltin<"__nvvm_bar_sync">; + // Membar def int_nvvm_membar_cta : GCCBuiltin<"__nvvm_membar_cta">, Intrinsic<[], [], []>; @@ -748,79 +754,34 @@ def llvm_anyi64ptr_ty : LLVMAnyPointerType; // (space)i64* def int_nvvm_membar_sys : GCCBuiltin<"__nvvm_membar_sys">, Intrinsic<[], [], []>; - -// Accessing special registers - def int_nvvm_read_ptx_sreg_tid_x : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_tid_x">; - def int_nvvm_read_ptx_sreg_tid_y : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_tid_y">; - def int_nvvm_read_ptx_sreg_tid_z : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_tid_z">; - - def int_nvvm_read_ptx_sreg_ntid_x : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ntid_x">; - def int_nvvm_read_ptx_sreg_ntid_y : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ntid_y">; - def int_nvvm_read_ptx_sreg_ntid_z : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ntid_z">; - - def int_nvvm_read_ptx_sreg_ctaid_x : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ctaid_x">; - def int_nvvm_read_ptx_sreg_ctaid_y : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ctaid_y">; - def int_nvvm_read_ptx_sreg_ctaid_z : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_ctaid_z">; - - def int_nvvm_read_ptx_sreg_nctaid_x : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_nctaid_x">; - def int_nvvm_read_ptx_sreg_nctaid_y : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_nctaid_y">; - def int_nvvm_read_ptx_sreg_nctaid_z : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_nctaid_z">; - - def int_nvvm_read_ptx_sreg_warpsize : - Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin<"__nvvm_read_ptx_sreg_warpsize">; - - -// Generated within nvvm. Use for ldu on sm_20 or later +// Generated within nvvm. Use for ldu on sm_20 or later. Second arg is the +// pointer's alignment. def int_nvvm_ldu_global_i : Intrinsic<[llvm_anyint_ty], [LLVMAnyPointerType>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldu.global.i">; def int_nvvm_ldu_global_f : Intrinsic<[llvm_anyfloat_ty], [LLVMAnyPointerType>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldu.global.f">; def int_nvvm_ldu_global_p : Intrinsic<[llvm_anyptr_ty], [LLVMAnyPointerType>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldu.global.p">; -// Generated within nvvm. Use for ldg on sm_35 or later +// Generated within nvvm. Use for ldg on sm_35 or later. Second arg is the +// pointer's alignment. def int_nvvm_ldg_global_i : Intrinsic<[llvm_anyint_ty], [LLVMAnyPointerType>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldg.global.i">; def int_nvvm_ldg_global_f : Intrinsic<[llvm_anyfloat_ty], [LLVMAnyPointerType>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldg.global.f">; def int_nvvm_ldg_global_p : Intrinsic<[llvm_anyptr_ty], [LLVMAnyPointerType>, llvm_i32_ty], - [IntrReadMem, NoCapture<0>], + [IntrReadMem, IntrArgMemOnly, NoCapture<0>], "llvm.nvvm.ldg.global.p">; // Use for generic pointers @@ -3666,9 +3627,8 @@ def int_nvvm_swap_lo_hi_b64 GCCBuiltin<"__nvvm_swap_lo_hi_b64">; -// Old PTX back-end intrinsics retained here for backwards-compatibility - -multiclass PTXReadSpecialRegisterIntrinsic_v4i32 { +// Accessing special registers. +multiclass PTXReadSRegIntrinsic_v4i32 { // FIXME: Do we need the 128-bit integer type version? // def _r64 : Intrinsic<[llvm_i128_ty], [], [IntrNoMem]>; @@ -3676,71 +3636,99 @@ multiclass PTXReadSpecialRegisterIntrinsic_v4i32 { // def _v4i16 : Intrinsic<[llvm_v4i32_ty], [], [IntrNoMem]>; def _x : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # regname # "_x">; def _y : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # regname # "_y">; def _z : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # regname # "_z">; def _w : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # regname # "_w">; } -class PTXReadSpecialRegisterIntrinsic_r32 +class PTXReadSRegIntrinsic_r32 : Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>, - GCCBuiltin; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # name>; -class PTXReadSpecialRegisterIntrinsic_r64 +class PTXReadSRegIntrinsic_r64 : Intrinsic<[llvm_i64_ty], [], [IntrNoMem]>, - GCCBuiltin; - -defm int_ptx_read_tid : PTXReadSpecialRegisterIntrinsic_v4i32 - <"__builtin_ptx_read_tid">; -defm int_ptx_read_ntid : PTXReadSpecialRegisterIntrinsic_v4i32 - <"__builtin_ptx_read_ntid">; - -def int_ptx_read_laneid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_laneid">; -def int_ptx_read_warpid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_warpid">; -def int_ptx_read_nwarpid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_nwarpid">; - -defm int_ptx_read_ctaid : PTXReadSpecialRegisterIntrinsic_v4i32 - <"__builtin_ptx_read_ctaid">; -defm int_ptx_read_nctaid : PTXReadSpecialRegisterIntrinsic_v4i32 - <"__builtin_ptx_read_nctaid">; - -def int_ptx_read_smid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_smid">; -def int_ptx_read_nsmid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_nsmid">; -def int_ptx_read_gridid : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_gridid">; - -def int_ptx_read_lanemask_eq : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_lanemask_eq">; -def int_ptx_read_lanemask_le : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_lanemask_le">; -def int_ptx_read_lanemask_lt : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_lanemask_lt">; -def int_ptx_read_lanemask_ge : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_lanemask_ge">; -def int_ptx_read_lanemask_gt : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_lanemask_gt">; - -def int_ptx_read_clock : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_clock">; -def int_ptx_read_clock64 : PTXReadSpecialRegisterIntrinsic_r64 - <"__builtin_ptx_read_clock64">; - -def int_ptx_read_pm0 : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_pm0">; -def int_ptx_read_pm1 : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_pm1">; -def int_ptx_read_pm2 : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_pm2">; -def int_ptx_read_pm3 : PTXReadSpecialRegisterIntrinsic_r32 - <"__builtin_ptx_read_pm3">; - -def int_ptx_bar_sync : Intrinsic<[], [llvm_i32_ty], []>, - GCCBuiltin<"__builtin_ptx_bar_sync">; + GCCBuiltin<"__nvvm_read_ptx_sreg_" # name>; + +defm int_nvvm_read_ptx_sreg_tid : PTXReadSRegIntrinsic_v4i32<"tid">; +defm int_nvvm_read_ptx_sreg_ntid : PTXReadSRegIntrinsic_v4i32<"ntid">; + +def int_nvvm_read_ptx_sreg_laneid : PTXReadSRegIntrinsic_r32<"laneid">; +def int_nvvm_read_ptx_sreg_warpid : PTXReadSRegIntrinsic_r32<"warpid">; +def int_nvvm_read_ptx_sreg_nwarpid : PTXReadSRegIntrinsic_r32<"nwarpid">; + +defm int_nvvm_read_ptx_sreg_ctaid : PTXReadSRegIntrinsic_v4i32<"ctaid">; +defm int_nvvm_read_ptx_sreg_nctaid : PTXReadSRegIntrinsic_v4i32<"nctaid">; + +def int_nvvm_read_ptx_sreg_smid : PTXReadSRegIntrinsic_r32<"smid">; +def int_nvvm_read_ptx_sreg_nsmid : PTXReadSRegIntrinsic_r32<"nsmid">; +def int_nvvm_read_ptx_sreg_gridid : PTXReadSRegIntrinsic_r32<"gridid">; + +def int_nvvm_read_ptx_sreg_lanemask_eq : + PTXReadSRegIntrinsic_r32<"lanemask_eq">; +def int_nvvm_read_ptx_sreg_lanemask_le : + PTXReadSRegIntrinsic_r32<"lanemask_le">; +def int_nvvm_read_ptx_sreg_lanemask_lt : + PTXReadSRegIntrinsic_r32<"lanemask_lt">; +def int_nvvm_read_ptx_sreg_lanemask_ge : + PTXReadSRegIntrinsic_r32<"lanemask_ge">; +def int_nvvm_read_ptx_sreg_lanemask_gt : + PTXReadSRegIntrinsic_r32<"lanemask_gt">; + +def int_nvvm_read_ptx_sreg_clock : PTXReadSRegIntrinsic_r32<"clock">; +def int_nvvm_read_ptx_sreg_clock64 : PTXReadSRegIntrinsic_r64<"clock64">; + +def int_nvvm_read_ptx_sreg_pm0 : PTXReadSRegIntrinsic_r32<"pm0">; +def int_nvvm_read_ptx_sreg_pm1 : PTXReadSRegIntrinsic_r32<"pm1">; +def int_nvvm_read_ptx_sreg_pm2 : PTXReadSRegIntrinsic_r32<"pm2">; +def int_nvvm_read_ptx_sreg_pm3 : PTXReadSRegIntrinsic_r32<"pm3">; + +def int_nvvm_read_ptx_sreg_warpsize : PTXReadSRegIntrinsic_r32<"warpsize">; + +// +// SHUFFLE +// + +// shfl.down.b32 dest, val, offset, mask_and_clamp +def int_nvvm_shfl_down_i32 : + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.down.i32">, + GCCBuiltin<"__nvvm_shfl_down_i32">; +def int_nvvm_shfl_down_f32 : + Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.down.f32">, + GCCBuiltin<"__nvvm_shfl_down_f32">; + +// shfl.up.b32 dest, val, offset, mask_and_clamp +def int_nvvm_shfl_up_i32 : + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.up.i32">, + GCCBuiltin<"__nvvm_shfl_up_i32">; +def int_nvvm_shfl_up_f32 : + Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.up.f32">, + GCCBuiltin<"__nvvm_shfl_up_f32">; + +// shfl.bfly.b32 dest, val, offset, mask_and_clamp +def int_nvvm_shfl_bfly_i32 : + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.bfly.i32">, + GCCBuiltin<"__nvvm_shfl_bfly_i32">; +def int_nvvm_shfl_bfly_f32 : + Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.bfly.f32">, + GCCBuiltin<"__nvvm_shfl_bfly_f32">; + +// shfl.idx.b32 dest, val, lane, mask_and_clamp +def int_nvvm_shfl_idx_i32 : + Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.idx.i32">, + GCCBuiltin<"__nvvm_shfl_idx_i32">; +def int_nvvm_shfl_idx_f32 : + Intrinsic<[llvm_float_ty], [llvm_float_ty, llvm_i32_ty, llvm_i32_ty], + [IntrNoMem, IntrConvergent], "llvm.nvvm.shfl.idx.f32">, + GCCBuiltin<"__nvvm_shfl_idx_f32">; +} diff --git a/include/llvm/IR/IntrinsicsPowerPC.td b/include/llvm/IR/IntrinsicsPowerPC.td index 5512b1063fb021e8987975223a4890f831b8cd6e..e195c0ebac3a2ccf0427d4cc442bd7594a303c54 100644 --- a/include/llvm/IR/IntrinsicsPowerPC.td +++ b/include/llvm/IR/IntrinsicsPowerPC.td @@ -23,9 +23,9 @@ let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.". def int_ppc_dcbi : Intrinsic<[], [llvm_ptr_ty], []>; def int_ppc_dcbst : Intrinsic<[], [llvm_ptr_ty], []>; def int_ppc_dcbt : Intrinsic<[], [llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_ppc_dcbtst: Intrinsic<[], [llvm_ptr_ty], - [IntrReadWriteArgMem, NoCapture<0>]>; + [IntrArgMemOnly, NoCapture<0>]>; def int_ppc_dcbz : Intrinsic<[], [llvm_ptr_ty], []>; def int_ppc_dcbzl : Intrinsic<[], [llvm_ptr_ty], []>; @@ -189,33 +189,33 @@ let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.". // Loads. These don't map directly to GCC builtins because they represent the // source address with a single pointer. def int_ppc_altivec_lvx : - Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_ppc_altivec_lvxl : - Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_ppc_altivec_lvebx : - Intrinsic<[llvm_v16i8_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v16i8_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_ppc_altivec_lvehx : - Intrinsic<[llvm_v8i16_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v8i16_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_ppc_altivec_lvewx : - Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; // Stores. These don't map directly to GCC builtins because they represent the // source address with a single pointer. def int_ppc_altivec_stvx : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_ppc_altivec_stvxl : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_ppc_altivec_stvebx : Intrinsic<[], [llvm_v16i8_ty, llvm_ptr_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_ppc_altivec_stvehx : Intrinsic<[], [llvm_v8i16_ty, llvm_ptr_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_ppc_altivec_stvewx : Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; // Comparisons setting a vector. def int_ppc_altivec_vcmpbfp : GCCBuiltin<"__builtin_altivec_vcmpbfp">, @@ -664,15 +664,15 @@ let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.". // Vector load. def int_ppc_vsx_lxvw4x : - Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_ppc_vsx_lxvd2x : - Intrinsic<[llvm_v2f64_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v2f64_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; // Vector store. def int_ppc_vsx_stxvw4x : - Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], [IntrReadWriteArgMem]>; + Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty], [IntrArgMemOnly]>; def int_ppc_vsx_stxvd2x : - Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], [IntrReadWriteArgMem]>; + Intrinsic<[], [llvm_v2f64_ty, llvm_ptr_ty], [IntrArgMemOnly]>; // Vector and scalar maximum. def int_ppc_vsx_xvmaxdp : PowerPC_VSX_Vec_DDD_Intrinsic<"xvmaxdp">; @@ -790,7 +790,7 @@ class PowerPC_QPX_FFFF_Intrinsic /// and returns a v4f64. class PowerPC_QPX_Load_Intrinsic : PowerPC_QPX_Intrinsic; + [llvm_v4f64_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; /// PowerPC_QPX_LoadPerm_Intrinsic - A PowerPC intrinsic that takes a pointer /// and returns a v4f64 permutation. @@ -803,7 +803,7 @@ class PowerPC_QPX_LoadPerm_Intrinsic class PowerPC_QPX_Store_Intrinsic : PowerPC_QPX_Intrinsic; + [IntrArgMemOnly]>; //===----------------------------------------------------------------------===// // PowerPC QPX Intrinsic Definitions. diff --git a/include/llvm/IR/IntrinsicsSystemZ.td b/include/llvm/IR/IntrinsicsSystemZ.td index 96e7ca52569642ecc3f138e0204a6f7a04728f60..bfc15b9bc09ea05bf4e94506449dc902d7e09275 100644 --- a/include/llvm/IR/IntrinsicsSystemZ.td +++ b/include/llvm/IR/IntrinsicsSystemZ.td @@ -217,7 +217,7 @@ let TargetPrefix = "s390" in { Intrinsic<[llvm_i32_ty], [], [IntrNoMem]>; def int_s390_ntstg : Intrinsic<[], [llvm_i64_ty, llvm_ptr64_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_s390_ppa_txassist : GCCBuiltin<"__builtin_tx_assist">, Intrinsic<[], [llvm_i32_ty]>; @@ -236,11 +236,11 @@ let TargetPrefix = "s390" in { def int_s390_vlbb : GCCBuiltin<"__builtin_s390_vlbb">, Intrinsic<[llvm_v16i8_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_s390_vll : GCCBuiltin<"__builtin_s390_vll">, Intrinsic<[llvm_v16i8_ty], [llvm_i32_ty, llvm_ptr_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_s390_vpdi : GCCBuiltin<"__builtin_s390_vpdi">, Intrinsic<[llvm_v2i64_ty], @@ -262,7 +262,7 @@ let TargetPrefix = "s390" in { Intrinsic<[], [llvm_v16i8_ty, llvm_i32_ty, llvm_ptr_ty], // In fact write-only but there's no property // for that. - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; defm int_s390_vupl : SystemZUnaryExtBHWF<"vupl">; defm int_s390_vupll : SystemZUnaryExtBHF<"vupll">; @@ -374,3 +374,14 @@ let TargetPrefix = "s390" in { [llvm_v2f64_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; } + +//===----------------------------------------------------------------------===// +// +// Misc intrinsics +// +//===----------------------------------------------------------------------===// + +let TargetPrefix = "s390" in { + def int_s390_tdc : Intrinsic<[llvm_i32_ty], [llvm_anyfloat_ty, llvm_i64_ty], + [IntrNoMem]>; +} diff --git a/include/llvm/IR/IntrinsicsWebAssembly.td b/include/llvm/IR/IntrinsicsWebAssembly.td index 3953aef43dad8d19ed94e77e44f5a9147ddd9afe..4234c466d9732f7504d3e40363e3c2ebc29cf9e1 100644 --- a/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/include/llvm/IR/IntrinsicsWebAssembly.td @@ -14,9 +14,9 @@ let TargetPrefix = "wasm" in { // All intrinsics start with "llvm.wasm.". -// Note that memory_size is not IntrNoMem because it must be sequenced with +// Note that current_memory is not IntrNoMem because it must be sequenced with // respect to grow_memory calls. -def int_wasm_memory_size : Intrinsic<[llvm_anyint_ty], [], [IntrReadMem]>; +def int_wasm_current_memory : Intrinsic<[llvm_anyint_ty], [], [IntrReadMem]>; def int_wasm_grow_memory : Intrinsic<[], [llvm_anyint_ty], []>; } diff --git a/include/llvm/IR/IntrinsicsX86.td b/include/llvm/IR/IntrinsicsX86.td index b93a0b9d22270ce000c1339b2b739939ae89e18a..74c971552bb323631048268eb6c18b0c81a774f3 100644 --- a/include/llvm/IR/IntrinsicsX86.td +++ b/include/llvm/IR/IntrinsicsX86.td @@ -25,6 +25,9 @@ let TargetPrefix = "x86" in { // Marks the EH registration node created in LLVM IR prior to code generation. def int_x86_seh_ehregnode : Intrinsic<[], [llvm_ptr_ty], []>; + // Marks the EH guard slot node created in LLVM IR prior to code generation. + def int_x86_seh_ehguard : Intrinsic<[], [llvm_ptr_ty], []>; + // Given a pointer to the end of an EH registration object, returns the true // parent frame address that can be used with llvm.localrecover. def int_x86_seh_recoverfp : Intrinsic<[llvm_ptr_ty], @@ -51,7 +54,7 @@ let TargetPrefix = "x86" in { def int_x86_rdtsc : GCCBuiltin<"__builtin_ia32_rdtsc">, Intrinsic<[llvm_i64_ty], [], []>; def int_x86_rdtscp : GCCBuiltin<"__builtin_ia32_rdtscp">, - Intrinsic<[llvm_i64_ty], [llvm_ptr_ty], [IntrReadWriteArgMem]>; + Intrinsic<[llvm_i64_ty], [llvm_ptr_ty], [IntrArgMemOnly]>; } // Read Performance-Monitoring Counter. @@ -142,16 +145,16 @@ let TargetPrefix = "x86" in { // Arithmetic ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse_add_ss : GCCBuiltin<"__builtin_ia32_addss">, + def int_x86_sse_add_ss : Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_sse_sub_ss : GCCBuiltin<"__builtin_ia32_subss">, + def int_x86_sse_sub_ss : Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_sse_mul_ss : GCCBuiltin<"__builtin_ia32_mulss">, + def int_x86_sse_mul_ss : Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_sse_div_ss : GCCBuiltin<"__builtin_ia32_divss">, + def int_x86_sse_div_ss : Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty], [IntrNoMem]>; def int_x86_sse_sqrt_ss : GCCBuiltin<"__builtin_ia32_sqrtss">, @@ -191,7 +194,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse_cmp_ss : GCCBuiltin<"__builtin_ia32_cmpss">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_sse_cmp_ps : GCCBuiltin<"__builtin_ia32_cmpps">, + def int_x86_sse_cmp_ps : Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_sse_comieq_ss : GCCBuiltin<"__builtin_ia32_comieq">, @@ -259,13 +262,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_x86mmx_ty], [IntrNoMem]>; } -// SIMD store ops -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse_storeu_ps : GCCBuiltin<"__builtin_ia32_storeups">, - Intrinsic<[], [llvm_ptr_ty, - llvm_v4f32_ty], [IntrReadWriteArgMem]>; -} - // Cacheability support ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse_sfence : GCCBuiltin<"__builtin_ia32_sfence">, @@ -291,16 +287,16 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // FP arithmetic ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse2_add_sd : GCCBuiltin<"__builtin_ia32_addsd">, + def int_x86_sse2_add_sd : Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty], [IntrNoMem]>; - def int_x86_sse2_sub_sd : GCCBuiltin<"__builtin_ia32_subsd">, + def int_x86_sse2_sub_sd : Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty], [IntrNoMem]>; - def int_x86_sse2_mul_sd : GCCBuiltin<"__builtin_ia32_mulsd">, + def int_x86_sse2_mul_sd : Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty], [IntrNoMem]>; - def int_x86_sse2_div_sd : GCCBuiltin<"__builtin_ia32_divsd">, + def int_x86_sse2_div_sd : Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty], [IntrNoMem]>; def int_x86_sse2_sqrt_sd : GCCBuiltin<"__builtin_ia32_sqrtsd">, @@ -328,7 +324,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse2_cmp_sd : GCCBuiltin<"__builtin_ia32_cmpsd">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_sse2_cmp_pd : GCCBuiltin<"__builtin_ia32_cmppd">, + def int_x86_sse2_cmp_pd : Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_sse2_comieq_sd : GCCBuiltin<"__builtin_ia32_comisdeq">, @@ -413,18 +409,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse2_pavg_w : GCCBuiltin<"__builtin_ia32_pavgw128">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem, Commutative]>; - def int_x86_sse2_pmaxu_b : GCCBuiltin<"__builtin_ia32_pmaxub128">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, - llvm_v16i8_ty], [IntrNoMem, Commutative]>; - def int_x86_sse2_pmaxs_w : GCCBuiltin<"__builtin_ia32_pmaxsw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, - llvm_v8i16_ty], [IntrNoMem, Commutative]>; - def int_x86_sse2_pminu_b : GCCBuiltin<"__builtin_ia32_pminub128">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, - llvm_v16i8_ty], [IntrNoMem, Commutative]>; - def int_x86_sse2_pmins_w : GCCBuiltin<"__builtin_ia32_pminsw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, - llvm_v8i16_ty], [IntrNoMem, Commutative]>; def int_x86_sse2_psad_bw : GCCBuiltin<"__builtin_ia32_psadbw128">, Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem, Commutative]>; @@ -485,8 +469,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Conversion ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse2_cvtdq2pd : GCCBuiltin<"__builtin_ia32_cvtdq2pd">, - Intrinsic<[llvm_v2f64_ty], [llvm_v4i32_ty], [IntrNoMem]>; def int_x86_sse2_cvtdq2ps : GCCBuiltin<"__builtin_ia32_cvtdq2ps">, Intrinsic<[llvm_v4f32_ty], [llvm_v4i32_ty], [IntrNoMem]>; def int_x86_sse2_cvtpd2dq : GCCBuiltin<"__builtin_ia32_cvtpd2dq">, @@ -497,10 +479,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v4f32_ty], [llvm_v2f64_ty], [IntrNoMem]>; def int_x86_sse2_cvtps2dq : GCCBuiltin<"__builtin_ia32_cvtps2dq">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_sse2_cvttps2dq : GCCBuiltin<"__builtin_ia32_cvttps2dq">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_sse2_cvtps2pd : GCCBuiltin<"__builtin_ia32_cvtps2pd">, - Intrinsic<[llvm_v2f64_ty], [llvm_v4f32_ty], [IntrNoMem]>; def int_x86_sse2_cvtsd2si : GCCBuiltin<"__builtin_ia32_cvtsd2si">, Intrinsic<[llvm_i32_ty], [llvm_v2f64_ty], [IntrNoMem]>; def int_x86_sse2_cvtsd2si64 : GCCBuiltin<"__builtin_ia32_cvtsd2si64">, @@ -529,19 +507,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v2f64_ty], [llvm_x86mmx_ty], [IntrNoMem]>; } -// SIMD store ops -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse2_storeu_pd : GCCBuiltin<"__builtin_ia32_storeupd">, - Intrinsic<[], [llvm_ptr_ty, - llvm_v2f64_ty], [IntrReadWriteArgMem]>; - def int_x86_sse2_storeu_dq : GCCBuiltin<"__builtin_ia32_storedqu">, - Intrinsic<[], [llvm_ptr_ty, - llvm_v16i8_ty], [IntrReadWriteArgMem]>; - def int_x86_sse2_storel_dq : GCCBuiltin<"__builtin_ia32_storelv4si">, - Intrinsic<[], [llvm_ptr_ty, - llvm_v4i32_ty], [IntrReadWriteArgMem]>; -} - // Misc. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse2_packsswb_128 : GCCBuiltin<"__builtin_ia32_packsswb128">, @@ -688,15 +653,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_ssse3_pshuf_b_128 : GCCBuiltin<"__builtin_ia32_pshufb128">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>; - def int_x86_sse2_pshuf_d : GCCBuiltin<"__builtin_ia32_pshufd">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_sse2_pshufl_w : GCCBuiltin<"__builtin_ia32_pshuflw">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_sse2_pshufh_w : GCCBuiltin<"__builtin_ia32_pshufhw">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; def int_x86_sse_pshuf_w : GCCBuiltin<"__builtin_ia32_pshufw">, Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i8_ty], [IntrNoMem]>; @@ -763,46 +719,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_i32_ty], [IntrNoMem]>; } -// Vector sign and zero extend -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse41_pmovsxbd : GCCBuiltin<"__builtin_ia32_pmovsxbd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovsxbq : GCCBuiltin<"__builtin_ia32_pmovsxbq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovsxbw : GCCBuiltin<"__builtin_ia32_pmovsxbw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovsxdq : GCCBuiltin<"__builtin_ia32_pmovsxdq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v4i32_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovsxwd : GCCBuiltin<"__builtin_ia32_pmovsxwd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovsxwq : GCCBuiltin<"__builtin_ia32_pmovsxwq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxbd : GCCBuiltin<"__builtin_ia32_pmovzxbd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxbq : GCCBuiltin<"__builtin_ia32_pmovzxbq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxbw : GCCBuiltin<"__builtin_ia32_pmovzxbw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxdq : GCCBuiltin<"__builtin_ia32_pmovzxdq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v4i32_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxwd : GCCBuiltin<"__builtin_ia32_pmovzxwd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_sse41_pmovzxwq : GCCBuiltin<"__builtin_ia32_pmovzxwq128">, - Intrinsic<[llvm_v2i64_ty], [llvm_v8i16_ty], - [IntrNoMem]>; -} - // Vector min element let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse41_phminposuw : GCCBuiltin<"__builtin_ia32_phminposuw128">, @@ -810,34 +726,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem]>; } -// Vector compare, min, max -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse41_pmaxsb : GCCBuiltin<"__builtin_ia32_pmaxsb128">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pmaxsd : GCCBuiltin<"__builtin_ia32_pmaxsd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pmaxud : GCCBuiltin<"__builtin_ia32_pmaxud128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pmaxuw : GCCBuiltin<"__builtin_ia32_pmaxuw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pminsb : GCCBuiltin<"__builtin_ia32_pminsb128">, - Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pminsd : GCCBuiltin<"__builtin_ia32_pminsd128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pminud : GCCBuiltin<"__builtin_ia32_pminud128">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], - [IntrNoMem, Commutative]>; - def int_x86_sse41_pminuw : GCCBuiltin<"__builtin_ia32_pminuw128">, - Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], - [IntrNoMem, Commutative]>; -} - // Advanced Encryption Standard (AES) Instructions let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_aesni_aesimc : GCCBuiltin<"__builtin_ia32_aesimc128">, @@ -882,22 +770,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem, Commutative]>; } -// Vector extract -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_sse41_pextrb : - Intrinsic<[llvm_i32_ty], [llvm_v16i8_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_sse41_pextrd : - Intrinsic<[llvm_i32_ty], [llvm_v4i32_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_sse41_pextrq : - Intrinsic<[llvm_i64_ty], [llvm_v2i64_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_sse41_extractps : GCCBuiltin<"__builtin_ia32_extractps128">, - Intrinsic<[llvm_i32_ty], [llvm_v4f32_ty, llvm_i32_ty], - [IntrNoMem]>; -} - // Vector insert let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_sse41_insertps : GCCBuiltin<"__builtin_ia32_insertps128">, @@ -1056,11 +928,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_i8_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_sse4a_insertq : GCCBuiltin<"__builtin_ia32_insertq">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty], [IntrNoMem]>; - - def int_x86_sse4a_movnt_ss : GCCBuiltin<"__builtin_ia32_movntss">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4f32_ty], []>; - def int_x86_sse4a_movnt_sd : GCCBuiltin<"__builtin_ia32_movntsd">, - Intrinsic<[], [llvm_ptr_ty, llvm_v2f64_ty], []>; } //===----------------------------------------------------------------------===// @@ -1471,42 +1338,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_vpermil_pd_128 : - GCCBuiltin<"__builtin_ia32_vpermilpd_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_i32_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_vpermil_pd_256 : - GCCBuiltin<"__builtin_ia32_vpermilpd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_i32_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_vpermil_pd_512 : - GCCBuiltin<"__builtin_ia32_vpermilpd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_i32_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_vpermil_ps_128 : - GCCBuiltin<"__builtin_ia32_vpermilps_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_i32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_vpermil_ps_256 : - GCCBuiltin<"__builtin_ia32_vpermilps256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_i32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_vpermil_ps_512 : - GCCBuiltin<"__builtin_ia32_vpermilps512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_i32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_vpermilvar_pd_256 : GCCBuiltin<"__builtin_ia32_vpermilvarpd256_mask">, Intrinsic<[llvm_v4f64_ty], @@ -1561,60 +1392,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pshuf_d_128 : - GCCBuiltin<"__builtin_ia32_pshufd128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_i16_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshuf_d_256 : - GCCBuiltin<"__builtin_ia32_pshufd256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_i16_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshuf_d_512 : - GCCBuiltin<"__builtin_ia32_pshufd512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_i16_ty, llvm_v16i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufh_w_128 : - GCCBuiltin<"__builtin_ia32_pshufhw128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_i32_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufh_w_256 : - GCCBuiltin<"__builtin_ia32_pshufhw256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_i32_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufh_w_512 : - GCCBuiltin<"__builtin_ia32_pshufhw512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_i32_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufl_w_128 : - GCCBuiltin<"__builtin_ia32_pshuflw128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_i32_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufl_w_256 : - GCCBuiltin<"__builtin_ia32_pshuflw256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_i32_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pshufl_w_512 : - GCCBuiltin<"__builtin_ia32_pshuflw512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_i32_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_shuf_f32x4_256 : GCCBuiltin<"__builtin_ia32_shuf_f32x4_256_mask">, Intrinsic<[llvm_v8f32_ty], @@ -1698,60 +1475,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_movshdup_128 : - GCCBuiltin<"__builtin_ia32_movshdup128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movshdup_256 : - GCCBuiltin<"__builtin_ia32_movshdup256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movshdup_512 : - GCCBuiltin<"__builtin_ia32_movshdup512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movsldup_128 : - GCCBuiltin<"__builtin_ia32_movsldup128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movsldup_256 : - GCCBuiltin<"__builtin_ia32_movsldup256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movsldup_512 : - GCCBuiltin<"__builtin_ia32_movsldup512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movddup_128 : - GCCBuiltin<"__builtin_ia32_movddup128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movddup_256 : - GCCBuiltin<"__builtin_ia32_movddup256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_movddup_512 : - GCCBuiltin<"__builtin_ia32_movddup512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrNoMem]>; } // Vector blend @@ -1773,32 +1496,24 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Vector compare let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx_cmp_pd_256 : GCCBuiltin<"__builtin_ia32_cmppd256">, + def int_x86_avx_cmp_pd_256 : Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx_cmp_ps_256 : GCCBuiltin<"__builtin_ia32_cmpps256">, + def int_x86_avx_cmp_ps_256 : Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; } // Vector convert let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx_cvtdq2_pd_256 : GCCBuiltin<"__builtin_ia32_cvtdq2pd256">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4i32_ty], [IntrNoMem]>; def int_x86_avx_cvtdq2_ps_256 : GCCBuiltin<"__builtin_ia32_cvtdq2ps256">, Intrinsic<[llvm_v8f32_ty], [llvm_v8i32_ty], [IntrNoMem]>; def int_x86_avx_cvt_pd2_ps_256 : GCCBuiltin<"__builtin_ia32_cvtpd2ps256">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f64_ty], [IntrNoMem]>; def int_x86_avx_cvt_ps2dq_256 : GCCBuiltin<"__builtin_ia32_cvtps2dq256">, Intrinsic<[llvm_v8i32_ty], [llvm_v8f32_ty], [IntrNoMem]>; - def int_x86_avx_cvt_ps2_pd_256 : GCCBuiltin<"__builtin_ia32_cvtps2pd256">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4f32_ty], [IntrNoMem]>; - def int_x86_avx_cvtt_pd2dq_256 : GCCBuiltin<"__builtin_ia32_cvttpd2dq256">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4f64_ty], [IntrNoMem]>; def int_x86_avx_cvt_pd2dq_256 : GCCBuiltin<"__builtin_ia32_cvtpd2dq256">, Intrinsic<[llvm_v4i32_ty], [llvm_v4f64_ty], [IntrNoMem]>; - def int_x86_avx_cvtt_ps2dq_256 : GCCBuiltin<"__builtin_ia32_cvttps2dq256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8f32_ty], [IntrNoMem]>; } // Vector bit test @@ -1977,10 +1692,10 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx_vbroadcastf128_pd_256 : GCCBuiltin<"__builtin_ia32_vbroadcastf128_pd256">, - Intrinsic<[llvm_v4f64_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v4f64_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx_vbroadcastf128_ps_256 : GCCBuiltin<"__builtin_ia32_vbroadcastf128_ps256">, - Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; + Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; } // SIMD load ops @@ -1989,82 +1704,20 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v32i8_ty], [llvm_ptr_ty], [IntrReadMem]>; } -// SIMD store ops -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx_storeu_pd_256 : GCCBuiltin<"__builtin_ia32_storeupd256">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4f64_ty], [IntrReadWriteArgMem]>; - def int_x86_avx_storeu_ps_256 : GCCBuiltin<"__builtin_ia32_storeups256">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8f32_ty], [IntrReadWriteArgMem]>; - def int_x86_avx_storeu_dq_256 : GCCBuiltin<"__builtin_ia32_storedqu256">, - Intrinsic<[], [llvm_ptr_ty, llvm_v32i8_ty], [IntrReadWriteArgMem]>; -} - // Conditional load ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx_maskload_pd : GCCBuiltin<"__builtin_ia32_maskloadpd">, Intrinsic<[llvm_v2f64_ty], [llvm_ptr_ty, llvm_v2i64_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx_maskload_ps : GCCBuiltin<"__builtin_ia32_maskloadps">, Intrinsic<[llvm_v4f32_ty], [llvm_ptr_ty, llvm_v4i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx_maskload_pd_256 : GCCBuiltin<"__builtin_ia32_maskloadpd256">, Intrinsic<[llvm_v4f64_ty], [llvm_ptr_ty, llvm_v4i64_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx_maskload_ps_256 : GCCBuiltin<"__builtin_ia32_maskloadps256">, Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty, llvm_v8i32_ty], - [IntrReadArgMem]>; - - def int_x86_avx512_mask_loadu_ps_128 : - GCCBuiltin<"__builtin_ia32_loadups128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_ps_256 : - GCCBuiltin<"__builtin_ia32_loadups256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_ps_512 : - GCCBuiltin<"__builtin_ia32_loadups512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_loadu_pd_128 : - GCCBuiltin<"__builtin_ia32_loadupd128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_pd_256 : - GCCBuiltin<"__builtin_ia32_loadupd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_pd_512 : - GCCBuiltin<"__builtin_ia32_loadupd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_load_ps_128 : - GCCBuiltin<"__builtin_ia32_loadaps128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_ps_256 : - GCCBuiltin<"__builtin_ia32_loadaps256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_ps_512 : - GCCBuiltin<"__builtin_ia32_loadaps512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_load_pd_128 : - GCCBuiltin<"__builtin_ia32_loadapd128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_pd_256 : - GCCBuiltin<"__builtin_ia32_loadapd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_pd_512 : - GCCBuiltin<"__builtin_ia32_loadapd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; } // Conditional move ops @@ -2079,173 +1732,31 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_mova_pd_128 : - GCCBuiltin<"__builtin_ia32_movapd128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_mova_pd_256 : - GCCBuiltin<"__builtin_ia32_movapd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_mova_pd_512 : - GCCBuiltin<"__builtin_ia32_movapd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_mova_ps_128 : - GCCBuiltin<"__builtin_ia32_movaps128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_mova_ps_256 : - GCCBuiltin<"__builtin_ia32_movaps256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_mova_ps_512 : - GCCBuiltin<"__builtin_ia32_movaps512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_mova_q_128 : - GCCBuiltin<"__builtin_ia32_movdqa64_128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_mova_q_256 : - GCCBuiltin<"__builtin_ia32_movdqa64_256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_mova_q_512 : - GCCBuiltin<"__builtin_ia32_movdqa64_512_mask">, - Intrinsic<[llvm_v8i64_ty], - [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_mova_d_128 : - GCCBuiltin<"__builtin_ia32_movdqa32_128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_mova_d_256 : - GCCBuiltin<"__builtin_ia32_movdqa32_256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_mova_d_512 : - GCCBuiltin<"__builtin_ia32_movdqa32_512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_movu_w_128 : - GCCBuiltin<"__builtin_ia32_movdquhi128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_movu_w_256 : - GCCBuiltin<"__builtin_ia32_movdquhi256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_movu_w_512 : - GCCBuiltin<"__builtin_ia32_movdquhi512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_movu_b_128 : - GCCBuiltin<"__builtin_ia32_movdquqi128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_movu_b_256 : - GCCBuiltin<"__builtin_ia32_movdquqi256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_movu_b_512 : - GCCBuiltin<"__builtin_ia32_movdquqi512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; } // Conditional store ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx_maskstore_pd : GCCBuiltin<"__builtin_ia32_maskstorepd">, Intrinsic<[], [llvm_ptr_ty, - llvm_v2i64_ty, llvm_v2f64_ty], [IntrReadWriteArgMem]>; + llvm_v2i64_ty, llvm_v2f64_ty], [IntrArgMemOnly]>; def int_x86_avx_maskstore_ps : GCCBuiltin<"__builtin_ia32_maskstoreps">, Intrinsic<[], [llvm_ptr_ty, - llvm_v4i32_ty, llvm_v4f32_ty], [IntrReadWriteArgMem]>; + llvm_v4i32_ty, llvm_v4f32_ty], [IntrArgMemOnly]>; def int_x86_avx_maskstore_pd_256 : GCCBuiltin<"__builtin_ia32_maskstorepd256">, Intrinsic<[], [llvm_ptr_ty, - llvm_v4i64_ty, llvm_v4f64_ty], [IntrReadWriteArgMem]>; + llvm_v4i64_ty, llvm_v4f64_ty], [IntrArgMemOnly]>; def int_x86_avx_maskstore_ps_256 : GCCBuiltin<"__builtin_ia32_maskstoreps256">, Intrinsic<[], [llvm_ptr_ty, - llvm_v8i32_ty, llvm_v8f32_ty], [IntrReadWriteArgMem]>; - - def int_x86_avx512_mask_storeu_ps_128 : - GCCBuiltin<"__builtin_ia32_storeups128_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_ps_256 : - GCCBuiltin<"__builtin_ia32_storeups256_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_ps_512 : - GCCBuiltin<"__builtin_ia32_storeups512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; - - def int_x86_avx512_mask_storeu_pd_128 : - GCCBuiltin<"__builtin_ia32_storeupd128_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_pd_256 : - GCCBuiltin<"__builtin_ia32_storeupd256_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_pd_512 : - GCCBuiltin<"__builtin_ia32_storeupd512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - - def int_x86_avx512_mask_store_ps_128 : - GCCBuiltin<"__builtin_ia32_storeaps128_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_store_ps_256 : - GCCBuiltin<"__builtin_ia32_storeaps256_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_store_ps_512 : - GCCBuiltin<"__builtin_ia32_storeaps512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; - - def int_x86_avx512_mask_store_pd_128 : - GCCBuiltin<"__builtin_ia32_storeapd128_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_store_pd_256 : - GCCBuiltin<"__builtin_ia32_storeapd256_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_store_pd_512 : - GCCBuiltin<"__builtin_ia32_storeapd512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + llvm_v8i32_ty, llvm_v8f32_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_store_ss : GCCBuiltin<"__builtin_ia32_storess_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; } -// Store ops using non-temporal hint -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_storent_q_512 : - GCCBuiltin<"__builtin_ia32_movntdq512">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty], [IntrReadWriteArgMem]>; - def int_x86_avx512_storent_pd_512 : - GCCBuiltin<"__builtin_ia32_movntpd512">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8f64_ty], [IntrReadWriteArgMem]>; - def int_x86_avx512_storent_ps_512 : - GCCBuiltin<"__builtin_ia32_movntps512">, - Intrinsic<[], [llvm_ptr_ty, llvm_v16f32_ty], [IntrReadWriteArgMem]>; -} //===----------------------------------------------------------------------===// // AVX2 @@ -2303,42 +1814,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Vector min, max let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx2_pmaxu_b : GCCBuiltin<"__builtin_ia32_pmaxub256">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, - llvm_v32i8_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmaxu_w : GCCBuiltin<"__builtin_ia32_pmaxuw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_v16i16_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmaxu_d : GCCBuiltin<"__builtin_ia32_pmaxud256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_v8i32_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmaxs_b : GCCBuiltin<"__builtin_ia32_pmaxsb256">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, - llvm_v32i8_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmaxs_w : GCCBuiltin<"__builtin_ia32_pmaxsw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_v16i16_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmaxs_d : GCCBuiltin<"__builtin_ia32_pmaxsd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_v8i32_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pminu_b : GCCBuiltin<"__builtin_ia32_pminub256">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, - llvm_v32i8_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pminu_w : GCCBuiltin<"__builtin_ia32_pminuw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_v16i16_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pminu_d : GCCBuiltin<"__builtin_ia32_pminud256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_v8i32_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmins_b : GCCBuiltin<"__builtin_ia32_pminsb256">, - Intrinsic<[llvm_v32i8_ty], [llvm_v32i8_ty, - llvm_v32i8_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmins_w : GCCBuiltin<"__builtin_ia32_pminsw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty, - llvm_v16i16_ty], [IntrNoMem, Commutative]>; - def int_x86_avx2_pmins_d : GCCBuiltin<"__builtin_ia32_pminsd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, - llvm_v8i32_ty], [IntrNoMem, Commutative]>; def int_x86_avx512_mask_pmaxs_b_128 : GCCBuiltin<"__builtin_ia32_pmaxsb128_mask">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; @@ -2537,25 +2012,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pslli_d : GCCBuiltin<"__builtin_ia32_pslldi512">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, - llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pslli_q : GCCBuiltin<"__builtin_ia32_psllqi512">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_psrli_d : GCCBuiltin<"__builtin_ia32_psrldi512">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, - llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_psrli_q : GCCBuiltin<"__builtin_ia32_psrlqi512">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_psrai_d : GCCBuiltin<"__builtin_ia32_psradi512">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, - llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_psrai_q : GCCBuiltin<"__builtin_ia32_psraqi512">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i32_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_psrl_w_128 : GCCBuiltin<"__builtin_ia32_psrlw128_mask">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; @@ -2728,21 +2184,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v64i8_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; } -// Permute -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_mask_perm_df_256 : GCCBuiltin<"__builtin_ia32_permdf256_mask">, - Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, - llvm_i8_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_perm_df_512 : GCCBuiltin<"__builtin_ia32_permdf512_mask">, - Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, - llvm_i8_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_perm_di_256 : GCCBuiltin<"__builtin_ia32_permdi256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, - llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_perm_di_512 : GCCBuiltin<"__builtin_ia32_permdi512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, - llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; -} + // Pack ops. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_packsswb : GCCBuiltin<"__builtin_ia32_packsswb256">, @@ -2895,46 +2337,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; } -// Vector sign and zero extend -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx2_pmovsxbd : GCCBuiltin<"__builtin_ia32_pmovsxbd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovsxbq : GCCBuiltin<"__builtin_ia32_pmovsxbq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovsxbw : GCCBuiltin<"__builtin_ia32_pmovsxbw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovsxdq : GCCBuiltin<"__builtin_ia32_pmovsxdq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i32_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovsxwd : GCCBuiltin<"__builtin_ia32_pmovsxwd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovsxwq : GCCBuiltin<"__builtin_ia32_pmovsxwq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxbd : GCCBuiltin<"__builtin_ia32_pmovzxbd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxbq : GCCBuiltin<"__builtin_ia32_pmovzxbq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxbw : GCCBuiltin<"__builtin_ia32_pmovzxbw256">, - Intrinsic<[llvm_v16i16_ty], [llvm_v16i8_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxdq : GCCBuiltin<"__builtin_ia32_pmovzxdq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i32_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxwd : GCCBuiltin<"__builtin_ia32_pmovzxwd256">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i16_ty], - [IntrNoMem]>; - def int_x86_avx2_pmovzxwq : GCCBuiltin<"__builtin_ia32_pmovzxwq256">, - Intrinsic<[llvm_v4i64_ty], [llvm_v8i16_ty], - [IntrNoMem]>; -} - // Vector blend let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_pblendvb : GCCBuiltin<"__builtin_ia32_pblendvb256">, @@ -2999,7 +2401,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_mask_pbroadcast_q_mem_512 : GCCBuiltin<"__builtin_ia32_pbroadcastq512_mem_mask">, Intrinsic<[llvm_v8i64_ty], - [llvm_i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + [llvm_i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; } // Vector permutation @@ -3073,9 +2475,9 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem]>; def int_x86_avx512_mask_insertf32x4_512 : - GCCBuiltin<"__builtin_ia32_insertf32x4_512_mask">, + GCCBuiltin<"__builtin_ia32_insertf32x4_mask">, Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v4f32_ty, llvm_i32_ty, llvm_v16f32_ty, llvm_i8_ty], + [llvm_v16f32_ty, llvm_v4f32_ty, llvm_i32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_insertf32x8_512 : @@ -3109,9 +2511,9 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". [IntrNoMem]>; def int_x86_avx512_mask_inserti32x4_512 : - GCCBuiltin<"__builtin_ia32_inserti32x4_512_mask">, + GCCBuiltin<"__builtin_ia32_inserti32x4_mask">, Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_v16i32_ty, llvm_i8_ty], + [llvm_v16i32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_inserti32x8_512 : @@ -3143,190 +2545,34 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_maskload_d : GCCBuiltin<"__builtin_ia32_maskloadd">, Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty, llvm_v4i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_maskload_q : GCCBuiltin<"__builtin_ia32_maskloadq">, Intrinsic<[llvm_v2i64_ty], [llvm_ptr_ty, llvm_v2i64_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_maskload_d_256 : GCCBuiltin<"__builtin_ia32_maskloadd256">, Intrinsic<[llvm_v8i32_ty], [llvm_ptr_ty, llvm_v8i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_maskload_q_256 : GCCBuiltin<"__builtin_ia32_maskloadq256">, Intrinsic<[llvm_v4i64_ty], [llvm_ptr_ty, llvm_v4i64_ty], - [IntrReadArgMem]>; - - def int_x86_avx512_mask_loadu_b_128 : - GCCBuiltin<"__builtin_ia32_loaddquqi128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_ptr_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_b_256 : - GCCBuiltin<"__builtin_ia32_loaddquqi256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_ptr_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_b_512 : - GCCBuiltin<"__builtin_ia32_loaddquqi512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_ptr_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_loadu_w_128 : - GCCBuiltin<"__builtin_ia32_loaddquhi128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_ptr_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_w_256 : - GCCBuiltin<"__builtin_ia32_loaddquhi256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_ptr_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_w_512 : - GCCBuiltin<"__builtin_ia32_loaddquhi512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_ptr_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_loadu_d_128 : - GCCBuiltin<"__builtin_ia32_loaddqusi128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_d_256 : - GCCBuiltin<"__builtin_ia32_loaddqusi256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_d_512 : - GCCBuiltin<"__builtin_ia32_loaddqusi512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_loadu_q_128 : - GCCBuiltin<"__builtin_ia32_loaddqudi128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_q_256 : - GCCBuiltin<"__builtin_ia32_loaddqudi256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_loadu_q_512 : - GCCBuiltin<"__builtin_ia32_loaddqudi512_mask">, - Intrinsic<[llvm_v8i64_ty], - [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_load_d_128 : - GCCBuiltin<"__builtin_ia32_movdqa32load128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_d_256 : - GCCBuiltin<"__builtin_ia32_movdqa32load256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_d_512 : - GCCBuiltin<"__builtin_ia32_movdqa32load512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrReadArgMem]>; - - def int_x86_avx512_mask_load_q_128 : - GCCBuiltin<"__builtin_ia32_movdqa64load128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_q_256 : - GCCBuiltin<"__builtin_ia32_movdqa64load256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_load_q_512 : - GCCBuiltin<"__builtin_ia32_movdqa64load512_mask">, - Intrinsic<[llvm_v8i64_ty], - [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; } // Conditional store ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_maskstore_d : GCCBuiltin<"__builtin_ia32_maskstored">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_v4i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx2_maskstore_q : GCCBuiltin<"__builtin_ia32_maskstoreq">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_v2i64_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx2_maskstore_d_256 : GCCBuiltin<"__builtin_ia32_maskstored256">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_v8i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx2_maskstore_q_256 : GCCBuiltin<"__builtin_ia32_maskstoreq256">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_v4i64_ty], - [IntrReadWriteArgMem]>; - - def int_x86_avx512_mask_storeu_b_128 : - GCCBuiltin<"__builtin_ia32_storedquqi128_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_b_256 : - GCCBuiltin<"__builtin_ia32_storedquqi256_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_b_512 : - GCCBuiltin<"__builtin_ia32_storedquqi512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrReadWriteArgMem]>; - - def int_x86_avx512_mask_storeu_w_128 : - GCCBuiltin<"__builtin_ia32_storedquhi128_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_w_256 : - GCCBuiltin<"__builtin_ia32_storedquhi256_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_w_512 : - GCCBuiltin<"__builtin_ia32_storedquhi512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; - - def int_x86_avx512_mask_storeu_d_128 : - GCCBuiltin<"__builtin_ia32_storedqusi128_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_d_256 : - GCCBuiltin<"__builtin_ia32_storedqusi256_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_d_512 : - GCCBuiltin<"__builtin_ia32_storedqusi512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; - - def int_x86_avx512_mask_storeu_q_128 : - GCCBuiltin<"__builtin_ia32_storedqudi128_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_q_256 : - GCCBuiltin<"__builtin_ia32_storedqudi256_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_storeu_q_512 : - GCCBuiltin<"__builtin_ia32_storedqudi512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - - def int_x86_avx512_mask_store_d_128 : - GCCBuiltin<"__builtin_ia32_movdqa32store128_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_store_d_256 : - GCCBuiltin<"__builtin_ia32_movdqa32store256_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_store_d_512 : - GCCBuiltin<"__builtin_ia32_movdqa32store512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; - - def int_x86_avx512_mask_store_q_128 : - GCCBuiltin<"__builtin_ia32_movdqa64store128_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_store_q_256 : - GCCBuiltin<"__builtin_ia32_movdqa64store256_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; - def int_x86_avx512_mask_store_q_512 : - GCCBuiltin<"__builtin_ia32_movdqa64store512_mask">, - Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; } // Variable bit shift ops @@ -3388,12 +2634,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_psll_dq_512 : GCCBuiltin<"__builtin_ia32_pslldq512">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_psrl_dq_512 : GCCBuiltin<"__builtin_ia32_psrldq512">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_i32_ty], - [IntrNoMem]>; def int_x86_avx512_mask_psll_d_128 : GCCBuiltin<"__builtin_ia32_pslld128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, @@ -3553,68 +2793,68 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx2_gather_d_pd : GCCBuiltin<"__builtin_ia32_gatherd_pd">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_pd_256 : GCCBuiltin<"__builtin_ia32_gatherd_pd256">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_pd : GCCBuiltin<"__builtin_ia32_gatherq_pd">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_pd_256 : GCCBuiltin<"__builtin_ia32_gatherq_pd256">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_ps : GCCBuiltin<"__builtin_ia32_gatherd_ps">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_ps_256 : GCCBuiltin<"__builtin_ia32_gatherd_ps256">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_ps : GCCBuiltin<"__builtin_ia32_gatherq_ps">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_ps_256 : GCCBuiltin<"__builtin_ia32_gatherq_ps256">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_q : GCCBuiltin<"__builtin_ia32_gatherd_q">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_q_256 : GCCBuiltin<"__builtin_ia32_gatherd_q256">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_q : GCCBuiltin<"__builtin_ia32_gatherq_q">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_q_256 : GCCBuiltin<"__builtin_ia32_gatherq_q256">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_d : GCCBuiltin<"__builtin_ia32_gatherd_d">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_d_d_256 : GCCBuiltin<"__builtin_ia32_gatherd_d256">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_d : GCCBuiltin<"__builtin_ia32_gatherq_d">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx2_gather_q_d_256 : GCCBuiltin<"__builtin_ia32_gatherq_d256">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; } // Misc. @@ -4255,25 +3495,26 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". //===----------------------------------------------------------------------===// // XOP +let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_xop_vpermil2pd : GCCBuiltin<"__builtin_ia32_vpermil2pd">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, - llvm_v2f64_ty, llvm_i8_ty], + llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_xop_vpermil2pd_256 : GCCBuiltin<"__builtin_ia32_vpermil2pd256">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_v4f64_ty, - llvm_v4f64_ty, llvm_i8_ty], + llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_xop_vpermil2ps : GCCBuiltin<"__builtin_ia32_vpermil2ps">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, - llvm_v4f32_ty, llvm_i8_ty], + llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_xop_vpermil2ps_256 : GCCBuiltin<"__builtin_ia32_vpermil2ps256">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_v8f32_ty, - llvm_v8f32_ty, llvm_i8_ty], + llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_xop_vfrcz_pd : GCCBuiltin<"__builtin_ia32_vfrczpd">, @@ -4493,6 +3734,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". GCCBuiltin<"__builtin_ia32_vpshlw">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem]>; +} //===----------------------------------------------------------------------===// // MMX @@ -4724,7 +3966,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_permvar_si_512 : GCCBuiltin<"__builtin_ia32_permvarsi512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, - llvm_v16i32_ty, llvm_v16i32_ty, llvm_i8_ty], [IntrNoMem]>; + llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; } // Pack ops. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". @@ -4894,6 +4136,13 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty], []>; } +//===----------------------------------------------------------------------===// +// CLFLUSHOPT +let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". + def int_x86_clflushopt : GCCBuiltin<"__builtin_ia32_clflushopt">, + Intrinsic<[], [llvm_ptr_ty], []>; +} + //===----------------------------------------------------------------------===// // Support protection key let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". @@ -4968,22 +4217,22 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_addcarryx_u32: GCCBuiltin<"__builtin_ia32_addcarryx_u32">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i32_ty, llvm_i32_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; def int_x86_addcarryx_u64: GCCBuiltin<"__builtin_ia32_addcarryx_u64">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i64_ty, llvm_i64_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; def int_x86_addcarry_u32: GCCBuiltin<"__builtin_ia32_addcarry_u32">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i32_ty, llvm_i32_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; def int_x86_addcarry_u64: GCCBuiltin<"__builtin_ia32_addcarry_u64">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i64_ty, llvm_i64_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; def int_x86_subborrow_u32: GCCBuiltin<"__builtin_ia32_subborrow_u32">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i32_ty, llvm_i32_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; def int_x86_subborrow_u64: GCCBuiltin<"__builtin_ia32_subborrow_u64">, Intrinsic<[llvm_i8_ty], [llvm_i8_ty, llvm_i64_ty, llvm_i64_ty, - llvm_ptr_ty], [IntrReadWriteArgMem]>; + llvm_ptr_ty], [IntrArgMemOnly]>; } //===----------------------------------------------------------------------===// @@ -4995,7 +4244,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_xend : GCCBuiltin<"__builtin_ia32_xend">, Intrinsic<[], [], []>; def int_x86_xabort : GCCBuiltin<"__builtin_ia32_xabort">, - Intrinsic<[], [llvm_i8_ty], [IntrNoReturn]>; + Intrinsic<[], [llvm_i8_ty], []>; def int_x86_xtest : GCCBuiltin<"__builtin_ia32_xtest">, Intrinsic<[llvm_i32_ty], [], []>; } @@ -5253,225 +4502,6 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; } -// Unpack ops. -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_mask_unpckh_pd_128 : - GCCBuiltin<"__builtin_ia32_unpckhpd128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckh_pd_256 : - GCCBuiltin<"__builtin_ia32_unpckhpd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckh_pd_512 : - GCCBuiltin<"__builtin_ia32_unpckhpd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckh_ps_128 : - GCCBuiltin<"__builtin_ia32_unpckhps128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckh_ps_256 : - GCCBuiltin<"__builtin_ia32_unpckhps256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckh_ps_512 : - GCCBuiltin<"__builtin_ia32_unpckhps512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_pd_128 : - GCCBuiltin<"__builtin_ia32_unpcklpd128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_pd_256 : - GCCBuiltin<"__builtin_ia32_unpcklpd256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_pd_512 : - GCCBuiltin<"__builtin_ia32_unpcklpd512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_ps_128 : - GCCBuiltin<"__builtin_ia32_unpcklps128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_ps_256 : - GCCBuiltin<"__builtin_ia32_unpcklps256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_unpckl_ps_512 : - GCCBuiltin<"__builtin_ia32_unpcklps512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhb_w_128 : - GCCBuiltin<"__builtin_ia32_punpckhbw128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhb_w_256 : - GCCBuiltin<"__builtin_ia32_punpckhbw256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v32i8_ty, llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhb_w_512 : - GCCBuiltin<"__builtin_ia32_punpckhbw512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhd_q_128 : - GCCBuiltin<"__builtin_ia32_punpckhdq128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhd_q_256 : - GCCBuiltin<"__builtin_ia32_punpckhdq256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhd_q_512 : - GCCBuiltin<"__builtin_ia32_punpckhdq512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhqd_q_128 : - GCCBuiltin<"__builtin_ia32_punpckhqdq128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhqd_q_256 : - GCCBuiltin<"__builtin_ia32_punpckhqdq256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhqd_q_512 : - GCCBuiltin<"__builtin_ia32_punpckhqdq512_mask">, - Intrinsic<[llvm_v8i64_ty], - [llvm_v8i64_ty, llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhw_d_128 : - GCCBuiltin<"__builtin_ia32_punpckhwd128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhw_d_256 : - GCCBuiltin<"__builtin_ia32_punpckhwd256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckhw_d_512 : - GCCBuiltin<"__builtin_ia32_punpckhwd512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklb_w_128 : - GCCBuiltin<"__builtin_ia32_punpcklbw128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklb_w_256 : - GCCBuiltin<"__builtin_ia32_punpcklbw256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v32i8_ty, llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklb_w_512 : - GCCBuiltin<"__builtin_ia32_punpcklbw512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckld_q_128 : - GCCBuiltin<"__builtin_ia32_punpckldq128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckld_q_256 : - GCCBuiltin<"__builtin_ia32_punpckldq256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpckld_q_512 : - GCCBuiltin<"__builtin_ia32_punpckldq512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklqd_q_128 : - GCCBuiltin<"__builtin_ia32_punpcklqdq128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklqd_q_256 : - GCCBuiltin<"__builtin_ia32_punpcklqdq256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklqd_q_512 : - GCCBuiltin<"__builtin_ia32_punpcklqdq512_mask">, - Intrinsic<[llvm_v8i64_ty], - [llvm_v8i64_ty, llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklw_d_128 : - GCCBuiltin<"__builtin_ia32_punpcklwd128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklw_d_256 : - GCCBuiltin<"__builtin_ia32_punpcklwd256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_punpcklw_d_512 : - GCCBuiltin<"__builtin_ia32_punpcklwd512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; -} - // Vector convert let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_mask_cvtdq2pd_128 : @@ -5543,13 +4573,13 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_mask_cvtsd2ss_round : GCCBuiltin<"__builtin_ia32_cvtsd2ss_round_mask">, Intrinsic<[llvm_v4f32_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], + [llvm_v4f32_ty, llvm_v2f64_ty, llvm_v4f32_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_cvtss2sd_round : GCCBuiltin<"__builtin_ia32_cvtss2sd_round_mask">, Intrinsic<[llvm_v2f64_ty], - [ llvm_v4f32_ty, llvm_v4f32_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], + [llvm_v2f64_ty, llvm_v4f32_ty, llvm_v2f64_ty, llvm_i8_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_avx512_mask_cvtpd2ps : @@ -6014,75 +5044,11 @@ def int_x86_avx512_mask_range_ps_512 : GCCBuiltin<"__builtin_ia32_rangeps512_mas let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_avx512_vbroadcast_ss_512 : GCCBuiltin<"__builtin_ia32_vbroadcastss512">, - Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_broadcast_ss_ps_512 : - GCCBuiltin<"__builtin_ia32_broadcastss512">, - Intrinsic<[llvm_v16f32_ty], [llvm_v4f32_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_broadcast_ss_ps_256 : - GCCBuiltin<"__builtin_ia32_broadcastss256_mask">, - Intrinsic<[llvm_v8f32_ty], [llvm_v4f32_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_broadcast_ss_ps_128 : - GCCBuiltin<"__builtin_ia32_broadcastss128_mask">, - Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_vbroadcast_sd_512 : GCCBuiltin<"__builtin_ia32_vbroadcastsd512">, - Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty], [IntrReadArgMem]>; - def int_x86_avx512_mask_broadcast_sd_pd_512 : - GCCBuiltin<"__builtin_ia32_broadcastsd512">, - Intrinsic<[llvm_v8f64_ty], [llvm_v2f64_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_broadcast_sd_pd_256 : - GCCBuiltin<"__builtin_ia32_broadcastsd256_mask">, - Intrinsic<[llvm_v4f64_ty], [llvm_v2f64_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_pbroadcastb_128 : - GCCBuiltin<"__builtin_ia32_pbroadcastb128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastb_256 : - GCCBuiltin<"__builtin_ia32_pbroadcastb256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v16i8_ty, llvm_v32i8_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastb_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastb512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v16i8_ty, llvm_v64i8_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastw_128 : - GCCBuiltin<"__builtin_ia32_pbroadcastw128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastw_256 : - GCCBuiltin<"__builtin_ia32_pbroadcastw256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v8i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastw_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastw512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v8i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastd_128 : - GCCBuiltin<"__builtin_ia32_pbroadcastd128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastd_256 : - GCCBuiltin<"__builtin_ia32_pbroadcastd256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v4i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastd_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastd512">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v4i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastq_128 : - GCCBuiltin<"__builtin_ia32_pbroadcastq128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastq_256 : - GCCBuiltin<"__builtin_ia32_pbroadcastq256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v2i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_pbroadcastq_512 : - GCCBuiltin<"__builtin_ia32_pbroadcastq512">, - Intrinsic<[llvm_v8i64_ty], - [llvm_v2i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_broadcastf32x2_256 : GCCBuiltin<"__builtin_ia32_broadcastf32x2_256_mask">, @@ -6263,81 +5229,7 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; } -//Bitwise Ops -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_mask_pand_d_128 : GCCBuiltin<"__builtin_ia32_pandd128_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pand_d_256 : GCCBuiltin<"__builtin_ia32_pandd256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pand_d_512 : GCCBuiltin<"__builtin_ia32_pandd512_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pand_q_128 : GCCBuiltin<"__builtin_ia32_pandq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, - llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pand_q_256 : GCCBuiltin<"__builtin_ia32_pandq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, - llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pand_q_512 : GCCBuiltin<"__builtin_ia32_pandq512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, - llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_d_128 : GCCBuiltin<"__builtin_ia32_pandnd128_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_d_256 : GCCBuiltin<"__builtin_ia32_pandnd256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_d_512 : GCCBuiltin<"__builtin_ia32_pandnd512_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_q_128 : GCCBuiltin<"__builtin_ia32_pandnq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, - llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_q_256 : GCCBuiltin<"__builtin_ia32_pandnq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, - llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pandn_q_512 : GCCBuiltin<"__builtin_ia32_pandnq512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, - llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_d_128 : GCCBuiltin<"__builtin_ia32_pord128_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_d_256 : GCCBuiltin<"__builtin_ia32_pord256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_d_512 : GCCBuiltin<"__builtin_ia32_pord512_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_q_128 : GCCBuiltin<"__builtin_ia32_porq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, - llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_q_256 : GCCBuiltin<"__builtin_ia32_porq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, - llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_por_q_512 : GCCBuiltin<"__builtin_ia32_porq512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, - llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_d_128 : GCCBuiltin<"__builtin_ia32_pxord128_mask">, - Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, - llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_d_256 : GCCBuiltin<"__builtin_ia32_pxord256_mask">, - Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, - llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_d_512 : GCCBuiltin<"__builtin_ia32_pxord512_mask">, - Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, - llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_q_128 : GCCBuiltin<"__builtin_ia32_pxorq128_mask">, - Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, - llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_q_256 : GCCBuiltin<"__builtin_ia32_pxorq256_mask">, - Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, - llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pxor_q_512 : GCCBuiltin<"__builtin_ia32_pxorq512_mask">, - Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, - llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; -} + // Arithmetic ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". @@ -7165,293 +6057,293 @@ let TargetPrefix = "x86" in { def int_x86_avx512_gather_dpd_512 : GCCBuiltin<"__builtin_ia32_gathersiv8df">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_dps_512 : GCCBuiltin<"__builtin_ia32_gathersiv16sf">, Intrinsic<[llvm_v16f32_ty], [llvm_v16f32_ty, llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_qpd_512 : GCCBuiltin<"__builtin_ia32_gatherdiv8df">, Intrinsic<[llvm_v8f64_ty], [llvm_v8f64_ty, llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_qps_512 : GCCBuiltin<"__builtin_ia32_gatherdiv16sf">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_dpq_512 : GCCBuiltin<"__builtin_ia32_gathersiv8di">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_dpi_512 : GCCBuiltin<"__builtin_ia32_gathersiv16si">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_qpq_512 : GCCBuiltin<"__builtin_ia32_gatherdiv8di">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather_qpi_512 : GCCBuiltin<"__builtin_ia32_gatherdiv16si">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3div2_df : GCCBuiltin<"__builtin_ia32_gather3div2df">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3div2_di : GCCBuiltin<"__builtin_ia32_gather3div2di">, Intrinsic<[llvm_v4i32_ty], [llvm_v2i64_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3div4_df : GCCBuiltin<"__builtin_ia32_gather3div4df">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3div4_di : GCCBuiltin<"__builtin_ia32_gather3div4di">, Intrinsic<[llvm_v8i32_ty], [llvm_v4i64_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3div4_sf : GCCBuiltin<"__builtin_ia32_gather3div4sf">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3div4_si : GCCBuiltin<"__builtin_ia32_gather3div4si">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3div8_sf : GCCBuiltin<"__builtin_ia32_gather3div8sf">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3div8_si : GCCBuiltin<"__builtin_ia32_gather3div8si">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3siv2_df : GCCBuiltin<"__builtin_ia32_gather3siv2df">, Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3siv2_di : GCCBuiltin<"__builtin_ia32_gather3siv2di">, Intrinsic<[llvm_v4i32_ty], [llvm_v2i64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3siv4_df : GCCBuiltin<"__builtin_ia32_gather3siv4df">, Intrinsic<[llvm_v4f64_ty], [llvm_v4f64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3siv4_di : GCCBuiltin<"__builtin_ia32_gather3siv4di">, Intrinsic<[llvm_v8i32_ty], [llvm_v4i64_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3siv4_sf : GCCBuiltin<"__builtin_ia32_gather3siv4sf">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3siv4_si : GCCBuiltin<"__builtin_ia32_gather3siv4si">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3siv8_sf : GCCBuiltin<"__builtin_ia32_gather3siv8sf">, Intrinsic<[llvm_v8f32_ty], [llvm_v8f32_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_gather3siv8_si : GCCBuiltin<"__builtin_ia32_gather3siv8si">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty, llvm_i32_ty], - [IntrReadArgMem]>; + [IntrReadMem, IntrArgMemOnly]>; // scatter def int_x86_avx512_scatter_dpd_512 : GCCBuiltin<"__builtin_ia32_scattersiv8df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i32_ty, llvm_v8f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_dps_512 : GCCBuiltin<"__builtin_ia32_scattersiv16sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i16_ty, llvm_v16i32_ty, llvm_v16f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_qpd_512 : GCCBuiltin<"__builtin_ia32_scatterdiv8df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i64_ty, llvm_v8f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_qps_512 : GCCBuiltin<"__builtin_ia32_scatterdiv16sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i64_ty, llvm_v8f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_dpq_512 : GCCBuiltin<"__builtin_ia32_scattersiv8di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i32_ty, llvm_v8i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_dpi_512 : GCCBuiltin<"__builtin_ia32_scattersiv16si">, Intrinsic<[], [llvm_ptr_ty, llvm_i16_ty, llvm_v16i32_ty, llvm_v16i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_qpq_512 : GCCBuiltin<"__builtin_ia32_scatterdiv8di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty,llvm_v8i64_ty, llvm_v8i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatter_qpi_512 : GCCBuiltin<"__builtin_ia32_scatterdiv16si">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i64_ty, llvm_v8i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatterdiv2_df : GCCBuiltin<"__builtin_ia32_scatterdiv2df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v2i64_ty, llvm_v2f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatterdiv2_di : GCCBuiltin<"__builtin_ia32_scatterdiv2di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v2i64_ty, llvm_v2i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatterdiv4_df : GCCBuiltin<"__builtin_ia32_scatterdiv4df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i64_ty, llvm_v4f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatterdiv4_di : GCCBuiltin<"__builtin_ia32_scatterdiv4di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i64_ty, llvm_v4i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatterdiv4_sf : GCCBuiltin<"__builtin_ia32_scatterdiv4sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v2i64_ty, llvm_v4f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatterdiv4_si : GCCBuiltin<"__builtin_ia32_scatterdiv4si">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v2i64_ty, llvm_v4i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatterdiv8_sf : GCCBuiltin<"__builtin_ia32_scatterdiv8sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i64_ty, llvm_v4f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scatterdiv8_si : GCCBuiltin<"__builtin_ia32_scatterdiv8si">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i64_ty, llvm_v4i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scattersiv2_df : GCCBuiltin<"__builtin_ia32_scattersiv2df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v2f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scattersiv2_di : GCCBuiltin<"__builtin_ia32_scattersiv2di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v2i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scattersiv4_df : GCCBuiltin<"__builtin_ia32_scattersiv4df">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v4f64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scattersiv4_di : GCCBuiltin<"__builtin_ia32_scattersiv4di">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v4i64_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scattersiv4_sf : GCCBuiltin<"__builtin_ia32_scattersiv4sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v4f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scattersiv4_si : GCCBuiltin<"__builtin_ia32_scattersiv4si">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scattersiv8_sf : GCCBuiltin<"__builtin_ia32_scattersiv8sf">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i32_ty, llvm_v8f32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_scattersiv8_si : GCCBuiltin<"__builtin_ia32_scattersiv8si">, Intrinsic<[], [llvm_ptr_ty, llvm_i8_ty, llvm_v8i32_ty, llvm_v8i32_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; // gather prefetch def int_x86_avx512_gatherpf_dpd_512 : GCCBuiltin<"__builtin_ia32_gatherpfdpd">, Intrinsic<[], [llvm_i8_ty, llvm_v8i32_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_gatherpf_dps_512 : GCCBuiltin<"__builtin_ia32_gatherpfdps">, Intrinsic<[], [llvm_i16_ty, llvm_v16i32_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_gatherpf_qpd_512 : GCCBuiltin<"__builtin_ia32_gatherpfqpd">, Intrinsic<[], [llvm_i8_ty, llvm_v8i64_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_gatherpf_qps_512 : GCCBuiltin<"__builtin_ia32_gatherpfqps">, Intrinsic<[], [llvm_i8_ty, llvm_v8i64_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; // scatter prefetch def int_x86_avx512_scatterpf_dpd_512 : GCCBuiltin<"__builtin_ia32_scatterpfdpd">, Intrinsic<[], [llvm_i8_ty, llvm_v8i32_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_scatterpf_dps_512 : GCCBuiltin<"__builtin_ia32_scatterpfdps">, Intrinsic<[], [llvm_i16_ty, llvm_v16i32_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_scatterpf_qpd_512 : GCCBuiltin<"__builtin_ia32_scatterpfqpd">, Intrinsic<[], [llvm_i8_ty, llvm_v8i64_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; def int_x86_avx512_scatterpf_qps_512 : GCCBuiltin<"__builtin_ia32_scatterpfqps">, Intrinsic<[], [llvm_i8_ty, llvm_v8i64_ty, llvm_ptr_ty, - llvm_i32_ty, llvm_i32_ty], [IntrReadWriteArgMem]>; + llvm_i32_ty, llvm_i32_ty], [IntrArgMemOnly]>; } // AVX-512 conflict detection instruction @@ -7490,117 +6382,32 @@ let TargetPrefix = "x86" in { [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_d_128 : - GCCBuiltin<"__builtin_ia32_vplzcntd_128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_d_256 : - GCCBuiltin<"__builtin_ia32_vplzcntd_256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_d_512 : - GCCBuiltin<"__builtin_ia32_vplzcntd_512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_q_128 : - GCCBuiltin<"__builtin_ia32_vplzcntq_128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_q_256 : - GCCBuiltin<"__builtin_ia32_vplzcntq_256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>; def int_x86_avx512_mask_lzcnt_q_512 : - GCCBuiltin<"__builtin_ia32_vplzcntq_512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>; } -// Vector blend -let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". - def int_x86_avx512_mask_blend_ps_512 : GCCBuiltin<"__builtin_ia32_blendmps_512_mask">, - Intrinsic<[llvm_v16f32_ty], - [llvm_v16f32_ty, llvm_v16f32_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_ps_256 : GCCBuiltin<"__builtin_ia32_blendmps_256_mask">, - Intrinsic<[llvm_v8f32_ty], - [llvm_v8f32_ty, llvm_v8f32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_ps_128 : GCCBuiltin<"__builtin_ia32_blendmps_128_mask">, - Intrinsic<[llvm_v4f32_ty], - [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_pd_512 : GCCBuiltin<"__builtin_ia32_blendmpd_512_mask">, - Intrinsic<[llvm_v8f64_ty], - [llvm_v8f64_ty, llvm_v8f64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_pd_256 : GCCBuiltin<"__builtin_ia32_blendmpd_256_mask">, - Intrinsic<[llvm_v4f64_ty], - [llvm_v4f64_ty, llvm_v4f64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_pd_128 : GCCBuiltin<"__builtin_ia32_blendmpd_128_mask">, - Intrinsic<[llvm_v2f64_ty], - [llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_blend_d_512 : GCCBuiltin<"__builtin_ia32_blendmd_512_mask">, - Intrinsic<[llvm_v16i32_ty], - [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_q_512 : GCCBuiltin<"__builtin_ia32_blendmq_512_mask">, - Intrinsic<[llvm_v8i64_ty], - [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_d_256 : GCCBuiltin<"__builtin_ia32_blendmd_256_mask">, - Intrinsic<[llvm_v8i32_ty], - [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_q_256 : GCCBuiltin<"__builtin_ia32_blendmq_256_mask">, - Intrinsic<[llvm_v4i64_ty], - [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_d_128 : GCCBuiltin<"__builtin_ia32_blendmd_128_mask">, - Intrinsic<[llvm_v4i32_ty], - [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_q_128 : GCCBuiltin<"__builtin_ia32_blendmq_128_mask">, - Intrinsic<[llvm_v2i64_ty], - [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_blend_w_512 : GCCBuiltin<"__builtin_ia32_blendmw_512_mask">, - Intrinsic<[llvm_v32i16_ty], - [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_w_256 : GCCBuiltin<"__builtin_ia32_blendmw_256_mask">, - Intrinsic<[llvm_v16i16_ty], - [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_w_128 : GCCBuiltin<"__builtin_ia32_blendmw_128_mask">, - Intrinsic<[llvm_v8i16_ty], - [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_b_512 : GCCBuiltin<"__builtin_ia32_blendmb_512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_b_256 : GCCBuiltin<"__builtin_ia32_blendmb_256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_blend_b_128 : GCCBuiltin<"__builtin_ia32_blendmb_128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrNoMem]>; - -} - let TargetPrefix = "x86" in { def int_x86_avx512_mask_valign_q_512 : GCCBuiltin<"__builtin_ia32_alignq512_mask">, @@ -7637,24 +6444,6 @@ let TargetPrefix = "x86" in { Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_palignr_128 : - GCCBuiltin<"__builtin_ia32_palignr128_mask">, - Intrinsic<[llvm_v16i8_ty], - [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty, llvm_v16i8_ty, - llvm_i16_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_palignr_256 : - GCCBuiltin<"__builtin_ia32_palignr256_mask">, - Intrinsic<[llvm_v32i8_ty], - [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty, llvm_v32i8_ty, - llvm_i32_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_palignr_512 : - GCCBuiltin<"__builtin_ia32_palignr512_mask">, - Intrinsic<[llvm_v64i8_ty], - [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i32_ty, llvm_v64i8_ty, - llvm_i64_ty], [IntrNoMem]>; } // Compares @@ -7666,161 +6455,84 @@ let TargetPrefix = "x86" in { def int_x86_avx512_vcomi_ss : GCCBuiltin<"__builtin_ia32_vcomiss">, Intrinsic<[llvm_i32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_b_512 : GCCBuiltin<"__builtin_ia32_pcmpeqb512_mask">, - Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_w_512 : GCCBuiltin<"__builtin_ia32_pcmpeqw512_mask">, - Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_d_512 : GCCBuiltin<"__builtin_ia32_pcmpeqd512_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_q_512 : GCCBuiltin<"__builtin_ia32_pcmpeqq512_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pcmpgt_b_512: GCCBuiltin<"__builtin_ia32_pcmpgtb512_mask">, - Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_w_512: GCCBuiltin<"__builtin_ia32_pcmpgtw512_mask">, - Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_d_512: GCCBuiltin<"__builtin_ia32_pcmpgtd512_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_q_512: GCCBuiltin<"__builtin_ia32_pcmpgtq512_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_cmp_b_512: GCCBuiltin<"__builtin_ia32_cmpb512_mask">, + def int_x86_avx512_mask_cmp_b_512: Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i32_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_w_512: GCCBuiltin<"__builtin_ia32_cmpw512_mask">, + def int_x86_avx512_mask_cmp_w_512: Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_d_512: GCCBuiltin<"__builtin_ia32_cmpd512_mask">, + def int_x86_avx512_mask_cmp_d_512: Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem ]>; - def int_x86_avx512_mask_cmp_q_512: GCCBuiltin<"__builtin_ia32_cmpq512_mask">, + def int_x86_avx512_mask_cmp_q_512: Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_b_512: GCCBuiltin<"__builtin_ia32_ucmpb512_mask">, + def int_x86_avx512_mask_ucmp_b_512: Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i32_ty, llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_w_512: GCCBuiltin<"__builtin_ia32_ucmpw512_mask">, + def int_x86_avx512_mask_ucmp_w_512: Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_d_512: GCCBuiltin<"__builtin_ia32_ucmpd512_mask">, + def int_x86_avx512_mask_ucmp_d_512: Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_q_512: GCCBuiltin<"__builtin_ia32_ucmpq512_mask">, + def int_x86_avx512_mask_ucmp_q_512: Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; // 256-bit - def int_x86_avx512_mask_pcmpeq_b_256 : GCCBuiltin<"__builtin_ia32_pcmpeqb256_mask">, - Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_w_256 : GCCBuiltin<"__builtin_ia32_pcmpeqw256_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_d_256 : GCCBuiltin<"__builtin_ia32_pcmpeqd256_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_q_256 : GCCBuiltin<"__builtin_ia32_pcmpeqq256_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pcmpgt_b_256: GCCBuiltin<"__builtin_ia32_pcmpgtb256_mask">, - Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_w_256: GCCBuiltin<"__builtin_ia32_pcmpgtw256_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_d_256: GCCBuiltin<"__builtin_ia32_pcmpgtd256_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_q_256: GCCBuiltin<"__builtin_ia32_pcmpgtq256_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_cmp_b_256: GCCBuiltin<"__builtin_ia32_cmpb256_mask">, + def int_x86_avx512_mask_cmp_b_256: Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_w_256: GCCBuiltin<"__builtin_ia32_cmpw256_mask">, + def int_x86_avx512_mask_cmp_w_256: Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_d_256: GCCBuiltin<"__builtin_ia32_cmpd256_mask">, + def int_x86_avx512_mask_cmp_d_256: Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_q_256: GCCBuiltin<"__builtin_ia32_cmpq256_mask">, + def int_x86_avx512_mask_cmp_q_256: Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_b_256: GCCBuiltin<"__builtin_ia32_ucmpb256_mask">, + def int_x86_avx512_mask_ucmp_b_256: Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_w_256: GCCBuiltin<"__builtin_ia32_ucmpw256_mask">, + def int_x86_avx512_mask_ucmp_w_256: Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_d_256: GCCBuiltin<"__builtin_ia32_ucmpd256_mask">, + def int_x86_avx512_mask_ucmp_d_256: Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_q_256: GCCBuiltin<"__builtin_ia32_ucmpq256_mask">, + def int_x86_avx512_mask_ucmp_q_256: Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; // 128-bit - def int_x86_avx512_mask_pcmpeq_b_128 : GCCBuiltin<"__builtin_ia32_pcmpeqb128_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_w_128 : GCCBuiltin<"__builtin_ia32_pcmpeqw128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_d_128 : GCCBuiltin<"__builtin_ia32_pcmpeqd128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpeq_q_128 : GCCBuiltin<"__builtin_ia32_pcmpeqq128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_pcmpgt_b_128: GCCBuiltin<"__builtin_ia32_pcmpgtb128_mask">, - Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_w_128: GCCBuiltin<"__builtin_ia32_pcmpgtw128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_d_128: GCCBuiltin<"__builtin_ia32_pcmpgtd128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_avx512_mask_pcmpgt_q_128: GCCBuiltin<"__builtin_ia32_pcmpgtq128_mask">, - Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrNoMem]>; - - def int_x86_avx512_mask_cmp_b_128: GCCBuiltin<"__builtin_ia32_cmpb128_mask">, + def int_x86_avx512_mask_cmp_b_128: Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_w_128: GCCBuiltin<"__builtin_ia32_cmpw128_mask">, + def int_x86_avx512_mask_cmp_w_128: Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_d_128: GCCBuiltin<"__builtin_ia32_cmpd128_mask">, + def int_x86_avx512_mask_cmp_d_128: Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_q_128: GCCBuiltin<"__builtin_ia32_cmpq128_mask">, + def int_x86_avx512_mask_cmp_q_128: Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_b_128: GCCBuiltin<"__builtin_ia32_ucmpb128_mask">, + def int_x86_avx512_mask_ucmp_b_128: Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty, llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_w_128: GCCBuiltin<"__builtin_ia32_ucmpw128_mask">, + def int_x86_avx512_mask_ucmp_w_128: Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_d_128: GCCBuiltin<"__builtin_ia32_ucmpd128_mask">, + def int_x86_avx512_mask_ucmp_d_128: Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_q_128: GCCBuiltin<"__builtin_ia32_ucmpq128_mask">, + def int_x86_avx512_mask_ucmp_q_128: Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i32_ty, llvm_i8_ty], [IntrNoMem]>; } @@ -7855,27 +6567,27 @@ let TargetPrefix = "x86" in { def int_x86_avx512_mask_compress_store_ps_512 : GCCBuiltin<"__builtin_ia32_compressstoresf512_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16f32_ty, - llvm_i16_ty], [IntrReadWriteArgMem]>; + llvm_i16_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_pd_512 : GCCBuiltin<"__builtin_ia32_compressstoredf512_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8f64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_ps_256 : GCCBuiltin<"__builtin_ia32_compressstoresf256_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8f32_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_pd_256 : GCCBuiltin<"__builtin_ia32_compressstoredf256_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4f64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_ps_128 : GCCBuiltin<"__builtin_ia32_compressstoresf128_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4f32_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_pd_128 : GCCBuiltin<"__builtin_ia32_compressstoredf128_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2f64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_d_512 : GCCBuiltin<"__builtin_ia32_compresssi512_mask">, @@ -7905,27 +6617,27 @@ let TargetPrefix = "x86" in { def int_x86_avx512_mask_compress_store_d_512 : GCCBuiltin<"__builtin_ia32_compressstoresi512_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, - llvm_i16_ty], [IntrReadWriteArgMem]>; + llvm_i16_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_q_512 : GCCBuiltin<"__builtin_ia32_compressstoredi512_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_d_256 : GCCBuiltin<"__builtin_ia32_compressstoresi256_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_q_256 : GCCBuiltin<"__builtin_ia32_compressstoredi256_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_d_128 : GCCBuiltin<"__builtin_ia32_compressstoresi128_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; def int_x86_avx512_mask_compress_store_q_128 : GCCBuiltin<"__builtin_ia32_compressstoredi128_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, - llvm_i8_ty], [IntrReadWriteArgMem]>; + llvm_i8_ty], [IntrArgMemOnly]>; // expand def int_x86_avx512_mask_expand_ps_512 : @@ -7956,27 +6668,27 @@ let TargetPrefix = "x86" in { def int_x86_avx512_mask_expand_load_ps_512 : GCCBuiltin<"__builtin_ia32_expandloadsf512_mask">, Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty, llvm_v16f32_ty, - llvm_i16_ty], [IntrReadArgMem]>; + llvm_i16_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_pd_512 : GCCBuiltin<"__builtin_ia32_expandloaddf512_mask">, Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty, llvm_v8f64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_ps_256 : GCCBuiltin<"__builtin_ia32_expandloadsf256_mask">, Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty, llvm_v8f32_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_pd_256 : GCCBuiltin<"__builtin_ia32_expandloaddf256_mask">, Intrinsic<[llvm_v4f64_ty], [llvm_ptr_ty, llvm_v4f64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_ps_128 : GCCBuiltin<"__builtin_ia32_expandloadsf128_mask">, Intrinsic<[llvm_v4f32_ty], [llvm_ptr_ty, llvm_v4f32_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_pd_128 : GCCBuiltin<"__builtin_ia32_expandloaddf128_mask">, Intrinsic<[llvm_v2f64_ty], [llvm_ptr_ty, llvm_v2f64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_d_512 : GCCBuiltin<"__builtin_ia32_expandsi512_mask">, @@ -8006,27 +6718,27 @@ let TargetPrefix = "x86" in { def int_x86_avx512_mask_expand_load_d_512 : GCCBuiltin<"__builtin_ia32_expandloadsi512_mask">, Intrinsic<[llvm_v16i32_ty], [llvm_ptr_ty, llvm_v16i32_ty, - llvm_i16_ty], [IntrReadArgMem]>; + llvm_i16_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_q_512 : GCCBuiltin<"__builtin_ia32_expandloaddi512_mask">, Intrinsic<[llvm_v8i64_ty], [llvm_ptr_ty, llvm_v8i64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_d_256 : GCCBuiltin<"__builtin_ia32_expandloadsi256_mask">, Intrinsic<[llvm_v8i32_ty], [llvm_ptr_ty, llvm_v8i32_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_q_256 : GCCBuiltin<"__builtin_ia32_expandloaddi256_mask">, Intrinsic<[llvm_v4i64_ty], [llvm_ptr_ty, llvm_v4i64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_d_128 : GCCBuiltin<"__builtin_ia32_expandloadsi128_mask">, Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty, llvm_v4i32_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; def int_x86_avx512_mask_expand_load_q_128 : GCCBuiltin<"__builtin_ia32_expandloaddi128_mask">, Intrinsic<[llvm_v2i64_ty], [llvm_ptr_ty, llvm_v2i64_ty, - llvm_i8_ty], [IntrReadArgMem]>; + llvm_i8_ty], [IntrReadMem, IntrArgMemOnly]>; } @@ -8041,7 +6753,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qb_128 : GCCBuiltin<"__builtin_ia32_pmovsqb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8051,7 +6763,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qb_128 : GCCBuiltin<"__builtin_ia32_pmovusqb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8061,7 +6773,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qb_256 : GCCBuiltin<"__builtin_ia32_pmovqb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8071,7 +6783,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qb_256 : GCCBuiltin<"__builtin_ia32_pmovsqb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8081,7 +6793,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qb_256 : GCCBuiltin<"__builtin_ia32_pmovusqb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8091,7 +6803,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qb_512 : GCCBuiltin<"__builtin_ia32_pmovqb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8101,7 +6813,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qb_512 : GCCBuiltin<"__builtin_ia32_pmovsqb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8111,7 +6823,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qb_512 : GCCBuiltin<"__builtin_ia32_pmovusqb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8121,7 +6833,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qw_128 : GCCBuiltin<"__builtin_ia32_pmovqw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8131,7 +6843,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qw_128 : GCCBuiltin<"__builtin_ia32_pmovsqw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8141,7 +6853,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qw_128 : GCCBuiltin<"__builtin_ia32_pmovusqw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8151,7 +6863,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qw_256 : GCCBuiltin<"__builtin_ia32_pmovqw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8161,7 +6873,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qw_256 : GCCBuiltin<"__builtin_ia32_pmovsqw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8171,7 +6883,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qw_256 : GCCBuiltin<"__builtin_ia32_pmovusqw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8181,7 +6893,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qw_512 : GCCBuiltin<"__builtin_ia32_pmovqw512_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8191,7 +6903,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qw_512 : GCCBuiltin<"__builtin_ia32_pmovsqw512_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8201,7 +6913,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qw_512 : GCCBuiltin<"__builtin_ia32_pmovusqw512_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8211,7 +6923,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qd_128 : GCCBuiltin<"__builtin_ia32_pmovqd128_mask">, Intrinsic<[llvm_v4i32_ty], @@ -8221,7 +6933,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqd128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qd_128 : GCCBuiltin<"__builtin_ia32_pmovsqd128_mask">, Intrinsic<[llvm_v4i32_ty], @@ -8231,7 +6943,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqd128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qd_128 : GCCBuiltin<"__builtin_ia32_pmovusqd128_mask">, Intrinsic<[llvm_v4i32_ty], @@ -8241,7 +6953,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqd128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v2i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qd_256 : GCCBuiltin<"__builtin_ia32_pmovqd256_mask">, Intrinsic<[llvm_v4i32_ty], @@ -8251,7 +6963,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqd256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qd_256 : GCCBuiltin<"__builtin_ia32_pmovsqd256_mask">, Intrinsic<[llvm_v4i32_ty], @@ -8261,7 +6973,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqd256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qd_256 : GCCBuiltin<"__builtin_ia32_pmovusqd256_mask">, Intrinsic<[llvm_v4i32_ty], @@ -8271,7 +6983,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqd256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_qd_512 : GCCBuiltin<"__builtin_ia32_pmovqd512_mask">, Intrinsic<[llvm_v8i32_ty], @@ -8281,7 +6993,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovqd512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_qd_512 : GCCBuiltin<"__builtin_ia32_pmovsqd512_mask">, Intrinsic<[llvm_v8i32_ty], @@ -8291,7 +7003,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsqd512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_qd_512 : GCCBuiltin<"__builtin_ia32_pmovusqd512_mask">, Intrinsic<[llvm_v8i32_ty], @@ -8301,7 +7013,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusqd512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i64_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_db_128 : GCCBuiltin<"__builtin_ia32_pmovdb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8311,7 +7023,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_db_128 : GCCBuiltin<"__builtin_ia32_pmovsdb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8321,7 +7033,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_db_128 : GCCBuiltin<"__builtin_ia32_pmovusdb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8331,7 +7043,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_db_256 : GCCBuiltin<"__builtin_ia32_pmovdb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8341,7 +7053,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_db_256 : GCCBuiltin<"__builtin_ia32_pmovsdb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8351,7 +7063,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_db_256 : GCCBuiltin<"__builtin_ia32_pmovusdb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8361,7 +7073,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_db_512 : GCCBuiltin<"__builtin_ia32_pmovdb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8371,7 +7083,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_db_512 : GCCBuiltin<"__builtin_ia32_pmovsdb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8381,7 +7093,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_db_512 : GCCBuiltin<"__builtin_ia32_pmovusdb512_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8391,7 +7103,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_dw_128 : GCCBuiltin<"__builtin_ia32_pmovdw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8401,7 +7113,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_dw_128 : GCCBuiltin<"__builtin_ia32_pmovsdw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8411,7 +7123,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_dw_128 : GCCBuiltin<"__builtin_ia32_pmovusdw128_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8421,7 +7133,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdw128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v4i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_dw_256 : GCCBuiltin<"__builtin_ia32_pmovdw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8431,7 +7143,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_dw_256 : GCCBuiltin<"__builtin_ia32_pmovsdw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8441,7 +7153,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_dw_256 : GCCBuiltin<"__builtin_ia32_pmovusdw256_mask">, Intrinsic<[llvm_v8i16_ty], @@ -8451,7 +7163,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdw256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i32_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_dw_512 : GCCBuiltin<"__builtin_ia32_pmovdw512_mask">, Intrinsic<[llvm_v16i16_ty], @@ -8461,7 +7173,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovdw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_dw_512 : GCCBuiltin<"__builtin_ia32_pmovsdw512_mask">, Intrinsic<[llvm_v16i16_ty], @@ -8471,7 +7183,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovsdw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_dw_512 : GCCBuiltin<"__builtin_ia32_pmovusdw512_mask">, Intrinsic<[llvm_v16i16_ty], @@ -8481,7 +7193,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovusdw512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i32_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_wb_128 : GCCBuiltin<"__builtin_ia32_pmovwb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8491,7 +7203,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovwb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_wb_128 : GCCBuiltin<"__builtin_ia32_pmovswb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8501,7 +7213,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovswb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_wb_128 : GCCBuiltin<"__builtin_ia32_pmovuswb128_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8511,7 +7223,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovuswb128mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v8i16_ty, llvm_i8_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_wb_256 : GCCBuiltin<"__builtin_ia32_pmovwb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8521,7 +7233,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovwb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_wb_256 : GCCBuiltin<"__builtin_ia32_pmovswb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8531,7 +7243,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovswb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_wb_256 : GCCBuiltin<"__builtin_ia32_pmovuswb256_mask">, Intrinsic<[llvm_v16i8_ty], @@ -8541,7 +7253,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovuswb256mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v16i16_ty, llvm_i16_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmov_wb_512 : GCCBuiltin<"__builtin_ia32_pmovwb512_mask">, Intrinsic<[llvm_v32i8_ty], @@ -8551,7 +7263,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovwb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovs_wb_512 : GCCBuiltin<"__builtin_ia32_pmovswb512_mask">, Intrinsic<[llvm_v32i8_ty], @@ -8561,7 +7273,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovswb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; def int_x86_avx512_mask_pmovus_wb_512 : GCCBuiltin<"__builtin_ia32_pmovuswb512_mask">, Intrinsic<[llvm_v32i8_ty], @@ -8571,7 +7283,7 @@ let TargetPrefix = "x86" in { GCCBuiltin<"__builtin_ia32_pmovuswb512mem_mask">, Intrinsic<[], [llvm_ptr_ty, llvm_v32i16_ty, llvm_i32_ty], - [IntrReadWriteArgMem]>; + [IntrArgMemOnly]>; } // Bitwise ternary logic @@ -8709,3 +7421,14 @@ let TargetPrefix = "x86" in { def int_x86_sha256msg2 : GCCBuiltin<"__builtin_ia32_sha256msg2">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], [IntrNoMem]>; } + +//===----------------------------------------------------------------------===// +// Thread synchronization ops with timer. +let TargetPrefix = "x86" in { + def int_x86_monitorx + : GCCBuiltin<"__builtin_ia32_monitorx">, + Intrinsic<[], [ llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty ], []>; + def int_x86_mwaitx + : GCCBuiltin<"__builtin_ia32_mwaitx">, + Intrinsic<[], [ llvm_i32_ty, llvm_i32_ty, llvm_i32_ty ], []>; +} diff --git a/include/llvm/IR/LLVMContext.h b/include/llvm/IR/LLVMContext.h index cd7fcfb7c17ce8f0e602c7b79ffdfc46303b8f2e..6f7a95037457056ee7a4ecc67bc8415ee8cea67f 100644 --- a/include/llvm/IR/LLVMContext.h +++ b/include/llvm/IR/LLVMContext.h @@ -16,7 +16,6 @@ #define LLVM_IR_LLVMCONTEXT_H #include "llvm/Support/CBindingWrapping.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Options.h" namespace llvm { @@ -26,11 +25,15 @@ class StringRef; class Twine; class Instruction; class Module; +class MDString; +class DICompositeType; class SMDiagnostic; class DiagnosticInfo; +enum DiagnosticSeverity : char; template class SmallVectorImpl; class Function; class DebugLoc; +class OptBisect; /// This is an important class for using LLVM in a threaded context. It /// (opaquely) owns and manages the core "global" data of LLVM's core @@ -65,6 +68,7 @@ public: MD_invariant_group = 16, // "invariant.group" MD_align = 17, // "align" MD_loop = 18, // "llvm.loop" + MD_type = 19, // "type" }; /// Known operand bundle tag IDs, which always have the same value. All @@ -95,7 +99,6 @@ public: /// tag registered with an LLVMContext has an unique ID. uint32_t getOperandBundleTagID(StringRef Tag) const; - /// Define the GC for a function void setGC(const Function &Fn, std::string GCName); @@ -108,13 +111,19 @@ public: /// Return true if the Context runtime configuration is set to discard all /// value names. When true, only GlobalValue names will be available in the /// IR. - bool discardValueNames(); + bool shouldDiscardValueNames() const; /// Set the Context runtime configuration to discard all value name (but /// GlobalValue). Clients can use this flag to save memory and runtime, /// especially in release mode. void setDiscardValueNames(bool Discard); + /// Whether there is a string map for uniquing debug info + /// identifiers across the context. Off by default. + bool isODRUniquingDebugTypes() const; + void enableDebugTypeODRUniquing(); + void disableDebugTypeODRUniquing(); + typedef void (*InlineAsmDiagHandlerTy)(const SMDiagnostic&, void *Context, unsigned LocCookie); @@ -165,6 +174,10 @@ public: /// setDiagnosticContext. void *getDiagnosticContext() const; + /// \brief Get the prefix that should be printed in front of a diagnostic of + /// the given \p Severity + static const char *getDiagnosticMessagePrefix(DiagnosticSeverity Severity); + /// \brief Report a message to the currently installed diagnostic handler. /// /// This function returns, in particular in the case of error reporting @@ -220,6 +233,9 @@ public: return OptionRegistry::instance().template get(); } + /// \brief Access the object which manages optimization bisection for failure + /// analysis. + OptBisect &getOptBisect(); private: LLVMContext(LLVMContext&) = delete; void operator=(LLVMContext&) = delete; @@ -235,10 +251,6 @@ private: friend class Module; }; -/// getGlobalContext - Returns a global context. This is for LLVM clients that -/// only care about operating on a single thread. -extern LLVMContext &getGlobalContext(); - // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMContext, LLVMContextRef) diff --git a/include/llvm/IR/LegacyPassManagers.h b/include/llvm/IR/LegacyPassManagers.h index b8e33478d6a9d3666db8076ffcbb270c75bbd31d..530fd7166498ecc58b9f2e128757ef9c6f7ed202 100644 --- a/include/llvm/IR/LegacyPassManagers.h +++ b/include/llvm/IR/LegacyPassManagers.h @@ -14,13 +14,11 @@ #ifndef LLVM_IR_LEGACYPASSMANAGERS_H #define LLVM_IR_LEGACYPASSMANAGERS_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Pass.h" -#include #include //===----------------------------------------------------------------------===// @@ -93,12 +91,13 @@ #include "llvm/Support/PrettyStackTrace.h" namespace llvm { - class Module; - class Pass; - class StringRef; - class Value; - class Timer; - class PMDataManager; +template class ArrayRef; +class Module; +class Pass; +class StringRef; +class Value; +class Timer; +class PMDataManager; // enums for debugging strings enum PassDebuggingString { diff --git a/include/llvm/IR/Mangler.h b/include/llvm/IR/Mangler.h index ea2f0c3f09f3d1a826a3d9b8df5a63a93dbe4494..349218e33817cd207d15704ea12d9948192708c9 100644 --- a/include/llvm/IR/Mangler.h +++ b/include/llvm/IR/Mangler.h @@ -16,13 +16,13 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/IR/GlobalValue.h" -#include "llvm/Support/raw_ostream.h" namespace llvm { class DataLayout; template class SmallVectorImpl; class Twine; +class raw_ostream; class Mangler { /// We need to give global values the same name every time they are mangled. diff --git a/include/llvm/IR/Metadata.def b/include/llvm/IR/Metadata.def index b1d22178e262049971dcc4321ad4e0729382fe1c..607f5ef125c90b5c4ef1090d59ea534fb9f3b761 100644 --- a/include/llvm/IR/Metadata.def +++ b/include/llvm/IR/Metadata.def @@ -77,6 +77,7 @@ HANDLE_METADATA_LEAF(MDString) HANDLE_METADATA_BRANCH(ValueAsMetadata) HANDLE_METADATA_LEAF(ConstantAsMetadata) HANDLE_METADATA_LEAF(LocalAsMetadata) +HANDLE_METADATA_LEAF(DistinctMDOperandPlaceholder) HANDLE_MDNODE_BRANCH(MDNode) HANDLE_MDNODE_LEAF_UNIQUABLE(MDTuple) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILocation) diff --git a/include/llvm/IR/Metadata.h b/include/llvm/IR/Metadata.h index 9f39bf95e8d70b705052f102f1816fb7abe1cff9..91f43d342d27f55b73b6ef5d49509fff82848f21 100644 --- a/include/llvm/IR/Metadata.h +++ b/include/llvm/IR/Metadata.h @@ -19,6 +19,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Constant.h" @@ -51,7 +52,7 @@ protected: enum StorageType { Uniqued, Distinct, Temporary }; /// \brief Storage flag for non-uniqued, otherwise unowned, metadata. - unsigned Storage : 2; + unsigned char Storage; // TODO: expose remaining bits to subclasses. unsigned short SubclassData16; @@ -59,39 +60,14 @@ protected: public: enum MetadataKind { - MDTupleKind, - DILocationKind, - GenericDINodeKind, - DISubrangeKind, - DIEnumeratorKind, - DIBasicTypeKind, - DIDerivedTypeKind, - DICompositeTypeKind, - DISubroutineTypeKind, - DIFileKind, - DICompileUnitKind, - DISubprogramKind, - DILexicalBlockKind, - DILexicalBlockFileKind, - DINamespaceKind, - DIModuleKind, - DITemplateTypeParameterKind, - DITemplateValueParameterKind, - DIGlobalVariableKind, - DILocalVariableKind, - DIExpressionKind, - DIObjCPropertyKind, - DIImportedEntityKind, - ConstantAsMetadataKind, - LocalAsMetadataKind, - MDStringKind, - DIMacroKind, - DIMacroFileKind +#define HANDLE_METADATA_LEAF(CLASS) CLASS##Kind, +#include "llvm/IR/Metadata.def" }; protected: Metadata(unsigned ID, StorageType Storage) : SubclassID(ID), Storage(Storage), SubclassData16(0), SubclassData32(0) { + static_assert(sizeof(*this) == 8, "Metdata fields poorly packed"); } ~Metadata() = default; @@ -283,20 +259,14 @@ private: LLVMContext &Context; uint64_t NextIndex; SmallDenseMap, 4> UseMap; - /// Flag that can be set to false if this metadata should not be - /// RAUW'ed, e.g. if it is used as the key of a map. - bool CanReplace; public: ReplaceableMetadataImpl(LLVMContext &Context) - : Context(Context), NextIndex(0), CanReplace(true) {} + : Context(Context), NextIndex(0) {} ~ReplaceableMetadataImpl() { assert(UseMap.empty() && "Cannot destroy in-use replaceable metadata"); } - /// Set the CanReplace flag to the given value. - void setCanReplace(bool Replaceable) { CanReplace = Replaceable; } - LLVMContext &getContext() const { return Context; } /// \brief Replace all uses of this with MD. @@ -316,7 +286,19 @@ private: void dropRef(void *Ref); void moveRef(void *Ref, void *New, const Metadata &MD); - static ReplaceableMetadataImpl *get(Metadata &MD); + /// Lazily construct RAUW support on MD. + /// + /// If this is an unresolved MDNode, RAUW support will be created on-demand. + /// ValueAsMetadata always has RAUW support. + static ReplaceableMetadataImpl *getOrCreate(Metadata &MD); + + /// Get RAUW support on MD, if it exists. + static ReplaceableMetadataImpl *getIfExists(Metadata &MD); + + /// Check whether this node will support RAUW. + /// + /// Returns \c true unless getOrCreate() would return null. + static bool isReplaceable(const Metadata &MD); }; /// \brief Value wrapper in the Metadata hierarchy. @@ -766,6 +748,13 @@ public: return nullptr; } + /// Ensure that this has RAUW support, and then return it. + ReplaceableMetadataImpl *getOrCreateReplaceableUses() { + if (!hasReplaceableUses()) + makeReplaceable(llvm::make_unique(getContext())); + return getReplaceableUses(); + } + /// \brief Assign RAUW support to this. /// /// Make this replaceable, taking ownership of \c ReplaceableUses (which must @@ -827,9 +816,9 @@ class MDNode : public Metadata { unsigned NumOperands; unsigned NumUnresolved; -protected: ContextAndReplaceableUses Context; +protected: void *operator new(size_t Size, unsigned NumOps); void operator delete(void *Mem); @@ -891,7 +880,7 @@ public: /// As forward declarations are resolved, their containers should get /// resolved automatically. However, if this (or one of its operands) is /// involved in a cycle, \a resolveCycles() needs to be called explicitly. - bool isResolved() const { return !Context.hasReplaceableUses(); } + bool isResolved() const { return !isTemporary() && !NumUnresolved; } bool isUniqued() const { return Storage == Uniqued; } bool isDistinct() const { return Storage == Distinct; } @@ -902,33 +891,17 @@ public: /// \pre \a isTemporary() must be \c true. void replaceAllUsesWith(Metadata *MD) { assert(isTemporary() && "Expected temporary node"); - assert(!isResolved() && "Expected RAUW support"); - Context.getReplaceableUses()->replaceAllUsesWith(MD); - } - - /// Set the CanReplace flag to the given value. - void setCanReplace(bool Replaceable) { - Context.getReplaceableUses()->setCanReplace(Replaceable); + if (Context.hasReplaceableUses()) + Context.getReplaceableUses()->replaceAllUsesWith(MD); } /// \brief Resolve cycles. /// /// Once all forward declarations have been resolved, force cycles to be - /// resolved. This interface is used when there are no more temporaries, - /// and thus unresolved nodes are part of cycles and no longer need RAUW - /// support. + /// resolved. /// /// \pre No operands (or operands' operands, etc.) have \a isTemporary(). - void resolveCycles() { resolveRecursivelyImpl(/* AllowTemps */ false); } - - /// \brief Resolve cycles while ignoring temporaries. - /// - /// This drops RAUW support for any temporaries, which can no longer - /// be uniqued. - /// - void resolveNonTemporaries() { - resolveRecursivelyImpl(/* AllowTemps */ true); - } + void resolveCycles(); /// \brief Replace a temporary node with a permanent one. /// @@ -981,15 +954,15 @@ protected: private: void handleChangedOperand(void *Ref, Metadata *New); + /// Resolve a unique, unresolved node. void resolve(); + + /// Drop RAUW support, if any. + void dropReplaceableUses(); + void resolveAfterOperandChange(Metadata *Old, Metadata *New); void decrementUnresolvedOperandCount(); - unsigned countUnresolvedOperands(); - - /// Resolve cycles recursively. If \p AllowTemps is true, then any temporary - /// metadata is ignored, otherwise it asserts when encountering temporary - /// metadata. - void resolveRecursivelyImpl(bool AllowTemps); + void countUnresolvedOperands(); /// \brief Mutate this to be "uniqued". /// @@ -1220,6 +1193,52 @@ public: typedef MDTupleTypedArrayWrapper CLASS##Array; #include "llvm/IR/Metadata.def" +/// Placeholder metadata for operands of distinct MDNodes. +/// +/// This is a lightweight placeholder for an operand of a distinct node. It's +/// purpose is to help track forward references when creating a distinct node. +/// This allows distinct nodes involved in a cycle to be constructed before +/// their operands without requiring a heavyweight temporary node with +/// full-blown RAUW support. +/// +/// Each placeholder supports only a single MDNode user. Clients should pass +/// an ID, retrieved via \a getID(), to indicate the "real" operand that this +/// should be replaced with. +/// +/// While it would be possible to implement move operators, they would be +/// fairly expensive. Leave them unimplemented to discourage their use +/// (clients can use std::deque, std::list, BumpPtrAllocator, etc.). +class DistinctMDOperandPlaceholder : public Metadata { + friend class MetadataTracking; + + Metadata **Use = nullptr; + + DistinctMDOperandPlaceholder() = delete; + DistinctMDOperandPlaceholder(DistinctMDOperandPlaceholder &&) = delete; + DistinctMDOperandPlaceholder(const DistinctMDOperandPlaceholder &) = delete; + +public: + explicit DistinctMDOperandPlaceholder(unsigned ID) + : Metadata(DistinctMDOperandPlaceholderKind, Distinct) { + SubclassData32 = ID; + } + + ~DistinctMDOperandPlaceholder() { + if (Use) + *Use = nullptr; + } + + unsigned getID() const { return SubclassData32; } + + /// Replace the use of this with MD. + void replaceUseWith(Metadata *MD) { + if (!Use) + return; + *Use = MD; + Use = nullptr; + } +}; + //===----------------------------------------------------------------------===// /// \brief A tuple of MDNodes. /// @@ -1296,6 +1315,8 @@ public: void setOperand(unsigned I, MDNode *New); StringRef getName() const; void print(raw_ostream &ROS, bool IsForDebug = false) const; + void print(raw_ostream &ROS, ModuleSlotTracker &MST, + bool IsForDebug = false) const; void dump() const; // --------------------------------------------------------------------------- diff --git a/include/llvm/IR/Module.h b/include/llvm/IR/Module.h index 09cf5318aa4cdda8da62a88d90483e8af41d2ca5..632b27e2d0dd5ce46813232a6dfe131f109ed5d2 100644 --- a/include/llvm/IR/Module.h +++ b/include/llvm/IR/Module.h @@ -15,12 +15,12 @@ #ifndef LLVM_IR_MODULE_H #define LLVM_IR_MODULE_H -#include "llvm/ADT/Optional.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Comdat.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalIFunc.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/CBindingWrapping.h" @@ -29,11 +29,13 @@ #include namespace llvm { +template class Optional; class FunctionType; class GVMaterializer; class LLVMContext; class RandomNumberGenerator; class StructType; +template class SmallPtrSetImpl; template<> struct ilist_traits : public ilist_default_traits { @@ -75,6 +77,8 @@ public: typedef SymbolTableList FunctionListType; /// The type for the list of aliases. typedef SymbolTableList AliasListType; + /// The type for the list of ifuncs. + typedef SymbolTableList IFuncListType; /// The type for the list of named metadata. typedef ilist NamedMDListType; /// The type of the comdat "symbol" table. @@ -100,6 +104,11 @@ public: /// The Global Alias constant iterator typedef AliasListType::const_iterator const_alias_iterator; + /// The Global IFunc iterators. + typedef IFuncListType::iterator ifunc_iterator; + /// The Global IFunc constant iterator + typedef IFuncListType::const_iterator const_ifunc_iterator; + /// The named metadata iterators. typedef NamedMDListType::iterator named_metadata_iterator; /// The named metadata constant iterators. @@ -163,6 +172,7 @@ private: GlobalListType GlobalList; ///< The Global Variables in the module FunctionListType FunctionList; ///< The Functions in the module AliasListType AliasList; ///< The Aliases in the module + IFuncListType IFuncList; ///< The IFuncs in the module NamedMDListType NamedMDList; ///< The named metadata in the module std::string GlobalScopeAsm; ///< Inline Asm at global scope. ValueSymbolTable *ValSymTab; ///< Symbol table for values @@ -383,6 +393,15 @@ public: /// name is not found. GlobalAlias *getNamedAlias(StringRef Name) const; +/// @} +/// @name Global IFunc Accessors +/// @{ + + /// Return the global ifunc in the module with the specified name, of + /// arbitrary type. This method returns null if a global with the specified + /// name is not found. + GlobalIFunc *getNamedIFunc(StringRef Name) const; + /// @} /// @name Named Metadata Accessors /// @{ @@ -486,6 +505,13 @@ public: static AliasListType Module::*getSublistAccess(GlobalAlias*) { return &Module::AliasList; } + /// Get the Module's list of ifuncs (constant). + const IFuncListType &getIFuncList() const { return IFuncList; } + /// Get the Module's list of ifuncs. + IFuncListType &getIFuncList() { return IFuncList; } + static IFuncListType Module::*getSublistAccess(GlobalIFunc*) { + return &Module::IFuncList; + } /// Get the Module's list of named metadata (constant). const NamedMDListType &getNamedMDList() const { return NamedMDList; } /// Get the Module's list of named metadata. @@ -560,9 +586,96 @@ public: } /// @} -/// @name Named Metadata Iteration +/// @name IFunc Iteration /// @{ + ifunc_iterator ifunc_begin() { return IFuncList.begin(); } + const_ifunc_iterator ifunc_begin() const { return IFuncList.begin(); } + ifunc_iterator ifunc_end () { return IFuncList.end(); } + const_ifunc_iterator ifunc_end () const { return IFuncList.end(); } + size_t ifunc_size () const { return IFuncList.size(); } + bool ifunc_empty() const { return IFuncList.empty(); } + + iterator_range ifuncs() { + return make_range(ifunc_begin(), ifunc_end()); + } + iterator_range ifuncs() const { + return make_range(ifunc_begin(), ifunc_end()); + } + +/// @} +/// @name Convenience iterators +/// @{ + + template class global_object_iterator_t { + friend Module; + + typename std::conditional::type + function_i, + function_e; + typename std::conditional::type global_i; + + typedef + typename std::conditional::type ModuleTy; + + global_object_iterator_t(ModuleTy &M) + : function_i(M.begin()), function_e(M.end()), + global_i(M.global_begin()) {} + global_object_iterator_t(ModuleTy &M, int) + : function_i(M.end()), function_e(M.end()), global_i(M.global_end()) {} + + public: + global_object_iterator_t &operator++() { + if (function_i != function_e) + ++function_i; + else + ++global_i; + return *this; + } + + typename std::conditional::type & + operator*() const { + if (function_i != function_e) + return *function_i; + else + return *global_i; + } + + bool operator!=(const global_object_iterator_t &other) const { + return function_i != other.function_i || global_i != other.global_i; + } + }; + + typedef global_object_iterator_t global_object_iterator; + typedef global_object_iterator_t + const_global_object_iterator; + + global_object_iterator global_object_begin() { + return global_object_iterator(*this); + } + global_object_iterator global_object_end() { + return global_object_iterator(*this, 0); + } + + const_global_object_iterator global_object_begin() const { + return const_global_object_iterator(*this); + } + const_global_object_iterator global_object_end() const { + return const_global_object_iterator(*this, 0); + } + + iterator_range global_objects() { + return make_range(global_object_begin(), global_object_end()); + } + iterator_range global_objects() const { + return make_range(global_object_begin(), global_object_end()); + } + + /// @} + /// @name Named Metadata Iteration + /// @{ + named_metadata_iterator named_metadata_begin() { return NamedMDList.begin(); } const_named_metadata_iterator named_metadata_begin() const { return NamedMDList.begin(); @@ -583,6 +696,58 @@ public: return make_range(named_metadata_begin(), named_metadata_end()); } + /// An iterator for DICompileUnits that skips those marked NoDebug. + class debug_compile_units_iterator + : public std::iterator { + NamedMDNode *CUs; + unsigned Idx; + void SkipNoDebugCUs(); + public: + explicit debug_compile_units_iterator(NamedMDNode *CUs, unsigned Idx) + : CUs(CUs), Idx(Idx) { + SkipNoDebugCUs(); + } + debug_compile_units_iterator &operator++() { + ++Idx; + SkipNoDebugCUs(); + return *this; + } + debug_compile_units_iterator operator++(int) { + debug_compile_units_iterator T(*this); + ++Idx; + return T; + } + bool operator==(const debug_compile_units_iterator &I) const { + return Idx == I.Idx; + } + bool operator!=(const debug_compile_units_iterator &I) const { + return Idx != I.Idx; + } + DICompileUnit *operator*() const; + DICompileUnit *operator->() const; + }; + + debug_compile_units_iterator debug_compile_units_begin() const { + auto *CUs = getNamedMetadata("llvm.dbg.cu"); + return debug_compile_units_iterator(CUs, 0); + } + + debug_compile_units_iterator debug_compile_units_end() const { + auto *CUs = getNamedMetadata("llvm.dbg.cu"); + return debug_compile_units_iterator(CUs, CUs ? CUs->getNumOperands() : 0); + } + + /// Return an iterator for all DICompileUnits listed in this Module's + /// llvm.dbg.cu named metadata node and aren't explicitly marked as + /// NoDebug. + iterator_range debug_compile_units() const { + auto *CUs = getNamedMetadata("llvm.dbg.cu"); + return make_range( + debug_compile_units_iterator(CUs, 0), + debug_compile_units_iterator(CUs, CUs ? CUs->getNumOperands() : 0)); + } +/// @} + /// Destroy ConstantArrays in LLVMContext if they are not used. /// ConstantArrays constructed during linking can cause quadratic memory /// explosion. Releasing all unused constants can cause a 20% LTO compile-time @@ -592,7 +757,6 @@ public: /// be called where all uses of the LLVMContext are understood. void dropTriviallyDeadConstantArrays(); -/// @} /// @name Utility functions for printing and dumping Module objects /// @{ @@ -637,14 +801,19 @@ public: void setPICLevel(PICLevel::Level PL); /// @} - /// @name Utility functions for querying and setting PGO summary - /// @{ +/// @} +/// @name Utility functions for querying and setting PIE level +/// @{ + + /// \brief Returns the PIE level (small or large model) + PIELevel::Level getPIELevel() const; - /// \brief Set maximum function count in PGO mode - void setMaximumFunctionCount(uint64_t); + /// \brief Set the PIE level (small or large model) + void setPIELevel(PIELevel::Level PL); +/// @} - /// \brief Returns maximum function count in PGO mode - Optional getMaximumFunctionCount(); + /// @name Utility functions for querying and setting PGO summary + /// @{ /// \brief Attach profile summary metadata to this module. void setProfileSummary(Metadata *M); @@ -654,6 +823,12 @@ public: /// @} }; +/// \brief Given "llvm.used" or "llvm.compiler.used" as a global name, collect +/// the initializer elements of that global in Set and return the global itself. +GlobalVariable *collectUsedGlobalVariables(const Module &M, + SmallPtrSetImpl &Set, + bool CompilerUsed); + /// An raw_ostream inserter for modules. inline raw_ostream &operator<<(raw_ostream &O, const Module &M) { M.print(O, nullptr); diff --git a/include/llvm/IR/ModuleSlotTracker.h b/include/llvm/IR/ModuleSlotTracker.h index 49730a66bdf64ad4b3cd62b3b5cc7cbb2337c81d..eb26fba906ea8cea513692bc2e87ebfa8820b1eb 100644 --- a/include/llvm/IR/ModuleSlotTracker.h +++ b/include/llvm/IR/ModuleSlotTracker.h @@ -30,6 +30,8 @@ class Value; class ModuleSlotTracker { /// Storage for a slot tracker. std::unique_ptr MachineStorage; + bool ShouldCreateStorage = false; + bool ShouldInitializeAllMetadata = false; const Module *M = nullptr; const Function *F = nullptr; @@ -53,7 +55,9 @@ public: /// Destructor to clean up storage. ~ModuleSlotTracker(); - SlotTracker *getMachine() const { return Machine; } + /// Lazily creates a slot tracker. + SlotTracker *getMachine(); + const Module *getModule() const { return M; } const Function *getCurrentFunction() const { return F; } diff --git a/include/llvm/IR/ModuleSummaryIndex.h b/include/llvm/IR/ModuleSummaryIndex.h index 30a7145cb42e721cd5fe888d0843e44452665fdb..6b866dbd9e96710bf907d3ea4db7e7d5f2820e26 100644 --- a/include/llvm/IR/ModuleSummaryIndex.h +++ b/include/llvm/IR/ModuleSummaryIndex.h @@ -18,12 +18,13 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" -#include "llvm/IR/Function.h" #include "llvm/IR/Module.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" + +#include namespace llvm { @@ -44,20 +45,80 @@ struct CalleeInfo { } }; +/// Struct to hold value either by GUID or Value*, depending on whether this +/// is a combined or per-module index, respectively. +struct ValueInfo { + /// The value representation used in this instance. + enum ValueInfoKind { + VI_GUID, + VI_Value, + }; + + /// Union of the two possible value types. + union ValueUnion { + GlobalValue::GUID Id; + const Value *V; + ValueUnion(GlobalValue::GUID Id) : Id(Id) {} + ValueUnion(const Value *V) : V(V) {} + }; + + /// The value being represented. + ValueUnion TheValue; + /// The value representation. + ValueInfoKind Kind; + /// Constructor for a GUID value + ValueInfo(GlobalValue::GUID Id = 0) : TheValue(Id), Kind(VI_GUID) {} + /// Constructor for a Value* value + ValueInfo(const Value *V) : TheValue(V), Kind(VI_Value) {} + /// Accessor for GUID value + GlobalValue::GUID getGUID() const { + assert(Kind == VI_GUID && "Not a GUID type"); + return TheValue.Id; + } + /// Accessor for Value* value + const Value *getValue() const { + assert(Kind == VI_Value && "Not a Value type"); + return TheValue.V; + } +}; + /// \brief Function and variable summary information to aid decisions and /// implementation of importing. -/// -/// This is a separate class from GlobalValueInfo to enable lazy reading of this -/// summary information from the combined index file during imporing. class GlobalValueSummary { public: /// \brief Sububclass discriminator (for dyn_cast<> et al.) - enum SummaryKind { FunctionKind, GlobalVarKind }; + enum SummaryKind { AliasKind, FunctionKind, GlobalVarKind }; + + /// Group flags (Linkage, hasSection, isOptSize, etc.) as a bitfield. + struct GVFlags { + /// \brief The linkage type of the associated global value. + /// + /// One use is to flag values that have local linkage types and need to + /// have module identifier appended before placing into the combined + /// index, to disambiguate from other values with the same name. + /// In the future this will be used to update and optimize linkage + /// types based on global summary-based analysis. + unsigned Linkage : 4; + + /// Indicate if the global value is located in a specific section. + unsigned HasSection : 1; + + /// Convenience Constructors + explicit GVFlags(GlobalValue::LinkageTypes Linkage, bool HasSection) + : Linkage(Linkage), HasSection(HasSection) {} + GVFlags(const GlobalValue &GV) + : Linkage(GV.getLinkage()), HasSection(GV.hasSection()) {} + }; private: /// Kind of summary for use in dyn_cast<> et al. SummaryKind Kind; + /// This is the hash of the name of the symbol in the original file. It is + /// identical to the GUID for global symbols, but differs for local since the + /// GUID includes the module level id in the hash. + GlobalValue::GUID OriginalName; + /// \brief Path of module IR containing value's definition, used to locate /// module during importing. /// @@ -67,29 +128,28 @@ private: /// module path string table. StringRef ModulePath; - /// \brief The linkage type of the associated global value. - /// - /// One use is to flag values that have local linkage types and need to - /// have module identifier appended before placing into the combined - /// index, to disambiguate from other values with the same name. - /// In the future this will be used to update and optimize linkage - /// types based on global summary-based analysis. - GlobalValue::LinkageTypes Linkage; - - /// List of GUIDs of values referenced by this global value's definition + GVFlags Flags; + + /// List of values referenced by this global value's definition /// (either by the initializer of a global variable, or referenced /// from within a function). This does not include functions called, which /// are listed in the derived FunctionSummary object. - std::vector RefEdgeList; + std::vector RefEdgeList; protected: /// GlobalValueSummary constructor. - GlobalValueSummary(SummaryKind K, GlobalValue::LinkageTypes Linkage) - : Kind(K), Linkage(Linkage) {} + GlobalValueSummary(SummaryKind K, GVFlags Flags) : Kind(K), Flags(Flags) {} public: virtual ~GlobalValueSummary() = default; + /// Returns the hash of the original name, it is identical to the GUID for + /// externally visible symbols, but not for local ones. + GlobalValue::GUID getOriginalName() { return OriginalName; } + + /// Initialize the original name hash in this summary. + void setOriginalName(GlobalValue::GUID Name) { OriginalName = Name; } + /// Which kind of summary subclass this is. SummaryKind getSummaryKind() const { return Kind; } @@ -100,44 +160,91 @@ public: /// Get the path to the module containing this function. StringRef modulePath() const { return ModulePath; } + /// Get the flags for this GlobalValue (see \p struct GVFlags). + GVFlags flags() { return Flags; } + /// Return linkage type recorded for this global value. - GlobalValue::LinkageTypes linkage() const { return Linkage; } + GlobalValue::LinkageTypes linkage() const { + return static_cast(Flags.Linkage); + } + + /// Sets the linkage to the value determined by global summary-based + /// optimization. Will be applied in the ThinLTO backends. + void setLinkage(GlobalValue::LinkageTypes Linkage) { + Flags.Linkage = Linkage; + } + + /// Return true if this summary is for a GlobalValue that needs promotion + /// to be referenced from another module. + bool needsRenaming() const { return GlobalValue::isLocalLinkage(linkage()); } + + /// Return true if this global value is located in a specific section. + bool hasSection() const { return Flags.HasSection; } /// Record a reference from this global value to the global value identified /// by \p RefGUID. - void addRefEdge(uint64_t RefGUID) { RefEdgeList.push_back(RefGUID); } + void addRefEdge(GlobalValue::GUID RefGUID) { RefEdgeList.push_back(RefGUID); } + + /// Record a reference from this global value to the global value identified + /// by \p RefV. + void addRefEdge(const Value *RefV) { RefEdgeList.push_back(RefV); } /// Record a reference from this global value to each global value identified /// in \p RefEdges. - void addRefEdges(DenseSet &RefEdges) { + void addRefEdges(DenseSet &RefEdges) { for (auto &RI : RefEdges) addRefEdge(RI); } - /// Return the list of GUIDs referenced by this global value definition. - std::vector &refs() { return RefEdgeList; } - const std::vector &refs() const { return RefEdgeList; } + /// Return the list of values referenced by this global value definition. + std::vector &refs() { return RefEdgeList; } + const std::vector &refs() const { return RefEdgeList; } +}; + +/// \brief Alias summary information. +class AliasSummary : public GlobalValueSummary { + GlobalValueSummary *AliaseeSummary; + +public: + /// Summary constructors. + AliasSummary(GVFlags Flags) : GlobalValueSummary(AliasKind, Flags) {} + + /// Check if this is an alias summary. + static bool classof(const GlobalValueSummary *GVS) { + return GVS->getSummaryKind() == AliasKind; + } + + void setAliasee(GlobalValueSummary *Aliasee) { AliaseeSummary = Aliasee; } + + const GlobalValueSummary &getAliasee() const { + return const_cast(this)->getAliasee(); + } + + GlobalValueSummary &getAliasee() { + assert(AliaseeSummary && "Unexpected missing aliasee summary"); + return *AliaseeSummary; + } }; /// \brief Function summary information to aid decisions and implementation of /// importing. class FunctionSummary : public GlobalValueSummary { public: - /// call edge pair. - typedef std::pair EdgeTy; + /// call edge pair. + typedef std::pair EdgeTy; private: /// Number of instructions (ignoring debug instructions, e.g.) computed /// during the initial compile step when the summary index is first built. unsigned InstCount; - /// List of call edge pairs from this function. + /// List of call edge pairs from this function. std::vector CallGraphEdgeList; public: /// Summary constructors. - FunctionSummary(GlobalValue::LinkageTypes Linkage, unsigned NumInsts) - : GlobalValueSummary(FunctionKind, Linkage), InstCount(NumInsts) {} + FunctionSummary(GVFlags Flags, unsigned NumInsts) + : GlobalValueSummary(FunctionKind, Flags), InstCount(NumInsts) {} /// Check if this is a function summary. static bool classof(const GlobalValueSummary *GVS) { @@ -150,18 +257,25 @@ public: /// Record a call graph edge from this function to the function identified /// by \p CalleeGUID, with \p CalleeInfo including the cumulative profile /// count (across all calls from this function) or 0 if no PGO. - void addCallGraphEdge(uint64_t CalleeGUID, CalleeInfo Info) { + void addCallGraphEdge(GlobalValue::GUID CalleeGUID, CalleeInfo Info) { CallGraphEdgeList.push_back(std::make_pair(CalleeGUID, Info)); } + /// Record a call graph edge from this function to the function identified + /// by \p CalleeV, with \p CalleeInfo including the cumulative profile + /// count (across all calls from this function) or 0 if no PGO. + void addCallGraphEdge(const Value *CalleeV, CalleeInfo Info) { + CallGraphEdgeList.push_back(std::make_pair(CalleeV, Info)); + } + /// Record a call graph edge from this function to each function recorded /// in \p CallGraphEdges. - void addCallGraphEdges(DenseMap &CallGraphEdges) { + void addCallGraphEdges(DenseMap &CallGraphEdges) { for (auto &EI : CallGraphEdges) addCallGraphEdge(EI.first, EI.second); } - /// Return the list of pairs. + /// Return the list of pairs. std::vector &calls() { return CallGraphEdgeList; } const std::vector &calls() const { return CallGraphEdgeList; } }; @@ -176,8 +290,7 @@ class GlobalVarSummary : public GlobalValueSummary { public: /// Summary constructors. - GlobalVarSummary(GlobalValue::LinkageTypes Linkage) - : GlobalValueSummary(GlobalVarKind, Linkage) {} + GlobalVarSummary(GVFlags Flags) : GlobalValueSummary(GlobalVarKind, Flags) {} /// Check if this is a global variable summary. static bool classof(const GlobalValueSummary *GVS) { @@ -185,77 +298,42 @@ public: } }; -/// \brief Class to hold pointer to summary object and information required -/// for parsing or writing it. -class GlobalValueInfo { -private: - /// Summary information used to help make ThinLTO importing decisions. - std::unique_ptr Summary; - - /// \brief The bitcode offset corresponding to either an associated - /// function's function body record, or to an associated summary record, - /// depending on whether this is a per-module or combined index. - /// - /// This bitcode offset is written to or read from the associated - /// \a ValueSymbolTable entry for a function. - /// For the per-module index this holds the bitcode offset of a - /// function's body record within bitcode module block in its module, - /// although this field is currently only used when writing the VST - /// (it is set to 0 and also unused when this is a global variable). - /// For the combined index this holds the offset of the corresponding - /// summary record, to enable associating the combined index - /// VST records with the summary records. - uint64_t BitcodeIndex; - -public: - GlobalValueInfo(uint64_t Offset = 0, - std::unique_ptr Summary = nullptr) - : Summary(std::move(Summary)), BitcodeIndex(Offset) {} - - /// Record the summary information parsed out of the summary block during - /// parsing or combined index creation. - void setSummary(std::unique_ptr GVSummary) { - Summary = std::move(GVSummary); - } - - /// Get the summary recorded for this global value. - GlobalValueSummary *summary() const { return Summary.get(); } - - /// Get the bitcode index recorded for this value symbol table entry. - uint64_t bitcodeIndex() const { return BitcodeIndex; } - - /// Set the bitcode index recorded for this value symbol table entry. - void setBitcodeIndex(uint64_t Offset) { BitcodeIndex = Offset; } -}; +/// 160 bits SHA1 +typedef std::array ModuleHash; -/// List of global value info structures for a particular value held +/// List of global value summary structures for a particular value held /// in the GlobalValueMap. Requires a vector in the case of multiple /// COMDAT values of the same name. -typedef std::vector> GlobalValueInfoList; +typedef std::vector> GlobalValueSummaryList; -/// Map from global value GUID to corresponding info structures. +/// Map from global value GUID to corresponding summary structures. /// Use a std::map rather than a DenseMap since it will likely incur /// less overhead, as the value type is not very small and the size /// of the map is unknown, resulting in inefficiencies due to repeated /// insertions and resizing. -typedef std::map GlobalValueInfoMapTy; +typedef std::map + GlobalValueSummaryMapTy; -/// Type used for iterating through the global value info map. -typedef GlobalValueInfoMapTy::const_iterator const_globalvalueinfo_iterator; -typedef GlobalValueInfoMapTy::iterator globalvalueinfo_iterator; +/// Type used for iterating through the global value summary map. +typedef GlobalValueSummaryMapTy::const_iterator const_gvsummary_iterator; +typedef GlobalValueSummaryMapTy::iterator gvsummary_iterator; /// String table to hold/own module path strings, which additionally holds the -/// module ID assigned to each module during the plugin step. The StringMap -/// makes a copy of and owns inserted strings. -typedef StringMap ModulePathStringTableTy; +/// module ID assigned to each module during the plugin step, as well as a hash +/// of the module. The StringMap makes a copy of and owns inserted strings. +typedef StringMap> ModulePathStringTableTy; + +/// Map of global value GUID to its summary, used to identify values defined in +/// a particular module, and provide efficient access to their summary. +typedef std::map GVSummaryMapTy; /// Class to hold module path string table and global value map, /// and encapsulate methods for operating on them. class ModuleSummaryIndex { private: - /// Map from value name to list of information instances for values of that + /// Map from value name to list of summary instances for values of that /// name (may be duplicates in the COMDAT case, e.g.). - GlobalValueInfoMapTy GlobalValueMap; + GlobalValueSummaryMapTy GlobalValueMap; /// Holds strings for combined index, mapping to the corresponding module ID. ModulePathStringTableTy ModulePathStringTable; @@ -268,53 +346,94 @@ public: ModuleSummaryIndex(const ModuleSummaryIndex &) = delete; void operator=(const ModuleSummaryIndex &) = delete; - globalvalueinfo_iterator begin() { return GlobalValueMap.begin(); } - const_globalvalueinfo_iterator begin() const { - return GlobalValueMap.begin(); - } - globalvalueinfo_iterator end() { return GlobalValueMap.end(); } - const_globalvalueinfo_iterator end() const { return GlobalValueMap.end(); } + gvsummary_iterator begin() { return GlobalValueMap.begin(); } + const_gvsummary_iterator begin() const { return GlobalValueMap.begin(); } + gvsummary_iterator end() { return GlobalValueMap.end(); } + const_gvsummary_iterator end() const { return GlobalValueMap.end(); } - /// Get the list of global value info objects for a given value name. - const GlobalValueInfoList &getGlobalValueInfoList(StringRef ValueName) { + /// Get the list of global value summary objects for a given value name. + const GlobalValueSummaryList &getGlobalValueSummaryList(StringRef ValueName) { return GlobalValueMap[GlobalValue::getGUID(ValueName)]; } - /// Get the list of global value info objects for a given value name. - const const_globalvalueinfo_iterator - findGlobalValueInfoList(StringRef ValueName) const { + /// Get the list of global value summary objects for a given value name. + const const_gvsummary_iterator + findGlobalValueSummaryList(StringRef ValueName) const { return GlobalValueMap.find(GlobalValue::getGUID(ValueName)); } - /// Get the list of global value info objects for a given value GUID. - const const_globalvalueinfo_iterator - findGlobalValueInfoList(uint64_t ValueGUID) const { + /// Get the list of global value summary objects for a given value GUID. + const const_gvsummary_iterator + findGlobalValueSummaryList(GlobalValue::GUID ValueGUID) const { return GlobalValueMap.find(ValueGUID); } - /// Add a global value info for a value of the given name. - void addGlobalValueInfo(StringRef ValueName, - std::unique_ptr Info) { - GlobalValueMap[GlobalValue::getGUID(ValueName)].push_back(std::move(Info)); + /// Add a global value summary for a value of the given name. + void addGlobalValueSummary(StringRef ValueName, + std::unique_ptr Summary) { + GlobalValueMap[GlobalValue::getGUID(ValueName)].push_back( + std::move(Summary)); + } + + /// Add a global value summary for a value of the given GUID. + void addGlobalValueSummary(GlobalValue::GUID ValueGUID, + std::unique_ptr Summary) { + GlobalValueMap[ValueGUID].push_back(std::move(Summary)); } - /// Add a global value info for a value of the given GUID. - void addGlobalValueInfo(uint64_t ValueGUID, - std::unique_ptr Info) { - GlobalValueMap[ValueGUID].push_back(std::move(Info)); + /// Find the summary for global \p GUID in module \p ModuleId, or nullptr if + /// not found. + GlobalValueSummary *findSummaryInModule(GlobalValue::GUID ValueGUID, + StringRef ModuleId) const { + auto CalleeInfoList = findGlobalValueSummaryList(ValueGUID); + if (CalleeInfoList == end()) { + return nullptr; // This function does not have a summary + } + auto Summary = + llvm::find_if(CalleeInfoList->second, + [&](const std::unique_ptr &Summary) { + return Summary->modulePath() == ModuleId; + }); + if (Summary == CalleeInfoList->second.end()) + return nullptr; + return Summary->get(); } - /// Table of modules, containing an id. - const StringMap &modulePaths() const { + /// Returns the first GlobalValueSummary for \p GV, asserting that there + /// is only one if \p PerModuleIndex. + GlobalValueSummary *getGlobalValueSummary(const GlobalValue &GV, + bool PerModuleIndex = true) const { + assert(GV.hasName() && "Can't get GlobalValueSummary for GV with no name"); + return getGlobalValueSummary(GlobalValue::getGUID(GV.getName()), + PerModuleIndex); + } + + /// Returns the first GlobalValueSummary for \p ValueGUID, asserting that + /// there + /// is only one if \p PerModuleIndex. + GlobalValueSummary *getGlobalValueSummary(GlobalValue::GUID ValueGUID, + bool PerModuleIndex = true) const; + + /// Table of modules, containing module hash and id. + const StringMap> &modulePaths() const { return ModulePathStringTable; } - /// Table of modules, containing an id. - StringMap &modulePaths() { return ModulePathStringTable; } + /// Table of modules, containing hash and id. + StringMap> &modulePaths() { + return ModulePathStringTable; + } /// Get the module ID recorded for the given module path. uint64_t getModuleId(const StringRef ModPath) const { - return ModulePathStringTable.lookup(ModPath); + return ModulePathStringTable.lookup(ModPath).first; + } + + /// Get the module SHA1 hash recorded for the given module path. + const ModuleHash &getModuleHash(const StringRef ModPath) const { + auto It = ModulePathStringTable.find(ModPath); + assert(It != ModulePathStringTable.end() && "Module not registered"); + return It->second.second; } /// Add the given per-module index into this module index/summary, @@ -326,18 +445,28 @@ public: /// Convenience method for creating a promoted global name /// for the given value name of a local, and its original module's ID. - static std::string getGlobalNameForLocal(StringRef Name, uint64_t ModId) { + static std::string getGlobalNameForLocal(StringRef Name, ModuleHash ModHash) { SmallString<256> NewName(Name); NewName += ".llvm."; - raw_svector_ostream(NewName) << ModId; + NewName += utohexstr(ModHash[0]); // Take the first 32 bits return NewName.str(); } - /// Add a new module path, mapped to the given module Id, and return StringRef - /// owned by string table map. - StringRef addModulePath(StringRef ModPath, uint64_t ModId) { - return ModulePathStringTable.insert(std::make_pair(ModPath, ModId)) - .first->first(); + /// Helper to obtain the unpromoted name for a global value (or the original + /// name if not promoted). + static StringRef getOriginalNameBeforePromote(StringRef Name) { + std::pair Pair = Name.split(".llvm."); + return Pair.first; + } + + /// Add a new module path with the given \p Hash, mapped to the given \p + /// ModID, and return an iterator to the entry in the index. + ModulePathStringTableTy::iterator + addModulePath(StringRef ModPath, uint64_t ModId, + ModuleHash Hash = ModuleHash{{0}}) { + return ModulePathStringTable.insert(std::make_pair( + ModPath, + std::make_pair(ModId, Hash))).first; } /// Check if the given Module has any functions available for exporting @@ -353,6 +482,16 @@ public: /// but if there was only one module or this was the first module we might /// not invoke mergeFrom. void removeEmptySummaryEntries(); + + /// Collect for the given module the list of function it defines + /// (GUID -> Summary). + void collectDefinedFunctionsForModule(StringRef ModulePath, + GVSummaryMapTy &GVSummaryMap) const; + + /// Collect for each module the list of Summaries it defines (GUID -> + /// Summary). + void collectDefinedGVSummariesPerModule( + StringMap &ModuleToDefinedGVSummaries) const; }; } // End llvm namespace diff --git a/include/llvm/IR/Operator.h b/include/llvm/IR/Operator.h index 50f34665a8ec558d17d29adeaaefc687678f67be..5880290f3d9919ac5207b056db2c35a4c60cee0c 100644 --- a/include/llvm/IR/Operator.h +++ b/include/llvm/IR/Operator.h @@ -79,7 +79,7 @@ public: }; private: - friend class BinaryOperator; + friend class Instruction; friend class ConstantExpr; void setHasNoUnsignedWrap(bool B) { SubclassOptionalData = @@ -130,7 +130,7 @@ public: }; private: - friend class BinaryOperator; + friend class Instruction; friend class ConstantExpr; void setIsExact(bool B) { SubclassOptionalData = (SubclassOptionalData & ~IsExact) | (B * IsExact); diff --git a/include/llvm/IR/OptBisect.h b/include/llvm/IR/OptBisect.h new file mode 100644 index 0000000000000000000000000000000000000000..9eee65e93e52f5c659ec14f841a132885ac004e3 --- /dev/null +++ b/include/llvm/IR/OptBisect.h @@ -0,0 +1,81 @@ +//===----------- llvm/IR/OptBisect.h - LLVM Bisect support -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares the interface for bisecting optimizations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_OPTBISECT_H +#define LLVM_IR_OPTBISECT_H + +namespace llvm { + +class Pass; +class StringRef; +class Twine; + +/// This class implements a mechanism to disable passes and individual +/// optimizations at compile time based on a command line option +/// (-opt-bisect-limit) in order to perform a bisecting search for +/// optimization-related problems. +class OptBisect { +public: + /// \brief Default constructor, initializes the OptBisect state based on the + /// -opt-bisect-limit command line argument. + /// + /// By default, bisection is disabled. + /// + /// Clients should not instantiate this class directly. All access should go + /// through LLVMContext. + OptBisect(); + + /// Checks the bisect limit to determine if the specified pass should run. + /// + /// This function will immediate return true if bisection is disabled. If the + /// bisect limit is set to -1, the function will print a message describing + /// the pass and the bisect number assigned to it and return true. Otherwise, + /// the function will print a message with the bisect number assigned to the + /// pass and indicating whether or not the pass will be run and return true if + /// the bisect limit has not yet been exceded or false if it has. + /// + /// Most passes should not call this routine directly. Instead, it is called + /// through a helper routine provided by the pass base class. For instance, + /// function passes should call FunctionPass::skipFunction(). + template + bool shouldRunPass(const Pass *P, const UnitT &U); + + /// Checks the bisect limit to determine if the optimization described by the + /// /p Desc argument should run. + /// + /// This function will immediate return true if bisection is disabled. If the + /// bisect limit is set to -1, the function will print a message with the + /// bisect number assigned to the optimization along with the /p Desc + /// description and return true. Otherwise, the function will print a message + /// with the bisect number assigned to the optimization and indicating whether + /// or not the pass will be run and return true if the bisect limit has not + /// yet been exceded or false if it has. + /// + /// Passes may call this function to provide more fine grained control over + /// individual optimizations performed by the pass. Passes which cannot be + /// skipped entirely (such as non-optional code generation passes) may still + /// call this function to control whether or not individual optional + /// transformations are performed. + bool shouldRunCase(const Twine &Desc); + +private: + bool checkPass(const StringRef PassName, const StringRef TargetDesc); + + bool BisectEnabled = false; + unsigned LastBisectNum = 0; +}; + +} // end namespace llvm + +#endif // LLVM_IR_OPTBISECT_H diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index 799f4aa6a00562098e7acc43e6c2d30fa841fb48..402d04a54a4126f5e6e2e3af7ae054564dc043e2 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -44,7 +44,6 @@ #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManagerInternal.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/TypeName.h" #include "llvm/Support/raw_ostream.h" @@ -55,9 +54,6 @@ namespace llvm { -class Module; -class Function; - /// \brief An abstract set of preserved analyses following a transformation pass /// run. /// @@ -148,6 +144,16 @@ public: PreservedPassIDs.count(PassID); } + /// \brief Query whether all of the analyses in the set are preserved. + bool preserved(PreservedAnalyses Arg) { + if (Arg.areAllPreserved()) + return areAllPreserved(); + for (void *P : Arg.PreservedPassIDs) + if (!preserved(P)) + return false; + return true; + } + /// \brief Test whether all passes are preserved. /// /// This is used primarily to optimize for the case of no changes which will @@ -276,8 +282,6 @@ public: Passes.emplace_back(new PassModelT(std::move(Pass))); } - static StringRef name() { return "PassManager"; } - private: typedef detail::PassConcept PassConceptT; @@ -746,7 +750,7 @@ public: /// In debug builds, it will also assert that the analysis manager is empty /// as no queries should arrive at the function analysis manager prior to /// this analysis being requested. - Result run(IRUnitT &IR) { return Result(*AM); } + Result run(IRUnitT &IR, AnalysisManager &) { return Result(*AM); } private: friend AnalysisInfoMixin< @@ -819,7 +823,7 @@ public: /// \brief Run the analysis pass and create our proxy result object. /// Nothing to see here, it just forwards the \c AM reference into the /// result. - Result run(IRUnitT &) { return Result(*AM); } + Result run(IRUnitT &, AnalysisManager &) { return Result(*AM); } private: friend AnalysisInfoMixin< @@ -977,7 +981,8 @@ struct InvalidateAnalysisPass /// analysis passes to be re-run to produce fresh results if any are needed. struct InvalidateAllAnalysesPass : PassInfoMixin { /// \brief Run this pass over some unit of IR. - template PreservedAnalyses run(IRUnitT &Arg) { + template + PreservedAnalyses run(IRUnitT &, AnalysisManager &) { return PreservedAnalyses::none(); } }; diff --git a/include/llvm/IR/PassManagerInternal.h b/include/llvm/IR/PassManagerInternal.h index e5bdd226a1c45e0a2882afb20bf25e23bd026a30..4351b5888283d5cbebee8058b7aac7ddcbdac5ee 100644 --- a/include/llvm/IR/PassManagerInternal.h +++ b/include/llvm/IR/PassManagerInternal.h @@ -18,8 +18,8 @@ #ifndef LLVM_IR_PASSMANAGERINTERNAL_H #define LLVM_IR_PASSMANAGERINTERNAL_H -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" namespace llvm { @@ -46,42 +46,14 @@ template struct PassConcept { virtual StringRef name() = 0; }; -/// \brief SFINAE metafunction for computing whether \c PassT has a run method -/// accepting an \c AnalysisManager. -template -class PassRunAcceptsAnalysisManager { - typedef char SmallType; - struct BigType { - char a, b; - }; - - template &)> - struct Checker; - - template static SmallType f(Checker *); - template static BigType f(...); - -public: - enum { Value = sizeof(f(nullptr)) == sizeof(SmallType) }; -}; - /// \brief A template wrapper used to implement the polymorphic API. /// /// Can be instantiated for any object which provides a \c run method accepting -/// an \c IRUnitT. It requires the pass to be a copyable object. When the -/// \c run method also accepts an \c AnalysisManager*, we pass it -/// along. +/// an \c IRUnitT& and an \c AnalysisManager&. It requires the pass to +/// be a copyable object. When the template ::Value> -struct PassModel; - -/// \brief Specialization of \c PassModel for passes that accept an analyis -/// manager. -template -struct PassModel - : PassConcept { + typename PreservedAnalysesT = PreservedAnalyses> +struct PassModel : PassConcept { explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. @@ -103,32 +75,6 @@ struct PassModel PassT Pass; }; -/// \brief Specialization of \c PassModel for passes that accept an analyis -/// manager. -template -struct PassModel - : PassConcept { - explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {} - // We have to explicitly define all the special member functions because MSVC - // refuses to generate them. - PassModel(const PassModel &Arg) : Pass(Arg.Pass) {} - PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {} - friend void swap(PassModel &LHS, PassModel &RHS) { - using std::swap; - swap(LHS.Pass, RHS.Pass); - } - PassModel &operator=(PassModel RHS) { - swap(*this, RHS); - return *this; - } - - PreservedAnalysesT run(IRUnitT &IR, AnalysisManager &) override { - return Pass.run(IR); - } - StringRef name() override { return PassT::name(); } - PassT Pass; -}; - /// \brief Abstract concept of an analysis result. /// /// This concept is parameterized over the IR unit that this result pertains @@ -261,17 +207,10 @@ template struct AnalysisPassConcept { /// \brief Wrapper to model the analysis pass concept. /// /// Can wrap any type which implements a suitable \c run method. The method -/// must accept the IRUnitT as an argument and produce an object which can be -/// wrapped in a \c AnalysisResultModel. -template ::Value> -struct AnalysisPassModel; - -/// \brief Specialization of \c AnalysisPassModel which passes an -/// \c AnalysisManager to PassT's run method. +/// must accept an \c IRUnitT& and an \c AnalysisManager& as arguments +/// and produce an object which can be wrapped in a \c AnalysisResultModel. template -struct AnalysisPassModel : AnalysisPassConcept { +struct AnalysisPassModel : AnalysisPassConcept { explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. @@ -306,44 +245,6 @@ struct AnalysisPassModel : AnalysisPassConcept { PassT Pass; }; -/// \brief Specialization of \c AnalysisPassModel which does not pass an -/// \c AnalysisManager to PassT's run method. -template -struct AnalysisPassModel : AnalysisPassConcept { - explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {} - // We have to explicitly define all the special member functions because MSVC - // refuses to generate them. - AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {} - AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {} - friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) { - using std::swap; - swap(LHS.Pass, RHS.Pass); - } - AnalysisPassModel &operator=(AnalysisPassModel RHS) { - swap(*this, RHS); - return *this; - } - - // FIXME: Replace PassT::Result with type traits when we use C++11. - typedef AnalysisResultModel - ResultModelT; - - /// \brief The model delegates to the \c PassT::run method. - /// - /// The return is wrapped in an \c AnalysisResultModel. - std::unique_ptr> - run(IRUnitT &IR, AnalysisManager &) override { - return make_unique(Pass.run(IR)); - } - - /// \brief The model delegates to a static \c PassT::name method. - /// - /// The returned string ref must point to constant immutable data! - StringRef name() override { return PassT::name(); } - - PassT Pass; -}; - } // End namespace detail } diff --git a/include/llvm/IR/PatternMatch.h b/include/llvm/IR/PatternMatch.h index f4d7d8c4441628c35d137039eda8cae860a72337..7da9afcf9463cdc081039eb725a624dee9f50b03 100644 --- a/include/llvm/IR/PatternMatch.h +++ b/include/llvm/IR/PatternMatch.h @@ -1312,6 +1312,43 @@ template inline Signum_match m_Signum(const Val_t &V) { return Signum_match(V); } +//===----------------------------------------------------------------------===// +// Matchers for two-operands operators with the operators in either order +// + +/// \brief Matches an ICmp with a predicate over LHS and RHS in either order. +/// Does not swap the predicate. +template +inline match_combine_or, + CmpClass_match> +m_c_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) { + return m_CombineOr(m_ICmp(Pred, L, R), m_ICmp(Pred, R, L)); +} + +/// \brief Matches an And with LHS and RHS in either order. +template +inline match_combine_or, + BinaryOp_match> +m_c_And(const LHS &L, const RHS &R) { + return m_CombineOr(m_And(L, R), m_And(R, L)); +} + +/// \brief Matches an Or with LHS and RHS in either order. +template +inline match_combine_or, + BinaryOp_match> +m_c_Or(const LHS &L, const RHS &R) { + return m_CombineOr(m_Or(L, R), m_Or(R, L)); +} + +/// \brief Matches an Xor with LHS and RHS in either order. +template +inline match_combine_or, + BinaryOp_match> +m_c_Xor(const LHS &L, const RHS &R) { + return m_CombineOr(m_Xor(L, R), m_Xor(R, L)); +} + } // end namespace PatternMatch } // end namespace llvm diff --git a/include/llvm/IR/ProfileSummary.h b/include/llvm/IR/ProfileSummary.h new file mode 100644 index 0000000000000000000000000000000000000000..f4248014c6e172edf3536e06b608e191e8bdb3ee --- /dev/null +++ b/include/llvm/IR/ProfileSummary.h @@ -0,0 +1,85 @@ +//===-- ProfileSummary.h - Profile summary data structure. ------*- C++ -*-===// +// +// 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 profile summary data structure. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_PROFILE_SUMMARY_H +#define LLVM_SUPPORT_PROFILE_SUMMARY_H + +#include +#include +#include + +#include "llvm/Support/Casting.h" + +namespace llvm { + +class LLVMContext; +class Metadata; +class MDTuple; +class MDNode; + +// The profile summary is one or more (Cutoff, MinCount, NumCounts) triplets. +// The semantics of counts depend on the type of profile. For instrumentation +// profile, counts are block counts and for sample profile, counts are +// per-line samples. Given a target counts percentile, we compute the minimum +// number of counts needed to reach this target and the minimum among these +// counts. +struct ProfileSummaryEntry { + uint32_t Cutoff; ///< The required percentile of counts. + uint64_t MinCount; ///< The minimum count for this percentile. + uint64_t NumCounts; ///< Number of counts >= the minimum count. + ProfileSummaryEntry(uint32_t TheCutoff, uint64_t TheMinCount, + uint64_t TheNumCounts) + : Cutoff(TheCutoff), MinCount(TheMinCount), NumCounts(TheNumCounts) {} +}; + +typedef std::vector SummaryEntryVector; + +class ProfileSummary { +public: + enum Kind { PSK_Instr, PSK_Sample }; + +private: + const Kind PSK; + static const char *KindStr[2]; + SummaryEntryVector DetailedSummary; + uint64_t TotalCount, MaxCount, MaxInternalCount, MaxFunctionCount; + uint32_t NumCounts, NumFunctions; + /// \brief Return detailed summary as metadata. + Metadata *getDetailedSummaryMD(LLVMContext &Context); + +public: + static const int Scale = 1000000; + ProfileSummary(Kind K, SummaryEntryVector DetailedSummary, + uint64_t TotalCount, uint64_t MaxCount, + uint64_t MaxInternalCount, uint64_t MaxFunctionCount, + uint32_t NumCounts, uint32_t NumFunctions) + : PSK(K), DetailedSummary(std::move(DetailedSummary)), + TotalCount(TotalCount), MaxCount(MaxCount), + MaxInternalCount(MaxInternalCount), MaxFunctionCount(MaxFunctionCount), + NumCounts(NumCounts), NumFunctions(NumFunctions) {} + Kind getKind() const { return PSK; } + /// \brief Return summary information as metadata. + Metadata *getMD(LLVMContext &Context); + /// \brief Construct profile summary from metdata. + static ProfileSummary *getFromMD(Metadata *MD); + SummaryEntryVector &getDetailedSummary() { return DetailedSummary; } + uint32_t getNumFunctions() { return NumFunctions; } + uint64_t getMaxFunctionCount() { return MaxFunctionCount; } + uint32_t getNumCounts() { return NumCounts; } + uint64_t getTotalCount() { return TotalCount; } + uint64_t getMaxCount() { return MaxCount; } + uint64_t getMaxInternalCount() { return MaxInternalCount; } +}; + +} // end namespace llvm +#endif diff --git a/include/llvm/IR/Statepoint.h b/include/llvm/IR/Statepoint.h index 416301572ae723561dc7f3e4673ed9915fdef042..5cd7fe1b576c2d34a34b79a48d4bd0e2d2acfc80 100644 --- a/include/llvm/IR/Statepoint.h +++ b/include/llvm/IR/Statepoint.h @@ -39,6 +39,7 @@ enum class StatepointFlags { }; class GCRelocateInst; +class GCResultInst; class ImmutableStatepoint; bool isStatepoint(ImmutableCallSite CS); @@ -46,16 +47,14 @@ bool isStatepoint(const Value *V); bool isStatepoint(const Value &V); bool isGCRelocate(ImmutableCallSite CS); - -bool isGCResult(const Value *V); bool isGCResult(ImmutableCallSite CS); /// Analogous to CallSiteBase, this provides most of the actual /// functionality for Statepoint and ImmutableStatepoint. It is /// templatized to allow easily specializing of const and non-const /// concrete subtypes. This is structured analogous to CallSite -/// rather than the IntrinsicInst.h helpers since we want to support -/// invokable statepoints in the near future. +/// rather than the IntrinsicInst.h helpers since we need to support +/// invokable statepoints. template class StatepointBase { @@ -253,11 +252,10 @@ public: /// Get the experimental_gc_result call tied to this statepoint. Can be /// nullptr if there isn't a gc_result tied to this statepoint. Guaranteed to /// be a CallInst if non-null. - InstructionTy *getGCResult() const { + const GCResultInst *getGCResult() const { for (auto *U : getInstruction()->users()) - if (isGCResult(U)) - return cast(U); - + if (auto *GRI = dyn_cast(U)) + return GRI; return nullptr; } @@ -306,11 +304,13 @@ public: explicit Statepoint(CallSite CS) : Base(CS) {} }; -/// This represents the gc.relocate intrinsic. -class GCRelocateInst : public IntrinsicInst { +/// Common base class for representing values projected from a statepoint. +/// Currently, the only projections available are gc.result and gc.relocate. +class GCProjectionInst : public IntrinsicInst { public: static inline bool classof(const IntrinsicInst *I) { - return I->getIntrinsicID() == Intrinsic::experimental_gc_relocate; + return I->getIntrinsicID() == Intrinsic::experimental_gc_relocate || + I->getIntrinsicID() == Intrinsic::experimental_gc_result; } static inline bool classof(const Value *V) { return isa(V) && classof(cast(V)); @@ -331,6 +331,7 @@ public: // This takes care both of relocates for call statepoints and relocates // on normal path of invoke statepoint. if (!isa(Token)) { + assert(isStatepoint(Token)); return cast(Token); } @@ -345,6 +346,17 @@ public: return InvokeBB->getTerminator(); } +}; + +/// Represents calls to the gc.relocate intrinsic. +class GCRelocateInst : public GCProjectionInst { +public: + static inline bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::experimental_gc_relocate; + } + static inline bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } /// The index into the associate statepoint's argument list /// which contains the base pointer of the pointer whose @@ -370,6 +382,17 @@ public: } }; +/// Represents calls to the gc.result intrinsic. +class GCResultInst : public GCProjectionInst { +public: + static inline bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::experimental_gc_result; + } + static inline bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + template std::vector diff --git a/include/llvm/IR/SymbolTableListTraits.h b/include/llvm/IR/SymbolTableListTraits.h index 5fc48d10d63f817d92aa409a0725b9ebec032a2f..60e04e2f9ecae018a5845c0a2df8987a8926bc33 100644 --- a/include/llvm/IR/SymbolTableListTraits.h +++ b/include/llvm/IR/SymbolTableListTraits.h @@ -49,6 +49,7 @@ class Function; class Instruction; class GlobalVariable; class GlobalAlias; +class GlobalIFunc; class Module; #define DEFINE_SYMBOL_TABLE_PARENT_TYPE(NODE, PARENT) \ template <> struct SymbolTableListParentType { typedef PARENT type; }; @@ -58,6 +59,7 @@ DEFINE_SYMBOL_TABLE_PARENT_TYPE(Argument, Function) DEFINE_SYMBOL_TABLE_PARENT_TYPE(Function, Module) DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalVariable, Module) DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalAlias, Module) +DEFINE_SYMBOL_TABLE_PARENT_TYPE(GlobalIFunc, Module) #undef DEFINE_SYMBOL_TABLE_PARENT_TYPE template class SymbolTableList; diff --git a/include/llvm/IR/TrackingMDRef.h b/include/llvm/IR/TrackingMDRef.h index 97efaff7a3771386757eeef25d4d67ef5f9b6152..fe513a8f9795155ce36673fc91a9bdb6959b5ea1 100644 --- a/include/llvm/IR/TrackingMDRef.h +++ b/include/llvm/IR/TrackingMDRef.h @@ -15,7 +15,6 @@ #define LLVM_IR_TRACKINGMDREF_H #include "llvm/IR/Metadata.h" -#include "llvm/Support/Casting.h" namespace llvm { diff --git a/include/llvm/IR/Type.h b/include/llvm/IR/Type.h index d1c2113b824e137a70c9c8b1b4b5f9b0e9ea1ccd..ef7ad733f47a7d40644f1d0ed7705e18530f6368 100644 --- a/include/llvm/IR/Type.h +++ b/include/llvm/IR/Type.h @@ -16,6 +16,7 @@ #define LLVM_IR_TYPE_H #include "llvm/ADT/APFloat.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Casting.h" @@ -75,7 +76,7 @@ public: }; private: - /// Context - This refers to the LLVMContext in which this type was uniqued. + /// This refers to the LLVMContext in which this type was uniqued. LLVMContext &Context; TypeID ID : 8; // The current base type of this type. @@ -96,15 +97,14 @@ protected: assert(getSubclassData() == val && "Subclass data too large for field"); } - /// NumContainedTys - Keeps track of how many Type*'s there are in the - /// ContainedTys list. + /// Keeps track of how many Type*'s there are in the ContainedTys list. unsigned NumContainedTys; - /// ContainedTys - A pointer to the array of Types contained by this Type. - /// For example, this includes the arguments of a function type, the elements - /// of a structure, the pointee of a pointer, the element type of an array, - /// etc. This pointer may be 0 for types that don't contain other types - /// (Integer, Double, Float). + /// A pointer to the array of Types contained by this Type. For example, this + /// includes the arguments of a function type, the elements of a structure, + /// the pointee of a pointer, the element type of an array, etc. This pointer + /// may be 0 for types that don't contain other types (Integer, Double, + /// Float). Type * const *ContainedTys; static bool isSequentialType(TypeID TyID) { @@ -122,41 +122,39 @@ public: bool NoDetails = false) const; void dump() const; - /// getContext - Return the LLVMContext in which this type was uniqued. + /// Return the LLVMContext in which this type was uniqued. LLVMContext &getContext() const { return Context; } //===--------------------------------------------------------------------===// // Accessors for working with types. // - /// getTypeID - Return the type id for the type. This will return one - /// of the TypeID enum elements defined above. - /// + /// Return the type id for the type. This will return one of the TypeID enum + /// elements defined above. TypeID getTypeID() const { return ID; } - /// isVoidTy - Return true if this is 'void'. + /// Return true if this is 'void'. bool isVoidTy() const { return getTypeID() == VoidTyID; } - /// isHalfTy - Return true if this is 'half', a 16-bit IEEE fp type. + /// Return true if this is 'half', a 16-bit IEEE fp type. bool isHalfTy() const { return getTypeID() == HalfTyID; } - /// isFloatTy - Return true if this is 'float', a 32-bit IEEE fp type. + /// Return true if this is 'float', a 32-bit IEEE fp type. bool isFloatTy() const { return getTypeID() == FloatTyID; } - /// isDoubleTy - Return true if this is 'double', a 64-bit IEEE fp type. + /// Return true if this is 'double', a 64-bit IEEE fp type. bool isDoubleTy() const { return getTypeID() == DoubleTyID; } - /// isX86_FP80Ty - Return true if this is x86 long double. + /// Return true if this is x86 long double. bool isX86_FP80Ty() const { return getTypeID() == X86_FP80TyID; } - /// isFP128Ty - Return true if this is 'fp128'. + /// Return true if this is 'fp128'. bool isFP128Ty() const { return getTypeID() == FP128TyID; } - /// isPPC_FP128Ty - Return true if this is powerpc long double. + /// Return true if this is powerpc long double. bool isPPC_FP128Ty() const { return getTypeID() == PPC_FP128TyID; } - /// isFloatingPointTy - Return true if this is one of the six floating point - /// types + /// Return true if this is one of the six floating-point types bool isFloatingPointTy() const { return getTypeID() == HalfTyID || getTypeID() == FloatTyID || getTypeID() == DoubleTyID || @@ -176,99 +174,81 @@ public: } } - /// isX86_MMXTy - Return true if this is X86 MMX. + /// Return true if this is X86 MMX. bool isX86_MMXTy() const { return getTypeID() == X86_MMXTyID; } - /// isFPOrFPVectorTy - Return true if this is a FP type or a vector of FP. - /// + /// Return true if this is a FP type or a vector of FP. bool isFPOrFPVectorTy() const { return getScalarType()->isFloatingPointTy(); } - /// isLabelTy - Return true if this is 'label'. + /// Return true if this is 'label'. bool isLabelTy() const { return getTypeID() == LabelTyID; } - /// isMetadataTy - Return true if this is 'metadata'. + /// Return true if this is 'metadata'. bool isMetadataTy() const { return getTypeID() == MetadataTyID; } - /// isTokenTy - Return true if this is 'token'. + /// Return true if this is 'token'. bool isTokenTy() const { return getTypeID() == TokenTyID; } - /// isIntegerTy - True if this is an instance of IntegerType. - /// + /// True if this is an instance of IntegerType. bool isIntegerTy() const { return getTypeID() == IntegerTyID; } - /// isIntegerTy - Return true if this is an IntegerType of the given width. + /// Return true if this is an IntegerType of the given width. bool isIntegerTy(unsigned Bitwidth) const; - /// isIntOrIntVectorTy - Return true if this is an integer type or a vector of - /// integer types. - /// + /// Return true if this is an integer type or a vector of integer types. bool isIntOrIntVectorTy() const { return getScalarType()->isIntegerTy(); } - /// isFunctionTy - True if this is an instance of FunctionType. - /// + /// True if this is an instance of FunctionType. bool isFunctionTy() const { return getTypeID() == FunctionTyID; } - /// isStructTy - True if this is an instance of StructType. - /// + /// True if this is an instance of StructType. bool isStructTy() const { return getTypeID() == StructTyID; } - /// isArrayTy - True if this is an instance of ArrayType. - /// + /// True if this is an instance of ArrayType. bool isArrayTy() const { return getTypeID() == ArrayTyID; } - /// isPointerTy - True if this is an instance of PointerType. - /// + /// True if this is an instance of PointerType. bool isPointerTy() const { return getTypeID() == PointerTyID; } - /// isPtrOrPtrVectorTy - Return true if this is a pointer type or a vector of - /// pointer types. - /// + /// Return true if this is a pointer type or a vector of pointer types. bool isPtrOrPtrVectorTy() const { return getScalarType()->isPointerTy(); } - /// isVectorTy - True if this is an instance of VectorType. - /// + /// True if this is an instance of VectorType. bool isVectorTy() const { return getTypeID() == VectorTyID; } - /// canLosslesslyBitCastTo - Return true if this type could be converted - /// with a lossless BitCast to type 'Ty'. For example, i8* to i32*. BitCasts - /// are valid for types of the same size only where no re-interpretation of - /// the bits is done. + /// Return true if this type could be converted with a lossless BitCast to + /// type 'Ty'. For example, i8* to i32*. BitCasts are valid for types of the + /// same size only where no re-interpretation of the bits is done. /// @brief Determine if this type could be losslessly bitcast to Ty bool canLosslesslyBitCastTo(Type *Ty) const; - /// isEmptyTy - Return true if this type is empty, that is, it has no - /// elements or all its elements are empty. + /// Return true if this type is empty, that is, it has no elements or all of + /// its elements are empty. bool isEmptyTy() const; - /// isFirstClassType - Return true if the type is "first class", meaning it - /// is a valid type for a Value. - /// + /// Return true if the type is "first class", meaning it is a valid type for a + /// Value. bool isFirstClassType() const { return getTypeID() != FunctionTyID && getTypeID() != VoidTyID; } - /// isSingleValueType - Return true if the type is a valid type for a - /// register in codegen. This includes all first-class types except struct - /// and array types. - /// + /// Return true if the type is a valid type for a register in codegen. This + /// includes all first-class types except struct and array types. bool isSingleValueType() const { return isFloatingPointTy() || isX86_MMXTy() || isIntegerTy() || isPointerTy() || isVectorTy(); } - /// isAggregateType - Return true if the type is an aggregate type. This - /// means it is valid as the first operand of an insertvalue or - /// extractvalue instruction. This includes struct and array types, but - /// does not include vector types. - /// + /// Return true if the type is an aggregate type. This means it is valid as + /// the first operand of an insertvalue or extractvalue instruction. This + /// includes struct and array types, but does not include vector types. bool isAggregateType() const { return getTypeID() == StructTyID || getTypeID() == ArrayTyID; } - /// isSized - Return true if it makes sense to take the size of this type. To - /// get the actual size for a particular target, it is reasonable to use the + /// Return true if it makes sense to take the size of this type. To get the + /// actual size for a particular target, it is reasonable to use the /// DataLayout subsystem to do this. - /// bool isSized(SmallPtrSetImpl *Visited = nullptr) const { // If it's a primitive, it is always sized. if (getTypeID() == IntegerTyID || isFloatingPointTy() || @@ -284,8 +264,8 @@ public: return isSizedDerivedType(Visited); } - /// getPrimitiveSizeInBits - Return the basic size of this type if it is a - /// primitive type. These are fixed by LLVM and are not target dependent. + /// Return the basic size of this type if it is a primitive type. These are + /// fixed by LLVM and are not target-dependent. /// This will return zero if the type does not have a size or is not a /// primitive type. /// @@ -296,18 +276,18 @@ public: /// unsigned getPrimitiveSizeInBits() const LLVM_READONLY; - /// getScalarSizeInBits - If this is a vector type, return the - /// getPrimitiveSizeInBits value for the element type. Otherwise return the - /// getPrimitiveSizeInBits value for this type. + /// If this is a vector type, return the getPrimitiveSizeInBits value for the + /// element type. Otherwise return the getPrimitiveSizeInBits value for this + /// type. unsigned getScalarSizeInBits() const LLVM_READONLY; - /// getFPMantissaWidth - Return the width of the mantissa of this type. This - /// is only valid on floating point types. If the FP type does not - /// have a stable mantissa (e.g. ppc long double), this method returns -1. + /// Return the width of the mantissa of this type. This is only valid on + /// floating-point types. If the FP type does not have a stable mantissa (e.g. + /// ppc long double), this method returns -1. int getFPMantissaWidth() const; - /// getScalarType - If this is a vector type, return the element type, - /// otherwise return 'this'. + /// If this is a vector type, return the element type, otherwise return + /// 'this'. Type *getScalarType() const LLVM_READONLY; //===--------------------------------------------------------------------===// @@ -328,17 +308,15 @@ public: return subtype_reverse_iterator(subtype_begin()); } - /// getContainedType - This method is used to implement the type iterator - /// (defined at the end of the file). For derived types, this returns the - /// types 'contained' in the derived type. - /// + /// This method is used to implement the type iterator (defined at the end of + /// the file). For derived types, this returns the types 'contained' in the + /// derived type. Type *getContainedType(unsigned i) const { assert(i < NumContainedTys && "Index out of range!"); return ContainedTys[i]; } - /// getNumContainedTypes - Return the number of types in the derived type. - /// + /// Return the number of types in the derived type. unsigned getNumContainedTypes() const { return NumContainedTys; } //===--------------------------------------------------------------------===// @@ -371,7 +349,7 @@ public: Type *getPointerElementType() const { return getSequentialElementType(); } - /// \brief Get the address space of this pointer or pointer vector type. + /// Get the address space of this pointer or pointer vector type. inline unsigned getPointerAddressSpace() const; //===--------------------------------------------------------------------===// @@ -379,7 +357,7 @@ public: // instances of Type. // - /// getPrimitiveType - Return a type based on an identifier. + /// Return a type based on an identifier. static Type *getPrimitiveType(LLVMContext &C, TypeID IDNumber); //===--------------------------------------------------------------------===// @@ -422,14 +400,14 @@ public: static PointerType *getInt32PtrTy(LLVMContext &C, unsigned AS = 0); static PointerType *getInt64PtrTy(LLVMContext &C, unsigned AS = 0); - /// getPointerTo - Return a pointer to the current type. This is equivalent - /// to PointerType::get(Foo, AddrSpace). + /// Return a pointer to the current type. This is equivalent to + /// PointerType::get(Foo, AddrSpace). PointerType *getPointerTo(unsigned AddrSpace = 0) const; private: - /// isSizedDerivedType - Derived types like structures and arrays are sized - /// iff all of the members of the type are sized as well. Since asking for - /// their size is relatively uncommon, move this operation out of line. + /// Derived types like structures and arrays are sized iff all of the members + /// of the type are sized as well. Since asking for their size is relatively + /// uncommon, move this operation out-of-line. bool isSizedDerivedType(SmallPtrSetImpl *Visited = nullptr) const; }; diff --git a/include/llvm/IR/Use.h b/include/llvm/IR/Use.h index dc65d2c65ee2ab790737a933f9b10639bf25ef58..e62eab56b1f19934bb48e543bf2f5cb4bed43da7 100644 --- a/include/llvm/IR/Use.h +++ b/include/llvm/IR/Use.h @@ -27,9 +27,7 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/Support/CBindingWrapping.h" -#include "llvm/Support/Compiler.h" #include -#include namespace llvm { diff --git a/include/llvm/IR/UseListOrder.h b/include/llvm/IR/UseListOrder.h index 1cabf03d1b009ed2ad813f70e68fddb4fdf98d88..b86425b6a697687e3a88087db8d9473c0d9e3dd9 100644 --- a/include/llvm/IR/UseListOrder.h +++ b/include/llvm/IR/UseListOrder.h @@ -15,8 +15,7 @@ #ifndef LLVM_IR_USELISTORDER_H #define LLVM_IR_USELISTORDER_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallVector.h" +#include #include namespace llvm { diff --git a/include/llvm/IR/User.h b/include/llvm/IR/User.h index 885ae197d2283439bd58f57081db81fa369064d2..4d6b30cd1124ce4e9034a58844349e8e8dfb3183 100644 --- a/include/llvm/IR/User.h +++ b/include/llvm/IR/User.h @@ -19,7 +19,6 @@ #ifndef LLVM_IR_USER_H #define LLVM_IR_USER_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Value.h" @@ -28,6 +27,9 @@ namespace llvm { +template class ArrayRef; +template class MutableArrayRef; + /// \brief Compile-time customization of User operands. /// /// Customizes operand-related allocators and accessors. diff --git a/include/llvm/IR/Value.def b/include/llvm/IR/Value.def index eb47738810f99f5f3670bb8738f542dfc9e9d372..48842d7f9cd56421c31f6685e2f95003ecce4436 100644 --- a/include/llvm/IR/Value.def +++ b/include/llvm/IR/Value.def @@ -60,9 +60,12 @@ HANDLE_VALUE(MemoryPhi) HANDLE_GLOBAL_VALUE(Function) HANDLE_GLOBAL_VALUE(GlobalAlias) +HANDLE_GLOBAL_VALUE(GlobalIFunc) HANDLE_GLOBAL_VALUE(GlobalVariable) HANDLE_CONSTANT(BlockAddress) HANDLE_CONSTANT(ConstantExpr) + +// ConstantAggregate. HANDLE_CONSTANT(ConstantArray) HANDLE_CONSTANT(ConstantStruct) HANDLE_CONSTANT(ConstantVector) @@ -88,6 +91,8 @@ HANDLE_CONSTANT_MARKER(ConstantFirstVal, Function) HANDLE_CONSTANT_MARKER(ConstantLastVal, ConstantTokenNone) HANDLE_CONSTANT_MARKER(ConstantDataFirstVal, UndefValue) HANDLE_CONSTANT_MARKER(ConstantDataLastVal, ConstantTokenNone) +HANDLE_CONSTANT_MARKER(ConstantAggregateFirstVal, ConstantArray) +HANDLE_CONSTANT_MARKER(ConstantAggregateLastVal, ConstantVector) #undef HANDLE_GLOBAL_VALUE #undef HANDLE_CONSTANT diff --git a/include/llvm/IR/Value.h b/include/llvm/IR/Value.h index 6d5694a07d4b6a782faaeb3d4a2bc25b9f6ee499..f3a342dadf73b2781cdec329c3e1a432488296f7 100644 --- a/include/llvm/IR/Value.h +++ b/include/llvm/IR/Value.h @@ -18,7 +18,6 @@ #include "llvm/IR/Use.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/Compiler.h" namespace llvm { @@ -28,9 +27,12 @@ class AssemblyAnnotationWriter; class BasicBlock; class Constant; class ConstantData; +class ConstantAggregate; class DataLayout; class Function; class GlobalAlias; +class GlobalIFunc; +class GlobalIndirectSymbol; class GlobalObject; class GlobalValue; class GlobalVariable; @@ -502,6 +504,14 @@ public: return const_cast(this)->stripInBoundsOffsets(); } + /// \brief Returns the number of bytes known to be dereferenceable for the + /// pointer value. + /// + /// If CanBeNull is set by this function the pointer can either be null or be + /// dereferenceable up to the returned number of bytes. + unsigned getPointerDereferenceableBytes(const DataLayout &DL, + bool &CanBeNull) const; + /// \brief Returns an alignment of the pointer value. /// /// Returns an alignment which is either specified explicitly, e.g. via @@ -700,6 +710,13 @@ template <> struct isa_impl { } }; +template <> struct isa_impl { + static inline bool doit(const Value &Val) { + return Val.getValueID() >= Value::ConstantAggregateFirstVal && + Val.getValueID() <= Value::ConstantAggregateLastVal; + } +}; + template <> struct isa_impl { static inline bool doit (const Value &Val) { return Val.getValueID() == Value::ArgumentVal; @@ -742,9 +759,21 @@ template <> struct isa_impl { } }; +template <> struct isa_impl { + static inline bool doit(const Value &Val) { + return Val.getValueID() == Value::GlobalIFuncVal; + } +}; + +template <> struct isa_impl { + static inline bool doit(const Value &Val) { + return isa(Val) || isa(Val); + } +}; + template <> struct isa_impl { static inline bool doit(const Value &Val) { - return isa(Val) || isa(Val); + return isa(Val) || isa(Val); } }; @@ -769,8 +798,7 @@ public: // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_ISA_CONVERSION_FUNCTIONS(Value, LLVMValueRef) -/* Specialized opaque value conversions. - */ +// Specialized opaque value conversions. inline Value **unwrap(LLVMValueRef *Vals) { return reinterpret_cast(Vals); } diff --git a/include/llvm/IR/ValueMap.h b/include/llvm/IR/ValueMap.h index ad518ac053b2bc6798abdda0cc16822e6b0a0c2d..85379ad468c4b94988fee826bdbd6f3ec324330a 100644 --- a/include/llvm/IR/ValueMap.h +++ b/include/llvm/IR/ValueMap.h @@ -27,6 +27,7 @@ #define LLVM_IR_VALUEMAP_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/IR/TrackingMDRef.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Mutex.h" @@ -84,8 +85,11 @@ class ValueMap { typedef DenseMap MDMapT; typedef typename Config::ExtraData ExtraData; MapT Map; - std::unique_ptr MDMap; + Optional MDMap; ExtraData Data; + + bool MayMapMetadata = true; + ValueMap(const ValueMap&) = delete; ValueMap& operator=(const ValueMap&) = delete; public: @@ -99,12 +103,27 @@ public: explicit ValueMap(const ExtraData &Data, unsigned NumInitBuckets = 64) : Map(NumInitBuckets), Data(Data) {} - bool hasMD() const { return MDMap; } + bool hasMD() const { return bool(MDMap); } MDMapT &MD() { if (!MDMap) - MDMap.reset(new MDMapT); + MDMap.emplace(); return *MDMap; } + Optional &getMDMap() { return MDMap; } + + bool mayMapMetadata() const { return MayMapMetadata; } + void enableMapMetadata() { MayMapMetadata = true; } + void disableMapMetadata() { MayMapMetadata = false; } + + /// Get the mapped metadata, if it's in the map. + Optional getMappedMD(const Metadata *MD) const { + if (!MDMap) + return None; + auto Where = MDMap->find(MD); + if (Where == MDMap->end()) + return None; + return Where->second.get(); + } typedef ValueMapIterator iterator; typedef ValueMapConstIterator const_iterator; diff --git a/include/llvm/IR/ValueSymbolTable.h b/include/llvm/IR/ValueSymbolTable.h index 65bd7fc2fec17a9595a9ab0fdf7035f9dbddd976..61a12db403ea7c08ccf4b9361ae889f6bb232ee8 100644 --- a/include/llvm/IR/ValueSymbolTable.h +++ b/include/llvm/IR/ValueSymbolTable.h @@ -14,13 +14,13 @@ #ifndef LLVM_IR_VALUESYMBOLTABLE_H #define LLVM_IR_VALUESYMBOLTABLE_H -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/IR/Value.h" #include "llvm/Support/DataTypes.h" namespace llvm { template class SymbolTableListTraits; + template class SmallString; class BasicBlock; class Function; class NamedMDNode; @@ -39,6 +39,7 @@ class ValueSymbolTable { friend class SymbolTableListTraits; friend class SymbolTableListTraits; friend class SymbolTableListTraits; + friend class SymbolTableListTraits; /// @name Types /// @{ public: diff --git a/include/llvm/IR/Verifier.h b/include/llvm/IR/Verifier.h index 4b00b57532f7b73dfa22ba3a74d7794117f10b50..fdb6ce400a8d50c860fa5c62c6259bf13cfa70c8 100644 --- a/include/llvm/IR/Verifier.h +++ b/include/llvm/IR/Verifier.h @@ -21,9 +21,7 @@ #ifndef LLVM_IR_VERIFIER_H #define LLVM_IR_VERIFIER_H -#include "llvm/ADT/StringRef.h" #include "llvm/IR/PassManager.h" -#include namespace llvm { @@ -43,10 +41,38 @@ bool verifyFunction(const Function &F, raw_ostream *OS = nullptr); /// \brief Check a module for errors. /// -/// If there are no errors, the function returns false. If an error is found, -/// a message describing the error is written to OS (if non-null) and true is -/// returned. -bool verifyModule(const Module &M, raw_ostream *OS = nullptr); +/// If there are no errors, the function returns false. If an error is +/// found, a message describing the error is written to OS (if +/// non-null) and true is returned. +/// +/// \return true if the module is broken. If BrokenDebugInfo is +/// supplied, DebugInfo verification failures won't be considered as +/// error and instead *BrokenDebugInfo will be set to true. Debug +/// info errors can be "recovered" from by stripping the debug info. +bool verifyModule(const Module &M, raw_ostream *OS = nullptr, + bool *BrokenDebugInfo = nullptr); + +FunctionPass *createVerifierPass(bool FatalErrors = true); + +/// Check a module for errors, and report separate error states for IR +/// and debug info errors. +class VerifierAnalysis : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static char PassID; + +public: + struct Result { + bool IRBroken, DebugInfoBroken; + }; + static void *ID() { return (void *)&PassID; } + Result run(Module &M, ModuleAnalysisManager &); + Result run(Function &F, FunctionAnalysisManager &); +}; + +/// Check a module for errors, but report debug info errors separately. +/// Otherwise behaves as the normal verifyModule. Debug info errors can be +/// "recovered" from by stripping the debug info. +bool verifyModule(bool &BrokenDebugInfo, const Module &M, raw_ostream *OS); /// \brief Create a verifier pass. /// @@ -58,18 +84,17 @@ bool verifyModule(const Module &M, raw_ostream *OS = nullptr); /// /// Note that this creates a pass suitable for the legacy pass manager. It has /// nothing to do with \c VerifierPass. -FunctionPass *createVerifierPass(bool FatalErrors = true); - class VerifierPass : public PassInfoMixin { bool FatalErrors; public: explicit VerifierPass(bool FatalErrors = true) : FatalErrors(FatalErrors) {} - PreservedAnalyses run(Module &M); - PreservedAnalyses run(Function &F); + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; + } // End llvm namespace #endif diff --git a/include/llvm/IRReader/IRReader.h b/include/llvm/IRReader/IRReader.h index 523cd3d6df72a543cec7a28afa0603fa137bb6aa..7b24ec11fb64659306fff2899316409e6e2c3482 100644 --- a/include/llvm/IRReader/IRReader.h +++ b/include/llvm/IRReader/IRReader.h @@ -15,11 +15,12 @@ #ifndef LLVM_IRREADER_IRREADER_H #define LLVM_IRREADER_IRREADER_H -#include "llvm/Support/MemoryBuffer.h" -#include +#include namespace llvm { +class StringRef; +class MemoryBufferRef; class Module; class SMDiagnostic; class LLVMContext; diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h index 16f978ae72ff53c12b7f1c3899e622dc31f7331e..3042ec2c3187d195a378f63488be2a92b4ff120c 100644 --- a/include/llvm/InitializePasses.h +++ b/include/llvm/InitializePasses.h @@ -19,97 +19,94 @@ namespace llvm { class PassRegistry; -/// initializeCore - Initialize all passes linked into the -/// TransformUtils library. +/// Initialize all passes linked into the TransformUtils library. void initializeCore(PassRegistry&); -/// initializeTransformUtils - Initialize all passes linked into the -/// TransformUtils library. +/// Initialize all passes linked into the TransformUtils library. void initializeTransformUtils(PassRegistry&); -/// initializeScalarOpts - Initialize all passes linked into the -/// ScalarOpts library. +/// Initialize all passes linked into the ScalarOpts library. void initializeScalarOpts(PassRegistry&); -/// initializeObjCARCOpts - Initialize all passes linked into the ObjCARCOpts -/// library. +/// Initialize all passes linked into the ObjCARCOpts library. void initializeObjCARCOpts(PassRegistry&); -/// initializeVectorization - Initialize all passes linked into the -/// Vectorize library. +/// Initialize all passes linked into the Vectorize library. void initializeVectorization(PassRegistry&); -/// initializeInstCombine - Initialize all passes linked into the -/// InstCombine library. +/// Initialize all passes linked into the InstCombine library. void initializeInstCombine(PassRegistry&); -/// initializeIPO - Initialize all passes linked into the IPO library. +/// Initialize all passes linked into the IPO library. void initializeIPO(PassRegistry&); -/// initializeInstrumentation - Initialize all passes linked into the -/// Instrumentation library. +/// Initialize all passes linked into the Instrumentation library. void initializeInstrumentation(PassRegistry&); -/// initializeAnalysis - Initialize all passes linked into the Analysis library. +/// Initialize all passes linked into the Analysis library. void initializeAnalysis(PassRegistry&); -/// initializeCodeGen - Initialize all passes linked into the CodeGen library. +/// Initialize all passes linked into the CodeGen library. void initializeCodeGen(PassRegistry&); /// Initialize all passes linked into the GlobalISel library. void initializeGlobalISel(PassRegistry &Registry); -/// initializeCodeGen - Initialize all passes linked into the CodeGen library. +/// Initialize all passes linked into the CodeGen library. void initializeTarget(PassRegistry&); void initializeAAEvalLegacyPassPass(PassRegistry&); -void initializeAddDiscriminatorsPass(PassRegistry&); +void initializeAAResultsWrapperPassPass(PassRegistry &); void initializeADCELegacyPassPass(PassRegistry&); -void initializeBDCEPass(PassRegistry&); +void initializeAddDiscriminatorsLegacyPassPass(PassRegistry&); +void initializeAddressSanitizerModulePass(PassRegistry&); +void initializeAddressSanitizerPass(PassRegistry&); void initializeAliasSetPrinterPass(PassRegistry&); +void initializeAlignmentFromAssumptionsPass(PassRegistry&); void initializeAlwaysInlinerPass(PassRegistry&); void initializeArgPromotionPass(PassRegistry&); +void initializeAssumptionCacheTrackerPass(PassRegistry &); void initializeAtomicExpandPass(PassRegistry&); -void initializeSampleProfileLoaderPass(PassRegistry&); -void initializeAlignmentFromAssumptionsPass(PassRegistry&); +void initializeBBVectorizePass(PassRegistry&); +void initializeBDCELegacyPassPass(PassRegistry &); void initializeBarrierNoopPass(PassRegistry&); void initializeBasicAAWrapperPassPass(PassRegistry&); -void initializeCallGraphWrapperPassPass(PassRegistry &); void initializeBlockExtractorPassPass(PassRegistry&); void initializeBlockFrequencyInfoWrapperPassPass(PassRegistry&); void initializeBoundsCheckingPass(PassRegistry&); void initializeBranchFolderPassPass(PassRegistry&); void initializeBranchProbabilityInfoWrapperPassPass(PassRegistry&); void initializeBreakCriticalEdgesPass(PassRegistry&); -void initializeCallGraphDOTPrinterPass(PassRegistry&); -void initializeCallGraphPrinterLegacyPassPass(PassRegistry&); -void initializeCallGraphViewerPass(PassRegistry&); void initializeCFGOnlyPrinterPass(PassRegistry&); void initializeCFGOnlyViewerPass(PassRegistry&); void initializeCFGPrinterPass(PassRegistry&); void initializeCFGSimplifyPassPass(PassRegistry&); -void initializeCFLAAWrapperPassPass(PassRegistry&); -void initializeExternalAAWrapperPassPass(PassRegistry&); -void initializeForwardControlFlowIntegrityPass(PassRegistry&); -void initializeFlattenCFGPassPass(PassRegistry&); -void initializeStructurizeCFGPass(PassRegistry&); void initializeCFGViewerPass(PassRegistry&); -void initializeConstantHoistingPass(PassRegistry&); +void initializeCFLAndersAAWrapperPassPass(PassRegistry&); +void initializeCFLSteensAAWrapperPassPass(PassRegistry&); +void initializeCallGraphDOTPrinterPass(PassRegistry&); +void initializeCallGraphPrinterLegacyPassPass(PassRegistry&); +void initializeCallGraphViewerPass(PassRegistry&); +void initializeCallGraphWrapperPassPass(PassRegistry &); void initializeCodeGenPreparePass(PassRegistry&); -void initializeConstantMergePass(PassRegistry&); +void initializeConstantHoistingLegacyPassPass(PassRegistry&); +void initializeConstantMergeLegacyPassPass(PassRegistry &); void initializeConstantPropagationPass(PassRegistry&); -void initializeMachineCopyPropagationPass(PassRegistry&); -void initializeCostModelAnalysisPass(PassRegistry&); void initializeCorrelatedValuePropagationPass(PassRegistry&); +void initializeCostModelAnalysisPass(PassRegistry&); void initializeCrossDSOCFIPass(PassRegistry&); void initializeDAEPass(PassRegistry&); void initializeDAHPass(PassRegistry&); -void initializeDCEPass(PassRegistry&); -void initializeDSEPass(PassRegistry&); +void initializeDCELegacyPassPass(PassRegistry&); +void initializeDSELegacyPassPass(PassRegistry&); +void initializeDataFlowSanitizerPass(PassRegistry&); void initializeDeadInstEliminationPass(PassRegistry&); void initializeDeadMachineInstructionElimPass(PassRegistry&); void initializeDelinearizationPass(PassRegistry &); +void initializeDemandedBitsWrapperPassPass(PassRegistry&); void initializeDependenceAnalysisPass(PassRegistry&); +void initializeDependenceAnalysisWrapperPassPass(PassRegistry&); +void initializeDetectDeadLanesPass(PassRegistry&); void initializeDivergenceAnalysisPass(PassRegistry&); void initializeDomOnlyPrinterPass(PassRegistry&); void initializeDomOnlyViewerPass(PassRegistry&); @@ -117,164 +114,201 @@ void initializeDomPrinterPass(PassRegistry&); void initializeDomViewerPass(PassRegistry&); void initializeDominanceFrontierWrapperPassPass(PassRegistry&); void initializeDominatorTreeWrapperPassPass(PassRegistry&); +void initializeDwarfEHPreparePass(PassRegistry&); +void initializeEarlyCSELegacyPassPass(PassRegistry &); void initializeEarlyIfConverterPass(PassRegistry&); void initializeEdgeBundlesPass(PassRegistry&); -void initializeExpandPostRAPass(PassRegistry&); -void initializeAAResultsWrapperPassPass(PassRegistry &); -void initializeGCOVProfilerPass(PassRegistry&); -void initializePGOInstrumentationGenPass(PassRegistry&); -void initializePGOInstrumentationUsePass(PassRegistry&); -void initializeInstrProfilingPass(PassRegistry&); -void initializeAddressSanitizerPass(PassRegistry&); -void initializeAddressSanitizerModulePass(PassRegistry&); -void initializeMemorySanitizerPass(PassRegistry&); -void initializeThreadSanitizerPass(PassRegistry&); -void initializeSanitizerCoverageModulePass(PassRegistry&); -void initializeDataFlowSanitizerPass(PassRegistry&); -void initializeScalarizerPass(PassRegistry&); -void initializeEarlyCSELegacyPassPass(PassRegistry &); -void initializeEliminateAvailableExternallyPass(PassRegistry&); +void initializeEfficiencySanitizerPass(PassRegistry&); +void initializeEliminateAvailableExternallyLegacyPassPass(PassRegistry &); void initializeExpandISelPseudosPass(PassRegistry&); +void initializeExpandPostRAPass(PassRegistry&); +void initializeExternalAAWrapperPassPass(PassRegistry&); +void initializeFinalizeMachineBundlesPass(PassRegistry&); +void initializeFlattenCFGPassPass(PassRegistry&); +void initializeFloat2IntLegacyPassPass(PassRegistry&); void initializeForceFunctionAttrsLegacyPassPass(PassRegistry&); +void initializeForwardControlFlowIntegrityPass(PassRegistry&); +void initializeFuncletLayoutPass(PassRegistry &); +void initializeFunctionImportPassPass(PassRegistry &); void initializeGCMachineCodeAnalysisPass(PassRegistry&); void initializeGCModuleInfoPass(PassRegistry&); +void initializeGCOVProfilerLegacyPassPass(PassRegistry&); void initializeGVNLegacyPassPass(PassRegistry&); -void initializeGlobalDCEPass(PassRegistry&); -void initializeGlobalOptPass(PassRegistry&); +void initializeGlobalDCELegacyPassPass(PassRegistry&); +void initializeGlobalMergePass(PassRegistry&); +void initializeGlobalOptLegacyPassPass(PassRegistry&); void initializeGlobalsAAWrapperPassPass(PassRegistry&); +void initializeGuardWideningLegacyPassPass(PassRegistry&); void initializeIPCPPass(PassRegistry&); -void initializeIPSCCPPass(PassRegistry&); +void initializeIPSCCPLegacyPassPass(PassRegistry &); +void initializeIRTranslatorPass(PassRegistry &); void initializeIVUsersPass(PassRegistry&); void initializeIfConverterPass(PassRegistry&); +void initializeImplicitNullChecksPass(PassRegistry&); +void initializeIndVarSimplifyLegacyPassPass(PassRegistry&); void initializeInductiveRangeCheckEliminationPass(PassRegistry&); -void initializeIndVarSimplifyPass(PassRegistry&); void initializeInferFunctionAttrsLegacyPassPass(PassRegistry&); void initializeInlineCostAnalysisPass(PassRegistry&); -void initializeInstructionCombiningPassPass(PassRegistry&); void initializeInstCountPass(PassRegistry&); void initializeInstNamerPass(PassRegistry&); -void initializeInternalizePassPass(PassRegistry&); +void initializeInstSimplifierPass(PassRegistry&); +void initializeInstrProfilingLegacyPassPass(PassRegistry &); +void initializeInstructionCombiningPassPass(PassRegistry&); +void initializeInterleavedAccessPass(PassRegistry &); +void initializeInternalizeLegacyPassPass(PassRegistry&); void initializeIntervalPartitionPass(PassRegistry&); -void initializeIRTranslatorPass(PassRegistry &); void initializeJumpThreadingPass(PassRegistry&); -void initializeLCSSAPass(PassRegistry&); -void initializeLICMPass(PassRegistry&); -void initializeLazyValueInfoPass(PassRegistry&); +void initializeLCSSAWrapperPassPass(PassRegistry &); +void initializeLegacyLICMPassPass(PassRegistry&); +void initializeLazyBlockFrequencyInfoPassPass(PassRegistry&); +void initializeLazyValueInfoWrapperPassPass(PassRegistry&); void initializeLintPass(PassRegistry&); +void initializeLiveDebugValuesPass(PassRegistry&); void initializeLiveDebugVariablesPass(PassRegistry&); void initializeLiveIntervalsPass(PassRegistry&); void initializeLiveRegMatrixPass(PassRegistry&); void initializeLiveStacksPass(PassRegistry&); void initializeLiveVariablesPass(PassRegistry&); +void initializeLoadCombinePass(PassRegistry&); void initializeLoaderPassPass(PassRegistry&); +void initializeLoadStoreVectorizerPass(PassRegistry&); void initializeLocalStackSlotPassPass(PassRegistry&); +void initializeLoopAccessLegacyAnalysisPass(PassRegistry&); void initializeLoopDataPrefetchPass(PassRegistry&); -void initializeLoopPassPass(PassRegistry&); -void initializeLoopDeletionPass(PassRegistry&); +void initializeLoopDeletionLegacyPassPass(PassRegistry&); +void initializeLoopDistributePass(PassRegistry&); void initializeLoopExtractorPass(PassRegistry&); +void initializeLoopIdiomRecognizeLegacyPassPass(PassRegistry&); void initializeLoopInfoWrapperPassPass(PassRegistry&); -void initializeLoopInterchangePass(PassRegistry &); void initializeLoopInstSimplifyPass(PassRegistry&); -void initializeLoopRotatePass(PassRegistry&); +void initializeLoopInterchangePass(PassRegistry &); +void initializeLoopLoadEliminationPass(PassRegistry&); +void initializeLoopPassPass(PassRegistry&); +void initializeLoopRerollPass(PassRegistry&); +void initializeLoopRotateLegacyPassPass(PassRegistry&); +void initializeLoopSimplifyCFGLegacyPassPass(PassRegistry&); void initializeLoopSimplifyPass(PassRegistry&); -void initializeLoopSimplifyCFGPass(PassRegistry&); void initializeLoopStrengthReducePass(PassRegistry&); -void initializeGlobalMergePass(PassRegistry&); -void initializeLoopRerollPass(PassRegistry&); void initializeLoopUnrollPass(PassRegistry&); void initializeLoopUnswitchPass(PassRegistry&); +void initializeLoopVectorizePass(PassRegistry&); void initializeLoopVersioningLICMPass(PassRegistry&); -void initializeLoopIdiomRecognizePass(PassRegistry&); -void initializeLowerAtomicPass(PassRegistry&); -void initializeLowerBitSetsPass(PassRegistry&); +void initializeLoopVersioningPassPass(PassRegistry &); +void initializeLowerAtomicLegacyPassPass(PassRegistry &); +void initializeLowerEmuTLSPass(PassRegistry&); void initializeLowerExpectIntrinsicPass(PassRegistry&); +void initializeLowerGuardIntrinsicPass(PassRegistry&); void initializeLowerIntrinsicsPass(PassRegistry&); void initializeLowerInvokePass(PassRegistry&); void initializeLowerSwitchPass(PassRegistry&); -void initializeLowerEmuTLSPass(PassRegistry&); +void initializeLowerTypeTestsPass(PassRegistry&); +void initializeMIRPrintingPassPass(PassRegistry&); void initializeMachineBlockFrequencyInfoPass(PassRegistry&); void initializeMachineBlockPlacementPass(PassRegistry&); void initializeMachineBlockPlacementStatsPass(PassRegistry&); void initializeMachineBranchProbabilityInfoPass(PassRegistry&); void initializeMachineCSEPass(PassRegistry&); -void initializeImplicitNullChecksPass(PassRegistry&); -void initializeMachineDominatorTreePass(PassRegistry&); +void initializeMachineCombinerPass(PassRegistry &); +void initializeMachineCopyPropagationPass(PassRegistry&); void initializeMachineDominanceFrontierPass(PassRegistry&); -void initializeMachinePostDominatorTreePass(PassRegistry&); +void initializeMachineDominatorTreePass(PassRegistry&); +void initializeMachineFunctionPrinterPassPass(PassRegistry&); void initializeMachineLICMPass(PassRegistry&); void initializeMachineLoopInfoPass(PassRegistry&); void initializeMachineModuleInfoPass(PassRegistry&); +void initializeMachinePostDominatorTreePass(PassRegistry&); void initializeMachineRegionInfoPassPass(PassRegistry&); void initializeMachineSchedulerPass(PassRegistry&); void initializeMachineSinkingPass(PassRegistry&); void initializeMachineTraceMetricsPass(PassRegistry&); void initializeMachineVerifierPassPass(PassRegistry&); -void initializeMemCpyOptPass(PassRegistry&); +void initializeMemCpyOptLegacyPassPass(PassRegistry&); void initializeMemDepPrinterPass(PassRegistry&); void initializeMemDerefPrinterPass(PassRegistry&); void initializeMemoryDependenceWrapperPassPass(PassRegistry&); -void initializeMemorySSALazyPass(PassRegistry&); -void initializeMemorySSAPrinterPassPass(PassRegistry&); -void initializeMergedLoadStoreMotionPass(PassRegistry &); -void initializeMetaRenamerPass(PassRegistry&); +void initializeMemorySSAWrapperPassPass(PassRegistry&); +void initializeMemorySSAPrinterLegacyPassPass(PassRegistry &); +void initializeMemorySanitizerPass(PassRegistry&); void initializeMergeFunctionsPass(PassRegistry&); +void initializeMergedLoadStoreMotionLegacyPassPass(PassRegistry &); +void initializeMetaRenamerPass(PassRegistry&); void initializeModuleDebugInfoPrinterPass(PassRegistry&); +void initializeModuleSummaryIndexWrapperPassPass(PassRegistry &); +void initializeNameAnonFunctionPass(PassRegistry &); void initializeNaryReassociatePass(PassRegistry&); void initializeNoAAPass(PassRegistry&); void initializeObjCARCAAWrapperPassPass(PassRegistry&); void initializeObjCARCAPElimPass(PassRegistry&); -void initializeObjCARCExpandPass(PassRegistry&); void initializeObjCARCContractPass(PassRegistry&); +void initializeObjCARCExpandPass(PassRegistry&); void initializeObjCARCOptPass(PassRegistry&); -void initializePAEvalPass(PassRegistry &); void initializeOptimizePHIsPass(PassRegistry&); -void initializePartiallyInlineLibCallsPass(PassRegistry&); +void initializePAEvalPass(PassRegistry &); void initializePEIPass(PassRegistry&); +void initializePGOIndirectCallPromotionLegacyPassPass(PassRegistry&); +void initializePGOInstrumentationGenLegacyPassPass(PassRegistry&); +void initializePGOInstrumentationUseLegacyPassPass(PassRegistry&); void initializePHIEliminationPass(PassRegistry&); -void initializePartialInlinerPass(PassRegistry&); +void initializePhysicalRegisterUsageInfoPass(PassRegistry &); +void initializePartialInlinerLegacyPassPass(PassRegistry &); +void initializePartiallyInlineLibCallsLegacyPassPass(PassRegistry &); +void initializePatchableFunctionPass(PassRegistry &); void initializePeepholeOptimizerPass(PassRegistry&); +void initializePlaceBackedgeSafepointsImplPass(PassRegistry&); +void initializePlaceSafepointsPass(PassRegistry&); void initializePostDomOnlyPrinterPass(PassRegistry&); void initializePostDomOnlyViewerPass(PassRegistry&); void initializePostDomPrinterPass(PassRegistry&); void initializePostDomViewerPass(PassRegistry&); void initializePostDominatorTreeWrapperPassPass(PassRegistry&); +void initializePostMachineSchedulerPass(PassRegistry&); void initializePostOrderFunctionAttrsLegacyPassPass(PassRegistry&); +void initializePostRAHazardRecognizerPass(PassRegistry&); void initializePostRASchedulerPass(PassRegistry&); -void initializePostMachineSchedulerPass(PassRegistry&); +void initializePreISelIntrinsicLoweringLegacyPassPass(PassRegistry&); +void initializePrintBasicBlockPassPass(PassRegistry&); void initializePrintFunctionPassWrapperPass(PassRegistry&); void initializePrintModulePassWrapperPass(PassRegistry&); -void initializePrintBasicBlockPassPass(PassRegistry&); void initializeProcessImplicitDefsPass(PassRegistry&); -void initializePromotePassPass(PassRegistry&); +void initializeProfileSummaryInfoWrapperPassPass(PassRegistry &); +void initializePromoteLegacyPassPass(PassRegistry &); void initializePruneEHPass(PassRegistry&); -void initializeReassociatePass(PassRegistry&); +void initializeReassociateLegacyPassPass(PassRegistry&); +void initializeRegBankSelectPass(PassRegistry &); void initializeRegToMemPass(PassRegistry&); void initializeRegionInfoPassPass(PassRegistry&); void initializeRegionOnlyPrinterPass(PassRegistry&); void initializeRegionOnlyViewerPass(PassRegistry&); void initializeRegionPrinterPass(PassRegistry&); void initializeRegionViewerPass(PassRegistry&); -void initializeReversePostOrderFunctionAttrsPass(PassRegistry&); +void initializeRegisterCoalescerPass(PassRegistry&); +void initializeRenameIndependentSubregsPass(PassRegistry&); +void initializeReversePostOrderFunctionAttrsLegacyPassPass(PassRegistry&); void initializeRewriteStatepointsForGCPass(PassRegistry&); -void initializeSafeStackPass(PassRegistry&); -void initializeSCCPPass(PassRegistry&); -void initializeSROALegacyPassPass(PassRegistry&); -void initializeSROA_DTPass(PassRegistry&); -void initializeSROA_SSAUpPass(PassRegistry&); +void initializeRewriteSymbolsPass(PassRegistry&); +void initializeSCCPLegacyPassPass(PassRegistry &); void initializeSCEVAAWrapperPassPass(PassRegistry&); +void initializeSLPVectorizerPass(PassRegistry&); +void initializeSROALegacyPassPass(PassRegistry&); +void initializeSafeStackPass(PassRegistry&); +void initializeSampleProfileLoaderLegacyPassPass(PassRegistry&); +void initializeSanitizerCoverageModulePass(PassRegistry&); void initializeScalarEvolutionWrapperPassPass(PassRegistry&); +void initializeScalarizerPass(PassRegistry&); +void initializeScopedNoAliasAAWrapperPassPass(PassRegistry&); +void initializeSeparateConstOffsetFromGEPPass(PassRegistry &); +void initializeShadowStackGCLoweringPass(PassRegistry&); void initializeShrinkWrapPass(PassRegistry &); void initializeSimpleInlinerPass(PassRegistry&); -void initializeShadowStackGCLoweringPass(PassRegistry&); -void initializeRegisterCoalescerPass(PassRegistry&); void initializeSingleLoopExtractorPass(PassRegistry&); -void initializeSinkingPass(PassRegistry&); -void initializeSeparateConstOffsetFromGEPPass(PassRegistry &); +void initializeSinkingLegacyPassPass(PassRegistry&); +void initializeSjLjEHPreparePass(PassRegistry&); void initializeSlotIndexesPass(PassRegistry&); -void initializeSpillPlacementPass(PassRegistry&); void initializeSpeculativeExecutionPass(PassRegistry&); -void initializeStackProtectorPass(PassRegistry&); +void initializeSpillPlacementPass(PassRegistry&); void initializeStackColoringPass(PassRegistry&); +void initializeStackMapLivenessPass(PassRegistry&); +void initializeStackProtectorPass(PassRegistry&); void initializeStackSlotColoringPass(PassRegistry&); void initializeStraightLineStrengthReducePass(PassRegistry &); void initializeStripDeadDebugInfoPass(PassRegistry&); @@ -282,48 +316,26 @@ void initializeStripDeadPrototypesLegacyPassPass(PassRegistry&); void initializeStripDebugDeclarePass(PassRegistry&); void initializeStripNonDebugSymbolsPass(PassRegistry&); void initializeStripSymbolsPass(PassRegistry&); +void initializeStructurizeCFGPass(PassRegistry&); void initializeTailCallElimPass(PassRegistry&); void initializeTailDuplicatePassPass(PassRegistry&); +void initializeTargetLibraryInfoWrapperPassPass(PassRegistry &); void initializeTargetPassConfigPass(PassRegistry&); void initializeTargetTransformInfoWrapperPassPass(PassRegistry &); -void initializeTargetLibraryInfoWrapperPassPass(PassRegistry &); -void initializeAssumptionCacheTrackerPass(PassRegistry &); +void initializeThreadSanitizerPass(PassRegistry&); void initializeTwoAddressInstructionPassPass(PassRegistry&); void initializeTypeBasedAAWrapperPassPass(PassRegistry&); -void initializeScopedNoAliasAAWrapperPassPass(PassRegistry&); void initializeUnifyFunctionExitNodesPass(PassRegistry&); -void initializeUnreachableBlockElimPass(PassRegistry&); +void initializeUnpackMachineBundlesPass(PassRegistry&); +void initializeUnreachableBlockElimLegacyPassPass(PassRegistry&); void initializeUnreachableMachineBlockElimPass(PassRegistry&); void initializeVerifierLegacyPassPass(PassRegistry&); void initializeVirtRegMapPass(PassRegistry&); void initializeVirtRegRewriterPass(PassRegistry&); -void initializeInstSimplifierPass(PassRegistry&); -void initializeUnpackMachineBundlesPass(PassRegistry&); -void initializeFinalizeMachineBundlesPass(PassRegistry&); -void initializeLoopAccessAnalysisPass(PassRegistry&); -void initializeLoopVectorizePass(PassRegistry&); -void initializeSLPVectorizerPass(PassRegistry&); -void initializeBBVectorizePass(PassRegistry&); -void initializeMachineFunctionPrinterPassPass(PassRegistry&); -void initializeMIRPrintingPassPass(PassRegistry&); -void initializeStackMapLivenessPass(PassRegistry&); -void initializeLiveDebugValuesPass(PassRegistry&); -void initializeMachineCombinerPass(PassRegistry &); -void initializeLoadCombinePass(PassRegistry&); -void initializeRewriteSymbolsPass(PassRegistry&); -void initializeWinEHPreparePass(PassRegistry&); -void initializePlaceBackedgeSafepointsImplPass(PassRegistry&); -void initializePlaceSafepointsPass(PassRegistry&); -void initializeDwarfEHPreparePass(PassRegistry&); -void initializeFloat2IntPass(PassRegistry&); -void initializeLoopDistributePass(PassRegistry&); -void initializeSjLjEHPreparePass(PassRegistry&); -void initializeDemandedBitsPass(PassRegistry&); -void initializeFuncletLayoutPass(PassRegistry &); -void initializeLoopLoadEliminationPass(PassRegistry&); -void initializeFunctionImportPassPass(PassRegistry &); -void initializeLoopVersioningPassPass(PassRegistry &); void initializeWholeProgramDevirtPass(PassRegistry &); +void initializeWinEHPreparePass(PassRegistry&); +void initializeWriteBitcodePassPass(PassRegistry &); +void initializeXRayInstrumentationPass(PassRegistry &); } #endif diff --git a/include/llvm/LTO/LTO.h b/include/llvm/LTO/LTO.h new file mode 100644 index 0000000000000000000000000000000000000000..5154c0007aaa5df79f79acfdfb4a1e8420af4b78 --- /dev/null +++ b/include/llvm/LTO/LTO.h @@ -0,0 +1,74 @@ +//===-LTO.h - LLVM Link Time Optimizer ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares functions and classes used to support LTO. It is intended +// to be used both by LTO classes as well as by clients (gold-plugin) that +// don't utilize the LTO code generator interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LTO_LTO_H +#define LLVM_LTO_LTO_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/IR/ModuleSummaryIndex.h" + +namespace llvm { + +class LLVMContext; +class MemoryBufferRef; +class Module; + +/// Helper to load a module from bitcode. +std::unique_ptr loadModuleFromBuffer(const MemoryBufferRef &Buffer, + LLVMContext &Context, bool Lazy); + +/// Provide a "loader" for the FunctionImporter to access function from other +/// modules. +class ModuleLoader { + /// The context that will be used for importing. + LLVMContext &Context; + + /// Map from Module identifier to MemoryBuffer. Used by clients like the + /// FunctionImported to request loading a Module. + StringMap &ModuleMap; + +public: + ModuleLoader(LLVMContext &Context, StringMap &ModuleMap) + : Context(Context), ModuleMap(ModuleMap) {} + + /// Load a module on demand. + std::unique_ptr operator()(StringRef Identifier) { + return loadModuleFromBuffer(ModuleMap[Identifier], Context, /*Lazy*/ true); + } +}; + + +/// Resolve Weak and LinkOnce values in the \p Index. Linkage changes recorded +/// in the index and the ThinLTO backends must apply the changes to the Module +/// via thinLTOResolveWeakForLinkerModule. +/// +/// This is done for correctness (if value exported, ensure we always +/// emit a copy), and compile-time optimization (allow drop of duplicates). +void thinLTOResolveWeakForLinkerInIndex( + ModuleSummaryIndex &Index, + function_ref + isPrevailing, + function_ref + recordNewLinkage); + +/// Update the linkages in the given \p Index to mark exported values +/// as external and non-exported values as internal. The ThinLTO backends +/// must apply the changes to the Module via thinLTOInternalizeModule. +void thinLTOInternalizeAndPromoteInIndex( + ModuleSummaryIndex &Index, + function_ref isExported); +} + +#endif diff --git a/include/llvm/LTO/LTOCodeGenerator.h b/include/llvm/LTO/legacy/LTOCodeGenerator.h similarity index 88% rename from include/llvm/LTO/LTOCodeGenerator.h rename to include/llvm/LTO/legacy/LTOCodeGenerator.h index 53fd0ace0c8b48ecdde9c985f6ddfbb0323a43a8..d083e37d75b886381120f0070435e5fe191d5493 100644 --- a/include/llvm/LTO/LTOCodeGenerator.h +++ b/include/llvm/LTO/legacy/LTOCodeGenerator.h @@ -36,9 +36,9 @@ #define LLVM_LTO_LTOCODEGENERATOR_H #include "llvm-c/lto.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Module.h" #include "llvm/Target/TargetMachine.h" @@ -47,6 +47,7 @@ #include namespace llvm { +template class ArrayRef; class LLVMContext; class DiagnosticInfo; class Linker; @@ -67,17 +68,21 @@ struct LTOCodeGenerator { ~LTOCodeGenerator(); /// Merge given module. Return true on success. + /// + /// Resets \a HasVerifiedInput. bool addModule(struct LTOModule *); /// Set the destination module. + /// + /// Resets \a HasVerifiedInput. void setModule(std::unique_ptr M); - void setTargetOptions(TargetOptions Options); + void setTargetOptions(const TargetOptions &Options); void setDebugInfo(lto_debug_model); - void setCodePICModel(Reloc::Model Model) { RelocModel = Model; } - + void setCodePICModel(Optional Model) { RelocModel = Model; } + /// Set the file type to be emitted (assembly or object code). - /// The default is TargetMachine::CGFT_ObjectFile. + /// The default is TargetMachine::CGFT_ObjectFile. void setFileType(TargetMachine::CodeGenFileType FT) { FileType = FT; } void setCpu(const char *MCpu) { this->MCpu = MCpu; } @@ -122,6 +127,8 @@ struct LTOCodeGenerator { /// Write the merged module to the file specified by the given path. Return /// true on success. + /// + /// Calls \a verifyMergedModuleOnce(). bool writeMergedModules(const char *Path); /// Compile the merged module into a *single* output file; the path to output @@ -146,6 +153,8 @@ struct LTOCodeGenerator { bool DisableVectorization); /// Optimizes the merged module. Returns true on success. + /// + /// Calls \a verifyMergedModuleOnce(). bool optimize(bool DisableVerify, bool DisableInline, bool DisableGVNLoadPRE, bool DisableVectorization); @@ -159,6 +168,8 @@ struct LTOCodeGenerator { /// than one element, code generation is done in parallel with out.size() /// threads. Output files will be written to members of out. Returns true on /// success. + /// + /// Calls \a verifyMergedModuleOnce(). bool compileOptimized(ArrayRef Out); void setDiagnosticHandler(lto_diagnostic_handler_t, void *); @@ -170,22 +181,28 @@ struct LTOCodeGenerator { private: void initializeLTOPasses(); + /// Verify the merged module on first call. + /// + /// Sets \a HasVerifiedInput on first call and doesn't run again on the same + /// input. + void verifyMergedModuleOnce(); + bool compileOptimizedToFile(const char **Name); void restoreLinkageForExternals(); void applyScopeRestrictions(); - void applyRestriction(GlobalValue &GV, ArrayRef Libcalls, - std::vector &MustPreserveList, - SmallPtrSetImpl &AsmUsed, - Mangler &Mangler); + void preserveDiscardableGVs( + Module &TheModule, + llvm::function_ref mustPreserveGV); + bool determineTarget(); + std::unique_ptr createTargetMachine(); static void DiagnosticHandler(const DiagnosticInfo &DI, void *Context); void DiagnosticHandler2(const DiagnosticInfo &DI); void emitError(const std::string &ErrMsg); - - typedef StringMap StringSet; + void emitWarning(const std::string &ErrMsg); LLVMContext &Context; std::unique_ptr MergedModule; @@ -193,9 +210,10 @@ private: std::unique_ptr TargetMach; bool EmitDwarfDebugInfo = false; bool ScopeRestrictionsDone = false; - Reloc::Model RelocModel = Reloc::Default; - StringSet MustPreserveSymbols; - StringSet AsmUndefinedRefs; + bool HasVerifiedInput = false; + Optional RelocModel; + StringSet<> MustPreserveSymbols; + StringSet<> AsmUndefinedRefs; StringMap ExternalSymbols; std::vector CodegenOptions; std::string FeatureStr; @@ -204,6 +222,8 @@ private: std::string NativeObjectPath; TargetOptions Options; CodeGenOpt::Level CGOptLevel = CodeGenOpt::Default; + const Target *MArch = nullptr; + std::string TripleStr; unsigned OptLevel = 2; lto_diagnostic_handler_t DiagHandler = nullptr; void *DiagContext = nullptr; diff --git a/include/llvm/LTO/LTOModule.h b/include/llvm/LTO/legacy/LTOModule.h similarity index 92% rename from include/llvm/LTO/LTOModule.h rename to include/llvm/LTO/legacy/LTOModule.h index 0d89d819c508353d42b69234f55f0c106c4d9c90..2e46219be19e29ce9a638e839853ddcaf99f3b6e 100644 --- a/include/llvm/LTO/LTOModule.h +++ b/include/llvm/LTO/legacy/LTOModule.h @@ -91,19 +91,22 @@ public: /// InitializeAllAsmPrinters(); /// InitializeAllAsmParsers(); static ErrorOr> - createFromFile(LLVMContext &Context, const char *path, TargetOptions options); + createFromFile(LLVMContext &Context, const char *path, + const TargetOptions &options); static ErrorOr> createFromOpenFile(LLVMContext &Context, int fd, const char *path, - size_t size, TargetOptions options); + size_t size, const TargetOptions &options); static ErrorOr> createFromOpenFileSlice(LLVMContext &Context, int fd, const char *path, - size_t map_size, off_t offset, TargetOptions options); + size_t map_size, off_t offset, + const TargetOptions &options); static ErrorOr> createFromBuffer(LLVMContext &Context, const void *mem, size_t length, - TargetOptions options, StringRef path = ""); + const TargetOptions &options, StringRef path = ""); static ErrorOr> createInLocalContext(std::unique_ptr Context, const void *mem, - size_t length, TargetOptions options, StringRef path); + size_t length, const TargetOptions &options, + StringRef path); const Module &getModule() const { return const_cast(this)->getModule(); @@ -202,7 +205,7 @@ private: /// Create an LTOModule (private version). static ErrorOr> - makeLTOModule(MemoryBufferRef Buffer, TargetOptions options, + makeLTOModule(MemoryBufferRef Buffer, const TargetOptions &options, LLVMContext &Context, bool ShouldBeLazy); }; } diff --git a/include/llvm/LTO/ThinLTOCodeGenerator.h b/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h similarity index 75% rename from include/llvm/LTO/ThinLTOCodeGenerator.h rename to include/llvm/LTO/legacy/ThinLTOCodeGenerator.h index 76dad3d8425d330ad35d04a29944f060556f6e13..539880e8d3a7a48fbb5e3e2ec7abc425669bb0b1 100644 --- a/include/llvm/LTO/ThinLTOCodeGenerator.h +++ b/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h @@ -17,9 +17,9 @@ #define LLVM_LTO_THINLTOCODEGENERATOR_H #include "llvm-c/lto.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" +#include "llvm/IR/ModuleSummaryIndex.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Target/TargetOptions.h" @@ -27,7 +27,7 @@ #include namespace llvm { -class ModuleSummaryIndex; +class StringRef; class LLVMContext; class TargetMachine; @@ -37,7 +37,7 @@ struct TargetMachineBuilder { std::string MCpu; std::string MAttr; TargetOptions Options; - Reloc::Model RelocModel = Reloc::Default; + Optional RelocModel; CodeGenOpt::Level CGOptLevel = CodeGenOpt::Default; std::unique_ptr create() const; @@ -108,10 +108,10 @@ public: */ struct CachingOptions { - std::string Path; - int PruningInterval = -1; // seconds, -1 to disable pruning - unsigned int Expiration; // seconds. - unsigned MaxPercentageOfAvailableSpace; // percentage. + std::string Path; // Path to the cache, empty to disable. + int PruningInterval = 1200; // seconds, -1 to disable pruning. + unsigned int Expiration = 7 * 24 * 3600; // seconds (1w default). + unsigned MaxPercentageOfAvailableSpace = 75; // percentage. }; /// Provide a path to a directory where to store the cached files for @@ -119,21 +119,26 @@ public: void setCacheDir(std::string Path) { CacheOptions.Path = std::move(Path); } /// Cache policy: interval (seconds) between two prune of the cache. Set to a - /// negative value (default) to disable pruning. + /// negative value (default) to disable pruning. A value of 0 will be ignored. void setCachePruningInterval(int Interval) { - CacheOptions.PruningInterval = Interval; + if (Interval) + CacheOptions.PruningInterval = Interval; } /// Cache policy: expiration (in seconds) for an entry. + /// A value of 0 will be ignored. void setCacheEntryExpiration(unsigned Expiration) { - CacheOptions.Expiration = Expiration; + if (Expiration) + CacheOptions.Expiration = Expiration; } /** * Sets the maximum cache size that can be persistent across build, in terms * of percentage of the available space on the the disk. Set to 100 to * indicate no limit, 50 to indicate that the cache size will not be left over - * half the available space. A value over 100 will be reduced to 100. + * half the available space. A value over 100 will be reduced to 100, and a + * value of 0 will be ignored. + * * * The formula looks like: * AvailableSpace = FreeSpace + ExistingCacheSize @@ -141,7 +146,8 @@ public: * */ void setMaxCacheSizeRelativeToAvailableSpace(unsigned Percentage) { - CacheOptions.MaxPercentageOfAvailableSpace = Percentage; + if (Percentage) + CacheOptions.MaxPercentageOfAvailableSpace = Percentage; } /**@}*/ @@ -162,13 +168,22 @@ public: } /// CodeModel - void setCodePICModel(Reloc::Model Model) { TMBuilder.RelocModel = Model; } + void setCodePICModel(Optional Model) { + TMBuilder.RelocModel = Model; + } /// CodeGen optimization level void setCodeGenOptLevel(CodeGenOpt::Level CGOptLevel) { TMBuilder.CGOptLevel = CGOptLevel; } + /// Disable CodeGen, only run the stages till codegen and stop. The output + /// will be bitcode. + void disableCodeGen(bool Disable) { DisableCodeGen = Disable; } + + /// Perform CodeGen only: disable all other stages. + void setCodeGenOnly(bool CGOnly) { CodeGenOnly = CGOnly; } + /**@}*/ /** @@ -183,16 +198,36 @@ public: std::unique_ptr linkCombinedIndex(); /** - * Perform promotion and renaming of exported internal functions. + * Perform promotion and renaming of exported internal functions, + * and additionally resolve weak and linkonce symbols. + * Index is updated to reflect linkage changes from weak resolution. */ void promote(Module &Module, ModuleSummaryIndex &Index); + /** + * Compute and emit the imported files for module at \p ModulePath. + */ + static void emitImports(StringRef ModulePath, StringRef OutputName, + ModuleSummaryIndex &Index); + /** * Perform cross-module importing for the module identified by * ModuleIdentifier. */ void crossModuleImport(Module &Module, ModuleSummaryIndex &Index); + /** + * Compute the list of summaries needed for importing into module. + */ + static void gatherImportedSummariesForModule( + StringRef ModulePath, ModuleSummaryIndex &Index, + std::map &ModuleToSummariesForIndex); + + /** + * Perform internalization. Index is updated to reflect linkage changes. + */ + void internalize(Module &Module, ModuleSummaryIndex &Index); + /** * Perform post-importing ThinLTO optimizations. */ @@ -228,6 +263,14 @@ private: /// Path to a directory to save the temporary bitcode files. std::string SaveTempsDir; + + /// Flag to enable/disable CodeGen. When set to true, the process stops after + /// optimizations and a bitcode is produced. + bool DisableCodeGen = false; + + /// Flag to indicate that only the CodeGen will be performed, no cross-module + /// importing or optimization. + bool CodeGenOnly = false; }; } #endif diff --git a/include/llvm/LTO/legacy/UpdateCompilerUsed.h b/include/llvm/LTO/legacy/UpdateCompilerUsed.h new file mode 100644 index 0000000000000000000000000000000000000000..4be0027e97d7cabc31db534355e8b3812f7bec43 --- /dev/null +++ b/include/llvm/LTO/legacy/UpdateCompilerUsed.h @@ -0,0 +1,32 @@ +//==------ UpdateCompilerUsed.h - LLVM Link Time Optimizer Utility --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares a helper class to update llvm.compiler_used metadata. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LTO_UPDATE_COMPILER_USED_H +#define LLVM_LTO_UPDATE_COMPILER_USED_H + +#include "llvm/ADT/StringSet.h" +#include "llvm/IR/GlobalValue.h" + +namespace llvm { +class Module; +class TargetMachine; + +/// Find all globals in \p TheModule that are referenced in +/// \p AsmUndefinedRefs, as well as the user-supplied functions definitions that +/// are also libcalls, and create or update the magic "llvm.compiler_used" +/// global in \p TheModule. +void updateCompilerUsed(Module &TheModule, const TargetMachine &TM, + const StringSet<> &AsmUndefinedRefs); +} + +#endif // LLVM_LTO_UPDATE_COMPILER_USED_H diff --git a/include/llvm/LibDriver/LibDriver.h b/include/llvm/LibDriver/LibDriver.h index 09495650c1b9054832869a5627b43cd423dfb84e..95feb60be40378bcc8f1a43653a144b1635bc2e2 100644 --- a/include/llvm/LibDriver/LibDriver.h +++ b/include/llvm/LibDriver/LibDriver.h @@ -15,12 +15,10 @@ #ifndef LLVM_LIBDRIVER_LIBDRIVER_H #define LLVM_LIBDRIVER_LIBDRIVER_H -#include "llvm/ADT/ArrayRef.h" - namespace llvm { +template class ArrayRef; -int libDriverMain(llvm::ArrayRef ARgs); - +int libDriverMain(ArrayRef ARgs); } #endif diff --git a/include/llvm/LineEditor/LineEditor.h b/include/llvm/LineEditor/LineEditor.h index bb106f87ca48759ca9dac52a2e9a82a33b49c412..68995d0633add4b67477212b8f467be967ec56fe 100644 --- a/include/llvm/LineEditor/LineEditor.h +++ b/include/llvm/LineEditor/LineEditor.h @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace llvm { @@ -137,7 +138,7 @@ private: template struct ListCompleterModel : ListCompleterConcept { - ListCompleterModel(T Value) : Value(Value) {} + ListCompleterModel(T Value) : Value(std::move(Value)) {} std::vector getCompletions(StringRef Buffer, size_t Pos) const override { return Value(Buffer, Pos); diff --git a/include/llvm/LinkAllIR.h b/include/llvm/LinkAllIR.h index 2b0604aee06716e1b3f3346013abc8957d882b10..77e19ce900e328c26e96652b7e494bd036a2812a 100644 --- a/include/llvm/LinkAllIR.h +++ b/include/llvm/LinkAllIR.h @@ -43,8 +43,9 @@ namespace { // to know that getenv() never returns -1, this will do the job. if (std::getenv("bar") != (char*) -1) return; - (void)new llvm::Module("", llvm::getGlobalContext()); - (void)new llvm::UnreachableInst(llvm::getGlobalContext()); + llvm::LLVMContext Context; + (void)new llvm::Module("", Context); + (void)new llvm::UnreachableInst(Context); (void) llvm::createVerifierPass(); } } ForceVMCoreLinking; diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index 158b2d0576b8c52f541a9c5f736c3450838d18ae..a12913e99990efd84da6e20fbf963d4e97adedb3 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -19,7 +19,8 @@ #include "llvm/Analysis/AliasSetTracker.h" #include "llvm/Analysis/AliasAnalysisEvaluator.h" #include "llvm/Analysis/BasicAliasAnalysis.h" -#include "llvm/Analysis/CFLAliasAnalysis.h" +#include "llvm/Analysis/CFLAndersAliasAnalysis.h" +#include "llvm/Analysis/CFLSteensAliasAnalysis.h" #include "llvm/Analysis/CallPrinter.h" #include "llvm/Analysis/DomPrinter.h" #include "llvm/Analysis/GlobalsModRef.h" @@ -73,7 +74,8 @@ namespace { (void) llvm::createCallGraphDOTPrinterPass(); (void) llvm::createCallGraphViewerPass(); (void) llvm::createCFGSimplificationPass(); - (void) llvm::createCFLAAWrapperPass(); + (void) llvm::createCFLAndersAAWrapperPass(); + (void) llvm::createCFLSteensAAWrapperPass(); (void) llvm::createStructurizeCFGPass(); (void) llvm::createConstantMergePass(); (void) llvm::createConstantPropagationPass(); @@ -82,22 +84,24 @@ namespace { (void) llvm::createDeadCodeEliminationPass(); (void) llvm::createDeadInstEliminationPass(); (void) llvm::createDeadStoreEliminationPass(); - (void) llvm::createDependenceAnalysisPass(); + (void) llvm::createDependenceAnalysisWrapperPass(); (void) llvm::createDivergenceAnalysisPass(); (void) llvm::createDomOnlyPrinterPass(); (void) llvm::createDomPrinterPass(); (void) llvm::createDomOnlyViewerPass(); (void) llvm::createDomViewerPass(); (void) llvm::createGCOVProfilerPass(); - (void) llvm::createPGOInstrumentationGenPass(); - (void) llvm::createPGOInstrumentationUsePass(); - (void) llvm::createInstrProfilingPass(); + (void) llvm::createPGOInstrumentationGenLegacyPass(); + (void) llvm::createPGOInstrumentationUseLegacyPass(); + (void) llvm::createPGOIndirectCallPromotionLegacyPass(); + (void) llvm::createInstrProfilingLegacyPass(); (void) llvm::createFunctionImportPass(); (void) llvm::createFunctionInliningPass(); (void) llvm::createAlwaysInlinerPass(); (void) llvm::createGlobalDCEPass(); (void) llvm::createGlobalOptimizerPass(); (void) llvm::createGlobalsAAWrapperPass(); + (void) llvm::createGuardWideningPass(); (void) llvm::createIPConstantPropagationPass(); (void) llvm::createIPSCCPPass(); (void) llvm::createInductiveRangeCheckEliminationPass(); @@ -143,7 +147,7 @@ namespace { (void) llvm::createRegionViewerPass(); (void) llvm::createSCCPPass(); (void) llvm::createSafeStackPass(); - (void) llvm::createScalarReplAggregatesPass(); + (void) llvm::createSROAPass(); (void) llvm::createSingleLoopExtractorPass(); (void) llvm::createStripSymbolsPass(); (void) llvm::createStripNonDebugSymbolsPass(); @@ -181,11 +185,13 @@ namespace { (void) llvm::createInstructionSimplifierPass(); (void) llvm::createLoopVectorizePass(); (void) llvm::createSLPVectorizerPass(); + (void) llvm::createLoadStoreVectorizerPass(); (void) llvm::createBBVectorizePass(); (void) llvm::createPartiallyInlineLibCallsPass(); (void) llvm::createScalarizerPass(); (void) llvm::createSeparateConstOffsetFromGEPPass(); (void) llvm::createSpeculativeExecutionPass(); + (void) llvm::createSpeculativeExecutionIfHasBranchDivergencePass(); (void) llvm::createRewriteSymbolsPass(); (void) llvm::createStraightLineStrengthReducePass(); (void) llvm::createMemDerefPrinter(); diff --git a/include/llvm/Linker/IRMover.h b/include/llvm/Linker/IRMover.h index 1675ec5a3e644d53855be592a9eee5156d6ec679..578940ed4069a473d384cd26c5cc54f28acc5f64 100644 --- a/include/llvm/Linker/IRMover.h +++ b/include/llvm/Linker/IRMover.h @@ -15,10 +15,12 @@ #include namespace llvm { +class Error; class GlobalValue; -class MDNode; +class Metadata; class Module; class StructType; +class TrackingMDRef; class Type; class IRMover { @@ -39,6 +41,9 @@ class IRMover { static bool isEqual(const StructType *LHS, const StructType *RHS); }; + /// Type of the Metadata map in \a ValueToValueMapTy. + typedef DenseMap MDMapT; + public: class IdentifiedStructTypeSet { // The set of opaque types is the composite module. @@ -66,17 +71,14 @@ public: /// not present in ValuesToLink. The GlobalValue and a ValueAdder callback /// are passed as an argument, and the callback is expected to be called /// if the GlobalValue needs to be added to the \p ValuesToLink and linked. - /// - /// Returns true on error. - bool move(std::unique_ptr Src, ArrayRef ValuesToLink, - std::function AddLazyFor, - DenseMap *ValIDToTempMDMap = nullptr, - bool IsMetadataLinkingPostpass = false); + Error move(std::unique_ptr Src, ArrayRef ValuesToLink, + std::function AddLazyFor); Module &getModule() { return Composite; } private: Module &Composite; IdentifiedStructTypeSet IdentifiedStructTypes; + MDMapT SharedMDs; ///< A Metadata map to use for all calls to \a move(). }; } // End llvm namespace diff --git a/include/llvm/Linker/Linker.h b/include/llvm/Linker/Linker.h index 78d6c23cd2a653b11710da2d6ab06ade31027ba2..b077c373326fc3392cef3ada4b65c653ea402513 100644 --- a/include/llvm/Linker/Linker.h +++ b/include/llvm/Linker/Linker.h @@ -29,7 +29,10 @@ public: None = 0, OverrideFromSrc = (1 << 0), LinkOnlyNeeded = (1 << 1), - InternalizeLinkedSymbols = (1 << 2) + InternalizeLinkedSymbols = (1 << 2), + /// Don't force link referenced linkonce definitions, import declaration. + DontForceLinkLinkonceODR = (1 << 3) + }; Linker(Module &M); @@ -41,23 +44,13 @@ public: /// For ThinLTO function importing/exporting the \p ModuleSummaryIndex /// is passed. If \p GlobalsToImport is provided, only the globals that /// are part of the set will be imported from the source module. - /// The \p ValIDToTempMDMap is populated by the linker when function - /// importing is performed. /// /// Returns true on error. bool linkInModule(std::unique_ptr Src, unsigned Flags = Flags::None, - DenseSet *GlobalsToImport = nullptr, - DenseMap *ValIDToTempMDMap = nullptr); + DenseSet *GlobalsToImport = nullptr); static bool linkModules(Module &Dest, std::unique_ptr Src, unsigned Flags = Flags::None); - - /// \brief Link metadata from \p Src into the composite. - /// - /// The \p ValIDToTempMDMap sound have been populated earlier during function - /// importing from \p Src. - bool linkInMetadata(std::unique_ptr Src, - DenseMap *ValIDToTempMDMap); }; } // End llvm namespace diff --git a/include/llvm/MC/MCAsmBackend.h b/include/llvm/MC/MCAsmBackend.h index f815b24c856f889325f5cb6f1a1a96c9a17bc9bc..ce17a2a067589efafa07794ddf46f6ba7333001f 100644 --- a/include/llvm/MC/MCAsmBackend.h +++ b/include/llvm/MC/MCAsmBackend.h @@ -29,7 +29,7 @@ class MCRelaxableFragment; class MCObjectWriter; class MCSection; class MCValue; -class raw_ostream; +class raw_pwrite_stream; /// Generic interface to target specific assembler backends. class MCAsmBackend { @@ -39,8 +39,6 @@ class MCAsmBackend { protected: // Can only create subclasses. MCAsmBackend(); - unsigned HasDataInCodeSupport : 1; - public: virtual ~MCAsmBackend(); @@ -51,17 +49,6 @@ public: /// emit the final object file. virtual MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const = 0; - /// Create a new ELFObjectTargetWriter to enable non-standard - /// ELFObjectWriters. - virtual MCELFObjectTargetWriter *createELFObjectTargetWriter() const { - llvm_unreachable("createELFObjectTargetWriter is not supported by asm " - "backend"); - } - - /// Check whether this target implements data-in-code markers. If not, data - /// region directives will be ignored. - bool hasDataInCodeSupport() const { return HasDataInCodeSupport; } - /// \name Target Fixup Interfaces /// @{ @@ -115,8 +102,10 @@ public: /// /// \param Inst The instruction to relax, which may be the same as the /// output. + /// \param STI the subtarget information for the associated instruction. /// \param [out] Res On return, the relaxed instruction. - virtual void relaxInstruction(const MCInst &Inst, MCInst &Res) const = 0; + virtual void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, + MCInst &Res) const = 0; /// @} @@ -132,6 +121,10 @@ public: /// \return - True on success. virtual bool writeNopData(uint64_t Count, MCObjectWriter *OW) const = 0; + /// Give backend an opportunity to finish layout after relaxation + virtual void finishLayout(MCAssembler const &Asm, + MCAsmLayout &Layout) const {} + /// Handle any target-specific assembler flags. By default, do nothing. virtual void handleAssemblerFlag(MCAssemblerFlag Flag) {} diff --git a/include/llvm/MC/MCAsmInfo.h b/include/llvm/MC/MCAsmInfo.h index 3106c8c501f31dbe43748ed65dcce19cb074dd64..e6ed5688d18d54eba7b23e8667722f0947377f62 100644 --- a/include/llvm/MC/MCAsmInfo.h +++ b/include/llvm/MC/MCAsmInfo.h @@ -53,6 +53,12 @@ namespace LCOMM { enum LCOMMType { NoAlignment, ByteAlignment, Log2Alignment }; } +enum class DebugCompressionType { + DCT_None, // no compression + DCT_Zlib, // zlib style complession + DCT_ZlibGnu // zlib-gnu style compression +}; + /// This class is intended to be used as a base class for asm /// properties and features specific to the target. class MCAsmInfo { @@ -356,13 +362,20 @@ protected: /// construction (see LLVMTargetMachine::initAsmInfo()). bool UseIntegratedAssembler; - /// Compress DWARF debug sections. Defaults to false. - bool CompressDebugSections; + /// Preserve Comments in assembly + bool PreserveAsmComments; + + /// Compress DWARF debug sections. Defaults to no compression. + DebugCompressionType CompressDebugSections; /// True if the integrated assembler should interpret 'a >> b' constant /// expressions as logical rather than arithmetic. bool UseLogicalShr; + // If true, emit GOTPCRELX/REX_GOTPCRELX instead of GOTPCREL, on + // X86_64 ELF. + bool RelaxELFRelocations = true; + public: explicit MCAsmInfo(); virtual ~MCAsmInfo(); @@ -487,7 +500,7 @@ public: bool getAlignmentIsInBytes() const { return AlignmentIsInBytes; } unsigned getTextAlignFillValue() const { return TextAlignFillValue; } const char *getGlobalDirective() const { return GlobalDirective; } - bool doesSetDirectiveSuppressesReloc() const { + bool doesSetDirectiveSuppressReloc() const { return SetDirectiveSuppressesReloc; } bool hasAggressiveSymbolFolding() const { return HasAggressiveSymbolFolding; } @@ -525,6 +538,10 @@ public: ExceptionHandling getExceptionHandlingType() const { return ExceptionsType; } WinEH::EncodingType getWinEHEncodingType() const { return WinEHEncodingType; } + void setExceptionsType(ExceptionHandling EH) { + ExceptionsType = EH; + } + /// Returns true if the exception handling method for the platform uses call /// frame information to unwind. bool usesCFIForEH() const { @@ -561,13 +578,26 @@ public: UseIntegratedAssembler = Value; } - bool compressDebugSections() const { return CompressDebugSections; } + /// Return true if assembly (inline or otherwise) should be parsed. + bool preserveAsmComments() const { return PreserveAsmComments; } - void setCompressDebugSections(bool CompressDebugSections) { + /// Set whether assembly (inline or otherwise) should be parsed. + virtual void setPreserveAsmComments(bool Value) { + PreserveAsmComments = Value; + } + + DebugCompressionType compressDebugSections() const { + return CompressDebugSections; + } + + void setCompressDebugSections(DebugCompressionType CompressDebugSections) { this->CompressDebugSections = CompressDebugSections; } bool shouldUseLogicalShr() const { return UseLogicalShr; } + + bool canRelaxRelocations() const { return RelaxELFRelocations; } + void setRelaxELFRelocations(bool V) { RelaxELFRelocations = V; } }; } diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index f15b9af3051da1c8a0f5bee7d9d24c9e140985d3..aa3b451152dfa0cea3f22e306cdf353b046706d0 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -246,8 +246,8 @@ public: // concrete and require clients to pass in a target like object. The other // option is to make this abstract, and have targets provide concrete // implementations as we do with AsmParser. - MCAssembler(MCContext &Context_, MCAsmBackend &Backend_, - MCCodeEmitter &Emitter_, MCObjectWriter &Writer_); + MCAssembler(MCContext &Context, MCAsmBackend &Backend, + MCCodeEmitter &Emitter, MCObjectWriter &Writer); ~MCAssembler(); /// Reuse an assembler instance diff --git a/include/llvm/MC/MCCodeGenInfo.h b/include/llvm/MC/MCCodeGenInfo.h deleted file mode 100644 index 0a4744f1d0f7d3d8ab1cc6aa71fa28fe5674aa6e..0000000000000000000000000000000000000000 --- a/include/llvm/MC/MCCodeGenInfo.h +++ /dev/null @@ -1,51 +0,0 @@ -//===-- llvm/MC/MCCodeGenInfo.h - Target CodeGen Info -----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file tracks information about the target which can affect codegen, -// asm parsing, and asm printing. For example, relocation model. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MC_MCCODEGENINFO_H -#define LLVM_MC_MCCODEGENINFO_H - -#include "llvm/Support/CodeGen.h" - -namespace llvm { - -class MCCodeGenInfo { - /// RelocationModel - Relocation model: static, pic, etc. - /// - Reloc::Model RelocationModel; - - /// CMModel - Code model. - /// - CodeModel::Model CMModel; - - /// OptLevel - Optimization level. - /// - CodeGenOpt::Level OptLevel; - -public: - void initMCCodeGenInfo(Reloc::Model RM = Reloc::Default, - CodeModel::Model CM = CodeModel::Default, - CodeGenOpt::Level OL = CodeGenOpt::Default); - - Reloc::Model getRelocationModel() const { return RelocationModel; } - - CodeModel::Model getCodeModel() const { return CMModel; } - - CodeGenOpt::Level getOptLevel() const { return OptLevel; } - - // Allow overriding OptLevel on a per-function basis. - void setOptLevel(CodeGenOpt::Level Level) { OptLevel = Level; } -}; -} // namespace llvm - -#endif diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index 44d195c1072e4da75605a5344258802b5217f993..fe1377e054e8288a899b706cb87184030278e19b 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -200,16 +200,19 @@ namespace llvm { std::string SectionName; StringRef GroupName; int SelectionKey; + unsigned UniqueID; COFFSectionKey(StringRef SectionName, StringRef GroupName, - int SelectionKey) + int SelectionKey, unsigned UniqueID) : SectionName(SectionName), GroupName(GroupName), - SelectionKey(SelectionKey) {} + SelectionKey(SelectionKey), UniqueID(UniqueID) {} bool operator<(const COFFSectionKey &Other) const { if (SectionName != Other.SectionName) return SectionName < Other.SectionName; if (GroupName != Other.GroupName) return GroupName < Other.GroupName; - return SelectionKey < Other.SelectionKey; + if (SelectionKey != Other.SelectionKey) + return SelectionKey < Other.SelectionKey; + return UniqueID < Other.UniqueID; } }; @@ -315,6 +318,13 @@ namespace llvm { /// \name Section Management /// @{ + enum : unsigned { + /// Pass this value as the UniqueID during section creation to get the + /// generic section with the given name and characteristics. The usual + /// sections such as .text use this ID. + GenericSectionID = ~0U + }; + /// Return the MCSection for the specified mach-o section. This requires /// the operands to be valid. MCSectionMachO *getMachOSection(StringRef Segment, StringRef Section, @@ -329,48 +339,56 @@ namespace llvm { BeginSymName); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags) { return getELFSection(Section, Type, Flags, nullptr); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, const char *BeginSymName) { return getELFSection(Section, Type, Flags, 0, "", BeginSymName); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - StringRef Group) { + const Twine &Group) { return getELFSection(Section, Type, Flags, EntrySize, Group, nullptr); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - StringRef Group, const char *BeginSymName) { + const Twine &Group, const char *BeginSymName) { return getELFSection(Section, Type, Flags, EntrySize, Group, ~0, BeginSymName); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - StringRef Group, unsigned UniqueID) { + const Twine &Group, unsigned UniqueID) { return getELFSection(Section, Type, Flags, EntrySize, Group, UniqueID, nullptr); } - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - StringRef Group, unsigned UniqueID, + const Twine &Group, unsigned UniqueID, const char *BeginSymName); - MCSectionELF *getELFSection(StringRef Section, unsigned Type, + MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *Group, unsigned UniqueID, const char *BeginSymName, const MCSectionELF *Associated); - MCSectionELF *createELFRelSection(StringRef Name, unsigned Type, + /// Get a section with the provided group identifier. This section is + /// named by concatenating \p Prefix with '.' then \p Suffix. The \p Type + /// describes the type of the section and \p Flags are used to further + /// configure this named section. + MCSectionELF *getELFNamedSection(const Twine &Prefix, const Twine &Suffix, + unsigned Type, unsigned Flags, + unsigned EntrySize = 0); + + MCSectionELF *createELFRelSection(const Twine &Name, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *Group, const MCSectionELF *Associated); @@ -382,6 +400,7 @@ namespace llvm { MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics, SectionKind Kind, StringRef COMDATSymName, int Selection, + unsigned UniqueID = GenericSectionID, const char *BeginSymName = nullptr); MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics, @@ -394,8 +413,9 @@ namespace llvm { /// section containing KeySym. For example, to create a debug info section /// associated with an inline function, pass the normal debug info section /// as Sec and the function symbol as KeySym. - MCSectionCOFF *getAssociativeCOFFSection(MCSectionCOFF *Sec, - const MCSymbol *KeySym); + MCSectionCOFF * + getAssociativeCOFFSection(MCSectionCOFF *Sec, const MCSymbol *KeySym, + unsigned UniqueID = GenericSectionID); // Create and save a copy of STI and return a reference to the copy. MCSubtargetInfo &getSubtargetCopy(const MCSubtargetInfo &STI); diff --git a/include/llvm/MC/MCDisassembler/MCDisassembler.h b/include/llvm/MC/MCDisassembler/MCDisassembler.h index e882133741270d206000a683882e57be00338165..9006d87abb43ddeefd404f94e3b19af7623621e6 100644 --- a/include/llvm/MC/MCDisassembler/MCDisassembler.h +++ b/include/llvm/MC/MCDisassembler/MCDisassembler.h @@ -10,12 +10,12 @@ #define LLVM_MC_MCDISASSEMBLER_MCDISASSEMBLER_H #include "llvm-c/Disassembler.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/MC/MCDisassembler/MCSymbolizer.h" #include "llvm/Support/DataTypes.h" namespace llvm { +template class ArrayRef; class MCInst; class MCSubtargetInfo; class raw_ostream; diff --git a/include/llvm/MC/MCDwarf.h b/include/llvm/MC/MCDwarf.h index c0ecbcb2ad12b7ca65300714f2f8fcef8b8764a1..0c555d377d8b091bd8d5da9919f11fba5c3856b6 100644 --- a/include/llvm/MC/MCDwarf.h +++ b/include/llvm/MC/MCDwarf.h @@ -15,20 +15,18 @@ #ifndef LLVM_MC_MCDWARF_H #define LLVM_MC_MCDWARF_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCSection.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Dwarf.h" -#include "llvm/Support/raw_ostream.h" -#include #include #include #include namespace llvm { +template class ArrayRef; +class raw_ostream; class MCAsmBackend; class MCContext; class MCObjectStreamer; diff --git a/include/llvm/MC/MCELFObjectWriter.h b/include/llvm/MC/MCELFObjectWriter.h index 83726257ad2cdcd7e01fe2cfeff2ce9f111bfc7f..376e21821316d286de87eef2a77d6d4a1c0f8027 100644 --- a/include/llvm/MC/MCELFObjectWriter.h +++ b/include/llvm/MC/MCELFObjectWriter.h @@ -11,8 +11,10 @@ #define LLVM_MC_MCELFOBJECTWRITER_H #include "llvm/ADT/Triple.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ELF.h" +#include "llvm/Support/raw_ostream.h" #include namespace llvm { @@ -31,10 +33,21 @@ struct ELFRelocationEntry { const MCSymbolELF *Symbol; // The symbol to relocate with. unsigned Type; // The type of the relocation. uint64_t Addend; // The addend to use. + const MCSymbolELF *OriginalSymbol; // The original value of Symbol if we changed it. + uint64_t OriginalAddend; // The original value of addend. ELFRelocationEntry(uint64_t Offset, const MCSymbolELF *Symbol, unsigned Type, - uint64_t Addend) - : Offset(Offset), Symbol(Symbol), Type(Type), Addend(Addend) {} + uint64_t Addend, const MCSymbolELF *OriginalSymbol, + uint64_t OriginalAddend) + : Offset(Offset), Symbol(Symbol), Type(Type), Addend(Addend), + OriginalSymbol(OriginalSymbol), OriginalAddend(OriginalAddend) {} + + void print(raw_ostream &Out) const { + Out << "Off=" << Offset << ", Sym=" << Symbol << ", Type=" << Type + << ", Addend=" << Addend << ", OriginalSymbol=" << OriginalSymbol + << ", OriginalAddend=" << OriginalAddend; + } + void dump() const { print(errs()); } }; class MCELFObjectTargetWriter { diff --git a/include/llvm/MC/MCELFStreamer.h b/include/llvm/MC/MCELFStreamer.h index 6eb2c2c343ffe7c5fb4eed7ce4a32d0f064fab4b..b108f0df52b692a931ae05e3ff07eb5d73af1491 100644 --- a/include/llvm/MC/MCELFStreamer.h +++ b/include/llvm/MC/MCELFStreamer.h @@ -15,7 +15,6 @@ #include "llvm/MC/MCObjectStreamer.h" #include "llvm/MC/SectionKind.h" #include "llvm/Support/DataTypes.h" -#include namespace llvm { class MCAsmBackend; diff --git a/include/llvm/MC/MCExpr.h b/include/llvm/MC/MCExpr.h index d1ab855d1570e5d8ed384e532c6733c7c47eb296..b0e4736565b07f2dd3d3ea75561e9fe532496685 100644 --- a/include/llvm/MC/MCExpr.h +++ b/include/llvm/MC/MCExpr.h @@ -73,7 +73,8 @@ public: /// \name Utility Methods /// @{ - void print(raw_ostream &OS, const MCAsmInfo *MAI) const; + void print(raw_ostream &OS, const MCAsmInfo *MAI, + bool InParens = false) const; void dump() const; /// @} @@ -250,33 +251,6 @@ public: VK_PPC_TLSLD, // symbol@tlsld VK_PPC_LOCAL, // symbol@local - VK_Mips_GPREL, - VK_Mips_GOT_CALL, - VK_Mips_GOT16, - VK_Mips_GOT, - VK_Mips_ABS_HI, - VK_Mips_ABS_LO, - VK_Mips_TLSGD, - VK_Mips_TLSLDM, - VK_Mips_DTPREL_HI, - VK_Mips_DTPREL_LO, - VK_Mips_GOTTPREL, - VK_Mips_TPREL_HI, - VK_Mips_TPREL_LO, - VK_Mips_GPOFF_HI, - VK_Mips_GPOFF_LO, - VK_Mips_GOT_DISP, - VK_Mips_GOT_PAGE, - VK_Mips_GOT_OFST, - VK_Mips_HIGHER, - VK_Mips_HIGHEST, - VK_Mips_GOT_HI16, - VK_Mips_GOT_LO16, - VK_Mips_CALL_HI16, - VK_Mips_CALL_LO16, - VK_Mips_PCREL_HI16, - VK_Mips_PCREL_LO16, - VK_COFF_IMGREL32, // symbol@imgrel (image-relative) VK_Hexagon_PCREL, diff --git a/include/llvm/MC/MCInstPrinter.h b/include/llvm/MC/MCInstPrinter.h index 0eafd02c51c63c6052e22792d11e4615c1585a4f..2119c5a633b47c1cf2ef56359815155aeb1a5bc5 100644 --- a/include/llvm/MC/MCInstPrinter.h +++ b/include/llvm/MC/MCInstPrinter.h @@ -10,11 +10,11 @@ #ifndef LLVM_MC_MCINSTPRINTER_H #define LLVM_MC_MCINSTPRINTER_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Format.h" namespace llvm { +template class ArrayRef; class MCInst; class raw_ostream; class MCAsmInfo; diff --git a/include/llvm/MC/MCLinkerOptimizationHint.h b/include/llvm/MC/MCLinkerOptimizationHint.h index a519c4b71b033163b8d4ff500d1e177d0164e844..200bb93f64c8de7a0421f50079c9dca73621a94b 100644 --- a/include/llvm/MC/MCLinkerOptimizationHint.h +++ b/include/llvm/MC/MCLinkerOptimizationHint.h @@ -20,7 +20,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/MC/MCMachObjectWriter.h" #include "llvm/Support/raw_ostream.h" namespace llvm { @@ -28,6 +27,7 @@ namespace llvm { // Forward declarations. class MCAsmLayout; class MCSymbol; +class MachObjectWriter; /// Linker Optimization Hint Type. enum MCLOHType { @@ -123,31 +123,12 @@ public: /// Emit this directive as: /// - void emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const { - raw_ostream &OutStream = ObjWriter.getStream(); - emit_impl(OutStream, ObjWriter, Layout); - } + void emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const; /// Get the size in bytes of this directive if emitted in \p ObjWriter with /// the given \p Layout. uint64_t getEmitSize(const MachObjectWriter &ObjWriter, - const MCAsmLayout &Layout) const { - class raw_counting_ostream : public raw_ostream { - uint64_t Count; - - void write_impl(const char *, size_t size) override { Count += size; } - - uint64_t current_pos() const override { return Count; } - - public: - raw_counting_ostream() : Count(0) {} - ~raw_counting_ostream() override { flush(); } - }; - - raw_counting_ostream OutStream; - emit_impl(OutStream, ObjWriter, Layout); - return OutStream.tell(); - } + const MCAsmLayout &Layout) const; }; class MCLOHContainer { diff --git a/include/llvm/MC/MCMachObjectWriter.h b/include/llvm/MC/MCMachObjectWriter.h index cd3db957afc10055cc0ec8221f8c3d85d976983d..1a685dbd608eebf7a040c723865300d25d2f70aa 100644 --- a/include/llvm/MC/MCMachObjectWriter.h +++ b/include/llvm/MC/MCMachObjectWriter.h @@ -11,7 +11,6 @@ #define LLVM_MC_MCMACHOBJECTWRITER_H #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallString.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCObjectWriter.h" diff --git a/include/llvm/MC/MCObjectFileInfo.h b/include/llvm/MC/MCObjectFileInfo.h index d0e34e63ff8226e53fcc4349995cfb62c365e8af..cef4e5b3eb933de7008e05bd5eda552edf9bde35 100644 --- a/include/llvm/MC/MCObjectFileInfo.h +++ b/include/llvm/MC/MCObjectFileInfo.h @@ -185,6 +185,7 @@ protected: MCSection *SixteenByteConstantSection; MCSection *LazySymbolPointerSection; MCSection *NonLazySymbolPointerSection; + MCSection *ThreadLocalPointerSection; /// COFF specific sections. MCSection *DrectveSection; @@ -193,12 +194,8 @@ protected: MCSection *SXDataSection; public: - void InitMCObjectFileInfo(const Triple &TT, Reloc::Model RM, - CodeModel::Model CM, MCContext &ctx); - LLVM_ATTRIBUTE_DEPRECATED( - void InitMCObjectFileInfo(StringRef TT, Reloc::Model RM, - CodeModel::Model CM, MCContext &ctx), - "StringRef GNU Triple argument replaced by a llvm::Triple object"); + void InitMCObjectFileInfo(const Triple &TT, bool PIC, CodeModel::Model CM, + MCContext &ctx); bool getSupportsWeakOmittedEHFrame() const { return SupportsWeakOmittedEHFrame; @@ -333,6 +330,9 @@ public: MCSection *getNonLazySymbolPointerSection() const { return NonLazySymbolPointerSection; } + MCSection *getThreadLocalPointerSection() const { + return ThreadLocalPointerSection; + } // COFF specific sections. MCSection *getDrectveSection() const { return DrectveSection; } @@ -347,18 +347,18 @@ public: enum Environment { IsMachO, IsELF, IsCOFF }; Environment getObjectFileType() const { return Env; } - Reloc::Model getRelocM() const { return RelocM; } + bool isPositionIndependent() const { return PositionIndependent; } private: Environment Env; - Reloc::Model RelocM; + bool PositionIndependent; CodeModel::Model CMModel; MCContext *Ctx; Triple TT; - void initMachOMCObjectFileInfo(Triple T); - void initELFMCObjectFileInfo(Triple T); - void initCOFFMCObjectFileInfo(Triple T); + void initMachOMCObjectFileInfo(const Triple &T); + void initELFMCObjectFileInfo(const Triple &T); + void initCOFFMCObjectFileInfo(const Triple &T); public: const Triple &getTargetTriple() const { return TT; } diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h index 7123072a5e3a6dacc250a7fa20198f41b8a8fc09..d7775f27868cbdc5727d7a9e0d4735c72823d88c 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -140,7 +140,13 @@ public: void EmitGPRel64Value(const MCExpr *Value) override; bool EmitRelocDirective(const MCExpr &Offset, StringRef Name, const MCExpr *Expr, SMLoc Loc) override; - void EmitFill(uint64_t NumBytes, uint8_t FillValue) override; + using MCStreamer::emitFill; + void emitFill(uint64_t NumBytes, uint8_t FillValue) override; + void emitFill(const MCExpr &NumBytes, uint64_t FillValue, + SMLoc Loc = SMLoc()) override; + void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, + SMLoc Loc = SMLoc()) override; + void FinishImpl() override; /// Emit the absolute difference between two symbols if possible. diff --git a/include/llvm/MC/MCParser/AsmLexer.h b/include/llvm/MC/MCParser/AsmLexer.h index 1bb6d212784eec327ae9fb2de4d1510a6c67fbec..c779121b6cf0df630b3d7560296a3b765b8596c4 100644 --- a/include/llvm/MC/MCParser/AsmLexer.h +++ b/include/llvm/MC/MCParser/AsmLexer.h @@ -29,7 +29,8 @@ class AsmLexer : public MCAsmLexer { const char *CurPtr; StringRef CurBuf; - bool isAtStartOfLine; + bool IsAtStartOfLine; + bool IsAtStartOfStatement; void operator=(const AsmLexer&) = delete; AsmLexer(const AsmLexer&) = delete; @@ -45,17 +46,15 @@ public: void setBuffer(StringRef Buf, const char *ptr = nullptr); StringRef LexUntilEndOfStatement() override; - StringRef LexUntilEndOfLine(); size_t peekTokens(MutableArrayRef Buf, bool ShouldSkipSpace = true) override; - bool isAtStartOfComment(const char *Ptr); - bool isAtStatementSeparator(const char *Ptr); - const MCAsmInfo &getMAI() const { return MAI; } private: + bool isAtStartOfComment(const char *Ptr); + bool isAtStatementSeparator(const char *Ptr); int getNextChar(); AsmToken ReturnError(const char *Loc, const std::string &Msg); @@ -67,6 +66,8 @@ private: AsmToken LexQuote(); AsmToken LexFloatLiteral(); AsmToken LexHexFloatLiteral(bool NoIntDigits); + + StringRef LexUntilEndOfLine(); }; } // end namespace llvm diff --git a/include/llvm/MC/MCParser/MCAsmLexer.h b/include/llvm/MC/MCParser/MCAsmLexer.h index 55279f49529af91046f671d337227f69908e3a8f..3dd22c93d363718787a59ba3cb3bb0496cda2a6e 100644 --- a/include/llvm/MC/MCParser/MCAsmLexer.h +++ b/include/llvm/MC/MCParser/MCAsmLexer.h @@ -11,10 +11,13 @@ #define LLVM_MC_MCPARSER_MCASMLEXER_H #include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/SMLoc.h" +#include namespace llvm { @@ -36,12 +39,15 @@ public: // Real values. Real, + // Comments + Comment, + HashDirective, // No-value. EndOfStatement, Colon, Space, Plus, Minus, Tilde, - Slash, // '/' + Slash, // '/' BackSlash, // '\' LParen, RParen, LBrac, RBrac, LCurly, RCurly, Star, Dot, Comma, Dollar, Equal, EqualEqual, @@ -64,7 +70,7 @@ private: public: AsmToken() {} AsmToken(TokenKind Kind, StringRef Str, APInt IntVal) - : Kind(Kind), Str(Str), IntVal(IntVal) {} + : Kind(Kind), Str(Str), IntVal(std::move(IntVal)) {} AsmToken(TokenKind Kind, StringRef Str, int64_t IntVal = 0) : Kind(Kind), Str(Str), IntVal(64, IntVal, true) {} @@ -150,8 +156,12 @@ public: const AsmToken &Lex() { assert(!CurTok.empty()); CurTok.erase(CurTok.begin()); - if (CurTok.empty()) - CurTok.emplace_back(LexToken()); + // LexToken may generate multiple tokens via UnLex but will always return + // the first one. Place returned value at head of CurTok vector. + if (CurTok.empty()) { + AsmToken T = LexToken(); + CurTok.insert(CurTok.begin(), T); + } return CurTok.front(); } diff --git a/include/llvm/MC/MCSection.h b/include/llvm/MC/MCSection.h index 09a98929113abc5fd2beedfa917f3f695c98c6f0..a8d7af9bd6512849083e9256b155b1d0ed687fee 100644 --- a/include/llvm/MC/MCSection.h +++ b/include/llvm/MC/MCSection.h @@ -15,7 +15,6 @@ #define LLVM_MC_MCSECTION_H #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" #include "llvm/MC/MCFragment.h" diff --git a/include/llvm/MC/MCSectionCOFF.h b/include/llvm/MC/MCSectionCOFF.h index d94682c8c381d866ac6b48496bfca0208af69406..c9fd8ea1605de0392280b4eafa09b7a54908cc5c 100644 --- a/include/llvm/MC/MCSectionCOFF.h +++ b/include/llvm/MC/MCSectionCOFF.h @@ -32,6 +32,13 @@ class MCSectionCOFF final : public MCSection { /// below. mutable unsigned Characteristics; + /// The unique IDs used with the .pdata and .xdata sections created internally + /// by the assembler. This ID is used to ensure that for every .text section, + /// there is exactly one .pdata and one .xdata section, which is required by + /// the Microsoft incremental linker. This data is mutable because this ID is + /// not notionally part of the section. + mutable unsigned WinCFISectionID = ~0U; + /// The COMDAT symbol of this section. Only valid if this is a COMDAT section. /// Two COMDAT sections are merged if they have the same COMDAT symbol. MCSymbol *COMDATSymbol; @@ -71,6 +78,12 @@ public: bool UseCodeAlign() const override; bool isVirtualSection() const override; + unsigned getOrAssignWinCFISectionID(unsigned *NextID) const { + if (WinCFISectionID == ~0U) + WinCFISectionID = (*NextID)++; + return WinCFISectionID; + } + static bool classof(const MCSection *S) { return S->getVariant() == SV_COFF; } }; diff --git a/include/llvm/MC/MCSectionELF.h b/include/llvm/MC/MCSectionELF.h index b3bb3ad4e02c34da0ed3b609c2565cc1118e80af..dabd787b0d45f8e4041f6312b201edf718cdaf96 100644 --- a/include/llvm/MC/MCSectionELF.h +++ b/include/llvm/MC/MCSectionELF.h @@ -75,6 +75,7 @@ public: unsigned getType() const { return Type; } unsigned getFlags() const { return Flags; } unsigned getEntrySize() const { return EntrySize; } + void setFlags(unsigned F) { Flags = F; } const MCSymbolELF *getGroup() const { return Group; } void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS, diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index baaf20bdfa7916c3b180ea50c10031a5329f8274..cd710ee4342516fa997630d53dedd0a7934b73a0 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -183,6 +183,12 @@ class MCStreamer { /// PushSection. SmallVector, 4> SectionStack; + /// The next unique ID to use when creating a WinCFI-related section (.pdata + /// or .xdata). This ID ensures that we have a one-to-one mapping from + /// code section to unwind info section, which MSVC's incremental linker + /// requires. + unsigned NextWinCFIID = 0; + protected: MCStreamer(MCContext &Ctx); @@ -246,7 +252,7 @@ public: /// correctly? virtual bool isIntegratedAssemblerRequired() const { return false; } - /// \brief Add a textual command. + /// \brief Add a textual comment. /// /// Typically for comments that can be emitted to the generated .s /// file if applicable as a QoI issue to make the output of the compiler @@ -268,6 +274,12 @@ public: /// only prints comments, the object streamer ignores it instead of asserting. virtual void emitRawComment(const Twine &T, bool TabPrefix = true); + /// \brief Add explicit comment T. T is required to be a valid + /// comment in the output and does not need to be escaped. + virtual void addExplicitComment(const Twine &T); + /// \brief Emit added explicit comments. + virtual void emitExplicitComments(); + /// AddBlankLine - Emit a blank line to a .s file to pretty it up. virtual void AddBlankLine() {} @@ -517,6 +529,10 @@ public: /// etc. virtual void EmitBytes(StringRef Data); + /// Functionally identical to EmitBytes. When emitting textual assembly, this + /// method uses .byte directives instead of .ascii or .asciz for readability. + virtual void EmitBinaryData(StringRef Data); + /// \brief Emit the expression \p Value into the output as a native /// integer of the given \p Size bytes. /// @@ -569,7 +585,29 @@ public: /// \brief Emit NumBytes bytes worth of the value specified by FillValue. /// This implements directives such as '.space'. - virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue); + virtual void emitFill(uint64_t NumBytes, uint8_t FillValue); + + /// \brief Emit \p Size bytes worth of the value specified by \p FillValue. + /// + /// This is used to implement assembler directives such as .space or .skip. + /// + /// \param NumBytes - The number of bytes to emit. + /// \param FillValue - The value to use when filling bytes. + /// \param Loc - The location of the expression for error reporting. + virtual void emitFill(const MCExpr &NumBytes, uint64_t FillValue, + SMLoc Loc = SMLoc()); + + /// \brief Emit \p NumValues copies of \p Size bytes. Each \p Size bytes is + /// taken from the lowest order 4 bytes of \p Expr expression. + /// + /// This is used to implement assembler directives such as .fill. + /// + /// \param NumValues - The number of copies of \p Size bytes to emit. + /// \param Size - The size (in bytes) of each repeated value. + /// \param Expr - The expression from which \p Size bytes are used. + virtual void emitFill(uint64_t NumValues, int64_t Size, int64_t Expr); + virtual void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, + SMLoc Loc = SMLoc()); /// \brief Emit NumBytes worth of zeros. /// This function properly handles data in virtual sections. @@ -720,6 +758,14 @@ public: virtual void EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except); virtual void EmitWinEHHandlerData(); + /// Get the .pdata section used for the given section. Typically the given + /// section is either the main .text section or some other COMDAT .text + /// section, but it may be any section containing code. + MCSection *getAssociatedPDataSection(const MCSection *TextSec); + + /// Get the .xdata section used for the given section. + MCSection *getAssociatedXDataSection(const MCSection *TextSec); + virtual void EmitSyntaxDirective(); /// \brief Emit a .reloc directive. diff --git a/include/llvm/MC/MCSubtargetInfo.h b/include/llvm/MC/MCSubtargetInfo.h index 446feefc4500decbbdd113b27acfe94f824d8f5b..5ede043fa2eea77f382db2045aac008674d138bb 100644 --- a/include/llvm/MC/MCSubtargetInfo.h +++ b/include/llvm/MC/MCSubtargetInfo.h @@ -14,6 +14,7 @@ #ifndef LLVM_MC_MCSUBTARGETINFO_H #define LLVM_MC_MCSUBTARGETINFO_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/MC/MCInstrItineraries.h" #include "llvm/MC/SubtargetFeature.h" #include diff --git a/include/llvm/MC/MCSymbol.h b/include/llvm/MC/MCSymbol.h index c51ecfcb0c5c9c018552c97f1315260cc8d23063..23e34b7869a56e0ad08b1f98cf2614ee1eef09e0 100644 --- a/include/llvm/MC/MCSymbol.h +++ b/include/llvm/MC/MCSymbol.h @@ -17,7 +17,7 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringMap.h" -#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCFragment.h" #include "llvm/Support/Compiler.h" namespace llvm { @@ -87,7 +87,7 @@ protected: /// IsUsed - True if this symbol has been used. mutable unsigned IsUsed : 1; - mutable bool IsRegistered : 1; + mutable unsigned IsRegistered : 1; /// This symbol is visible outside this translation unit. mutable unsigned IsExternal : 1; diff --git a/include/llvm/MC/MCSymbolMachO.h b/include/llvm/MC/MCSymbolMachO.h index 260c516a04ae50ea1200901e247be549f4ba1f5f..25220e4a81090a18e75bddcb114fdbbb9a823867 100644 --- a/include/llvm/MC/MCSymbolMachO.h +++ b/include/llvm/MC/MCSymbolMachO.h @@ -9,6 +9,7 @@ #ifndef LLVM_MC_MCSYMBOLMACHO_H #define LLVM_MC_MCSYMBOLMACHO_H +#include "llvm/ADT/Twine.h" #include "llvm/MC/MCSymbol.h" namespace llvm { diff --git a/include/llvm/MC/MCTargetOptions.h b/include/llvm/MC/MCTargetOptions.h index 4b66a750cb7df6c12d1b866414eabb004191bff1..1d170b757cb3ac0e81821e6cb5219deaddc004db 100644 --- a/include/llvm/MC/MCTargetOptions.h +++ b/include/llvm/MC/MCTargetOptions.h @@ -36,6 +36,10 @@ public: bool ShowMCEncoding : 1; bool ShowMCInst : 1; bool AsmVerbose : 1; + + /// Preserve Comments in Assembly. + bool PreserveAsmComments : 1; + int DwarfVersion; /// getABIName - If this returns a non-empty string this represents the /// textual name of the ABI that we want the backend to use, e.g. o32, or diff --git a/include/llvm/MC/MCWin64EH.h b/include/llvm/MC/MCWin64EH.h index 0e81a191cd2c61f9549116693478510de1f8d542..83ea738de8c3d918a1416b5c9cf0697681413253 100644 --- a/include/llvm/MC/MCWin64EH.h +++ b/include/llvm/MC/MCWin64EH.h @@ -17,7 +17,6 @@ #include "llvm/MC/MCWinEH.h" #include "llvm/Support/Win64EH.h" -#include namespace llvm { class MCStreamer; diff --git a/include/llvm/MC/MCWinEH.h b/include/llvm/MC/MCWinEH.h index 723d7a397c496576d78a01034954724c16cdee76..4ca52a6654eb7f51ffd24ce82064d281d0935dc8 100644 --- a/include/llvm/MC/MCWinEH.h +++ b/include/llvm/MC/MCWinEH.h @@ -13,11 +13,9 @@ #include namespace llvm { -class MCContext; class MCSection; class MCStreamer; class MCSymbol; -class StringRef; namespace WinEH { struct Instruction { @@ -31,50 +29,35 @@ struct Instruction { }; struct FrameInfo { - const MCSymbol *Begin; - const MCSymbol *End; - const MCSymbol *ExceptionHandler; - const MCSymbol *Function; - const MCSymbol *PrologEnd; - const MCSymbol *Symbol; + const MCSymbol *Begin = nullptr; + const MCSymbol *End = nullptr; + const MCSymbol *ExceptionHandler = nullptr; + const MCSymbol *Function = nullptr; + const MCSymbol *PrologEnd = nullptr; + const MCSymbol *Symbol = nullptr; + const MCSection *TextSection = nullptr; - bool HandlesUnwind; - bool HandlesExceptions; + bool HandlesUnwind = false; + bool HandlesExceptions = false; - int LastFrameInst; - const FrameInfo *ChainedParent; + int LastFrameInst = -1; + const FrameInfo *ChainedParent = nullptr; std::vector Instructions; - FrameInfo() - : Begin(nullptr), End(nullptr), ExceptionHandler(nullptr), - Function(nullptr), PrologEnd(nullptr), Symbol(nullptr), - HandlesUnwind(false), HandlesExceptions(false), LastFrameInst(-1), - ChainedParent(nullptr), Instructions() {} + FrameInfo() = default; FrameInfo(const MCSymbol *Function, const MCSymbol *BeginFuncEHLabel) - : Begin(BeginFuncEHLabel), End(nullptr), ExceptionHandler(nullptr), - Function(Function), PrologEnd(nullptr), Symbol(nullptr), - HandlesUnwind(false), HandlesExceptions(false), LastFrameInst(-1), - ChainedParent(nullptr), Instructions() {} + : Begin(BeginFuncEHLabel), Function(Function) {} FrameInfo(const MCSymbol *Function, const MCSymbol *BeginFuncEHLabel, const FrameInfo *ChainedParent) - : Begin(BeginFuncEHLabel), End(nullptr), ExceptionHandler(nullptr), - Function(Function), PrologEnd(nullptr), Symbol(nullptr), - HandlesUnwind(false), HandlesExceptions(false), LastFrameInst(-1), - ChainedParent(ChainedParent), Instructions() {} + : Begin(BeginFuncEHLabel), Function(Function), + ChainedParent(ChainedParent) {} }; class UnwindEmitter { public: - static MCSection *getPDataSection(const MCSymbol *Function, - MCContext &Context); - static MCSection *getXDataSection(const MCSymbol *Function, - MCContext &Context); + virtual ~UnwindEmitter(); - virtual ~UnwindEmitter() { } - - // - // This emits the unwind info sections (.pdata and .xdata in PE/COFF). - // + /// This emits the unwind info sections (.pdata and .xdata in PE/COFF). virtual void Emit(MCStreamer &Streamer) const = 0; virtual void EmitUnwindInfo(MCStreamer &Streamer, FrameInfo *FI) const = 0; }; diff --git a/include/llvm/MC/StringTableBuilder.h b/include/llvm/MC/StringTableBuilder.h index 5a5e518f976df1d8f41701119ad3095259dd0eb9..f2b8ecd2d99786d11acd50d3c01643f6c34d5b7f 100644 --- a/include/llvm/MC/StringTableBuilder.h +++ b/include/llvm/MC/StringTableBuilder.h @@ -23,7 +23,7 @@ public: private: SmallString<256> StringTable; - DenseMap StringIndexMap; + DenseMap, size_t> StringIndexMap; size_t Size = 0; Kind K; unsigned Alignment; @@ -57,7 +57,10 @@ public: /// after the table is finalized. size_t getOffset(StringRef S) const; - const DenseMap &getMap() const { return StringIndexMap; } + const DenseMap, size_t> &getMap() const { + return StringIndexMap; + } + size_t getSize() const { return Size; } void clear(); diff --git a/include/llvm/MC/SubtargetFeature.h b/include/llvm/MC/SubtargetFeature.h index 75d1e7997119d67e7c83a60dfc65815e2609d7d2..ed4abd772821f58944929f89ac10b1f93987a4f8 100644 --- a/include/llvm/MC/SubtargetFeature.h +++ b/include/llvm/MC/SubtargetFeature.h @@ -18,12 +18,13 @@ #ifndef LLVM_MC_SUBTARGETFEATURE_H #define LLVM_MC_SUBTARGETFEATURE_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/DataTypes.h" #include +#include namespace llvm { +template class ArrayRef; class raw_ostream; class StringRef; diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index 936413eb74b0d87f615b2fa3a96143c7257fb1aa..cfba2567371ac20ead23ac3ad09fab6951d7b875 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -14,6 +14,7 @@ #ifndef LLVM_OBJECT_ARCHIVE_H #define LLVM_OBJECT_ARCHIVE_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Object/Binary.h" @@ -78,6 +79,7 @@ public: ErrorOr getNext() const; ErrorOr getName() const; + ErrorOr getFullName() const; StringRef getRawName() const { return getHeader()->getName(); } sys::TimeValue getLastModified() const { return getHeader()->getLastModified(); @@ -100,26 +102,25 @@ public: ErrorOr getMemoryBufferRef() const; - ErrorOr> + Expected> getAsBinary(LLVMContext *Context = nullptr) const; }; class child_iterator { - ErrorOr child; + Child C; + Error *E; public: - child_iterator() : child(Child(nullptr, nullptr, nullptr)) {} - child_iterator(const Child &c) : child(c) {} - child_iterator(std::error_code EC) : child(EC) {} - const ErrorOr *operator->() const { return &child; } - const ErrorOr &operator*() const { return child; } + child_iterator() : C(Child(nullptr, nullptr, nullptr)), E(nullptr) {} + child_iterator(const Child &C, Error *E) : C(C), E(E) {} + const Child *operator->() const { return &C; } + const Child &operator*() const { return C; } bool operator==(const child_iterator &other) const { - // We ignore error states so that comparisions with end() work, which - // allows range loops. - if (child.getError() || other.child.getError()) - return false; - return *child == *other.child; + // Ignore errors here: If an error occurred during increment then getNext + // will have been set to child_end(), and the following comparison should + // do the right thing. + return C == other.C; } bool operator!=(const child_iterator &other) const { @@ -129,8 +130,15 @@ public: // Code in loops with child_iterators must check for errors on each loop // iteration. And if there is an error break out of the loop. child_iterator &operator++() { // Preincrement - assert(child && "Can't increment iterator with error"); - child = child->getNext(); + assert(E && "Can't increment iterator with no Error attached"); + if (auto ChildOrErr = C.getNext()) + C = *ChildOrErr; + else { + ErrorAsOutParameter ErrAsOutParam(*E); + C = C.getParent()->child_end().C; + *E = errorCodeToError(ChildOrErr.getError()); + E = nullptr; + } return *this; } }; @@ -175,23 +183,25 @@ public: } }; - Archive(MemoryBufferRef Source, std::error_code &EC); - static ErrorOr> create(MemoryBufferRef Source); + Archive(MemoryBufferRef Source, Error &Err); + static Expected> create(MemoryBufferRef Source); enum Kind { K_GNU, K_MIPS64, K_BSD, + K_DARWIN64, K_COFF }; Kind kind() const { return (Kind)Format; } bool isThin() const { return IsThin; } - child_iterator child_begin(bool SkipInternal = true) const; + child_iterator child_begin(Error &Err, bool SkipInternal = true) const; child_iterator child_end() const; - iterator_range children(bool SkipInternal = true) const { - return make_range(child_begin(SkipInternal), child_end()); + iterator_range children(Error &Err, + bool SkipInternal = true) const { + return make_range(child_begin(Err, SkipInternal), child_end()); } symbol_iterator symbol_begin() const; @@ -206,12 +216,16 @@ public: } // check if a symbol is in the archive - child_iterator findSym(StringRef name) const; + Expected> findSym(StringRef name) const; bool hasSymbolTable() const; StringRef getSymbolTable() const { return SymbolTable; } uint32_t getNumberOfSymbols() const; + std::vector> takeThinBuffers() { + return std::move(ThinBuffers); + } + private: StringRef SymbolTable; StringRef StringTable; @@ -220,7 +234,7 @@ private: uint16_t FirstRegularStartOfFile = -1; void setFirstRegular(const Child &C); - unsigned Format : 2; + unsigned Format : 3; unsigned IsThin : 1; mutable std::vector> ThinBuffers; }; diff --git a/include/llvm/Object/ArchiveWriter.h b/include/llvm/Object/ArchiveWriter.h index b5d2ba3580809a3c6b5b816006105407659f8a7d..55b58fac4f66ba07abad0c05cd9331ce64d40846 100644 --- a/include/llvm/Object/ArchiveWriter.h +++ b/include/llvm/Object/ArchiveWriter.h @@ -20,29 +20,36 @@ namespace llvm { -class NewArchiveIterator { - bool IsNewMember; - StringRef Name; - - object::Archive::Child OldMember; - -public: - NewArchiveIterator(const object::Archive::Child &OldMember, StringRef Name); - NewArchiveIterator(StringRef FileName); - bool isNewMember() const; - StringRef getName() const; - - const object::Archive::Child &getOld() const; - - StringRef getNew() const; - llvm::ErrorOr getFD(sys::fs::file_status &NewStatus) const; - const sys::fs::file_status &getStatus() const; +struct NewArchiveMember { + std::unique_ptr Buf; + sys::TimeValue ModTime = sys::TimeValue::PosixZeroTime(); + unsigned UID = 0, GID = 0, Perms = 0644; + + NewArchiveMember() = default; + NewArchiveMember(NewArchiveMember &&Other) + : Buf(std::move(Other.Buf)), ModTime(Other.ModTime), UID(Other.UID), + GID(Other.GID), Perms(Other.Perms) {} + NewArchiveMember &operator=(NewArchiveMember &&Other) { + Buf = std::move(Other.Buf); + ModTime = Other.ModTime; + UID = Other.UID; + GID = Other.GID; + Perms = Other.Perms; + return *this; + } + NewArchiveMember(MemoryBufferRef BufRef); + + static Expected + getOldMember(const object::Archive::Child &OldMember, bool Deterministic); + + static Expected getFile(StringRef FileName, + bool Deterministic); }; std::pair -writeArchive(StringRef ArcName, std::vector &NewMembers, +writeArchive(StringRef ArcName, std::vector &NewMembers, bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, - bool Thin); + bool Thin, std::unique_ptr OldArchiveBuf = nullptr); } #endif diff --git a/include/llvm/Object/Binary.h b/include/llvm/Object/Binary.h index bd6709f08073a441adb246f62a222590458d39e1..5dff5406fcddc8cc9de7a011b03b767c52be18a7 100644 --- a/include/llvm/Object/Binary.h +++ b/include/llvm/Object/Binary.h @@ -134,8 +134,8 @@ public: /// @brief Create a Binary from Source, autodetecting the file type. /// /// @param Source The data to create the Binary from. -ErrorOr> createBinary(MemoryBufferRef Source, - LLVMContext *Context = nullptr); +Expected> createBinary(MemoryBufferRef Source, + LLVMContext *Context = nullptr); template class OwningBinary { std::unique_ptr Bin; @@ -185,7 +185,7 @@ template const T* OwningBinary::getBinary() const { return Bin.get(); } -ErrorOr> createBinary(StringRef Path); +Expected> createBinary(StringRef Path); } } diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index 5ae58051b785d8bfb932f66b452a377f6a92ef04..dcc58b06e228d0101ee18c3247d9aa954323ef9f 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -169,6 +169,26 @@ struct import_directory_table_entry { support::ulittle32_t ImportAddressTableRVA; }; +struct debug_directory { + support::ulittle32_t Characteristics; + support::ulittle32_t TimeDateStamp; + support::ulittle16_t MajorVersion; + support::ulittle16_t MinorVersion; + support::ulittle32_t Type; + support::ulittle32_t SizeOfData; + support::ulittle32_t AddressOfRawData; + support::ulittle32_t PointerToRawData; +}; + +/// Information that is resent in debug_directory::AddressOfRawData if Type is +/// IMAGE_DEBUG_TYPE_CODEVIEW. +struct debug_pdb_info { + support::ulittle32_t Signature; + uint8_t Guid[16]; + support::ulittle32_t Age; + // PDBFileName: The null-terminated PDB file name follows. +}; + template struct import_lookup_table_entry { IntTy Data; @@ -439,20 +459,32 @@ struct coff_aux_function_definition { support::ulittle32_t TotalSize; support::ulittle32_t PointerToLinenumber; support::ulittle32_t PointerToNextFunction; + char Unused1[2]; }; +static_assert(sizeof(coff_aux_function_definition) == 18, + "auxiliary entry must be 18 bytes"); + struct coff_aux_bf_and_ef_symbol { char Unused1[4]; support::ulittle16_t Linenumber; char Unused2[6]; support::ulittle32_t PointerToNextFunction; + char Unused3[2]; }; +static_assert(sizeof(coff_aux_bf_and_ef_symbol) == 18, + "auxiliary entry must be 18 bytes"); + struct coff_aux_weak_external { support::ulittle32_t TagIndex; support::ulittle32_t Characteristics; + char Unused1[10]; }; +static_assert(sizeof(coff_aux_weak_external) == 18, + "auxiliary entry must be 18 bytes"); + struct coff_aux_section_definition { support::ulittle32_t Length; support::ulittle16_t NumberOfRelocations; @@ -470,12 +502,19 @@ struct coff_aux_section_definition { } }; +static_assert(sizeof(coff_aux_section_definition) == 18, + "auxiliary entry must be 18 bytes"); + struct coff_aux_clr_token { uint8_t AuxType; uint8_t Reserved; support::ulittle32_t SymbolTableIndex; + char MBZ[12]; }; +static_assert(sizeof(coff_aux_clr_token) == 18, + "auxiliary entry must be 18 bytes"); + struct coff_import_header { support::ulittle16_t Sig1; support::ulittle16_t Sig2; @@ -595,12 +634,13 @@ private: const char *StringTable; uint32_t StringTableSize; const import_directory_table_entry *ImportDirectory; - uint32_t NumberOfImportDirectory; const delay_import_directory_table_entry *DelayImportDirectory; uint32_t NumberOfDelayImportDirectory; const export_directory_table_entry *ExportDirectory; const coff_base_reloc_block_header *BaseRelocHeader; const coff_base_reloc_block_header *BaseRelocEnd; + const debug_directory *DebugDirectoryBegin; + const debug_directory *DebugDirectoryEnd; std::error_code getString(uint32_t offset, StringRef &Res) const; @@ -614,6 +654,7 @@ private: std::error_code initDelayImportTablePtr(); std::error_code initExportTablePtr(); std::error_code initBaseRelocPtr(); + std::error_code initDebugDirectoryPtr(); public: uintptr_t getSymbolTable() const { @@ -679,13 +720,13 @@ public: } protected: void moveSymbolNext(DataRefImpl &Symb) const override; - ErrorOr getSymbolName(DataRefImpl Symb) const override; - ErrorOr getSymbolAddress(DataRefImpl Symb) const override; + Expected getSymbolName(DataRefImpl Symb) const override; + Expected getSymbolAddress(DataRefImpl Symb) const override; uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; - ErrorOr getSymbolType(DataRefImpl Symb) const override; - ErrorOr getSymbolSection(DataRefImpl Symb) const override; + Expected getSymbolType(DataRefImpl Symb) const override; + Expected getSymbolSection(DataRefImpl Symb) const override; void moveSectionNext(DataRefImpl &Sec) const override; std::error_code getSectionName(DataRefImpl Sec, StringRef &Res) const override; @@ -694,6 +735,7 @@ protected: std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; bool isSectionBSS(DataRefImpl Sec) const override; @@ -725,6 +767,7 @@ public: uint8_t getBytesInAddress() const override; StringRef getFileFormatName() const override; unsigned getArch() const override; + SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } import_directory_iterator import_directory_begin() const; import_directory_iterator import_directory_end() const; @@ -734,12 +777,21 @@ public: export_directory_iterator export_directory_end() const; base_reloc_iterator base_reloc_begin() const; base_reloc_iterator base_reloc_end() const; + const debug_directory *debug_directory_begin() const { + return DebugDirectoryBegin; + } + const debug_directory *debug_directory_end() const { + return DebugDirectoryEnd; + } iterator_range import_directories() const; iterator_range delay_import_directories() const; iterator_range export_directories() const; iterator_range base_relocs() const; + iterator_range debug_directories() const { + return make_range(debug_directory_begin(), debug_directory_end()); + } const dos_header *getDOSHeader() const { if (!PE32Header && !PE32PlusHeader) @@ -808,9 +860,28 @@ public: uint64_t getImageBase() const; std::error_code getVaPtr(uint64_t VA, uintptr_t &Res) const; std::error_code getRvaPtr(uint32_t Rva, uintptr_t &Res) const; + + /// Given an RVA base and size, returns a valid array of bytes or an error + /// code if the RVA and size is not contained completely within a valid + /// section. + std::error_code getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size, + ArrayRef &Contents) const; + std::error_code getHintName(uint32_t Rva, uint16_t &Hint, StringRef &Name) const; + /// Get PDB information out of a codeview debug directory entry. + std::error_code getDebugPDBInfo(const debug_directory *DebugDir, + const debug_pdb_info *&Info, + StringRef &PDBFileName) const; + + /// Get PDB information from an executable. If the information is not present, + /// Info will be set to nullptr and PDBFileName will be empty. An error is + /// returned only on corrupt object files. Convenience accessor that can be + /// used if the debug directory is not already handy. + std::error_code getDebugPDBInfo(const debug_pdb_info *&Info, + StringRef &PDBFileName) const; + bool isRelocatableObject() const override; bool is64() const { return PE32PlusHeader; } @@ -839,9 +910,6 @@ public: std::error_code getImportTableEntry(const import_directory_table_entry *&Result) const; - std::error_code - getImportLookupEntry(const import_lookup_table_entry32 *&Result) const; - private: const import_directory_table_entry *ImportTable; uint32_t Index; @@ -913,7 +981,9 @@ public: void moveNext(); std::error_code getSymbolName(StringRef &Result) const; + std::error_code isOrdinal(bool &Result) const; std::error_code getOrdinal(uint16_t &Result) const; + std::error_code getHintNameRVA(uint32_t &Result) const; private: const import_lookup_table_entry32 *Entry32; @@ -941,6 +1011,30 @@ private: const COFFObjectFile *OwningObject; }; +// Corresponds to `_FPO_DATA` structure in the PE/COFF spec. +struct FpoData { + support::ulittle32_t Offset; // ulOffStart: Offset 1st byte of function code + support::ulittle32_t Size; // cbProcSize: # bytes in function + support::ulittle32_t NumLocals; // cdwLocals: # bytes in locals/4 + support::ulittle16_t NumParams; // cdwParams: # bytes in params/4 + support::ulittle16_t Attributes; + + // cbProlog: # bytes in prolog + int getPrologSize() const { return Attributes & 0xF; } + + // cbRegs: # regs saved + int getNumSavedRegs() const { return (Attributes >> 8) & 0x7; } + + // fHasSEH: true if seh is func + bool hasSEH() const { return (Attributes >> 9) & 1; } + + // fUseBP: true if EBP has been allocated + bool useBP() const { return (Attributes >> 10) & 1; } + + // cbFrame: frame pointer + int getFP() const { return Attributes >> 14; } +}; + } // end namespace object } // end namespace llvm diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index 6a100a55152ad72d75b88d5a88a03a1631f054ed..80b8be03810cc89db283e290238a382c3b6a799d 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -54,9 +54,12 @@ public: typedef Elf_Versym_Impl Elf_Versym; typedef Elf_Hash_Impl Elf_Hash; typedef Elf_GnuHash_Impl Elf_GnuHash; - typedef iterator_range Elf_Dyn_Range; - typedef iterator_range Elf_Shdr_Range; - typedef iterator_range Elf_Sym_Range; + typedef typename ELFT::DynRange Elf_Dyn_Range; + typedef typename ELFT::ShdrRange Elf_Shdr_Range; + typedef typename ELFT::SymRange Elf_Sym_Range; + typedef typename ELFT::RelRange Elf_Rel_Range; + typedef typename ELFT::RelaRange Elf_Rela_Range; + typedef typename ELFT::PhdrRange Elf_Phdr_Range; const uint8_t *base() const { return reinterpret_cast(Buf.data()); @@ -109,7 +112,7 @@ public: const Elf_Shdr *section_begin() const; const Elf_Shdr *section_end() const; Elf_Shdr_Range sections() const { - return make_range(section_begin(), section_end()); + return makeArrayRef(section_begin(), section_end()); } const Elf_Sym *symbol_begin(const Elf_Shdr *Sec) const { @@ -128,11 +131,9 @@ public: return symbol_begin(Sec) + Size / sizeof(Elf_Sym); } Elf_Sym_Range symbols(const Elf_Shdr *Sec) const { - return make_range(symbol_begin(Sec), symbol_end(Sec)); + return makeArrayRef(symbol_begin(Sec), symbol_end(Sec)); } - typedef iterator_range Elf_Rela_Range; - const Elf_Rela *rela_begin(const Elf_Shdr *sec) const { if (sec->sh_entsize != sizeof(Elf_Rela)) report_fatal_error("Invalid relocation entry size"); @@ -147,7 +148,7 @@ public: } Elf_Rela_Range relas(const Elf_Shdr *Sec) const { - return make_range(rela_begin(Sec), rela_end(Sec)); + return makeArrayRef(rela_begin(Sec), rela_end(Sec)); } const Elf_Rel *rel_begin(const Elf_Shdr *sec) const { @@ -163,9 +164,8 @@ public: return rel_begin(sec) + Size / sizeof(Elf_Rel); } - typedef iterator_range Elf_Rel_Range; Elf_Rel_Range rels(const Elf_Shdr *Sec) const { - return make_range(rel_begin(Sec), rel_end(Sec)); + return makeArrayRef(rel_begin(Sec), rel_end(Sec)); } /// \brief Iterate over program header table. @@ -179,10 +179,8 @@ public: return program_header_begin() + Header->e_phnum; } - typedef iterator_range Elf_Phdr_Range; - const Elf_Phdr_Range program_headers() const { - return make_range(program_header_begin(), program_header_end()); + return makeArrayRef(program_header_begin(), program_header_end()); } uint64_t getNumSections() const; diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h index 5acb4ae3f4e481c04fbec5fd6d76216a9ec3ca13..6dcd2d486813a1ac3159a8371360cd2fc5ef5145 100644 --- a/include/llvm/Object/ELFObjectFile.h +++ b/include/llvm/Object/ELFObjectFile.h @@ -14,23 +14,28 @@ #ifndef LLVM_OBJECT_ELFOBJECTFILE_H #define LLVM_OBJECT_ELFOBJECTFILE_H -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Object/Binary.h" #include "llvm/Object/ELF.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include +#include +#include +#include namespace llvm { namespace object { @@ -47,6 +52,7 @@ class ELFObjectFileBase : public ObjectFile { protected: ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source); + virtual uint16_t getEMachine() const = 0; virtual uint64_t getSymbolSize(DataRefImpl Symb) const = 0; virtual uint8_t getSymbolOther(DataRefImpl Symb) const = 0; virtual uint8_t getSymbolELFType(DataRefImpl Symb) const = 0; @@ -55,14 +61,16 @@ protected: virtual uint64_t getSectionFlags(DataRefImpl Sec) const = 0; virtual ErrorOr getRelocationAddend(DataRefImpl Rel) const = 0; -public: +public: typedef iterator_range elf_symbol_iterator_range; virtual elf_symbol_iterator_range getDynamicSymbolIterators() const = 0; elf_symbol_iterator_range symbols() const; static inline bool classof(const Binary *v) { return v->isELF(); } + + SubtargetFeatures getFeatures() const override; }; class ELFSectionRef : public SectionRef { @@ -175,6 +183,7 @@ ELFObjectFileBase::symbols() const { } template class ELFObjectFile : public ELFObjectFileBase { + uint16_t getEMachine() const override; uint64_t getSymbolSize(DataRefImpl Sym) const override; public: @@ -197,18 +206,18 @@ protected: ArrayRef ShndxTable; void moveSymbolNext(DataRefImpl &Symb) const override; - ErrorOr getSymbolName(DataRefImpl Symb) const override; - ErrorOr getSymbolAddress(DataRefImpl Symb) const override; + Expected getSymbolName(DataRefImpl Symb) const override; + Expected getSymbolAddress(DataRefImpl Symb) const override; uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; uint32_t getSymbolAlignment(DataRefImpl Symb) const override; uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; uint8_t getSymbolOther(DataRefImpl Symb) const override; uint8_t getSymbolELFType(DataRefImpl Symb) const override; - ErrorOr getSymbolType(DataRefImpl Symb) const override; - ErrorOr getSymbolSection(const Elf_Sym *Symb, - const Elf_Shdr *SymTab) const; - ErrorOr getSymbolSection(DataRefImpl Symb) const override; + Expected getSymbolType(DataRefImpl Symb) const override; + Expected getSymbolSection(const Elf_Sym *Symb, + const Elf_Shdr *SymTab) const; + Expected getSymbolSection(DataRefImpl Symb) const override; void moveSectionNext(DataRefImpl &Sec) const override; std::error_code getSectionName(DataRefImpl Sec, @@ -218,6 +227,7 @@ protected: std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; bool isSectionBSS(DataRefImpl Sec) const override; @@ -284,11 +294,9 @@ protected: // A symbol is exported if its binding is either GLOBAL or WEAK, and its // visibility is either DEFAULT or PROTECTED. All other symbols are not // exported. - if ((Binding == ELF::STB_GLOBAL || Binding == ELF::STB_WEAK) && - (Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_PROTECTED)) - return true; - - return false; + return ((Binding == ELF::STB_GLOBAL || Binding == ELF::STB_WEAK) && + (Visibility == ELF::STV_DEFAULT || + Visibility == ELF::STV_PROTECTED)); } // This flag is used for classof, to distinguish ELFObjectFile from @@ -354,7 +362,7 @@ void ELFObjectFile::moveSymbolNext(DataRefImpl &Sym) const { } template -ErrorOr ELFObjectFile::getSymbolName(DataRefImpl Sym) const { +Expected ELFObjectFile::getSymbolName(DataRefImpl Sym) const { const Elf_Sym *ESym = getSymbol(Sym); const Elf_Shdr *SymTableSec = *EF.getSection(Sym.d.a); const Elf_Shdr *StringTableSec = *EF.getSection(SymTableSec->sh_link); @@ -389,7 +397,7 @@ uint64_t ELFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { } template -ErrorOr +Expected ELFObjectFile::getSymbolAddress(DataRefImpl Symb) const { uint64_t Result = getSymbolValue(Symb); const Elf_Sym *ESym = getSymbol(Symb); @@ -407,7 +415,7 @@ ELFObjectFile::getSymbolAddress(DataRefImpl Symb) const { ErrorOr SectionOrErr = EF.getSection(ESym, SymTab, ShndxTable); if (std::error_code EC = SectionOrErr.getError()) - return EC; + return errorCodeToError(EC); const Elf_Shdr *Section = *SectionOrErr; if (Section) Result += Section->sh_addr; @@ -424,6 +432,11 @@ uint32_t ELFObjectFile::getSymbolAlignment(DataRefImpl Symb) const { return 0; } +template +uint16_t ELFObjectFile::getEMachine() const { + return EF.getHeader()->e_machine; +} + template uint64_t ELFObjectFile::getSymbolSize(DataRefImpl Sym) const { return getSymbol(Sym)->st_size; @@ -445,7 +458,7 @@ uint8_t ELFObjectFile::getSymbolELFType(DataRefImpl Symb) const { } template -ErrorOr +Expected ELFObjectFile::getSymbolType(DataRefImpl Symb) const { const Elf_Sym *ESym = getSymbol(Symb); @@ -488,12 +501,17 @@ uint32_t ELFObjectFile::getSymbolFlags(DataRefImpl Sym) const { Result |= SymbolRef::SF_FormatSpecific; if (EF.getHeader()->e_machine == ELF::EM_ARM) { - if (ErrorOr NameOrErr = getSymbolName(Sym)) { + if (Expected NameOrErr = getSymbolName(Sym)) { StringRef Name = *NameOrErr; if (Name.startswith("$d") || Name.startswith("$t") || Name.startswith("$a")) Result |= SymbolRef::SF_FormatSpecific; + } else { + // TODO: Actually report errors helpfully. + consumeError(NameOrErr.takeError()); } + if (ESym->getType() == ELF::STT_FUNC && (ESym->st_value & 1) == 1) + Result |= SymbolRef::SF_Thumb; } if (ESym->st_shndx == ELF::SHN_UNDEF) @@ -512,12 +530,12 @@ uint32_t ELFObjectFile::getSymbolFlags(DataRefImpl Sym) const { } template -ErrorOr +Expected ELFObjectFile::getSymbolSection(const Elf_Sym *ESym, const Elf_Shdr *SymTab) const { ErrorOr ESecOrErr = EF.getSection(ESym, SymTab, ShndxTable); if (std::error_code EC = ESecOrErr.getError()) - return EC; + return errorCodeToError(EC); const Elf_Shdr *ESec = *ESecOrErr; if (!ESec) @@ -529,7 +547,7 @@ ELFObjectFile::getSymbolSection(const Elf_Sym *ESym, } template -ErrorOr +Expected ELFObjectFile::getSymbolSection(DataRefImpl Symb) const { const Elf_Sym *Sym = getSymbol(Symb); const Elf_Shdr *SymTab = *EF.getSection(Symb.d.a); @@ -576,6 +594,11 @@ uint64_t ELFObjectFile::getSectionAlignment(DataRefImpl Sec) const { return getSection(Sec)->sh_addralign; } +template +bool ELFObjectFile::isSectionCompressed(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags & ELF::SHF_COMPRESSED; +} + template bool ELFObjectFile::isSectionText(DataRefImpl Sec) const { return getSection(Sec)->sh_flags & ELF::SHF_EXECINSTR; @@ -940,7 +963,7 @@ template bool ELFObjectFile::isRelocatableObject() const { return EF.getHeader()->e_type == ELF::ET_REL; } -} -} +} // end namespace object +} // end namespace llvm -#endif +#endif // LLVM_OBJECT_ELFOBJECTFILE_H diff --git a/include/llvm/Object/ELFTypes.h b/include/llvm/Object/ELFTypes.h index d5a9c00598fe9f9fd7247b3ffa547b5f5c6d8f7d..55028f360dbf3c052b79a58b062eedae2f800c0c 100644 --- a/include/llvm/Object/ELFTypes.h +++ b/include/llvm/Object/ELFTypes.h @@ -34,6 +34,7 @@ template struct Elf_Vernaux_Impl; template struct Elf_Versym_Impl; template struct Elf_Hash_Impl; template struct Elf_GnuHash_Impl; +template struct Elf_Chdr_Impl; template struct ELFType { private: @@ -59,9 +60,13 @@ public: typedef Elf_Versym_Impl> Versym; typedef Elf_Hash_Impl> Hash; typedef Elf_GnuHash_Impl> GnuHash; - typedef iterator_range DynRange; - typedef iterator_range ShdrRange; - typedef iterator_range SymRange; + typedef Elf_Chdr_Impl> Chdr; + typedef ArrayRef DynRange; + typedef ArrayRef ShdrRange; + typedef ArrayRef SymRange; + typedef ArrayRef RelRange; + typedef ArrayRef RelaRange; + typedef ArrayRef PhdrRange; typedef packed Half; typedef packed Word; @@ -254,14 +259,14 @@ struct Elf_Sym_Impl : Elf_Sym_Base { return getBinding() != ELF::STB_LOCAL; } - ErrorOr getName(StringRef StrTab) const; + Expected getName(StringRef StrTab) const; }; template -ErrorOr Elf_Sym_Impl::getName(StringRef StrTab) const { +Expected Elf_Sym_Impl::getName(StringRef StrTab) const { uint32_t Offset = this->st_name; if (Offset >= StrTab.size()) - return object_error::parse_failed; + return errorCodeToError(object_error::parse_failed); return StringRef(StrTab.data() + Offset); } @@ -555,6 +560,25 @@ struct Elf_GnuHash_Impl { } }; +// Compressed section headers. +// http://www.sco.com/developers/gabi/latest/ch4.sheader.html#compression_header +template +struct Elf_Chdr_Impl> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + Elf_Word ch_type; + Elf_Word ch_size; + Elf_Word ch_addralign; +}; + +template +struct Elf_Chdr_Impl> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + Elf_Word ch_type; + Elf_Word ch_reserved; + Elf_Xword ch_size; + Elf_Xword ch_addralign; +}; + // MIPS .reginfo section template struct Elf_Mips_RegInfo; diff --git a/include/llvm/Object/Error.h b/include/llvm/Object/Error.h index d29c2dc2559017acf62960d3a84142ef119a87e9..cd55e5dc26d7b2415833572ca3a8df33854983d6 100644 --- a/include/llvm/Object/Error.h +++ b/include/llvm/Object/Error.h @@ -34,9 +34,6 @@ enum class object_error { string_table_non_null_end, invalid_section_index, bitcode_section_not_found, - macho_small_load_command, - macho_load_segment_too_many_sections, - macho_load_segment_too_small, }; inline std::error_code make_error_code(object_error e) { @@ -67,16 +64,21 @@ public: class GenericBinaryError : public ErrorInfo { public: static char ID; - GenericBinaryError(std::string FileName, Twine Msg); - GenericBinaryError(std::string FileName, Twine Msg, object_error ECOverride); - const std::string &getFileName() const { return FileName; } + GenericBinaryError(Twine Msg); + GenericBinaryError(Twine Msg, object_error ECOverride); const std::string &getMessage() const { return Msg; } void log(raw_ostream &OS) const override; private: - std::string FileName; std::string Msg; }; +/// isNotObjectErrorInvalidFileType() is used when looping through the children +/// of an archive after calling getAsBinary() on the child and it returns an +/// llvm::Error. In the cases we want to loop through the children and ignore the +/// non-objects in the archive this is used to test the error to see if an +/// error() function needs to called on the llvm::Error. +Error isNotObjectErrorInvalidFileType(llvm::Error Err); + } // end namespace object. } // end namespace llvm. diff --git a/include/llvm/Object/IRObjectFile.h b/include/llvm/Object/IRObjectFile.h index ef655287c34c6aa9d7fb735538a3224e2d60e5bf..9fe011e17d627d2b0a46feb3987d269eb5dee6d7 100644 --- a/include/llvm/Object/IRObjectFile.h +++ b/include/llvm/Object/IRObjectFile.h @@ -20,6 +20,7 @@ namespace llvm { class Mangler; class Module; class GlobalValue; +class Triple; namespace object { class ObjectFile; @@ -59,6 +60,15 @@ public: /// error code if not found. static ErrorOr findBitcodeInObject(const ObjectFile &Obj); + /// Parse inline ASM and collect the symbols that are not defined in + /// the current module. + /// + /// For each found symbol, call \p AsmUndefinedRefs with the name of the + /// symbol found and the associated flags. + static void CollectAsmUndefinedRefs( + const Triple &TheTriple, StringRef InlineAsm, + function_ref AsmUndefinedRefs); + /// \brief Finds and returns bitcode in the given memory buffer (which may /// be either a bitcode file or a native object file with embedded bitcode), /// or an error code if not found. diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index 24c0ffe56c022d44691b21bf5ee4638abe8f3865..7906db1e8a77df2244836fceec40967d8c4ff1c9 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -199,18 +199,18 @@ public: void moveSymbolNext(DataRefImpl &Symb) const override; uint64_t getNValue(DataRefImpl Sym) const; - ErrorOr getSymbolName(DataRefImpl Symb) const override; + Expected getSymbolName(DataRefImpl Symb) const override; // MachO specific. std::error_code getIndirectName(DataRefImpl Symb, StringRef &Res) const; unsigned getSectionType(SectionRef Sec) const; - ErrorOr getSymbolAddress(DataRefImpl Symb) const override; + Expected getSymbolAddress(DataRefImpl Symb) const override; uint32_t getSymbolAlignment(DataRefImpl Symb) const override; uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; - ErrorOr getSymbolType(DataRefImpl Symb) const override; + Expected getSymbolType(DataRefImpl Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; - ErrorOr getSymbolSection(DataRefImpl Symb) const override; + Expected getSymbolSection(DataRefImpl Symb) const override; unsigned getSymbolSectionID(SymbolRef Symb) const; unsigned getSectionID(SectionRef Sec) const; @@ -222,6 +222,7 @@ public: std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; bool isSectionBSS(DataRefImpl Sec) const override; @@ -252,6 +253,7 @@ public: // MachO specific. basic_symbol_iterator getSymbolByIndex(unsigned Index) const; + uint64_t getSymbolIndex(DataRefImpl Symb) const; section_iterator section_begin() const override; section_iterator section_end() const override; @@ -260,7 +262,8 @@ public: StringRef getFileFormatName() const override; unsigned getArch() const override; - Triple getArch(const char **McpuDefault, Triple *ThumbTriple) const; + SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } + Triple getArchTriple(const char **McpuDefault = nullptr) const; relocation_iterator section_rel_begin(unsigned Index) const; relocation_iterator section_rel_end(unsigned Index) const; @@ -406,12 +409,8 @@ public: StringRef &Suffix); static Triple::ArchType getArch(uint32_t CPUType); - static Triple getArch(uint32_t CPUType, uint32_t CPUSubType, - const char **McpuDefault = nullptr); - static Triple getThumbArch(uint32_t CPUType, uint32_t CPUSubType, - const char **McpuDefault = nullptr); - static Triple getArch(uint32_t CPUType, uint32_t CPUSubType, - const char **McpuDefault, Triple *ThumbTriple); + static Triple getArchTriple(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault = nullptr); static bool isValidArch(StringRef ArchFlag); static Triple getHostArch(); diff --git a/include/llvm/Object/MachOUniversal.h b/include/llvm/Object/MachOUniversal.h index a11d381a700a20840fe16631d6aef86350180477..7eb2af944f3dc58ba181f7aea64c1cce3afb8508 100644 --- a/include/llvm/Object/MachOUniversal.h +++ b/include/llvm/Object/MachOUniversal.h @@ -14,21 +14,22 @@ #ifndef LLVM_OBJECT_MACHOUNIVERSAL_H #define LLVM_OBJECT_MACHOUNIVERSAL_H -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Object/Archive.h" #include "llvm/Object/Binary.h" #include "llvm/Object/MachO.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/MachO.h" namespace llvm { +class StringRef; + namespace object { class MachOUniversalBinary : public Binary { virtual void anchor(); + uint32_t Magic; uint32_t NumberOfObjects; public: class ObjectForArch { @@ -37,6 +38,7 @@ public: uint32_t Index; /// \brief Descriptor of the object. MachO::fat_arch Header; + MachO::fat_arch_64 Header64; public: ObjectForArch(const MachOUniversalBinary *Parent, uint32_t Index); @@ -51,19 +53,58 @@ public: } ObjectForArch getNext() const { return ObjectForArch(Parent, Index + 1); } - uint32_t getCPUType() const { return Header.cputype; } - uint32_t getCPUSubType() const { return Header.cpusubtype; } - uint32_t getOffset() const { return Header.offset; } - uint32_t getSize() const { return Header.size; } - uint32_t getAlign() const { return Header.align; } + uint32_t getCPUType() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.cputype; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.cputype; + } + uint32_t getCPUSubType() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.cpusubtype; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.cpusubtype; + } + uint32_t getOffset() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.offset; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.offset; + } + uint32_t getSize() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.size; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.size; + } + uint32_t getAlign() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.align; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.align; + } + uint32_t getReserved() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return 0; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.reserved; + } std::string getArchTypeName() const { - Triple T = MachOObjectFile::getArch(Header.cputype, Header.cpusubtype); - return T.getArchName(); + if (Parent->getMagic() == MachO::FAT_MAGIC) { + Triple T = + MachOObjectFile::getArchTriple(Header.cputype, Header.cpusubtype); + return T.getArchName(); + } else { // Parent->getMagic() == MachO::FAT_MAGIC_64 + Triple T = + MachOObjectFile::getArchTriple(Header64.cputype, + Header64.cpusubtype); + return T.getArchName(); + } } - ErrorOr> getAsObjectFile() const; + Expected> getAsObjectFile() const; - ErrorOr> getAsArchive() const; + Expected> getAsArchive() const; }; class object_iterator { @@ -86,8 +127,8 @@ public: } }; - MachOUniversalBinary(MemoryBufferRef Souce, std::error_code &EC); - static ErrorOr> + MachOUniversalBinary(MemoryBufferRef Souce, Error &Err); + static Expected> create(MemoryBufferRef Source); object_iterator begin_objects() const { @@ -101,6 +142,7 @@ public: return make_range(begin_objects(), end_objects()); } + uint32_t getMagic() const { return Magic; } uint32_t getNumberOfObjects() const { return NumberOfObjects; } // Cast methods. @@ -108,7 +150,7 @@ public: return V->isMachOUniversalBinary(); } - ErrorOr> + Expected> getObjectForArch(StringRef ArchName) const; }; diff --git a/include/llvm/Object/ModuleSummaryIndexObjectFile.h b/include/llvm/Object/ModuleSummaryIndexObjectFile.h index f3f023a8efc2e8bfbc22d1cb24761a44b0f667f7..d021fb29427f0f26e0997f4699ce6050955d0b4d 100644 --- a/include/llvm/Object/ModuleSummaryIndexObjectFile.h +++ b/include/llvm/Object/ModuleSummaryIndexObjectFile.h @@ -81,32 +81,23 @@ public: /// \brief Looks for summary sections in the given memory buffer, /// returns true if found, else false. - static bool - hasGlobalValueSummaryInMemBuffer(MemoryBufferRef Object, - DiagnosticHandlerFunction DiagnosticHandler); + static bool hasGlobalValueSummaryInMemBuffer( + MemoryBufferRef Object, + const DiagnosticHandlerFunction &DiagnosticHandler); /// \brief Parse module summary index in the given memory buffer. /// Return new ModuleSummaryIndexObjectFile instance containing parsed module /// summary/index. static ErrorOr> - create(MemoryBufferRef Object, DiagnosticHandlerFunction DiagnosticHandler, - bool IsLazy = false); - - /// \brief Parse the summary information for global value with the - /// given name out of the given buffer. Parsed information is - /// stored on the index object saved in this object. - std::error_code - findGlobalValueSummaryInMemBuffer(MemoryBufferRef Object, - DiagnosticHandlerFunction DiagnosticHandler, - StringRef ValueName); + create(MemoryBufferRef Object, + const DiagnosticHandlerFunction &DiagnosticHandler); }; } /// Parse the module summary index out of an IR file and return the module /// summary index object if found, or nullptr if not. -ErrorOr> -getModuleSummaryIndexForFile(StringRef Path, - DiagnosticHandlerFunction DiagnosticHandler); +ErrorOr> getModuleSummaryIndexForFile( + StringRef Path, const DiagnosticHandlerFunction &DiagnosticHandler); } #endif diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 5c875a2f9ebc3e9bd347126bbab2ae3824afc31a..6272a5f056eb8c8c267767a401a763e59fc35ecd 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -15,13 +15,13 @@ #define LLVM_OBJECT_OBJECTFILE_H #include "llvm/ADT/StringRef.h" +#include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include -#include namespace llvm { namespace object { @@ -90,6 +90,7 @@ public: /// @brief Get the alignment of this section as the actual value (not log 2). uint64_t getAlignment() const; + bool isCompressed() const; bool isText() const; bool isData() const; bool isBSS() const; @@ -131,10 +132,10 @@ public: assert(isa(BasicSymbolRef::getObject())); } - ErrorOr getName() const; + Expected getName() const; /// Returns the symbol virtual address (i.e. address at which it will be /// mapped). - ErrorOr getAddress() const; + Expected getAddress() const; /// Return the value of the symbol depending on the object this can be an /// offset or a virtual address. @@ -143,11 +144,11 @@ public: /// @brief Get the alignment of this symbol as the actual value (not log 2). uint32_t getAlignment() const; uint64_t getCommonSize() const; - ErrorOr getType() const; + Expected getType() const; /// @brief Get section this symbol is defined in reference to. Result is /// end_sections() if it is undefined or is an absolute symbol. - ErrorOr getSection() const; + Expected getSection() const; const ObjectFile *getObject() const; }; @@ -194,15 +195,15 @@ protected: // Implementations assume that the DataRefImpl is valid and has not been // modified externally. It's UB otherwise. friend class SymbolRef; - virtual ErrorOr getSymbolName(DataRefImpl Symb) const = 0; + virtual Expected getSymbolName(DataRefImpl Symb) const = 0; std::error_code printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override; - virtual ErrorOr getSymbolAddress(DataRefImpl Symb) const = 0; + virtual Expected getSymbolAddress(DataRefImpl Symb) const = 0; virtual uint64_t getSymbolValueImpl(DataRefImpl Symb) const = 0; virtual uint32_t getSymbolAlignment(DataRefImpl Symb) const; virtual uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const = 0; - virtual ErrorOr getSymbolType(DataRefImpl Symb) const = 0; - virtual ErrorOr + virtual Expected getSymbolType(DataRefImpl Symb) const = 0; + virtual Expected getSymbolSection(DataRefImpl Symb) const = 0; // Same as above for SectionRef. @@ -215,6 +216,7 @@ protected: virtual std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const = 0; virtual uint64_t getSectionAlignment(DataRefImpl Sec) const = 0; + virtual bool isSectionCompressed(DataRefImpl Sec) const = 0; virtual bool isSectionText(DataRefImpl Sec) const = 0; virtual bool isSectionData(DataRefImpl Sec) const = 0; virtual bool isSectionBSS(DataRefImpl Sec) const = 0; @@ -261,6 +263,7 @@ public: virtual StringRef getFileFormatName() const = 0; virtual /* Triple::ArchType */ unsigned getArch() const = 0; + virtual SubtargetFeatures getFeatures() const = 0; /// Returns platform-specific object flags, if any. virtual std::error_code getPlatformFlags(unsigned &Result) const { @@ -275,12 +278,12 @@ public: /// @param ObjectPath The path to the object file. ObjectPath.isObject must /// return true. /// @brief Create ObjectFile from path. - static ErrorOr> + static Expected> createObjectFile(StringRef ObjectPath); - static ErrorOr> + static Expected> createObjectFile(MemoryBufferRef Object, sys::fs::file_magic Type); - static ErrorOr> + static Expected> createObjectFile(MemoryBufferRef Object) { return createObjectFile(Object, sys::fs::file_magic::unknown); } @@ -305,11 +308,11 @@ public: inline SymbolRef::SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner) : BasicSymbolRef(SymbolP, Owner) {} -inline ErrorOr SymbolRef::getName() const { +inline Expected SymbolRef::getName() const { return getObject()->getSymbolName(getRawDataRefImpl()); } -inline ErrorOr SymbolRef::getAddress() const { +inline Expected SymbolRef::getAddress() const { return getObject()->getSymbolAddress(getRawDataRefImpl()); } @@ -325,11 +328,11 @@ inline uint64_t SymbolRef::getCommonSize() const { return getObject()->getCommonSymbolSize(getRawDataRefImpl()); } -inline ErrorOr SymbolRef::getSection() const { +inline Expected SymbolRef::getSection() const { return getObject()->getSymbolSection(getRawDataRefImpl()); } -inline ErrorOr SymbolRef::getType() const { +inline Expected SymbolRef::getType() const { return getObject()->getSymbolType(getRawDataRefImpl()); } @@ -381,6 +384,10 @@ inline uint64_t SectionRef::getAlignment() const { return OwningObject->getSectionAlignment(SectionPimpl); } +inline bool SectionRef::isCompressed() const { + return OwningObject->isSectionCompressed(SectionPimpl); +} + inline bool SectionRef::isText() const { return OwningObject->isSectionText(SectionPimpl); } diff --git a/include/llvm/Object/RelocVisitor.h b/include/llvm/Object/RelocVisitor.h index f171f8e1fd4a689472e2dce4a486bd47e0c42724..5e0df98d86279fc4aadf7a92353bebe4f64af0c7 100644 --- a/include/llvm/Object/RelocVisitor.h +++ b/include/llvm/Object/RelocVisitor.h @@ -16,7 +16,6 @@ #ifndef LLVM_OBJECT_RELOCVISITOR_H #define LLVM_OBJECT_RELOCVISITOR_H -#include "llvm/ADT/StringRef.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" diff --git a/include/llvm/Object/StackMapParser.h b/include/llvm/Object/StackMapParser.h index 1bd26d04263432739e443bdf7b2b0a4e2517564a..e58162de1501eeab7425b2a9b9a4ce18199b4f72 100644 --- a/include/llvm/Object/StackMapParser.h +++ b/include/llvm/Object/StackMapParser.h @@ -11,9 +11,7 @@ #define LLVM_CODEGEN_STACKMAPPARSER_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" -#include #include namespace llvm { diff --git a/include/llvm/Object/SymbolicFile.h b/include/llvm/Object/SymbolicFile.h index 0c5b38111a9c0aa94db22af6ae499bb778a7266d..894c2670f265c1dd34ff6d5566081d909f511c3c 100644 --- a/include/llvm/Object/SymbolicFile.h +++ b/include/llvm/Object/SymbolicFile.h @@ -16,6 +16,7 @@ #include "llvm/Object/Binary.h" #include "llvm/Support/Format.h" +#include namespace llvm { namespace object { @@ -58,7 +59,7 @@ class content_iterator content_type Current; public: - content_iterator(content_type symb) : Current(symb) {} + content_iterator(content_type symb) : Current(std::move(symb)) {} const content_type *operator->() const { return &Current; } @@ -153,15 +154,15 @@ public: } // construction aux. - static ErrorOr> + static Expected> createSymbolicFile(MemoryBufferRef Object, sys::fs::file_magic Type, LLVMContext *Context); - static ErrorOr> + static Expected> createSymbolicFile(MemoryBufferRef Object) { return createSymbolicFile(Object, sys::fs::file_magic::unknown, nullptr); } - static ErrorOr> + static Expected> createSymbolicFile(StringRef ObjectPath); static inline bool classof(const Binary *v) { diff --git a/include/llvm/ObjectYAML/MachOYAML.h b/include/llvm/ObjectYAML/MachOYAML.h new file mode 100644 index 0000000000000000000000000000000000000000..bb15e64789d0cbb0f8fbc0eb3d9c612cff0a0f8f --- /dev/null +++ b/include/llvm/ObjectYAML/MachOYAML.h @@ -0,0 +1,296 @@ +//===- MachOYAML.h - Mach-O YAMLIO implementation ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file declares classes for handling the YAML representation +/// of Mach-O. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_MACHOYAML_H +#define LLVM_OBJECTYAML_MACHOYAML_H + +#include "llvm/ObjectYAML/YAML.h" +#include "llvm/Support/MachO.h" + +namespace llvm { +namespace MachOYAML { + +struct Section { + char sectname[16]; + char segname[16]; + llvm::yaml::Hex64 addr; + uint64_t size; + llvm::yaml::Hex32 offset; + uint32_t align; + llvm::yaml::Hex32 reloff; + uint32_t nreloc; + llvm::yaml::Hex32 flags; + llvm::yaml::Hex32 reserved1; + llvm::yaml::Hex32 reserved2; + llvm::yaml::Hex32 reserved3; +}; + +struct FileHeader { + llvm::yaml::Hex32 magic; + llvm::yaml::Hex32 cputype; + llvm::yaml::Hex32 cpusubtype; + llvm::yaml::Hex32 filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + llvm::yaml::Hex32 flags; + llvm::yaml::Hex32 reserved; +}; + +struct LoadCommand { + virtual ~LoadCommand(); + llvm::MachO::macho_load_command Data; + std::vector
Sections; + std::vector PayloadBytes; + std::string PayloadString; + uint64_t ZeroPadBytes; +}; + +struct NListEntry { + uint32_t n_strx; + uint8_t n_type; + uint8_t n_sect; + uint16_t n_desc; + uint64_t n_value; +}; +struct RebaseOpcode { + MachO::RebaseOpcode Opcode; + uint8_t Imm; + std::vector ExtraData; +}; + +struct BindOpcode { + MachO::BindOpcode Opcode; + uint8_t Imm; + std::vector ULEBExtraData; + std::vector SLEBExtraData; + StringRef Symbol; +}; + +struct ExportEntry { + ExportEntry() + : TerminalSize(0), NodeOffset(0), Name(), Flags(0), Address(0), Other(0), + ImportName(), Children() {} + uint64_t TerminalSize; + uint64_t NodeOffset; + std::string Name; + llvm::yaml::Hex64 Flags; + llvm::yaml::Hex64 Address; + llvm::yaml::Hex64 Other; + std::string ImportName; + std::vector Children; +}; + +struct LinkEditData { + std::vector RebaseOpcodes; + std::vector BindOpcodes; + std::vector WeakBindOpcodes; + std::vector LazyBindOpcodes; + MachOYAML::ExportEntry ExportTrie; + std::vector NameList; + std::vector StringTable; +}; + +struct Object { + FileHeader Header; + std::vector LoadCommands; + std::vector
Sections; + LinkEditData LinkEdit; +}; + +struct FatHeader { + llvm::yaml::Hex32 magic; + uint32_t nfat_arch; +}; + +struct FatArch { + llvm::yaml::Hex32 cputype; + llvm::yaml::Hex32 cpusubtype; + llvm::yaml::Hex64 offset; + uint64_t size; + uint32_t align; + llvm::yaml::Hex32 reserved; +}; + +struct UniversalBinary { + FatHeader Header; + std::vector FatArchs; + std::vector Slices; +}; + +} // namespace llvm::MachOYAML +} // namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::LoadCommand) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Section) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex8) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex64) +LLVM_YAML_IS_SEQUENCE_VECTOR(int64_t) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::RebaseOpcode) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::BindOpcode) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::ExportEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::NListEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Object) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::FatArch) + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::FileHeader &FileHeader); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::Object &Object); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::FatHeader &FatHeader); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::FatArch &FatArch); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::UniversalBinary &UniversalBinary); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::LoadCommand &LoadCommand); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::LinkEditData &LinkEditData); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::RebaseOpcode &RebaseOpcode); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::BindOpcode &BindOpcode); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::ExportEntry &ExportEntry); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::Section &Section); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachOYAML::NListEntry &NListEntry); +}; + +#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ + io.enumCase(value, #LCName, MachO::LCName); + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, MachO::LoadCommandType &value) { +#include "llvm/Support/MachO.def" + io.enumFallback(value); + } +}; + +#define ENUM_CASE(Enum) io.enumCase(value, #Enum, MachO::Enum); + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, MachO::RebaseOpcode &value) { + ENUM_CASE(REBASE_OPCODE_DONE) + ENUM_CASE(REBASE_OPCODE_SET_TYPE_IMM) + ENUM_CASE(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB) + ENUM_CASE(REBASE_OPCODE_ADD_ADDR_ULEB) + ENUM_CASE(REBASE_OPCODE_ADD_ADDR_IMM_SCALED) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_IMM_TIMES) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_ULEB_TIMES) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB) + ENUM_CASE(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB) + io.enumFallback(value); + } +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, MachO::BindOpcode &value) { + ENUM_CASE(BIND_OPCODE_DONE) + ENUM_CASE(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM) + ENUM_CASE(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB) + ENUM_CASE(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM) + ENUM_CASE(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM) + ENUM_CASE(BIND_OPCODE_SET_TYPE_IMM) + ENUM_CASE(BIND_OPCODE_SET_ADDEND_SLEB) + ENUM_CASE(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB) + ENUM_CASE(BIND_OPCODE_ADD_ADDR_ULEB) + ENUM_CASE(BIND_OPCODE_DO_BIND) + ENUM_CASE(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB) + ENUM_CASE(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED) + ENUM_CASE(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB) + io.enumFallback(value); + } +}; + +// This trait is used for 16-byte chars in Mach structures used for strings +typedef char char_16[16]; + +template <> struct ScalarTraits { + static void output(const char_16 &Val, void *, llvm::raw_ostream &Out); + + static StringRef input(StringRef Scalar, void *, char_16 &Val); + static bool mustQuote(StringRef S); +}; + +// This trait is used for UUIDs. It reads and writes them matching otool's +// formatting style. +typedef uint8_t uuid_t[16]; + +template <> struct ScalarTraits { + static void output(const uuid_t &Val, void *, llvm::raw_ostream &Out); + + static StringRef input(StringRef Scalar, void *, uuid_t &Val); + static bool mustQuote(StringRef S); +}; + +// Load Command struct mapping traits + +#define LOAD_COMMAND_STRUCT(LCStruct) \ + template <> struct MappingTraits { \ + static void mapping(IO &IO, MachO::LCStruct &LoadCommand); \ + }; + +#include "llvm/Support/MachO.def" + +// Extra structures used by load commands +template <> struct MappingTraits { + static void mapping(IO &IO, MachO::dylib &LoadCommand); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachO::fvmlib &LoadCommand); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachO::section &LoadCommand); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, MachO::section_64 &LoadCommand); +}; + +} // namespace llvm::yaml + +} // namespace llvm + +#endif diff --git a/include/llvm/ObjectYAML/ObjectYAML.h b/include/llvm/ObjectYAML/ObjectYAML.h new file mode 100644 index 0000000000000000000000000000000000000000..1d6462347770c56ea0b103a41f1805c678f92727 --- /dev/null +++ b/include/llvm/ObjectYAML/ObjectYAML.h @@ -0,0 +1,35 @@ +//===- ObjectYAML.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTYAML_OBJECTYAML_H +#define LLVM_OBJECTYAML_OBJECTYAML_H + +#include "llvm/Support/YAMLTraits.h" +#include "llvm/ObjectYAML/ELFYAML.h" +#include "llvm/ObjectYAML/COFFYAML.h" +#include "llvm/ObjectYAML/MachOYAML.h" + +namespace llvm { +namespace yaml { + +struct YamlObjectFile { + std::unique_ptr Elf; + std::unique_ptr Coff; + std::unique_ptr MachO; + std::unique_ptr FatMachO; +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, YamlObjectFile &ObjectFile); +}; + +} // namespace yaml +} // namespace llvm + +#endif diff --git a/include/llvm/Option/OptParser.td b/include/llvm/Option/OptParser.td index dbf240d748051ca4c69df15acdf4d09ad4647180..4da86f09750db626e5bc4e40058b9dfdac640e56 100644 --- a/include/llvm/Option/OptParser.td +++ b/include/llvm/Option/OptParser.td @@ -46,6 +46,9 @@ def KIND_JOINED_OR_SEPARATE : OptionKind<"JoinedOrSeparate">; def KIND_JOINED_AND_SEPARATE : OptionKind<"JoinedAndSeparate">; // An option which consumes all remaining arguments if there are any. def KIND_REMAINING_ARGS : OptionKind<"RemainingArgs">; +// An option which consumes an optional joined argument and any other remaining +// arguments. +def KIND_REMAINING_ARGS_JOINED : OptionKind<"RemainingArgsJoined">; // Define the option flags. diff --git a/include/llvm/Option/Option.h b/include/llvm/Option/Option.h index 494987a135ef0237f05e86212fdb25c5f022ad60..139f281b3c4ce97c385bcd475e5237dbcf02f7fd 100644 --- a/include/llvm/Option/Option.h +++ b/include/llvm/Option/Option.h @@ -51,6 +51,7 @@ public: JoinedClass, SeparateClass, RemainingArgsClass, + RemainingArgsJoinedClass, CommaJoinedClass, MultiArgClass, JoinedOrSeparateClass, @@ -150,6 +151,7 @@ public: case MultiArgClass: case JoinedOrSeparateClass: case RemainingArgsClass: + case RemainingArgsJoinedClass: return RenderSeparateStyle; } llvm_unreachable("Unexpected kind!"); diff --git a/include/llvm/Pass.h b/include/llvm/Pass.h index 99604cdbc9caa012e9317d29906933c68330bf1f..2a21b82876bbbb1cba3375b04821e9169256f285 100644 --- a/include/llvm/Pass.h +++ b/include/llvm/Pass.h @@ -29,7 +29,6 @@ #ifndef LLVM_PASS_H #define LLVM_PASS_H -#include "llvm/Support/Compiler.h" #include namespace llvm { @@ -251,6 +250,11 @@ public: explicit ModulePass(char &pid) : Pass(PT_Module, pid) {} // Force out-of-line virtual method. ~ModulePass() override; + +protected: + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when optimization bisect is over the limit. + bool skipModule(Module &M) const; }; @@ -310,9 +314,10 @@ public: PassManagerType getPotentialPassManagerType() const override; protected: - /// skipOptnoneFunction - This function has Attribute::OptimizeNone - /// and most transformation passes should skip it. - bool skipOptnoneFunction(const Function &F) const; + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when Attribute::OptimizeNone is set or when + /// optimization bisect is over the limit. + bool skipFunction(const Function &F) const; }; @@ -359,9 +364,10 @@ public: PassManagerType getPotentialPassManagerType() const override; protected: - /// skipOptnoneFunction - Containing function has Attribute::OptimizeNone - /// and most transformation passes should skip it. - bool skipOptnoneFunction(const BasicBlock &BB) const; + /// Optional passes call this function to check whether the pass should be + /// skipped. This is the case when Attribute::OptimizeNone is set or when + /// optimization bisect is over the limit. + bool skipBasicBlock(const BasicBlock &BB) const; }; /// If the user specifies the -time-passes argument on an LLVM tool command line diff --git a/include/llvm/PassAnalysisSupport.h b/include/llvm/PassAnalysisSupport.h index 492a4ef464f806654c1747baa148f36a1f5d495c..abd9929380575f3df430c50fe1ad5fadfb82ec67 100644 --- a/include/llvm/PassAnalysisSupport.h +++ b/include/llvm/PassAnalysisSupport.h @@ -20,11 +20,11 @@ #define LLVM_PASSANALYSISSUPPORT_H #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Pass.h" #include namespace llvm { +class StringRef; //===----------------------------------------------------------------------===// /// Represent the analysis usage information of a pass. This tracks analyses @@ -153,9 +153,9 @@ public: /// Find pass that is implementing PI. Pass *findImplPass(AnalysisID PI) { Pass *ResultPass = nullptr; - for (unsigned i = 0; i < AnalysisImpls.size() ; ++i) { - if (AnalysisImpls[i].first == PI) { - ResultPass = AnalysisImpls[i].second; + for (const auto &AnalysisImpl : AnalysisImpls) { + if (AnalysisImpl.first == PI) { + ResultPass = AnalysisImpl.second; break; } } diff --git a/include/llvm/PassRegistry.h b/include/llvm/PassRegistry.h index e7fe1f53a4d40ba773367c192e11ee592f116ca4..4bb19675585e5a4cc4f2df1593874b98d7927618 100644 --- a/include/llvm/PassRegistry.h +++ b/include/llvm/PassRegistry.h @@ -20,7 +20,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" #include "llvm/PassInfo.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/RWMutex.h" @@ -28,6 +27,7 @@ namespace llvm { +class StringRef; class PassInfo; struct PassRegistrationListener; diff --git a/include/llvm/PassSupport.h b/include/llvm/PassSupport.h index 7c3d49f02e8fb1f6a0d0f8870e536c4213702161..ba6d84f04ba0b2b2700caaf39a346e26e2350570 100644 --- a/include/llvm/PassSupport.h +++ b/include/llvm/PassSupport.h @@ -26,73 +26,57 @@ #include "llvm/PassInfo.h" #include "llvm/PassRegistry.h" #include "llvm/Support/Atomic.h" -#include "llvm/Support/Compiler.h" -#include +#include "llvm/Support/Threading.h" +#include namespace llvm { class TargetMachine; -#define CALL_ONCE_INITIALIZATION(function) \ - static volatile sys::cas_flag initialized = 0; \ - sys::cas_flag old_val = sys::CompareAndSwap(&initialized, 1, 0); \ - if (old_val == 0) { \ - function(Registry); \ - sys::MemoryFence(); \ - TsanIgnoreWritesBegin(); \ - TsanHappensBefore(&initialized); \ - initialized = 2; \ - TsanIgnoreWritesEnd(); \ - } else { \ - sys::cas_flag tmp = initialized; \ - sys::MemoryFence(); \ - while (tmp != 2) { \ - tmp = initialized; \ - sys::MemoryFence(); \ - } \ - } \ - TsanHappensAfter(&initialized); - -#define INITIALIZE_PASS(passName, arg, name, cfg, analysis) \ - static void* initialize##passName##PassOnce(PassRegistry &Registry) { \ - PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ - PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ - Registry.registerPass(*PI, true); \ - return PI; \ - } \ - void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ +#define INITIALIZE_PASS(passName, arg, name, cfg, analysis) \ + static void *initialize##passName##PassOnce(PassRegistry &Registry) { \ + PassInfo *PI = new PassInfo( \ + name, arg, &passName::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + return PI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } -#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis) \ - static void* initialize##passName##PassOnce(PassRegistry &Registry) { - -#define INITIALIZE_PASS_DEPENDENCY(depName) \ - initialize##depName##Pass(Registry); -#define INITIALIZE_AG_DEPENDENCY(depName) \ - initialize##depName##AnalysisGroup(Registry); - -#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis) \ - PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ - PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ - Registry.registerPass(*PI, true); \ - return PI; \ - } \ - void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ +#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis) \ + static void *initialize##passName##PassOnce(PassRegistry &Registry) { + +#define INITIALIZE_PASS_DEPENDENCY(depName) initialize##depName##Pass(Registry); +#define INITIALIZE_AG_DEPENDENCY(depName) \ + initialize##depName##AnalysisGroup(Registry); + +#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis) \ + PassInfo *PI = new PassInfo( \ + name, arg, &passName::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + return PI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } -#define INITIALIZE_PASS_WITH_OPTIONS(PassName, Arg, Name, Cfg, Analysis) \ - INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \ - PassName::registerOptions(); \ +#define INITIALIZE_PASS_WITH_OPTIONS(PassName, Arg, Name, Cfg, Analysis) \ + INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \ + PassName::registerOptions(); \ INITIALIZE_PASS_END(PassName, Arg, Name, Cfg, Analysis) #define INITIALIZE_PASS_WITH_OPTIONS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \ - INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \ - PassName::registerOptions(); \ + INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \ + PassName::registerOptions(); -template -Pass *callDefaultCtor() { return new PassName(); } +template Pass *callDefaultCtor() { return new PassName(); } template Pass *callTargetMachineCtor(TargetMachine *TM) { return new PassName(TM); @@ -115,20 +99,17 @@ template Pass *callTargetMachineCtor(TargetMachine *TM) { /// /// static RegisterPass tmp("passopt", "My Name"); /// -template -struct RegisterPass : public PassInfo { - +template struct RegisterPass : public PassInfo { // Register Pass using default constructor... RegisterPass(const char *PassArg, const char *Name, bool CFGOnly = false, bool is_analysis = false) - : PassInfo(Name, PassArg, &passName::ID, - PassInfo::NormalCtor_t(callDefaultCtor), - CFGOnly, is_analysis) { + : PassInfo(Name, PassArg, &passName::ID, + PassInfo::NormalCtor_t(callDefaultCtor), CFGOnly, + is_analysis) { PassRegistry::getPassRegistry()->registerPass(*this); } }; - /// RegisterAnalysisGroup - Register a Pass as a member of an analysis _group_. /// Analysis groups are used to define an interface (which need not derive from /// Pass) that is required by passes to do their job. Analysis Groups differ @@ -150,70 +131,73 @@ struct RegisterPass : public PassInfo { /// class RegisterAGBase : public PassInfo { public: - RegisterAGBase(const char *Name, - const void *InterfaceID, - const void *PassID = nullptr, - bool isDefault = false); + RegisterAGBase(const char *Name, const void *InterfaceID, + const void *PassID = nullptr, bool isDefault = false); }; -template +template struct RegisterAnalysisGroup : public RegisterAGBase { explicit RegisterAnalysisGroup(PassInfo &RPB) - : RegisterAGBase(RPB.getPassName(), - &Interface::ID, RPB.getTypeInfo(), - Default) { - } + : RegisterAGBase(RPB.getPassName(), &Interface::ID, RPB.getTypeInfo(), + Default) {} explicit RegisterAnalysisGroup(const char *Name) - : RegisterAGBase(Name, &Interface::ID) { - } + : RegisterAGBase(Name, &Interface::ID) {} }; -#define INITIALIZE_ANALYSIS_GROUP(agName, name, defaultPass) \ - static void* initialize##agName##AnalysisGroupOnce(PassRegistry &Registry) { \ - initialize##defaultPass##Pass(Registry); \ - PassInfo *AI = new PassInfo(name, & agName :: ID); \ - Registry.registerAnalysisGroup(& agName ::ID, 0, *AI, false, true); \ - return AI; \ - } \ - void llvm::initialize##agName##AnalysisGroup(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##agName##AnalysisGroupOnce) \ +#define INITIALIZE_ANALYSIS_GROUP(agName, name, defaultPass) \ + static void *initialize##agName##AnalysisGroupOnce(PassRegistry &Registry) { \ + initialize##defaultPass##Pass(Registry); \ + PassInfo *AI = new PassInfo(name, &agName::ID); \ + Registry.registerAnalysisGroup(&agName::ID, 0, *AI, false, true); \ + return AI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##agName##AnalysisGroupFlag); \ + void llvm::initialize##agName##AnalysisGroup(PassRegistry &Registry) { \ + llvm::call_once(Initialize##agName##AnalysisGroupFlag, \ + initialize##agName##AnalysisGroupOnce, \ + std::ref(Registry)); \ } - -#define INITIALIZE_AG_PASS(passName, agName, arg, name, cfg, analysis, def) \ - static void* initialize##passName##PassOnce(PassRegistry &Registry) { \ - if (!def) initialize##agName##AnalysisGroup(Registry); \ - PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ - PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ - Registry.registerPass(*PI, true); \ - \ - PassInfo *AI = new PassInfo(name, & agName :: ID); \ - Registry.registerAnalysisGroup(& agName ::ID, & passName ::ID, \ - *AI, def, true); \ - return AI; \ - } \ - void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ +#define INITIALIZE_AG_PASS(passName, agName, arg, name, cfg, analysis, def) \ + static void *initialize##passName##PassOnce(PassRegistry &Registry) { \ + if (!def) \ + initialize##agName##AnalysisGroup(Registry); \ + PassInfo *PI = new PassInfo( \ + name, arg, &passName::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + \ + PassInfo *AI = new PassInfo(name, &agName::ID); \ + Registry.registerAnalysisGroup(&agName::ID, &passName::ID, *AI, def, \ + true); \ + return AI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } - #define INITIALIZE_AG_PASS_BEGIN(passName, agName, arg, n, cfg, analysis, def) \ - static void* initialize##passName##PassOnce(PassRegistry &Registry) { \ - if (!def) initialize##agName##AnalysisGroup(Registry); - -#define INITIALIZE_AG_PASS_END(passName, agName, arg, n, cfg, analysis, def) \ - PassInfo *PI = new PassInfo(n, arg, & passName ::ID, \ - PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ - Registry.registerPass(*PI, true); \ - \ - PassInfo *AI = new PassInfo(n, & agName :: ID); \ - Registry.registerAnalysisGroup(& agName ::ID, & passName ::ID, \ - *AI, def, true); \ - return AI; \ - } \ - void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ - CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + static void *initialize##passName##PassOnce(PassRegistry &Registry) { \ + if (!def) \ + initialize##agName##AnalysisGroup(Registry); + +#define INITIALIZE_AG_PASS_END(passName, agName, arg, n, cfg, analysis, def) \ + PassInfo *PI = new PassInfo( \ + n, arg, &passName::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + \ + PassInfo *AI = new PassInfo(n, &agName::ID); \ + Registry.registerAnalysisGroup(&agName::ID, &passName::ID, *AI, def, true); \ + return AI; \ + } \ + LLVM_DEFINE_ONCE_FLAG(Initialize##passName##PassFlag); \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + llvm::call_once(Initialize##passName##PassFlag, \ + initialize##passName##PassOnce, std::ref(Registry)); \ } //===--------------------------------------------------------------------------- @@ -224,7 +208,6 @@ struct RegisterAnalysisGroup : public RegisterAGBase { /// loaded). /// struct PassRegistrationListener { - PassRegistrationListener() {} virtual ~PassRegistrationListener() {} @@ -244,7 +227,6 @@ struct PassRegistrationListener { virtual void passEnumerate(const PassInfo *) {} }; - } // End llvm namespace #endif diff --git a/include/llvm/Passes/PassBuilder.h b/include/llvm/Passes/PassBuilder.h index 264a21c21bf0fe32309f727573cd869644de7ccd..1723fb7b5f6cd56cd63f09b623ffc09dcd214ca6 100644 --- a/include/llvm/Passes/PassBuilder.h +++ b/include/llvm/Passes/PassBuilder.h @@ -16,12 +16,12 @@ #ifndef LLVM_PASSES_PASSBUILDER_H #define LLVM_PASSES_PASSBUILDER_H -#include "llvm/ADT/StringRef.h" #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Analysis/LoopPassManager.h" #include "llvm/IR/PassManager.h" namespace llvm { +class StringRef; class AAManager; class TargetMachine; @@ -123,6 +123,15 @@ public: explicit PassBuilder(TargetMachine *TM = nullptr) : TM(TM) {} + /// \brief Cross register the analysis managers through their proxies. + /// + /// This is an interface that can be used to cross register each + // AnalysisManager with all the others analysis managers. + void crossRegisterProxies(LoopAnalysisManager &LAM, + FunctionAnalysisManager &FAM, + CGSCCAnalysisManager &CGAM, + ModuleAnalysisManager &MAM); + /// \brief Registers all available module analysis passes. /// /// This is an interface that can be used to populate a \c diff --git a/include/llvm/ProfileData/CoverageMapping.h b/include/llvm/ProfileData/Coverage/CoverageMapping.h similarity index 94% rename from include/llvm/ProfileData/CoverageMapping.h rename to include/llvm/ProfileData/Coverage/CoverageMapping.h index 6cf4bab19db8e922af49dd84ac931567411add8f..cb0e17b94f9a7cae2e60c71d80cd2fdca2382c14 100644 --- a/include/llvm/ProfileData/CoverageMapping.h +++ b/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -23,13 +23,13 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/raw_ostream.h" #include #include namespace llvm { namespace coverage { + enum class coveragemap_error { success = 0, eof, @@ -38,14 +38,37 @@ enum class coveragemap_error { truncated, malformed }; -} // end of coverage namespace. + +const std::error_category &coveragemap_category(); + +inline std::error_code make_error_code(coveragemap_error E) { + return std::error_code(static_cast(E), coveragemap_category()); } -namespace std { -template <> -struct is_error_code_enum : std::true_type { +class CoverageMapError : public ErrorInfo { +public: + CoverageMapError(coveragemap_error Err) : Err(Err) { + assert(Err != coveragemap_error::success && "Not an error"); + } + + std::string message() const override; + + void log(raw_ostream &OS) const override { OS << message(); } + + std::error_code convertToErrorCode() const override { + return make_error_code(Err); + } + + coveragemap_error get() const { return Err; } + + static char ID; + +private: + coveragemap_error Err; }; -} + +} // end of coverage namespace. +} // end of llvm namespace namespace llvm { class IndexedInstrProfReader; @@ -265,7 +288,7 @@ public: /// \brief Return the number of times that a region of code associated with /// this counter was executed. - ErrorOr evaluate(const Counter &C) const; + Expected evaluate(const Counter &C) const; }; /// \brief Code coverage information for a single function. @@ -370,13 +393,6 @@ struct CoverageSegment { return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry) == std::tie(R.Line, R.Col, R.Count, R.HasCount, R.IsRegionEntry); } - - void setCount(uint64_t NewCount) { - Count = NewCount; - HasCount = true; - } - - void addCount(uint64_t NewCount) { setCount(Count + NewCount); } }; /// \brief Coverage information to be processed or displayed. @@ -400,14 +416,14 @@ public: Expansions(std::move(RHS.Expansions)) {} /// \brief Get the name of the file this data covers. - StringRef getFilename() { return Filename; } + StringRef getFilename() const { return Filename; } std::vector::iterator begin() { return Segments.begin(); } std::vector::iterator end() { return Segments.end(); } bool empty() { return Segments.empty(); } /// \brief Expansions that can be further processed. - std::vector getExpansions() { return Expansions; } + ArrayRef getExpansions() { return Expansions; } }; /// \brief The mapping of profile information to coverage data. @@ -422,12 +438,12 @@ class CoverageMapping { public: /// \brief Load the coverage mapping using the given readers. - static ErrorOr> + static Expected> load(CoverageMappingReader &CoverageReader, IndexedInstrProfReader &ProfileReader); /// \brief Load the coverage mapping from the given files. - static ErrorOr> + static Expected> load(StringRef ObjectFilename, StringRef ProfileFilename, StringRef Arch = StringRef()); @@ -445,7 +461,7 @@ public: /// The given filename must be the name as recorded in the coverage /// information. That is, only names returned from getUniqueSourceFiles will /// yield a result. - CoverageData getCoverageForFile(StringRef Filename); + CoverageData getCoverageForFile(StringRef Filename) const; /// \brief Gets all of the functions covered by this profile. iterator_range getCoveredFunctions() const { @@ -473,12 +489,6 @@ public: CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion); }; -const std::error_category &coveragemap_category(); - -inline std::error_code make_error_code(coveragemap_error E) { - return std::error_code(static_cast(E), coveragemap_category()); -} - // Profile coverage map has the following layout: // [CoverageMapFileHeader] // [ArrayStart] @@ -508,14 +518,13 @@ template struct CovMapFunctionRecordV1 { } // Return the PGO name of the function */ template - std::error_code getFuncName(InstrProfSymtab &ProfileNames, - StringRef &FuncName) const { + Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { IntPtrT NameRef = getFuncNameRef(); uint32_t NameS = support::endian::byte_swap(NameSize); FuncName = ProfileNames.getFuncName(NameRef, NameS); if (NameS && FuncName.empty()) - return coveragemap_error::malformed; - return std::error_code(); + return make_error(coveragemap_error::malformed); + return Error::success(); } }; @@ -537,11 +546,10 @@ struct CovMapFunctionRecord { } // Return the PGO name of the function */ template - std::error_code getFuncName(InstrProfSymtab &ProfileNames, - StringRef &FuncName) const { + Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { uint64_t NameRef = getFuncNameRef(); FuncName = ProfileNames.getFuncName(NameRef); - return std::error_code(); + return Error::success(); } }; diff --git a/include/llvm/ProfileData/CoverageMappingReader.h b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h similarity index 86% rename from include/llvm/ProfileData/CoverageMappingReader.h rename to include/llvm/ProfileData/Coverage/CoverageMappingReader.h index 7dfce5b8c642bdc0a5175940203a6721a2461097..db907f128d931e5edb7211cbed5ee2b43d1b856e 100644 --- a/include/llvm/ProfileData/CoverageMappingReader.h +++ b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h @@ -19,7 +19,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/ProfileData/CoverageMapping.h" +#include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -69,7 +69,7 @@ public: class CoverageMappingReader { public: - virtual std::error_code readNextRecord(CoverageMappingRecord &Record) = 0; + virtual Error readNextRecord(CoverageMappingRecord &Record) = 0; CoverageMappingIterator begin() { return CoverageMappingIterator(this); } CoverageMappingIterator end() { return CoverageMappingIterator(); } virtual ~CoverageMappingReader() {} @@ -82,10 +82,10 @@ protected: RawCoverageReader(StringRef Data) : Data(Data) {} - std::error_code readULEB128(uint64_t &Result); - std::error_code readIntMax(uint64_t &Result, uint64_t MaxPlus1); - std::error_code readSize(uint64_t &Result); - std::error_code readString(StringRef &Result); + Error readULEB128(uint64_t &Result); + Error readIntMax(uint64_t &Result, uint64_t MaxPlus1); + Error readSize(uint64_t &Result); + Error readString(StringRef &Result); }; /// \brief Reader for the raw coverage filenames. @@ -100,7 +100,17 @@ public: RawCoverageFilenamesReader(StringRef Data, std::vector &Filenames) : RawCoverageReader(Data), Filenames(Filenames) {} - std::error_code read(); + Error read(); +}; + +/// \brief Checks if the given coverage mapping data is exported for +/// an unused function. +class RawCoverageMappingDummyChecker : public RawCoverageReader { +public: + RawCoverageMappingDummyChecker(StringRef MappingData) + : RawCoverageReader(MappingData) {} + + Expected isDummy(); }; /// \brief Reader for the raw coverage mapping data. @@ -125,12 +135,12 @@ public: Filenames(Filenames), Expressions(Expressions), MappingRegions(MappingRegions) {} - std::error_code read(); + Error read(); private: - std::error_code decodeCounter(unsigned Value, Counter &C); - std::error_code readCounter(Counter &C); - std::error_code + Error decodeCounter(unsigned Value, Counter &C); + Error readCounter(Counter &C); + Error readMappingRegionsSubArray(std::vector &MappingRegions, unsigned InferredFileID, size_t NumFileIDs); }; @@ -170,11 +180,11 @@ private: BinaryCoverageReader() : CurrentRecord(0) {} public: - static ErrorOr> + static Expected> create(std::unique_ptr &ObjectBuffer, StringRef Arch); - std::error_code readNextRecord(CoverageMappingRecord &Record) override; + Error readNextRecord(CoverageMappingRecord &Record) override; }; } // end namespace coverage diff --git a/include/llvm/ProfileData/CoverageMappingWriter.h b/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h similarity index 97% rename from include/llvm/ProfileData/CoverageMappingWriter.h rename to include/llvm/ProfileData/Coverage/CoverageMappingWriter.h index 2e3b0378d032f705427b4c66951fa9a4ee8a7ad6..10269cc50f3539a64e1a1918eab1ab3fec956b87 100644 --- a/include/llvm/ProfileData/CoverageMappingWriter.h +++ b/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h @@ -17,7 +17,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ProfileData/CoverageMapping.h" +#include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/Support/raw_ostream.h" namespace llvm { diff --git a/include/llvm/ProfileData/InstrProf.h b/include/llvm/ProfileData/InstrProf.h index 31fcffe2ef75afdcd94b06bd240101e21ddc031f..75646b7616592470f574f1dfa52c9df939322a03 100644 --- a/include/llvm/ProfileData/InstrProf.h +++ b/include/llvm/ProfileData/InstrProf.h @@ -20,16 +20,15 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Metadata.h" #include "llvm/ProfileData/InstrProfData.inc" #include "llvm/ProfileData/ProfileCommon.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include #include -#include #include #include @@ -59,6 +58,20 @@ inline StringRef getInstrProfDataSectionName(bool AddSegment) { : INSTR_PROF_DATA_SECT_NAME_STR; } +/// Return the name of data section containing pointers to value profile +/// counters/nodes. +inline StringRef getInstrProfValuesSectionName(bool AddSegment) { + return AddSegment ? "__DATA," INSTR_PROF_VALS_SECT_NAME_STR + : INSTR_PROF_VALS_SECT_NAME_STR; +} + +/// Return the name of data section containing nodes holdling value +/// profiling data. +inline StringRef getInstrProfVNodesSectionName(bool AddSegment) { + return AddSegment ? "__DATA," INSTR_PROF_VNODES_SECT_NAME_STR + : INSTR_PROF_VNODES_SECT_NAME_STR; +} + /// Return the name profile runtime entry point to do value profiling /// for a given site. inline StringRef getInstrProfValueProfFuncName() { @@ -81,6 +94,12 @@ inline StringRef getInstrProfDataVarPrefix() { return "__profd_"; } /// Return the name prefix of profile counter variables. inline StringRef getInstrProfCountersVarPrefix() { return "__profc_"; } +/// Return the name prefix of value profile variables. +inline StringRef getInstrProfValuesVarPrefix() { return "__profvp_"; } + +/// Return the name of value profile node array variables: +inline StringRef getInstrProfVNodesVarName() { return "__llvm_prf_vnodes"; } + /// Return the name prefix of the COMDAT group for instrumentation variables /// associated with a COMDAT function. inline StringRef getInstrProfComdatPrefix() { return "__profv_"; } @@ -155,8 +174,9 @@ inline StringRef getInstrProfFileOverriderFuncName() { inline StringRef getInstrProfNameSeparator() { return "\01"; } /// Return the modified name for function \c F suitable to be -/// used the key for profile lookup. -std::string getPGOFuncName(const Function &F, +/// used the key for profile lookup. Variable \c InLTO indicates if this +/// is called in LTO optimization passes. +std::string getPGOFuncName(const Function &F, bool InLTO = false, uint64_t Version = INSTR_PROF_INDEX_VERSION); /// Return the modified name for a function suitable to be @@ -203,17 +223,17 @@ StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName, /// third field is the uncompressed strings; otherwise it is the /// compressed string. When the string compression is off, the /// second field will have value zero. -int collectPGOFuncNameStrings(const std::vector &NameStrs, - bool doCompression, std::string &Result); +Error collectPGOFuncNameStrings(const std::vector &NameStrs, + bool doCompression, std::string &Result); /// Produce \c Result string with the same format described above. The input /// is vector of PGO function name variables that are referenced. -int collectPGOFuncNameStrings(const std::vector &NameVars, - std::string &Result, bool doCompression = true); +Error collectPGOFuncNameStrings(const std::vector &NameVars, + std::string &Result, bool doCompression = true); class InstrProfSymtab; /// \c NameStrings is a string composed of one of more sub-strings encoded in /// the format described above. The substrings are seperated by 0 or more zero /// bytes. This method decodes the string and populates the \c Symtab. -int readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab); +Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab); enum InstrProfValueKind : uint32_t { #define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value, @@ -229,10 +249,9 @@ void annotateValueSite(Module &M, Instruction &Inst, const InstrProfRecord &InstrProfR, InstrProfValueKind ValueKind, uint32_t SiteIndx, uint32_t MaxMDCount = 3); -/// Same as the above interface but using the ValueData array directly, as -/// well as \p Sum. +/// Same as the above interface but using an ArrayRef, as well as \p Sum. void annotateValueSite(Module &M, Instruction &Inst, - const InstrProfValueData VD[], uint32_t NV, + ArrayRef VDs, uint64_t Sum, InstrProfValueKind ValueKind, uint32_t MaxMDCount); @@ -245,6 +264,16 @@ bool getValueProfDataFromInst(const Instruction &Inst, InstrProfValueData ValueData[], uint32_t &ActualNumValueData, uint64_t &TotalC); +inline StringRef getPGOFuncNameMetadataName() { return "PGOFuncName"; } + +/// Return the PGOFuncName meta data associated with a function. +MDNode *getPGOFuncNameMetadata(const Function &F); + +/// Create the PGOFuncName meta data if PGOFuncName is different from +/// function's raw name. This should only apply to internal linkage functions +/// declared by users only. +void createPGOFuncNameMetadata(Function &F, StringRef PGOFuncName); + const std::error_category &instrprof_category(); enum class instrprof_error { @@ -262,22 +291,105 @@ enum class instrprof_error { hash_mismatch, count_mismatch, counter_overflow, - value_site_count_mismatch + value_site_count_mismatch, + compress_failed, + uncompress_failed }; inline std::error_code make_error_code(instrprof_error E) { return std::error_code(static_cast(E), instrprof_category()); } -inline instrprof_error MergeResult(instrprof_error &Accumulator, - instrprof_error Result) { - // Prefer first error encountered as later errors may be secondary effects of - // the initial problem. - if (Accumulator == instrprof_error::success && - Result != instrprof_error::success) - Accumulator = Result; - return Accumulator; -} +class InstrProfError : public ErrorInfo { +public: + InstrProfError(instrprof_error Err) : Err(Err) { + assert(Err != instrprof_error::success && "Not an error"); + } + + std::string message() const override; + + void log(raw_ostream &OS) const override { OS << message(); } + + std::error_code convertToErrorCode() const override { + return make_error_code(Err); + } + + instrprof_error get() const { return Err; } + + /// Consume an Error and return the raw enum value contained within it. The + /// Error must either be a success value, or contain a single InstrProfError. + static instrprof_error take(Error E) { + auto Err = instrprof_error::success; + handleAllErrors(std::move(E), [&Err](const InstrProfError &IPE) { + assert(Err == instrprof_error::success && "Multiple errors encountered"); + Err = IPE.get(); + }); + return Err; + } + + static char ID; + +private: + instrprof_error Err; +}; + +class SoftInstrProfErrors { + /// Count the number of soft instrprof_errors encountered and keep track of + /// the first such error for reporting purposes. + + /// The first soft error encountered. + instrprof_error FirstError; + + /// The number of hash mismatches. + unsigned NumHashMismatches; + + /// The number of count mismatches. + unsigned NumCountMismatches; + + /// The number of counter overflows. + unsigned NumCounterOverflows; + + /// The number of value site count mismatches. + unsigned NumValueSiteCountMismatches; + +public: + SoftInstrProfErrors() + : FirstError(instrprof_error::success), NumHashMismatches(0), + NumCountMismatches(0), NumCounterOverflows(0), + NumValueSiteCountMismatches(0) {} + + ~SoftInstrProfErrors() { + assert(FirstError == instrprof_error::success && + "Unchecked soft error encountered"); + } + + /// Track a soft error (\p IE) and increment its associated counter. + void addError(instrprof_error IE); + + /// Get the number of hash mismatches. + unsigned getNumHashMismatches() const { return NumHashMismatches; } + + /// Get the number of count mismatches. + unsigned getNumCountMismatches() const { return NumCountMismatches; } + + /// Get the number of counter overflows. + unsigned getNumCounterOverflows() const { return NumCounterOverflows; } + + /// Get the number of value site count mismatches. + unsigned getNumValueSiteCountMismatches() const { + return NumValueSiteCountMismatches; + } + + /// Return the first encountered error and reset FirstError to a success + /// value. + Error takeError() { + if (FirstError == instrprof_error::success) + return Error::success(); + auto E = make_error(FirstError); + FirstError = instrprof_error::success; + return E; + } +}; namespace object { class SectionRef; @@ -303,13 +415,17 @@ private: StringSet<> NameTab; // A map from MD5 keys to function name strings. std::vector> MD5NameMap; + // A map from MD5 keys to function define. We only populate this map + // when build the Symtab from a Module. + std::vector> MD5FuncMap; // A map from function runtime address to function name MD5 hash. // This map is only populated and used by raw instr profile reader. AddrHashMap AddrToMD5Map; public: InstrProfSymtab() - : Data(), Address(0), NameTab(), MD5NameMap(), AddrToMD5Map() {} + : Data(), Address(0), NameTab(), MD5NameMap(), MD5FuncMap(), + AddrToMD5Map() {} /// Create InstrProfSymtab from an object file section which /// contains function PGO names. When section may contain raw @@ -317,18 +433,19 @@ public: /// only initialize the symtab with reference to the data and /// the section base address. The decompression will be delayed /// until before it is used. See also \c create(StringRef) method. - std::error_code create(object::SectionRef &Section); + Error create(object::SectionRef &Section); /// This interface is used by reader of CoverageMapping test /// format. - inline std::error_code create(StringRef D, uint64_t BaseAddr); + inline Error create(StringRef D, uint64_t BaseAddr); /// \c NameStrings is a string composed of one of more sub-strings /// encoded in the format described in \c collectPGOFuncNameStrings. /// This method is a wrapper to \c readPGOFuncNameStrings method. - inline std::error_code create(StringRef NameStrings); + inline Error create(StringRef NameStrings); /// A wrapper interface to populate the PGO symtab with functions /// decls from module \c M. This interface is used by transformation - /// passes such as indirect function call promotion. - void create(const Module &M); + /// passes such as indirect function call promotion. Variable \c InLTO + /// indicates if this is called from LTO optimization passes. + void create(Module &M, bool InLTO = false); /// Create InstrProfSymtab from a set of names iteratable from /// \p IterRange. This interface is used by IndexedProfReader. template void create(const NameIterRange &IterRange); @@ -358,6 +475,8 @@ public: /// Return function's PGO name from the name's md5 hash value. /// If not found, return an empty string. inline StringRef getFuncName(uint64_t FuncMD5Hash); + /// Return function from the name's md5 hash. Return nullptr if not found. + inline Function *getFunction(uint64_t FuncMD5Hash); /// Return the function's original assembly name by stripping off /// the prefix attached (to symbols with priviate linkage). For /// global functions, it returns the same string as getFuncName. @@ -366,16 +485,14 @@ public: inline StringRef getNameData() const { return Data; } }; -std::error_code InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) { +Error InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) { Data = D; Address = BaseAddr; - return std::error_code(); + return Error::success(); } -std::error_code InstrProfSymtab::create(StringRef NameStrings) { - if (readPGOFuncNameStrings(NameStrings, *this)) - return make_error_code(instrprof_error::malformed); - return std::error_code(); +Error InstrProfSymtab::create(StringRef NameStrings) { + return readPGOFuncNameStrings(NameStrings, *this); } template @@ -388,6 +505,7 @@ void InstrProfSymtab::create(const NameIterRange &IterRange) { void InstrProfSymtab::finalizeSymtab() { std::sort(MD5NameMap.begin(), MD5NameMap.end(), less_first()); + std::sort(MD5FuncMap.begin(), MD5FuncMap.end(), less_first()); std::sort(AddrToMD5Map.begin(), AddrToMD5Map.end(), less_first()); AddrToMD5Map.erase(std::unique(AddrToMD5Map.begin(), AddrToMD5Map.end()), AddrToMD5Map.end()); @@ -403,6 +521,16 @@ StringRef InstrProfSymtab::getFuncName(uint64_t FuncMD5Hash) { return StringRef(); } +Function* InstrProfSymtab::getFunction(uint64_t FuncMD5Hash) { + auto Result = + std::lower_bound(MD5FuncMap.begin(), MD5FuncMap.end(), FuncMD5Hash, + [](const std::pair &LHS, + uint64_t RHS) { return LHS.first < RHS; }); + if (Result != MD5FuncMap.end() && Result->first == FuncMD5Hash) + return Result->second; + return nullptr; +} + // See also getPGOFuncName implementation. These two need to be // matched. StringRef InstrProfSymtab::getOrigFuncName(uint64_t FuncMD5Hash) { @@ -434,19 +562,21 @@ struct InstrProfValueSiteRecord { /// Merge data from another InstrProfValueSiteRecord /// Optionally scale merged counts by \p Weight. - instrprof_error merge(InstrProfValueSiteRecord &Input, uint64_t Weight = 1); + void merge(SoftInstrProfErrors &SIPE, InstrProfValueSiteRecord &Input, + uint64_t Weight = 1); /// Scale up value profile data counts. - instrprof_error scale(uint64_t Weight); + void scale(SoftInstrProfErrors &SIPE, uint64_t Weight); }; /// Profiling information for a single function. struct InstrProfRecord { - InstrProfRecord() {} + InstrProfRecord() : SIPE() {} InstrProfRecord(StringRef Name, uint64_t Hash, std::vector Counts) - : Name(Name), Hash(Hash), Counts(std::move(Counts)) {} + : Name(Name), Hash(Hash), Counts(std::move(Counts)), SIPE() {} StringRef Name; uint64_t Hash; std::vector Counts; + SoftInstrProfErrors SIPE; typedef std::vector> ValueMapType; @@ -481,11 +611,11 @@ struct InstrProfRecord { /// Merge the counts in \p Other into this one. /// Optionally scale merged counts by \p Weight. - instrprof_error merge(InstrProfRecord &Other, uint64_t Weight = 1); + void merge(InstrProfRecord &Other, uint64_t Weight = 1); /// Scale up profile counts (including value profile data) by /// \p Weight. - instrprof_error scale(uint64_t Weight); + void scale(uint64_t Weight); /// Sort value profile data (per site) by count. void sortValueData() { @@ -502,6 +632,9 @@ struct InstrProfRecord { getValueSitesForKind(Kind).clear(); } + /// Get the error contained within the record's soft error counter. + Error takeError() { return SIPE.takeError(); } + private: std::vector IndirectCallSites; const std::vector & @@ -528,10 +661,10 @@ private: // Merge Value Profile data from Src record to this record for ValueKind. // Scale merged value counts by \p Weight. - instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src, - uint64_t Weight); + void mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src, + uint64_t Weight); // Scale up value profile data count. - instrprof_error scaleValueProfData(uint32_t ValueKind, uint64_t Weight); + void scaleValueProfData(uint32_t ValueKind, uint64_t Weight); }; uint32_t InstrProfRecord::getNumValueKinds() const { @@ -616,27 +749,6 @@ void InstrProfValueSiteRecord::sortByCount() { ValueData.resize(max_s); } -/* -* Initialize the record for runtime value profile data. -* Return 0 if the initialization is successful, otherwise -* return 1. -*/ -int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord, - const uint16_t *NumValueSites, - ValueProfNode **Nodes); - -/* Release memory allocated for the runtime record. */ -void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord); - -/* Return the size of ValueProfData structure that can be used to store - the value profile data collected at runtime. */ -uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record); - -/* Return a ValueProfData instance that stores the data collected at runtime. */ -ValueProfData * -serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, - ValueProfData *Dst); - namespace IndexedInstrProf { enum class HashT : uint32_t { @@ -782,6 +894,8 @@ namespace RawInstrProf { // struct has more fields to describe value profile information. // Version 3: Compressed name section support. Function PGO name reference // from control data struct is changed from raw pointer to Name's MD5 value. +// Version 4: ValueDataBegin and ValueDataSizes fields are removed from the +// raw header. const uint64_t Version = INSTR_PROF_RAW_VERSION; template inline uint64_t getMagic(); @@ -816,9 +930,4 @@ struct Header { } // end namespace llvm -namespace std { -template <> -struct is_error_code_enum : std::true_type {}; -} - #endif // LLVM_PROFILEDATA_INSTRPROF_H diff --git a/include/llvm/ProfileData/InstrProfData.inc b/include/llvm/ProfileData/InstrProfData.inc index b092c3bbe6683c8520918721b3fa0f85dad7263d..4138e18fa22f96243cc83203f7a395c91fdd2ea4 100644 --- a/include/llvm/ProfileData/InstrProfData.inc +++ b/include/llvm/ProfileData/InstrProfData.inc @@ -57,6 +57,12 @@ * \*===----------------------------------------------------------------------===*/ +/* Functions marked with INSTR_PROF_VISIBILITY must have hidden visibility in + * the compiler runtime. */ +#ifndef INSTR_PROF_VISIBILITY +#define INSTR_PROF_VISIBILITY +#endif + /* INSTR_PROF_DATA start. */ /* Definition of member fields of the per-function control structure. */ #ifndef INSTR_PROF_DATA @@ -66,7 +72,7 @@ #endif INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), NameRef, \ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ - IndexedInstrProf::ComputeHash(getPGOFuncNameVarInitializer(Inc->getName())))) + IndexedInstrProf::ComputeHash(getPGOFuncNameVarInitializer(Inc->getName())))) INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ Inc->getHash()->getZExtValue())) @@ -80,7 +86,7 @@ INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \ INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \ FunctionAddr) INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \ - ConstantPointerNull::get(Int8PtrTy)) + ValuesPtrExpr) INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \ ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters)) INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \ @@ -88,6 +94,33 @@ INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \ #undef INSTR_PROF_DATA /* INSTR_PROF_DATA end. */ + +/* This is an internal data structure used by value profiler. It + * is defined here to allow serialization code sharing by LLVM + * to be used in unit test. + * + * typedef struct ValueProfNode { + * // InstrProfValueData VData; + * uint64_t Value; + * uint64_t Count; + * struct ValueProfNode *Next; + * } ValueProfNode; + */ +/* INSTR_PROF_VALUE_NODE start. */ +#ifndef INSTR_PROF_VALUE_NODE +#define INSTR_PROF_VALUE_NODE(Type, LLVMType, Name, Initializer) +#else +#define INSTR_PROF_DATA_DEFINED +#endif +INSTR_PROF_VALUE_NODE(uint64_t, llvm::Type::getInt64Ty(Ctx), Value, \ + ConstantInt::get(llvm::Type::GetInt64Ty(Ctx), 0)) +INSTR_PROF_VALUE_NODE(uint64_t, llvm::Type::getInt64Ty(Ctx), Count, \ + ConstantInt::get(llvm::Type::GetInt64Ty(Ctx), 0)) +INSTR_PROF_VALUE_NODE(PtrToNodeT, llvm::Type::getInt8PtrTy(Ctx), Next, \ + ConstantInt::get(llvm::Type::GetInt8PtrTy(Ctx), 0)) +#undef INSTR_PROF_VALUE_NODE +/* INSTR_PROF_VALUE_NODE end. */ + /* INSTR_PROF_RAW_HEADER start */ /* Definition of member fields of the raw profile header data structure. */ #ifndef INSTR_PROF_RAW_HEADER @@ -103,8 +136,6 @@ INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize) INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin) INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin) INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last) -INSTR_PROF_RAW_HEADER(uint64_t, ValueDataSize, ValueDataSize) -INSTR_PROF_RAW_HEADER(uint64_t, ValueDataDelta, (uintptr_t)ValueDataBegin) #undef INSTR_PROF_RAW_HEADER /* INSTR_PROF_RAW_HEADER end */ @@ -173,7 +204,7 @@ COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \ #else COVMAP_FUNC_RECORD(const int64_t, llvm::Type::getInt64Ty(Ctx), NameRef, \ llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ - llvm::IndexedInstrProf::ComputeHash(NameValue))) + llvm::IndexedInstrProf::ComputeHash(NameValue))) #endif COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), DataSize, \ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\ @@ -297,16 +328,15 @@ typedef struct ValueProfData { static std::unique_ptr serializeFrom(const InstrProfRecord &Record); /*! - * Check the integrity of the record. Return the error code when - * an error is detected, otherwise return instrprof_error::success. + * Check the integrity of the record. */ - instrprof_error checkIntegrity(); + Error checkIntegrity(); /*! * Return a pointer to \c ValueProfileData instance ready to be read. * All data in the instance are properly byte swapped. The input * data is assumed to be in little endian order. */ - static ErrorOr> + static Expected> getValueProfData(const unsigned char *SrcBuffer, const unsigned char *const SrcBufferEnd, support::endianness SrcDataEndianness); @@ -363,45 +393,14 @@ typedef struct ValueProfRecordClosure { ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes); } ValueProfRecordClosure; -/* - * A wrapper struct that represents value profile runtime data. - * Like InstrProfRecord class which is used by profiling host tools, - * ValueProfRuntimeRecord also implements the abstract intefaces defined in - * ValueProfRecordClosure so that the runtime data can be serialized using - * shared C implementation. In this structure, NumValueSites and Nodes - * members are the primary fields while other fields hold the derived - * information for fast implementation of closure interfaces. - */ -typedef struct ValueProfRuntimeRecord { - /* Number of sites for each value profile kind. */ - const uint16_t *NumValueSites; - /* An array of linked-list headers. The size of of the array is the - * total number of value profile sites : sum(NumValueSites[*])). Each - * linked-list stores the values profiled for a value profile site. */ - ValueProfNode **Nodes; - - /* Total number of value profile kinds which have at least one - * value profile sites. */ - uint32_t NumValueKinds; - /* An array recording the number of values tracked at each site. - * The size of the array is TotalNumValueSites. */ - uint8_t *SiteCountArray[IPVK_Last + 1]; - ValueProfNode **NodesKind[IPVK_Last + 1]; -} ValueProfRuntimeRecord; - -/* Forward declarations of C interfaces. */ -int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord, - const uint16_t *NumValueSites, - ValueProfNode **Nodes); -void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord); -uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record); -ValueProfData * -serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, - ValueProfData *Dst); -uint32_t getNumValueKindsRT(const void *R); -ValueProfRecord *getFirstValueProfRecord(ValueProfData *VPD); -ValueProfRecord *getValueProfRecordNext(ValueProfRecord *VPR); -InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *VPR); +INSTR_PROF_VISIBILITY ValueProfRecord * +getFirstValueProfRecord(ValueProfData *VPD); +INSTR_PROF_VISIBILITY ValueProfRecord * +getValueProfRecordNext(ValueProfRecord *VPR); +INSTR_PROF_VISIBILITY InstrProfValueData * +getValueProfRecordValueData(ValueProfRecord *VPR); +INSTR_PROF_VISIBILITY uint32_t +getValueProfRecordHeaderSize(uint32_t NumValueSites); #undef INSTR_PROF_VALUE_PROF_DATA #endif /* INSTR_PROF_VALUE_PROF_DATA */ @@ -425,7 +424,7 @@ InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *VPR); * \brief Return the \c ValueProfRecord header size including the * padding bytes. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) { uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) + sizeof(uint8_t) * NumValueSites; @@ -438,7 +437,7 @@ uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) { * \brief Return the total size of the value profile record including the * header and the value data. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordSize(uint32_t NumValueSites, uint32_t NumValueData) { return getValueProfRecordHeaderSize(NumValueSites) + @@ -448,7 +447,7 @@ uint32_t getValueProfRecordSize(uint32_t NumValueSites, /*! * \brief Return the pointer to the start of value data array. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) { return (InstrProfValueData *)((char *)This + getValueProfRecordHeaderSize( This->NumValueSites)); @@ -457,7 +456,7 @@ InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) { /*! * \brief Return the total number of value data for \c This record. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) { uint32_t NumValueData = 0; uint32_t I; @@ -469,7 +468,7 @@ uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) { /*! * \brief Use this method to advance to the next \c This \c ValueProfRecord. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) { uint32_t NumValueData = getValueProfRecordNumValueData(This); return (ValueProfRecord *)((char *)This + @@ -480,7 +479,7 @@ ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) { /*! * \brief Return the first \c ValueProfRecord instance. */ -INSTR_PROF_INLINE +INSTR_PROF_VISIBILITY INSTR_PROF_INLINE ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) { return (ValueProfRecord *)((char *)This + sizeof(ValueProfData)); } @@ -491,13 +490,11 @@ ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) { * Return the total size in bytes of the on-disk value profile data * given the data stored in Record. */ -uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) { +INSTR_PROF_VISIBILITY uint32_t +getValueProfDataSize(ValueProfRecordClosure *Closure) { uint32_t Kind; uint32_t TotalSize = sizeof(ValueProfData); const void *Record = Closure->Record; - uint32_t NumValueKinds = Closure->GetNumValueKinds(Record); - if (NumValueKinds == 0) - return TotalSize; for (Kind = IPVK_First; Kind <= IPVK_Last; Kind++) { uint32_t NumValueSites = Closure->GetNumValueSites(Record, Kind); @@ -513,9 +510,10 @@ uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) { * Extract value profile data of a function for the profile kind \c ValueKind * from the \c Closure and serialize the data into \c This record instance. */ -void serializeValueProfRecordFrom(ValueProfRecord *This, - ValueProfRecordClosure *Closure, - uint32_t ValueKind, uint32_t NumValueSites) { +INSTR_PROF_VISIBILITY void +serializeValueProfRecordFrom(ValueProfRecord *This, + ValueProfRecordClosure *Closure, + uint32_t ValueKind, uint32_t NumValueSites) { uint32_t S; const void *Record = Closure->Record; This->Kind = ValueKind; @@ -533,12 +531,16 @@ void serializeValueProfRecordFrom(ValueProfRecord *This, /*! * Extract value profile data of a function from the \c Closure * and serialize the data into \c DstData if it is not NULL or heap - * memory allocated by the \c Closure's allocator method. + * memory allocated by the \c Closure's allocator method. If \c + * DstData is not null, the caller is expected to set the TotalSize + * in DstData. */ -ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure, - ValueProfData *DstData) { +INSTR_PROF_VISIBILITY ValueProfData * +serializeValueProfDataFrom(ValueProfRecordClosure *Closure, + ValueProfData *DstData) { uint32_t Kind; - uint32_t TotalSize = getValueProfDataSize(Closure); + uint32_t TotalSize = + DstData ? DstData->TotalSize : getValueProfDataSize(Closure); ValueProfData *VPD = DstData ? DstData : Closure->AllocValueProfData(TotalSize); @@ -556,130 +558,6 @@ ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure, return VPD; } -/* - * The value profiler runtime library stores the value profile data - * for a given function in \c NumValueSites and \c Nodes structures. - * \c ValueProfRuntimeRecord class is used to encapsulate the runtime - * profile data and provides fast interfaces to retrieve the profile - * information. This interface is used to initialize the runtime record - * and pre-compute the information needed for efficient implementation - * of callbacks required by ValueProfRecordClosure class. - */ -int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord, - const uint16_t *NumValueSites, - ValueProfNode **Nodes) { - unsigned I, J, S = 0, NumValueKinds = 0; - RuntimeRecord->NumValueSites = NumValueSites; - RuntimeRecord->Nodes = Nodes; - for (I = 0; I <= IPVK_Last; I++) { - uint16_t N = NumValueSites[I]; - if (!N) { - RuntimeRecord->SiteCountArray[I] = INSTR_PROF_NULLPTR; - continue; - } - NumValueKinds++; - RuntimeRecord->SiteCountArray[I] = (uint8_t *)calloc(N, 1); - if (!RuntimeRecord->SiteCountArray[I]) - return 1; - RuntimeRecord->NodesKind[I] = Nodes ? &Nodes[S] : INSTR_PROF_NULLPTR; - for (J = 0; J < N; J++) { - /* Compute value count for each site. */ - uint32_t C = 0; - ValueProfNode *Site = - Nodes ? RuntimeRecord->NodesKind[I][J] : INSTR_PROF_NULLPTR; - while (Site) { - C++; - Site = Site->Next; - } - if (C > UCHAR_MAX) - C = UCHAR_MAX; - RuntimeRecord->SiteCountArray[I][J] = C; - } - S += N; - } - RuntimeRecord->NumValueKinds = NumValueKinds; - return 0; -} - -void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord) { - unsigned I; - for (I = 0; I <= IPVK_Last; I++) { - if (RuntimeRecord->SiteCountArray[I]) - free(RuntimeRecord->SiteCountArray[I]); - } -} - -/* ValueProfRecordClosure Interface implementation for - * ValueProfDataRuntimeRecord. */ -uint32_t getNumValueKindsRT(const void *R) { - return ((const ValueProfRuntimeRecord *)R)->NumValueKinds; -} - -uint32_t getNumValueSitesRT(const void *R, uint32_t VK) { - return ((const ValueProfRuntimeRecord *)R)->NumValueSites[VK]; -} - -uint32_t getNumValueDataForSiteRT(const void *R, uint32_t VK, uint32_t S) { - const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; - return Record->SiteCountArray[VK][S]; -} - -uint32_t getNumValueDataRT(const void *R, uint32_t VK) { - unsigned I, S = 0; - const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; - if (Record->SiteCountArray[VK] == INSTR_PROF_NULLPTR) - return 0; - for (I = 0; I < Record->NumValueSites[VK]; I++) - S += Record->SiteCountArray[VK][I]; - return S; -} - -void getValueForSiteRT(const void *R, InstrProfValueData *Dst, uint32_t VK, - uint32_t S) { - unsigned I, N = 0; - const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R; - N = getNumValueDataForSiteRT(R, VK, S); - if (N == 0) - return; - ValueProfNode *VNode = Record->NodesKind[VK][S]; - for (I = 0; I < N; I++) { - Dst[I] = VNode->VData; - VNode = VNode->Next; - } -} - -ValueProfData *allocValueProfDataRT(size_t TotalSizeInBytes) { - return (ValueProfData *)calloc(TotalSizeInBytes, 1); -} - -static ValueProfRecordClosure RTRecordClosure = { - INSTR_PROF_NULLPTR, getNumValueKindsRT, getNumValueSitesRT, - getNumValueDataRT, getNumValueDataForSiteRT, INSTR_PROF_NULLPTR, - getValueForSiteRT, allocValueProfDataRT}; - -/* - * Return the size of ValueProfData structure to store data - * recorded in the runtime record. - */ -uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record) { - RTRecordClosure.Record = Record; - return getValueProfDataSize(&RTRecordClosure); -} - -/* - * Return a ValueProfData instance that stores the data collected - * from runtime. If \c DstData is provided by the caller, the value - * profile data will be store in *DstData and DstData is returned, - * otherwise the method will allocate space for the value data and - * return pointer to the newly allocated space. - */ -ValueProfData * -serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, - ValueProfData *DstData) { - RTRecordClosure.Record = Record; - return serializeValueProfDataFrom(&RTRecordClosure, DstData); -} - #undef INSTR_PROF_COMMON_API_IMPL #endif /* INSTR_PROF_COMMON_API_IMPL */ @@ -711,7 +589,7 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, (uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129 /* Raw profile format version (start from 1). */ -#define INSTR_PROF_RAW_VERSION 3 +#define INSTR_PROF_RAW_VERSION 4 /* Indexed profile format version (start from 1). */ #define INSTR_PROF_INDEX_VERSION 4 /* Coverage mapping format vresion (start from 0). */ @@ -731,6 +609,12 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, #define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data #define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names #define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts +/* Array of pointers. Each pointer points to a list + * of value nodes associated with one value site. + */ +#define INSTR_PROF_VALS_SECT_NAME __llvm_prf_vals +/* Value profile nodes section. */ +#define INSTR_PROF_VNODES_SECT_NAME __llvm_prf_vnds #define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap #define INSTR_PROF_DATA_SECT_NAME_STR \ @@ -741,6 +625,10 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record, INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME) #define INSTR_PROF_COVMAP_SECT_NAME_STR \ INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME) +#define INSTR_PROF_VALS_SECT_NAME_STR \ + INSTR_PROF_QUOTE(INSTR_PROF_VALS_SECT_NAME) +#define INSTR_PROF_VNODES_SECT_NAME_STR \ + INSTR_PROF_QUOTE(INSTR_PROF_VNODES_SECT_NAME) /* Macros to define start/stop section symbol for a given * section on Linux. For instance @@ -770,15 +658,6 @@ typedef struct InstrProfValueData { uint64_t Count; } InstrProfValueData; -/* This is an internal data structure used by value profiler. It - * is defined here to allow serialization code sharing by LLVM - * to be used in unit test. - */ -typedef struct ValueProfNode { - InstrProfValueData VData; - struct ValueProfNode *Next; -} ValueProfNode; - #endif /* INSTR_PROF_DATA_INC */ #else diff --git a/include/llvm/ProfileData/InstrProfReader.h b/include/llvm/ProfileData/InstrProfReader.h index 74610f7ff558b3ce193cfdefbdb2f46d5163c478..65b11f61d10bc36bb87d07533f89102d76597283 100644 --- a/include/llvm/ProfileData/InstrProfReader.h +++ b/include/llvm/ProfileData/InstrProfReader.h @@ -19,7 +19,6 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/EndianStream.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/OnDiskHashTable.h" @@ -51,16 +50,16 @@ public: /// Base class and interface for reading profiling data of any known instrprof /// format. Provides an iterator over InstrProfRecords. class InstrProfReader { - std::error_code LastError; + instrprof_error LastError; public: InstrProfReader() : LastError(instrprof_error::success), Symtab() {} virtual ~InstrProfReader() {} /// Read the header. Required before reading first record. - virtual std::error_code readHeader() = 0; + virtual Error readHeader() = 0; /// Read a single record. - virtual std::error_code readNextRecord(InstrProfRecord &Record) = 0; + virtual Error readNextRecord(InstrProfRecord &Record) = 0; /// Iterator over profile data. InstrProfIterator begin() { return InstrProfIterator(this); } InstrProfIterator end() { return InstrProfIterator(); } @@ -80,28 +79,35 @@ public: protected: std::unique_ptr Symtab; - /// Set the current std::error_code and return same. - std::error_code error(std::error_code EC) { - LastError = EC; - return EC; + /// Set the current error and return same. + Error error(instrprof_error Err) { + LastError = Err; + if (Err == instrprof_error::success) + return Error::success(); + return make_error(Err); } + Error error(Error E) { return error(InstrProfError::take(std::move(E))); } - /// Clear the current error code and return a successful one. - std::error_code success() { return error(instrprof_error::success); } + /// Clear the current error and return a successful one. + Error success() { return error(instrprof_error::success); } public: /// Return true if the reader has finished reading the profile data. bool isEOF() { return LastError == instrprof_error::eof; } /// Return true if the reader encountered an error reading profiling data. - bool hasError() { return LastError && !isEOF(); } - /// Get the current error code. - std::error_code getError() { return LastError; } + bool hasError() { return LastError != instrprof_error::success && !isEOF(); } + /// Get the current error. + Error getError() { + if (hasError()) + return make_error(LastError); + return Error::success(); + } /// Factory method to create an appropriately typed reader for the given /// instrprof file. - static ErrorOr> create(std::string Path); + static Expected> create(const Twine &Path); - static ErrorOr> + static Expected> create(std::unique_ptr Buffer); }; @@ -123,7 +129,7 @@ private: TextInstrProfReader(const TextInstrProfReader &) = delete; TextInstrProfReader &operator=(const TextInstrProfReader &) = delete; - std::error_code readValueProfileData(InstrProfRecord &Record); + Error readValueProfileData(InstrProfRecord &Record); public: TextInstrProfReader(std::unique_ptr DataBuffer_) @@ -136,9 +142,9 @@ public: bool isIRLevelProfile() const override { return IsIRLevelProfile; } /// Read the header. - std::error_code readHeader() override; + Error readHeader() override; /// Read a single record. - std::error_code readNextRecord(InstrProfRecord &Record) override; + Error readNextRecord(InstrProfRecord &Record) override; InstrProfSymtab &getSymtab() override { assert(Symtab.get()); @@ -170,8 +176,9 @@ private: const uint64_t *CountersStart; const char *NamesStart; uint64_t NamesSize; + // After value profile is all read, this pointer points to + // the header of next profile data (if exists) const uint8_t *ValueDataStart; - const char *ProfileEnd; uint32_t ValueKindLast; uint32_t CurValueDataSize; @@ -184,8 +191,8 @@ public: : DataBuffer(std::move(DataBuffer)) { } static bool hasFormat(const MemoryBuffer &DataBuffer); - std::error_code readHeader() override; - std::error_code readNextRecord(InstrProfRecord &Record) override; + Error readHeader() override; + Error readNextRecord(InstrProfRecord &Record) override; bool isIRLevelProfile() const override { return (Version & VARIANT_MASK_IR_PROF) != 0; } @@ -196,9 +203,9 @@ public: } private: - void createSymtab(InstrProfSymtab &Symtab); - std::error_code readNextHeader(const char *CurrentPos); - std::error_code readHeader(const RawInstrProf::Header &Header); + Error createSymtab(InstrProfSymtab &Symtab); + Error readNextHeader(const char *CurrentPos); + Error readHeader(const RawInstrProf::Header &Header); template IntT swap(IntT Int) const { return ShouldSwapBytes ? sys::getSwappedBytes(Int) : Int; } @@ -215,15 +222,19 @@ private: inline uint8_t getNumPaddingBytes(uint64_t SizeInBytes) { return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t)); } - std::error_code readName(InstrProfRecord &Record); - std::error_code readFuncHash(InstrProfRecord &Record); - std::error_code readRawCounts(InstrProfRecord &Record); - std::error_code readValueProfilingData(InstrProfRecord &Record); + Error readName(InstrProfRecord &Record); + Error readFuncHash(InstrProfRecord &Record); + Error readRawCounts(InstrProfRecord &Record); + Error readValueProfilingData(InstrProfRecord &Record); bool atEnd() const { return Data == DataEnd; } void advanceData() { Data++; ValueDataStart += CurValueDataSize; } + const char *getNextHeaderPos() const { + assert(atEnd()); + return (const char *)ValueDataStart; + } const uint64_t *getCounter(IntPtrT CounterPtr) const { ptrdiff_t Offset = (swap(CounterPtr) - CountersDelta) / sizeof(uint64_t); @@ -295,9 +306,9 @@ public: struct InstrProfReaderIndexBase { // Read all the profile records with the same key pointed to the current // iterator. - virtual std::error_code getRecords(ArrayRef &Data) = 0; + virtual Error getRecords(ArrayRef &Data) = 0; // Read all the profile records with the key equal to FuncName - virtual std::error_code getRecords(StringRef FuncName, + virtual Error getRecords(StringRef FuncName, ArrayRef &Data) = 0; virtual void advanceToNextKey() = 0; virtual bool atEnd() const = 0; @@ -325,9 +336,9 @@ public: const unsigned char *const Base, IndexedInstrProf::HashT HashType, uint64_t Version); - std::error_code getRecords(ArrayRef &Data) override; - std::error_code getRecords(StringRef FuncName, - ArrayRef &Data) override; + Error getRecords(ArrayRef &Data) override; + Error getRecords(StringRef FuncName, + ArrayRef &Data) override; void advanceToNextKey() override { RecordIterator++; } bool atEnd() const override { return RecordIterator == HashTable->data_end(); @@ -353,7 +364,7 @@ private: /// The index into the profile data. std::unique_ptr Index; /// Profile summary data. - std::unique_ptr Summary; + std::unique_ptr Summary; IndexedInstrProfReader(const IndexedInstrProfReader &) = delete; IndexedInstrProfReader &operator=(const IndexedInstrProfReader &) = delete; @@ -374,27 +385,27 @@ public: static bool hasFormat(const MemoryBuffer &DataBuffer); /// Read the file header. - std::error_code readHeader() override; + Error readHeader() override; /// Read a single record. - std::error_code readNextRecord(InstrProfRecord &Record) override; + Error readNextRecord(InstrProfRecord &Record) override; /// Return the pointer to InstrProfRecord associated with FuncName /// and FuncHash - ErrorOr getInstrProfRecord(StringRef FuncName, - uint64_t FuncHash); + Expected getInstrProfRecord(StringRef FuncName, + uint64_t FuncHash); /// Fill Counts with the profile data for the given function name. - std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash, - std::vector &Counts); + Error getFunctionCounts(StringRef FuncName, uint64_t FuncHash, + std::vector &Counts); /// Return the maximum of all known function counts. uint64_t getMaximumFunctionCount() { return Summary->getMaxFunctionCount(); } /// Factory method to create an indexed reader. - static ErrorOr> - create(std::string Path); + static Expected> + create(const Twine &Path); - static ErrorOr> + static Expected> create(std::unique_ptr Buffer); // Used for testing purpose only. @@ -406,7 +417,7 @@ public: // to be used by llvm-profdata (for dumping). Avoid using this when // the client is the compiler. InstrProfSymtab &getSymtab() override; - InstrProfSummary &getSummary() { return *(Summary.get()); } + ProfileSummary &getSummary() { return *(Summary.get()); } }; } // end namespace llvm diff --git a/include/llvm/ProfileData/InstrProfWriter.h b/include/llvm/ProfileData/InstrProfWriter.h index 8b02d3cc9ed31e66715a37bd86eb3303c80d262b..7d292731cccb833f796bccc64ebb29c568e5f704 100644 --- a/include/llvm/ProfileData/InstrProfWriter.h +++ b/include/llvm/ProfileData/InstrProfWriter.h @@ -46,7 +46,7 @@ public: /// Add function counts for the given function. If there are already counts /// for this function and the hash and number of counts match, each counter is /// summed. Optionally scale counts by \p Weight. - std::error_code addRecord(InstrProfRecord &&I, uint64_t Weight = 1); + Error addRecord(InstrProfRecord &&I, uint64_t Weight = 1); /// Write the profile to \c OS void write(raw_fd_ostream &OS); /// Write the profile in text format to \c OS @@ -58,13 +58,15 @@ public: std::unique_ptr writeBuffer(); /// Set the ProfileKind. Report error if mixing FE and IR level profiles. - std::error_code setIsIRLevelProfile(bool IsIRLevel) { + Error setIsIRLevelProfile(bool IsIRLevel) { if (ProfileKind == PF_Unknown) { ProfileKind = IsIRLevel ? PF_IRLevel: PF_FE; - return instrprof_error::success; + return Error::success(); } - return (IsIRLevel == (ProfileKind == PF_IRLevel)) ? - instrprof_error::success : instrprof_error::unsupported_version; + return (IsIRLevel == (ProfileKind == PF_IRLevel)) + ? Error::success() + : make_error( + instrprof_error::unsupported_version); } // Internal interface for testing purpose only. diff --git a/include/llvm/ProfileData/ProfileCommon.h b/include/llvm/ProfileData/ProfileCommon.h index c9cc756b0c6a9b5ad379ea5c7a86572a60fbfff7..ecb228ca59c471696e33ba556bef5c68cb4074f7 100644 --- a/include/llvm/ProfileData/ProfileCommon.h +++ b/include/llvm/ProfileData/ProfileCommon.h @@ -15,13 +15,15 @@ #ifndef LLVM_PROFILEDATA_PROFILE_COMMON_H #define LLVM_PROFILEDATA_PROFILE_COMMON_H -#include "llvm/ADT/APInt.h" #include #include #include +#include #include -#include "llvm/Support/Casting.h" +#include "llvm/IR/ProfileSummary.h" +#include "llvm/Support/Error.h" +#include "llvm/ADT/ArrayRef.h" namespace llvm { class Function; @@ -40,134 +42,54 @@ class MDNode; inline const char *getHotSectionPrefix() { return ".hot"; } inline const char *getUnlikelySectionPrefix() { return ".unlikely"; } -// The profile summary is one or more (Cutoff, MinCount, NumCounts) triplets. -// The semantics of counts depend on the type of profile. For instrumentation -// profile, counts are block counts and for sample profile, counts are -// per-line samples. Given a target counts percentile, we compute the minimum -// number of counts needed to reach this target and the minimum among these -// counts. -struct ProfileSummaryEntry { - uint32_t Cutoff; ///< The required percentile of counts. - uint64_t MinCount; ///< The minimum count for this percentile. - uint64_t NumCounts; ///< Number of counts >= the minimum count. - ProfileSummaryEntry(uint32_t TheCutoff, uint64_t TheMinCount, - uint64_t TheNumCounts) - : Cutoff(TheCutoff), MinCount(TheMinCount), NumCounts(TheNumCounts) {} -}; - -typedef std::vector SummaryEntryVector; - -class ProfileSummary { -public: - enum Kind { PSK_Instr, PSK_Sample }; +class ProfileSummaryBuilder { private: - const Kind PSK; - static const char *KindStr[2]; // We keep track of the number of times a count (block count or samples) // appears in the profile. The map is kept sorted in the descending order of // counts. std::map> CountFrequencies; + std::vector DetailedSummaryCutoffs; + protected: SummaryEntryVector DetailedSummary; - std::vector DetailedSummaryCutoffs; - uint64_t TotalCount, MaxCount, MaxFunctionCount; - uint32_t NumCounts, NumFunctions; - ProfileSummary(Kind K, std::vector Cutoffs) - : PSK(K), DetailedSummaryCutoffs(Cutoffs), TotalCount(0), MaxCount(0), + ProfileSummaryBuilder(std::vector Cutoffs) + : DetailedSummaryCutoffs(std::move(Cutoffs)), TotalCount(0), MaxCount(0), MaxFunctionCount(0), NumCounts(0), NumFunctions(0) {} - ProfileSummary(Kind K) - : PSK(K), TotalCount(0), MaxCount(0), MaxFunctionCount(0), NumCounts(0), - NumFunctions(0) {} - ProfileSummary(Kind K, SummaryEntryVector DetailedSummary, - uint64_t TotalCount, uint64_t MaxCount, - uint64_t MaxFunctionCount, uint32_t NumCounts, - uint32_t NumFunctions) - : PSK(K), DetailedSummary(DetailedSummary), TotalCount(TotalCount), - MaxCount(MaxCount), MaxFunctionCount(MaxFunctionCount), - NumCounts(NumCounts), NumFunctions(NumFunctions) {} - ~ProfileSummary() = default; inline void addCount(uint64_t Count); - /// \brief Return metadata specific to the profile format. - /// Derived classes implement this method to return a vector of Metadata. - virtual std::vector getFormatSpecificMD(LLVMContext &Context) = 0; - /// \brief Return detailed summary as metadata. - Metadata *getDetailedSummaryMD(LLVMContext &Context); + ~ProfileSummaryBuilder() = default; + void computeDetailedSummary(); + uint64_t TotalCount, MaxCount, MaxFunctionCount; + uint32_t NumCounts, NumFunctions; public: - static const int Scale = 1000000; - Kind getKind() const { return PSK; } - const char *getKindStr() const { return KindStr[PSK]; } - // \brief Returns true if F is a hot function. - static bool isFunctionHot(const Function *F); - // \brief Returns true if F is unlikley executed. - static bool isFunctionUnlikely(const Function *F); - inline SummaryEntryVector &getDetailedSummary(); - void computeDetailedSummary(); /// \brief A vector of useful cutoff values for detailed summary. - static const std::vector DefaultCutoffs; - /// \brief Return summary information as metadata. - Metadata *getMD(LLVMContext &Context); - /// \brief Construct profile summary from metdata. - static ProfileSummary *getFromMD(Metadata *MD); - uint32_t getNumFunctions() { return NumFunctions; } - uint64_t getMaxFunctionCount() { return MaxFunctionCount; } + static const ArrayRef DefaultCutoffs; }; -class InstrProfSummary final : public ProfileSummary { +class InstrProfSummaryBuilder final : public ProfileSummaryBuilder { uint64_t MaxInternalBlockCount; inline void addEntryCount(uint64_t Count); inline void addInternalCount(uint64_t Count); -protected: - std::vector getFormatSpecificMD(LLVMContext &Context) override; - public: - InstrProfSummary(std::vector Cutoffs) - : ProfileSummary(PSK_Instr, Cutoffs), MaxInternalBlockCount(0) {} - InstrProfSummary(const IndexedInstrProf::Summary &S); - InstrProfSummary(uint64_t TotalCount, uint64_t MaxBlockCount, - uint64_t MaxInternalBlockCount, uint64_t MaxFunctionCount, - uint32_t NumBlocks, uint32_t NumFunctions, - SummaryEntryVector Summary) - : ProfileSummary(PSK_Instr, Summary, TotalCount, MaxBlockCount, - MaxFunctionCount, NumBlocks, NumFunctions), - MaxInternalBlockCount(MaxInternalBlockCount) {} - static bool classof(const ProfileSummary *PS) { - return PS->getKind() == PSK_Instr; - } + InstrProfSummaryBuilder(std::vector Cutoffs) + : ProfileSummaryBuilder(std::move(Cutoffs)), MaxInternalBlockCount(0) {} void addRecord(const InstrProfRecord &); - uint32_t getNumBlocks() { return NumCounts; } - uint64_t getTotalCount() { return TotalCount; } - uint64_t getMaxBlockCount() { return MaxCount; } - uint64_t getMaxInternalBlockCount() { return MaxInternalBlockCount; } + std::unique_ptr getSummary(); }; -class SampleProfileSummary final : public ProfileSummary { -protected: - std::vector getFormatSpecificMD(LLVMContext &Context) override; +class SampleProfileSummaryBuilder final : public ProfileSummaryBuilder { public: - uint32_t getNumLinesWithSamples() { return NumCounts; } - uint64_t getTotalSamples() { return TotalCount; } - uint64_t getMaxSamplesPerLine() { return MaxCount; } void addRecord(const sampleprof::FunctionSamples &FS); - SampleProfileSummary(std::vector Cutoffs) - : ProfileSummary(PSK_Sample, Cutoffs) {} - SampleProfileSummary(uint64_t TotalSamples, uint64_t MaxSamplesPerLine, - uint64_t MaxFunctionCount, int32_t NumLinesWithSamples, - uint32_t NumFunctions, - SummaryEntryVector DetailedSummary) - : ProfileSummary(PSK_Sample, DetailedSummary, TotalSamples, - MaxSamplesPerLine, MaxFunctionCount, NumLinesWithSamples, - NumFunctions) {} - static bool classof(const ProfileSummary *PS) { - return PS->getKind() == PSK_Sample; - } + SampleProfileSummaryBuilder(std::vector Cutoffs) + : ProfileSummaryBuilder(std::move(Cutoffs)) {} + std::unique_ptr getSummary(); }; // This is called when a count is seen in the profile. -void ProfileSummary::addCount(uint64_t Count) { +void ProfileSummaryBuilder::addCount(uint64_t Count) { TotalCount += Count; if (Count > MaxCount) MaxCount = Count; @@ -175,11 +97,6 @@ void ProfileSummary::addCount(uint64_t Count) { CountFrequencies[Count]++; } -SummaryEntryVector &ProfileSummary::getDetailedSummary() { - if (!DetailedSummaryCutoffs.empty() && DetailedSummary.empty()) - computeDetailedSummary(); - return DetailedSummary; -} } // end namespace llvm #endif diff --git a/include/llvm/ProfileData/SampleProf.h b/include/llvm/ProfileData/SampleProf.h index d731dec1c1cb8319224629f2ee161f9eb615eeb5..9fefefa627b1d58c4c5253430ece5ab00170b1b7 100644 --- a/include/llvm/ProfileData/SampleProf.h +++ b/include/llvm/ProfileData/SampleProf.h @@ -204,8 +204,8 @@ public: } sampleprof_error addCalledTargetSamples(uint32_t LineOffset, uint32_t Discriminator, - std::string FName, uint64_t Num, - uint64_t Weight = 1) { + const std::string &FName, + uint64_t Num, uint64_t Weight = 1) { return BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget( FName, Num, Weight); } diff --git a/include/llvm/ProfileData/SampleProfReader.h b/include/llvm/ProfileData/SampleProfReader.h index 716f672fc2d2a7feada01e97d1c28a57c2dbcafa..bf86721709c7b1a785aafa84bf04b7a4ab28d92b 100644 --- a/include/llvm/ProfileData/SampleProfReader.h +++ b/include/llvm/ProfileData/SampleProfReader.h @@ -289,14 +289,14 @@ public: /// \brief Create a sample profile reader appropriate to the file format. static ErrorOr> - create(StringRef Filename, LLVMContext &C); + create(const Twine &Filename, LLVMContext &C); /// \brief Create a sample profile reader from the supplied memory buffer. static ErrorOr> create(std::unique_ptr &B, LLVMContext &C); /// \brief Return the profile summary. - SampleProfileSummary &getSummary() { return *(Summary.get()); } + ProfileSummary &getSummary() { return *(Summary.get()); } protected: /// \brief Map every function to its associated profile. @@ -313,7 +313,7 @@ protected: std::unique_ptr Buffer; /// \brief Profile summary information. - std::unique_ptr Summary; + std::unique_ptr Summary; /// \brief Compute summary for this profile. void computeSummary(); diff --git a/include/llvm/ProfileData/SampleProfWriter.h b/include/llvm/ProfileData/SampleProfWriter.h index b605d45989026293dbebe7927ce79abba85554c4..f6f2e2702e31674f57a62777fc7a29a45c1d10b3 100644 --- a/include/llvm/ProfileData/SampleProfWriter.h +++ b/include/llvm/ProfileData/SampleProfWriter.h @@ -76,7 +76,7 @@ protected: std::unique_ptr OutputStream; /// \brief Profile summary. - std::unique_ptr Summary; + std::unique_ptr Summary; /// \brief Compute summary for this profile. void computeSummary(const StringMap &ProfileMap); diff --git a/include/llvm/Support/AArch64TargetParser.def b/include/llvm/Support/AArch64TargetParser.def new file mode 100644 index 0000000000000000000000000000000000000000..67f981b8f2fadcdb3a29c06bf72db1aae3dc23e4 --- /dev/null +++ b/include/llvm/Support/AArch64TargetParser.def @@ -0,0 +1,72 @@ +//===- AARCH64TargetParser.def - AARCH64 target parsing defines ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides defines to build up the AARCH64 target parser's logic. +// +//===----------------------------------------------------------------------===// + +// NOTE: NO INCLUDE GUARD DESIRED! + +#ifndef AARCH64_ARCH +#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) +#endif +AARCH64_ARCH("armv8-a", AK_ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A, + FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_FP16 | AArch64::AEK_PROFILE)) +AARCH64_ARCH("armv8.1-a", AK_ARMV8_1A, "8.1-A", "v8.1a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_FP16 | AArch64::AEK_PROFILE)) +AARCH64_ARCH("armv8.2-a", AK_ARMV8_2A, "8.2-A", "v8.2a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_FP16 | AArch64::AEK_PROFILE | + AArch64::AEK_RAS)) +#undef AARCH64_ARCH + +#ifndef AARCH64_ARCH_EXT_NAME +#define AARCH64_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) +#endif +// FIXME: This would be nicer were it tablegen +AARCH64_ARCH_EXT_NAME("invalid", AArch64::AEK_INVALID, nullptr, nullptr) +AARCH64_ARCH_EXT_NAME("none", AArch64::AEK_NONE, nullptr, nullptr) +AARCH64_ARCH_EXT_NAME("crc", AArch64::AEK_CRC, "+crc", "-crc") +AARCH64_ARCH_EXT_NAME("crypto", AArch64::AEK_CRYPTO, "+crypto","-crypto") +AARCH64_ARCH_EXT_NAME("fp", AArch64::AEK_FP, "+fp-armv8", "-fp-armv8") +AARCH64_ARCH_EXT_NAME("simd", AArch64::AEK_SIMD, "+neon", "-neon") +AARCH64_ARCH_EXT_NAME("fp16", AArch64::AEK_FP16, "+fullfp16", "-fullfp16") +AARCH64_ARCH_EXT_NAME("profile", AArch64::AEK_PROFILE, "+spe", "-spe") +AARCH64_ARCH_EXT_NAME("ras", AArch64::AEK_RAS, "+ras", "-ras") +#undef AARCH64_ARCH_EXT_NAME + +#ifndef AARCH64_CPU_NAME +#define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) +#endif +AARCH64_CPU_NAME("cortex-a35", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("cortex-a53", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true, + ( AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("cortex-a57", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("cortex-a72", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("cortex-a73", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("cyclone", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("exynos-m1", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("kryo", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +AARCH64_CPU_NAME("vulcan", AK_ARMV8_1A, FK_CRYPTO_NEON_FP_ARMV8, false, + (AArch64::AEK_SIMD | AArch64::AEK_CRC | AArch64::AEK_CRYPTO)) +// Invalid CPU +AARCH64_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, AArch64::AEK_INVALID) +#undef AARCH64_CPU_NAME diff --git a/include/llvm/Support/ARMTargetParser.def b/include/llvm/Support/ARMTargetParser.def index a42a5d2e8635d05c00ec6c89f758d163245b116f..195f7112d6a0b1e2a8e47034d373cb53ea62d5b8 100644 --- a/include/llvm/Support/ARMTargetParser.def +++ b/include/llvm/Support/ARMTargetParser.def @@ -45,188 +45,198 @@ ARM_FPU("softvfp", FK_SOFTVFP, FV_NONE, NS_None, FR_None) #define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) #endif ARM_ARCH("invalid", AK_INVALID, nullptr, nullptr, - ARMBuildAttrs::CPUArch::Pre_v4, FK_NONE, AEK_NONE) + ARMBuildAttrs::CPUArch::Pre_v4, FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv2", AK_ARMV2, "2", "v2", ARMBuildAttrs::CPUArch::Pre_v4, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv2a", AK_ARMV2A, "2A", "v2a", ARMBuildAttrs::CPUArch::Pre_v4, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv3", AK_ARMV3, "3", "v3", ARMBuildAttrs::CPUArch::Pre_v4, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv3m", AK_ARMV3M, "3M", "v3m", ARMBuildAttrs::CPUArch::Pre_v4, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv4", AK_ARMV4, "4", "v4", ARMBuildAttrs::CPUArch::v4, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv4t", AK_ARMV4T, "4T", "v4t", ARMBuildAttrs::CPUArch::v4T, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv5t", AK_ARMV5T, "5T", "v5", ARMBuildAttrs::CPUArch::v5T, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv5te", AK_ARMV5TE, "5TE", "v5e", ARMBuildAttrs::CPUArch::v5TE, - FK_NONE, AEK_DSP) + FK_NONE, ARM::AEK_DSP) ARM_ARCH("armv5tej", AK_ARMV5TEJ, "5TEJ", "v5e", ARMBuildAttrs::CPUArch::v5TEJ, - FK_NONE, AEK_DSP) + FK_NONE, ARM::AEK_DSP) ARM_ARCH("armv6", AK_ARMV6, "6", "v6", ARMBuildAttrs::CPUArch::v6, - FK_VFPV2, AEK_DSP) + FK_VFPV2, ARM::AEK_DSP) ARM_ARCH("armv6k", AK_ARMV6K, "6K", "v6k", ARMBuildAttrs::CPUArch::v6K, - FK_VFPV2, AEK_DSP) + FK_VFPV2, ARM::AEK_DSP) ARM_ARCH("armv6t2", AK_ARMV6T2, "6T2", "v6t2", ARMBuildAttrs::CPUArch::v6T2, - FK_NONE, AEK_DSP) + FK_NONE, ARM::AEK_DSP) ARM_ARCH("armv6kz", AK_ARMV6KZ, "6KZ", "v6kz", ARMBuildAttrs::CPUArch::v6KZ, - FK_VFPV2, (AEK_SEC | AEK_DSP)) + FK_VFPV2, (ARM::AEK_SEC | ARM::AEK_DSP)) ARM_ARCH("armv6-m", AK_ARMV6M, "6-M", "v6m", ARMBuildAttrs::CPUArch::v6_M, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv7-a", AK_ARMV7A, "7-A", "v7", ARMBuildAttrs::CPUArch::v7, - FK_NEON, AEK_DSP) + FK_NEON, ARM::AEK_DSP) ARM_ARCH("armv7-r", AK_ARMV7R, "7-R", "v7r", ARMBuildAttrs::CPUArch::v7, - FK_NONE, (AEK_HWDIV | AEK_DSP)) + FK_NONE, (ARM::AEK_HWDIV | ARM::AEK_DSP)) ARM_ARCH("armv7-m", AK_ARMV7M, "7-M", "v7m", ARMBuildAttrs::CPUArch::v7, - FK_NONE, AEK_HWDIV) + FK_NONE, ARM::AEK_HWDIV) ARM_ARCH("armv7e-m", AK_ARMV7EM, "7E-M", "v7em", ARMBuildAttrs::CPUArch::v7E_M, - FK_NONE, (AEK_HWDIV | AEK_DSP)) + FK_NONE, (ARM::AEK_HWDIV | ARM::AEK_DSP)) ARM_ARCH("armv8-a", AK_ARMV8A, "8-A", "v8", ARMBuildAttrs::CPUArch::v8_A, - FK_CRYPTO_NEON_FP_ARMV8, (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | - AEK_HWDIV | AEK_DSP | AEK_CRC)) -ARM_ARCH("armv8.1-a", AK_ARMV8_1A, "8.1-A", "v8.1a", ARMBuildAttrs::CPUArch::v8_A, - FK_CRYPTO_NEON_FP_ARMV8, (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | - AEK_HWDIV | AEK_DSP | AEK_CRC)) -ARM_ARCH("armv8.2-a", AK_ARMV8_2A, "8.2-A", "v8.2a", ARMBuildAttrs::CPUArch::v8_A, - FK_CRYPTO_NEON_FP_ARMV8, (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | - AEK_HWDIV | AEK_DSP | AEK_CRC)) + FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV | ARM::AEK_DSP | ARM::AEK_CRC)) +ARM_ARCH("armv8.1-a", AK_ARMV8_1A, "8.1-A", "v8.1a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV | ARM::AEK_DSP | ARM::AEK_CRC | ARM::AEK_RAS)) +ARM_ARCH("armv8.2-a", AK_ARMV8_2A, "8.2-A", "v8.2a", + ARMBuildAttrs::CPUArch::v8_A, FK_CRYPTO_NEON_FP_ARMV8, + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV | ARM::AEK_DSP | ARM::AEK_CRC)) ARM_ARCH("armv8-m.base", AK_ARMV8MBaseline, "8-M.Baseline", "v8m.base", - ARMBuildAttrs::CPUArch::v8_M_Base, FK_NONE, AEK_HWDIV) + ARMBuildAttrs::CPUArch::v8_M_Base, FK_NONE, ARM::AEK_HWDIV) ARM_ARCH("armv8-m.main", AK_ARMV8MMainline, "8-M.Mainline", "v8m.main", - ARMBuildAttrs::CPUArch::v8_M_Main, FK_FPV5_D16, AEK_HWDIV) + ARMBuildAttrs::CPUArch::v8_M_Main, FK_FPV5_D16, ARM::AEK_HWDIV) // Non-standard Arch names. ARM_ARCH("iwmmxt", AK_IWMMXT, "iwmmxt", "", ARMBuildAttrs::CPUArch::v5TE, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("iwmmxt2", AK_IWMMXT2, "iwmmxt2", "", ARMBuildAttrs::CPUArch::v5TE, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("xscale", AK_XSCALE, "xscale", "v5e", ARMBuildAttrs::CPUArch::v5TE, - FK_NONE, AEK_NONE) + FK_NONE, ARM::AEK_NONE) ARM_ARCH("armv7s", AK_ARMV7S, "7-S", "v7s", ARMBuildAttrs::CPUArch::v7, - FK_NEON_VFPV4, AEK_DSP) + FK_NEON_VFPV4, ARM::AEK_DSP) ARM_ARCH("armv7k", AK_ARMV7K, "7-K", "v7k", ARMBuildAttrs::CPUArch::v7, - FK_NONE, AEK_DSP) + FK_NONE, ARM::AEK_DSP) #undef ARM_ARCH #ifndef ARM_ARCH_EXT_NAME #define ARM_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) #endif // FIXME: This would be nicer were it tablegen -ARM_ARCH_EXT_NAME("invalid", AEK_INVALID, nullptr, nullptr) -ARM_ARCH_EXT_NAME("none", AEK_NONE, nullptr, nullptr) -ARM_ARCH_EXT_NAME("crc", AEK_CRC, "+crc", "-crc") -ARM_ARCH_EXT_NAME("crypto", AEK_CRYPTO, "+crypto","-crypto") -ARM_ARCH_EXT_NAME("dsp", AEK_DSP, "+dsp", "-dsp") -ARM_ARCH_EXT_NAME("fp", AEK_FP, nullptr, nullptr) -ARM_ARCH_EXT_NAME("idiv", (AEK_HWDIVARM | AEK_HWDIV), nullptr, nullptr) -ARM_ARCH_EXT_NAME("mp", AEK_MP, nullptr, nullptr) -ARM_ARCH_EXT_NAME("simd", AEK_SIMD, nullptr, nullptr) -ARM_ARCH_EXT_NAME("sec", AEK_SEC, nullptr, nullptr) -ARM_ARCH_EXT_NAME("virt", AEK_VIRT, nullptr, nullptr) -ARM_ARCH_EXT_NAME("fp16", AEK_FP16, "+fullfp16", "-fullfp16") -ARM_ARCH_EXT_NAME("os", AEK_OS, nullptr, nullptr) -ARM_ARCH_EXT_NAME("iwmmxt", AEK_IWMMXT, nullptr, nullptr) -ARM_ARCH_EXT_NAME("iwmmxt2", AEK_IWMMXT2, nullptr, nullptr) -ARM_ARCH_EXT_NAME("maverick", AEK_MAVERICK, nullptr, nullptr) -ARM_ARCH_EXT_NAME("xscale", AEK_XSCALE, nullptr, nullptr) +ARM_ARCH_EXT_NAME("invalid", ARM::AEK_INVALID, nullptr, nullptr) +ARM_ARCH_EXT_NAME("none", ARM::AEK_NONE, nullptr, nullptr) +ARM_ARCH_EXT_NAME("crc", ARM::AEK_CRC, "+crc", "-crc") +ARM_ARCH_EXT_NAME("crypto", ARM::AEK_CRYPTO, "+crypto","-crypto") +ARM_ARCH_EXT_NAME("dsp", ARM::AEK_DSP, "+dsp", "-dsp") +ARM_ARCH_EXT_NAME("fp", ARM::AEK_FP, nullptr, nullptr) +ARM_ARCH_EXT_NAME("idiv", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIV), nullptr, nullptr) +ARM_ARCH_EXT_NAME("mp", ARM::AEK_MP, nullptr, nullptr) +ARM_ARCH_EXT_NAME("simd", ARM::AEK_SIMD, nullptr, nullptr) +ARM_ARCH_EXT_NAME("sec", ARM::AEK_SEC, nullptr, nullptr) +ARM_ARCH_EXT_NAME("virt", ARM::AEK_VIRT, nullptr, nullptr) +ARM_ARCH_EXT_NAME("fp16", ARM::AEK_FP16, "+fullfp16", "-fullfp16") +ARM_ARCH_EXT_NAME("ras", ARM::AEK_RAS, "+ras", "-ras") +ARM_ARCH_EXT_NAME("os", ARM::AEK_OS, nullptr, nullptr) +ARM_ARCH_EXT_NAME("iwmmxt", ARM::AEK_IWMMXT, nullptr, nullptr) +ARM_ARCH_EXT_NAME("iwmmxt2", ARM::AEK_IWMMXT2, nullptr, nullptr) +ARM_ARCH_EXT_NAME("maverick", ARM::AEK_MAVERICK, nullptr, nullptr) +ARM_ARCH_EXT_NAME("xscale", ARM::AEK_XSCALE, nullptr, nullptr) #undef ARM_ARCH_EXT_NAME #ifndef ARM_HW_DIV_NAME #define ARM_HW_DIV_NAME(NAME, ID) #endif -ARM_HW_DIV_NAME("invalid", AEK_INVALID) -ARM_HW_DIV_NAME("none", AEK_NONE) -ARM_HW_DIV_NAME("thumb", AEK_HWDIV) -ARM_HW_DIV_NAME("arm", AEK_HWDIVARM) -ARM_HW_DIV_NAME("arm,thumb", (AEK_HWDIVARM | AEK_HWDIV)) +ARM_HW_DIV_NAME("invalid", ARM::AEK_INVALID) +ARM_HW_DIV_NAME("none", ARM::AEK_NONE) +ARM_HW_DIV_NAME("thumb", ARM::AEK_HWDIV) +ARM_HW_DIV_NAME("arm", ARM::AEK_HWDIVARM) +ARM_HW_DIV_NAME("arm,thumb", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIV)) #undef ARM_HW_DIV_NAME #ifndef ARM_CPU_NAME #define ARM_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) #endif -ARM_CPU_NAME("arm2", AK_ARMV2, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm3", AK_ARMV2A, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm6", AK_ARMV3, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm7m", AK_ARMV3M, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm8", AK_ARMV4, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm810", AK_ARMV4, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("strongarm", AK_ARMV4, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("strongarm110", AK_ARMV4, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("strongarm1100", AK_ARMV4, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("strongarm1110", AK_ARMV4, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm7tdmi", AK_ARMV4T, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm7tdmi-s", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm710t", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm720t", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm9", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm9tdmi", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm920", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm920t", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm922t", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm9312", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm940t", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("ep9312", AK_ARMV4T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm10tdmi", AK_ARMV5T, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm1020t", AK_ARMV5T, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm9e", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm946e-s", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm966e-s", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm968e-s", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm10e", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm1020e", AK_ARMV5TE, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm1022e", AK_ARMV5TE, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm926ej-s", AK_ARMV5TEJ, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm1136j-s", AK_ARMV6, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm1136jf-s", AK_ARMV6, FK_VFPV2, true, AEK_NONE) -ARM_CPU_NAME("arm1136jz-s", AK_ARMV6, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm1176j-s", AK_ARMV6K, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm1176jz-s", AK_ARMV6KZ, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("mpcore", AK_ARMV6K, FK_VFPV2, false, AEK_NONE) -ARM_CPU_NAME("mpcorenovfp", AK_ARMV6K, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("arm1176jzf-s", AK_ARMV6KZ, FK_VFPV2, true, AEK_NONE) -ARM_CPU_NAME("arm1156t2-s", AK_ARMV6T2, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("arm1156t2f-s", AK_ARMV6T2, FK_VFPV2, false, AEK_NONE) -ARM_CPU_NAME("cortex-m0", AK_ARMV6M, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("cortex-m0plus", AK_ARMV6M, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("cortex-m1", AK_ARMV6M, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("sc000", AK_ARMV6M, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("cortex-a5", AK_ARMV7A, FK_NEON_VFPV4, false, (AEK_SEC | AEK_MP)) +ARM_CPU_NAME("arm2", AK_ARMV2, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm3", AK_ARMV2A, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm6", AK_ARMV3, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm7m", AK_ARMV3M, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm8", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm810", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm", AK_ARMV4, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm110", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm1100", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("strongarm1110", AK_ARMV4, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm7tdmi", AK_ARMV4T, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm7tdmi-s", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm710t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm720t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9tdmi", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm920", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm920t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm922t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9312", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm940t", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("ep9312", AK_ARMV4T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm10tdmi", AK_ARMV5T, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1020t", AK_ARMV5T, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm9e", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm946e-s", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm966e-s", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm968e-s", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm10e", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1020e", AK_ARMV5TE, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1022e", AK_ARMV5TE, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm926ej-s", AK_ARMV5TEJ, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1136j-s", AK_ARMV6, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1136jf-s", AK_ARMV6, FK_VFPV2, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1136jz-s", AK_ARMV6, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1176j-s", AK_ARMV6K, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1176jz-s", AK_ARMV6KZ, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("mpcore", AK_ARMV6K, FK_VFPV2, false, ARM::AEK_NONE) +ARM_CPU_NAME("mpcorenovfp", AK_ARMV6K, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("arm1176jzf-s", AK_ARMV6KZ, FK_VFPV2, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1156t2-s", AK_ARMV6T2, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("arm1156t2f-s", AK_ARMV6T2, FK_VFPV2, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m0", AK_ARMV6M, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m0plus", AK_ARMV6M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m1", AK_ARMV6M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("sc000", AK_ARMV6M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-a5", AK_ARMV7A, FK_NEON_VFPV4, false, + (ARM::AEK_SEC | ARM::AEK_MP)) ARM_CPU_NAME("cortex-a7", AK_ARMV7A, FK_NEON_VFPV4, false, - (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | AEK_HWDIV)) -ARM_CPU_NAME("cortex-a8", AK_ARMV7A, FK_NEON, true, AEK_SEC) -ARM_CPU_NAME("cortex-a9", AK_ARMV7A, FK_NEON_FP16, false, (AEK_SEC | AEK_MP)) + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV)) +ARM_CPU_NAME("cortex-a8", AK_ARMV7A, FK_NEON, true, ARM::AEK_SEC) +ARM_CPU_NAME("cortex-a9", AK_ARMV7A, FK_NEON_FP16, false, (ARM::AEK_SEC | ARM::AEK_MP)) ARM_CPU_NAME("cortex-a12", AK_ARMV7A, FK_NEON_VFPV4, false, - (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | AEK_HWDIV)) + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV)) ARM_CPU_NAME("cortex-a15", AK_ARMV7A, FK_NEON_VFPV4, false, - (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | AEK_HWDIV)) + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV)) ARM_CPU_NAME("cortex-a17", AK_ARMV7A, FK_NEON_VFPV4, false, - (AEK_SEC | AEK_MP | AEK_VIRT | AEK_HWDIVARM | AEK_HWDIV)) + (ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIV)) ARM_CPU_NAME("krait", AK_ARMV7A, FK_NEON_VFPV4, false, - (AEK_HWDIVARM | AEK_HWDIV)) -ARM_CPU_NAME("cortex-r4", AK_ARMV7R, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("cortex-r4f", AK_ARMV7R, FK_VFPV3_D16, false, AEK_NONE) + (ARM::AEK_HWDIVARM | ARM::AEK_HWDIV)) +ARM_CPU_NAME("cortex-r4", AK_ARMV7R, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-r4f", AK_ARMV7R, FK_VFPV3_D16, false, ARM::AEK_NONE) ARM_CPU_NAME("cortex-r5", AK_ARMV7R, FK_VFPV3_D16, false, - (AEK_MP | AEK_HWDIVARM)) + (ARM::AEK_MP | ARM::AEK_HWDIVARM)) ARM_CPU_NAME("cortex-r7", AK_ARMV7R, FK_VFPV3_D16_FP16, false, - (AEK_MP | AEK_HWDIVARM)) + (ARM::AEK_MP | ARM::AEK_HWDIVARM)) ARM_CPU_NAME("cortex-r8", AK_ARMV7R, FK_VFPV3_D16_FP16, false, - (AEK_MP | AEK_HWDIVARM)) -ARM_CPU_NAME("sc300", AK_ARMV7M, FK_NONE, false, AEK_NONE) -ARM_CPU_NAME("cortex-m3", AK_ARMV7M, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("cortex-m4", AK_ARMV7EM, FK_FPV4_SP_D16, true, AEK_NONE) -ARM_CPU_NAME("cortex-m7", AK_ARMV7EM, FK_FPV5_D16, false, AEK_NONE) -ARM_CPU_NAME("cortex-a32", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) -ARM_CPU_NAME("cortex-a35", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) -ARM_CPU_NAME("cortex-a53", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true, AEK_CRC) -ARM_CPU_NAME("cortex-a57", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) -ARM_CPU_NAME("cortex-a72", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) -ARM_CPU_NAME("cyclone", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) -ARM_CPU_NAME("exynos-m1", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, AEK_CRC) + (ARM::AEK_MP | ARM::AEK_HWDIVARM)) +ARM_CPU_NAME("sc300", AK_ARMV7M, FK_NONE, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m3", AK_ARMV7M, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m4", AK_ARMV7EM, FK_FPV4_SP_D16, true, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-m7", AK_ARMV7EM, FK_FPV5_D16, false, ARM::AEK_NONE) +ARM_CPU_NAME("cortex-a32", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a35", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a53", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, true, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a57", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a72", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cortex-a73", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("cyclone", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) +ARM_CPU_NAME("exynos-m1", AK_ARMV8A, FK_CRYPTO_NEON_FP_ARMV8, false, ARM::AEK_CRC) // Non-standard Arch names. -ARM_CPU_NAME("iwmmxt", AK_IWMMXT, FK_NONE, true, AEK_NONE) -ARM_CPU_NAME("xscale", AK_XSCALE, FK_NONE, true, AEK_NONE) +ARM_CPU_NAME("iwmmxt", AK_IWMMXT, FK_NONE, true, ARM::AEK_NONE) +ARM_CPU_NAME("xscale", AK_XSCALE, FK_NONE, true, ARM::AEK_NONE) ARM_CPU_NAME("swift", AK_ARMV7S, FK_NEON_VFPV4, true, - (AEK_HWDIVARM | AEK_HWDIV)) + (ARM::AEK_HWDIVARM | ARM::AEK_HWDIV)) // Invalid CPU -ARM_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, AEK_INVALID) +ARM_CPU_NAME("invalid", AK_INVALID, FK_INVALID, true, ARM::AEK_INVALID) #undef ARM_CPU_NAME diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h index 043d823146091ef083f5d602602fbf7845e6dcf7..1c9508661d6fc6f60d120ea14a0c85ec931ef39c 100644 --- a/include/llvm/Support/Allocator.h +++ b/include/llvm/Support/Allocator.h @@ -278,6 +278,8 @@ public: return TotalMemory; } + size_t getBytesAllocated() const { return BytesAllocated; } + void PrintStats() const { detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated, getTotalMemory()); diff --git a/include/llvm/Support/Atomic.h b/include/llvm/Support/Atomic.h index 9ec23e8270238eff268fb9b0a8c712fa4c73f7e0..d03714b009c513f8b093c2cdc152f74d5d1409bc 100644 --- a/include/llvm/Support/Atomic.h +++ b/include/llvm/Support/Atomic.h @@ -9,6 +9,10 @@ // // This file declares the llvm::sys atomic operations. // +// DO NOT USE IN NEW CODE! +// +// New code should always rely on the std::atomic facilities in C++11. +// //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_ATOMIC_H @@ -28,11 +32,6 @@ namespace llvm { cas_flag CompareAndSwap(volatile cas_flag* ptr, cas_flag new_value, cas_flag old_value); - cas_flag AtomicIncrement(volatile cas_flag* ptr); - cas_flag AtomicDecrement(volatile cas_flag* ptr); - cas_flag AtomicAdd(volatile cas_flag* ptr, cas_flag val); - cas_flag AtomicMul(volatile cas_flag* ptr, cas_flag val); - cas_flag AtomicDiv(volatile cas_flag* ptr, cas_flag val); } } diff --git a/include/llvm/Support/AtomicOrdering.h b/include/llvm/Support/AtomicOrdering.h new file mode 100644 index 0000000000000000000000000000000000000000..8837fab1957577ebe6c82f1065683d79ea15b4f6 --- /dev/null +++ b/include/llvm/Support/AtomicOrdering.h @@ -0,0 +1,153 @@ +//===-- llvm/Support/AtomicOrdering.h ---Atomic Ordering---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Atomic ordering constants. +/// +/// These values are used by LLVM to represent atomic ordering for C++11's +/// memory model and more, as detailed in docs/Atomics.rst. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ATOMICORDERING_H +#define LLVM_SUPPORT_ATOMICORDERING_H + +#include + +namespace llvm { + +/// Atomic ordering for C11 / C++11's memody models. +/// +/// These values cannot change because they are shared with standard library +/// implementations as well as with other compilers. +enum class AtomicOrderingCABI { + relaxed = 0, + consume = 1, + acquire = 2, + release = 3, + acq_rel = 4, + seq_cst = 5, +}; + +bool operator<(AtomicOrderingCABI, AtomicOrderingCABI) = delete; +bool operator>(AtomicOrderingCABI, AtomicOrderingCABI) = delete; +bool operator<=(AtomicOrderingCABI, AtomicOrderingCABI) = delete; +bool operator>=(AtomicOrderingCABI, AtomicOrderingCABI) = delete; + +// Validate an integral value which isn't known to fit within the enum's range +// is a valid AtomicOrderingCABI. +template static inline bool isValidAtomicOrderingCABI(Int I) { + return (Int)AtomicOrderingCABI::relaxed <= I && + I <= (Int)AtomicOrderingCABI::seq_cst; +} + +/// Atomic ordering for LLVM's memory model. +/// +/// C++ defines ordering as a lattice. LLVM supplements this with NotAtomic and +/// Unordered, which are both below the C++ orders. +/// +/// not_atomic-->unordered-->relaxed-->release--------------->acq_rel-->seq_cst +/// \-->consume-->acquire--/ +enum class AtomicOrdering { + NotAtomic = 0, + Unordered = 1, + Monotonic = 2, // Equivalent to C++'s relaxed. + // Consume = 3, // Not specified yet. + Acquire = 4, + Release = 5, + AcquireRelease = 6, + SequentiallyConsistent = 7 +}; + +bool operator<(AtomicOrdering, AtomicOrdering) = delete; +bool operator>(AtomicOrdering, AtomicOrdering) = delete; +bool operator<=(AtomicOrdering, AtomicOrdering) = delete; +bool operator>=(AtomicOrdering, AtomicOrdering) = delete; + +// Validate an integral value which isn't known to fit within the enum's range +// is a valid AtomicOrdering. +template static inline bool isValidAtomicOrdering(Int I) { + return (Int)AtomicOrdering::NotAtomic <= I && + I <= (Int)AtomicOrdering::SequentiallyConsistent; +} + +/// String used by LLVM IR to represent atomic ordering. +static inline const char *toIRString(AtomicOrdering ao) { + static const char *names[8] = {"not_atomic", "unordered", "monotonic", + "consume", "acquire", "release", + "acq_rel", "seq_cst"}; + return names[(size_t)ao]; +} + +/// Returns true if ao is stronger than other as defined by the AtomicOrdering +/// lattice, which is based on C++'s definition. +static inline bool isStrongerThan(AtomicOrdering ao, AtomicOrdering other) { + static const bool lookup[8][8] = { + // NA UN RX CO AC RE AR SC + /* NotAtomic */ {0, 0, 0, 0, 0, 0, 0, 0}, + /* Unordered */ {1, 0, 0, 0, 0, 0, 0, 0}, + /* relaxed */ {1, 1, 0, 0, 0, 0, 0, 0}, + /* consume */ {1, 1, 1, 0, 0, 0, 0, 0}, + /* acquire */ {1, 1, 1, 1, 0, 0, 0, 0}, + /* release */ {1, 1, 1, 0, 0, 0, 0, 0}, + /* acq_rel */ {1, 1, 1, 1, 1, 1, 0, 0}, + /* seq_cst */ {1, 1, 1, 1, 1, 1, 1, 0}, + }; + return lookup[(size_t)ao][(size_t)other]; +} + +static inline bool isAtLeastOrStrongerThan(AtomicOrdering ao, + AtomicOrdering other) { + static const bool lookup[8][8] = { + // NA UN RX CO AC RE AR SC + /* NotAtomic */ {1, 0, 0, 0, 0, 0, 0, 0}, + /* Unordered */ {1, 1, 0, 0, 0, 0, 0, 0}, + /* relaxed */ {1, 1, 1, 0, 0, 0, 0, 0}, + /* consume */ {1, 1, 1, 1, 0, 0, 0, 0}, + /* acquire */ {1, 1, 1, 1, 1, 0, 0, 0}, + /* release */ {1, 1, 1, 0, 0, 1, 0, 0}, + /* acq_rel */ {1, 1, 1, 1, 1, 1, 1, 0}, + /* seq_cst */ {1, 1, 1, 1, 1, 1, 1, 1}, + }; + return lookup[(size_t)ao][(size_t)other]; +} + +static inline bool isStrongerThanUnordered(AtomicOrdering ao) { + return isStrongerThan(ao, AtomicOrdering::Unordered); +} + +static inline bool isStrongerThanMonotonic(AtomicOrdering ao) { + return isStrongerThan(ao, AtomicOrdering::Monotonic); +} + +static inline bool isAcquireOrStronger(AtomicOrdering ao) { + return isAtLeastOrStrongerThan(ao, AtomicOrdering::Acquire); +} + +static inline bool isReleaseOrStronger(AtomicOrdering ao) { + return isAtLeastOrStrongerThan(ao, AtomicOrdering::Release); +} + +static inline AtomicOrderingCABI toCABI(AtomicOrdering ao) { + static const AtomicOrderingCABI lookup[8] = { + /* NotAtomic */ AtomicOrderingCABI::relaxed, + /* Unordered */ AtomicOrderingCABI::relaxed, + /* relaxed */ AtomicOrderingCABI::relaxed, + /* consume */ AtomicOrderingCABI::consume, + /* acquire */ AtomicOrderingCABI::acquire, + /* release */ AtomicOrderingCABI::release, + /* acq_rel */ AtomicOrderingCABI::acq_rel, + /* seq_cst */ AtomicOrderingCABI::seq_cst, + }; + return lookup[(size_t)ao]; +} + +} // end namespace llvm + +#endif // LLVM_SUPPORT_ATOMICORDERING_H diff --git a/include/llvm/Support/COFF.h b/include/llvm/Support/COFF.h index 32bedbb2904b4a73c4ae913cf8f46423fb3f5d9e..7dad3e82bda6b489491f23f76315f72be0e3cf04 100644 --- a/include/llvm/Support/COFF.h +++ b/include/llvm/Support/COFF.h @@ -377,7 +377,6 @@ namespace COFF { uint8_t unused[10]; }; - /// These are not documented in the spec, but are located in WinNT.h. enum WeakExternalCharacteristics { IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY = 1, IMAGE_WEAK_EXTERN_SEARCH_LIBRARY = 2, @@ -530,7 +529,7 @@ namespace COFF { EXCEPTION_TABLE, CERTIFICATE_TABLE, BASE_RELOCATION_TABLE, - DEBUG, + DEBUG_DIRECTORY, ARCHITECTURE, GLOBAL_PTR, TLS_TABLE, @@ -599,7 +598,13 @@ namespace COFF { IMAGE_DEBUG_TYPE_OMAP_TO_SRC = 7, IMAGE_DEBUG_TYPE_OMAP_FROM_SRC = 8, IMAGE_DEBUG_TYPE_BORLAND = 9, - IMAGE_DEBUG_TYPE_CLSID = 11 + IMAGE_DEBUG_TYPE_RESERVED10 = 10, + IMAGE_DEBUG_TYPE_CLSID = 11, + IMAGE_DEBUG_TYPE_VC_FEATURE = 12, + IMAGE_DEBUG_TYPE_POGO = 13, + IMAGE_DEBUG_TYPE_ILTCG = 14, + IMAGE_DEBUG_TYPE_MPX = 15, + IMAGE_DEBUG_TYPE_REPRO = 16, }; enum BaseRelocationType { diff --git a/include/llvm/Support/CachePruning.h b/include/llvm/Support/CachePruning.h new file mode 100644 index 0000000000000000000000000000000000000000..3834141191399ac1d36a88baac6ab1e82cb90d13 --- /dev/null +++ b/include/llvm/Support/CachePruning.h @@ -0,0 +1,69 @@ +//=- CachePruning.h - Helper to manage the pruning of a cache dir -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements pruning of a directory intended for cache storage, using +// various policies. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CACHE_PRUNING_H +#define LLVM_SUPPORT_CACHE_PRUNING_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +/// Handle pruning a directory provided a path and some options to control what +/// to prune. +class CachePruning { +public: + /// Prepare to prune \p Path. + CachePruning(StringRef Path) : Path(Path) {} + + /// Define the pruning interval. This is intended to be used to avoid scanning + /// the directory too often. It does not impact the decision of which file to + /// prune. A value of 0 forces the scan to occurs. + CachePruning &setPruningInterval(int PruningInterval) { + Interval = PruningInterval; + return *this; + } + + /// Define the expiration for a file. When a file hasn't been accessed for + /// \p ExpireAfter seconds, it is removed from the cache. A value of 0 disable + /// the expiration-based pruning. + CachePruning &setEntryExpiration(unsigned ExpireAfter) { + Expiration = ExpireAfter; + return *this; + } + + /// Define the maximum size for the cache directory, in terms of percentage of + /// the available space on the the disk. Set to 100 to indicate no limit, 50 + /// to indicate that the cache size will not be left over half the + /// available disk space. A value over 100 will be reduced to 100. A value of + /// 0 disable the size-based pruning. + CachePruning &setMaxSize(unsigned Percentage) { + PercentageOfAvailableSpace = std::min(100u, Percentage); + return *this; + } + + /// Peform pruning using the supplied options, returns true if pruning + /// occured, i.e. if PruningInterval was expired. + bool prune(); + +private: + // Options that matches the setters above. + std::string Path; + unsigned Expiration = 0; + unsigned Interval = 0; + unsigned PercentageOfAvailableSpace = 0; +}; + +} // namespace llvm + +#endif \ No newline at end of file diff --git a/include/llvm/Support/CodeGen.h b/include/llvm/Support/CodeGen.h index 0ff3d56363cd714fd6e84fced663ca4b0ee32687..e19abf8271eb16c45d1d2670770fdb761d1eb0d8 100644 --- a/include/llvm/Support/CodeGen.h +++ b/include/llvm/Support/CodeGen.h @@ -19,7 +19,7 @@ namespace llvm { // Relocation model types. namespace Reloc { - enum Model { Default, Static, PIC_, DynamicNoPIC }; + enum Model { Static, PIC_, DynamicNoPIC }; } // Code model types. @@ -29,6 +29,11 @@ namespace llvm { } namespace PICLevel { + // This is used to map -fpic/-fPIC. + enum Level { NotPIC=0, SmallPIC=1, BigPIC=2 }; + } + + namespace PIELevel { enum Level { Default=0, Small=1, Large=2 }; } diff --git a/include/llvm/Support/CodeGenCWrappers.h b/include/llvm/Support/CodeGenCWrappers.h index a97f1a4ec19628aac9deee5e7131c4c8f6051fab..6db4433a435062828408a2ed8e36737c83f58549 100644 --- a/include/llvm/Support/CodeGenCWrappers.h +++ b/include/llvm/Support/CodeGenCWrappers.h @@ -17,8 +17,8 @@ #define LLVM_SUPPORT_CODEGENCWRAPPERS_H #include "llvm-c/TargetMachine.h" +#include "llvm/Support/CodeGen.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/CodeGenCWrappers.h" namespace llvm { diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index 943d2df37708943ef1d61de858863c564c3452a1..70465a0e3fd350aa56b9f5467964bf74eb8ae8c1 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -21,10 +21,12 @@ #define LLVM_SUPPORT_COMMANDLINE_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/ManagedStatic.h" #include #include #include @@ -43,8 +45,9 @@ namespace cl { //===----------------------------------------------------------------------===// // ParseCommandLineOptions - Command line option processing entry point. // -void ParseCommandLineOptions(int argc, const char *const *argv, - const char *Overview = nullptr); +bool ParseCommandLineOptions(int argc, const char *const *argv, + const char *Overview = nullptr, + bool IgnoreErrors = false); //===----------------------------------------------------------------------===// // ParseEnvironmentOptions - Environment variable option processing alternate @@ -170,6 +173,45 @@ public: // The general Option Category (used as default category). extern OptionCategory GeneralCategory; +//===----------------------------------------------------------------------===// +// SubCommand class +// +class SubCommand { +private: + const char *const Name = nullptr; + const char *const Description = nullptr; + +protected: + void registerSubCommand(); + void unregisterSubCommand(); + +public: + SubCommand(const char *const Name, const char *const Description = nullptr) + : Name(Name), Description(Description) { + registerSubCommand(); + } + SubCommand() {} + + void reset(); + + operator bool() const; + + const char *getName() const { return Name; } + const char *getDescription() const { return Description; } + + SmallVector
[[@LINE-44]]
// before
+// HTML-FILTER-NOT: 
[[@LINE-45]]
// before
+// HTML: 
161
[[@LINE-44]]
int main() {
+// HTML: 
161
[[@LINE-44]]
  int x = 0
+// HTML: 
161
[[@LINE-44]]
+// HTML: 
0
[[@LINE-44]]
  if (x) {
+// HTML: 
0
[[@LINE-44]]
+// HTML: 
161
[[@LINE-44]]
  }
+// HTML: 
161
[[@LINE-44]]
    x = 1;
+// HTML: 
161
[[@LINE-44]]
  }
+// HTML: 
161
[[@LINE-44]]
+// HTML: 
16.2k
[[@LINE-44]]
  for (int i = 0; i < 100; ++i)
+// HTML: 
16.1k
[[@LINE-44]]
    x = 1;
+// HTML: 
16.1k
[[@LINE-44]]
  }
+// HTML: 
161
[[@LINE-44]]
+// HTML: 
161
[[@LINE-44]]
  x = x < 10
+// HTML: 
161
[[@LINE-44]]
  x = x > 10
+// HTML: 
0
[[@LINE-44]]
        x - 1:
+// HTML: 
161
[[@LINE-44]]
        x + 1;
+// HTML: 
161
[[@LINE-44]]
+// HTML: 
161
[[@LINE-44]]
  return 0;
+// HTML: 
161
[[@LINE-44]]
}
+// HTML-WHOLE-FILE: 
[[@LINE-44]]
// after
+// HTML-FILTER-NOT: 
[[@LINE-45]]
// after
diff --git a/test/tools/llvm-cov/showTemplateInstantiations.cpp b/test/tools/llvm-cov/showTemplateInstantiations.cpp
index a9be473dc91564c83b7ec0aedfd4f768bdea99ca..8fc45898a8b17c61a6d14f555d1404b51175fba6 100644
--- a/test/tools/llvm-cov/showTemplateInstantiations.cpp
+++ b/test/tools/llvm-cov/showTemplateInstantiations.cpp
@@ -1,25 +1,25 @@
-// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -filename-equivalence %s | FileCheck -check-prefix=CHECK -check-prefix=ALL %s
-// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -filename-equivalence -name=_Z4funcIbEiT_ %s | FileCheck -check-prefix=CHECK -check-prefix=FILTER %s
+// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -filename-equivalence %s | FileCheck -check-prefixes=SHARED,ALL %s
+// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -filename-equivalence -name=_Z4funcIbEiT_ %s | FileCheck -check-prefixes=SHARED,FILTER %s
 
-// before coverage   // WHOLE-FILE:   | [[@LINE]]|// before
+// before coverage   // ALL:          | [[@LINE]]|// before
                      // FILTER-NOT:   | [[@LINE-1]]|// before
 template // ALL:          | [[@LINE]]|template
 int func(T x) {      // ALL-NEXT:    2| [[@LINE]]|int func(T x) {
   if(x)              // ALL-NEXT:    2| [[@LINE]]|  if(x)
     return 0;        // ALL-NEXT:    1| [[@LINE]]|    return 0;
-  else               // ALL-NEXT:    1| [[@LINE]]|  else
+  else               // ALL-NEXT:    2| [[@LINE]]|  else
     return 1;        // ALL-NEXT:    1| [[@LINE]]|    return 1;
   int j = 1;         // ALL-NEXT:    0| [[@LINE]]|  int j = 1;
-}                    // ALL-NEXT:    1| [[@LINE]]|}
+}                    // ALL-NEXT:    2| [[@LINE]]|}
 
-                     // CHECK:       {{^ *(\| )?}}_Z4funcIbEiT_:
-                     // CHECK-NEXT:  1| [[@LINE-9]]|int func(T x) {
-                     // CHECK-NEXT:  1| [[@LINE-9]]|  if(x)
-                     // CHECK-NEXT:  1| [[@LINE-9]]|    return 0;
-                     // CHECK-NEXT:  1| [[@LINE-9]]|  else
-                     // CHECK-NEXT:  0| [[@LINE-9]]|    return 1;
-                     // CHECK-NEXT:  0| [[@LINE-9]]|  int j = 1;
-                     // CHECK-NEXT:  1| [[@LINE-9]]|}
+                     // SHARED:       {{^ *(\| )?}}_Z4funcIbEiT_:
+                     // SHARED-NEXT:  1| [[@LINE-9]]|int func(T x) {
+                     // SHARED-NEXT:  1| [[@LINE-9]]|  if(x)
+                     // SHARED-NEXT:  1| [[@LINE-9]]|    return 0;
+                     // SHARED-NEXT:  1| [[@LINE-9]]|  else
+                     // SHARED-NEXT:  0| [[@LINE-9]]|    return 1;
+                     // SHARED-NEXT:  0| [[@LINE-9]]|  int j = 1;
+                     // SHARED-NEXT:  1| [[@LINE-9]]|}
 
                      // ALL:         {{^ *}}| _Z4funcIiEiT_:
                      // FILTER-NOT:  {{^ *(\| )?}} _Z4funcIiEiT_:
@@ -38,3 +38,48 @@ int main() {         // ALL:         1| [[@LINE]]|int main() {
 }                    // ALL-NEXT:    1| [[@LINE]]|}
 // after coverage    // ALL-NEXT:     | [[@LINE]]|// after
                      // FILTER-NOT:   | [[@LINE-1]]|// after
+
+// Test html output.
+// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -filename-equivalence %s -format html -o %t.html.dir
+// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -filename-equivalence -name=_Z4funcIbEiT_ %s -format html -o %t.html.dir
+// RUN: FileCheck -check-prefixes=HTML-SHARED,HTML-ALL -input-file=%t.html.dir/coverage/tmp/showTemplateInstantiations.cpp.html %s
+// RUN: FileCheck -check-prefixes=HTML-SHARED,HTML-FILTER -input-file=%t.html.dir/functions.html %s
+
+// HTML-ALL: 
[[@LINE-44]]
// before
+// HTML-FILTER-NOT: 
[[@LINE-45]]
// before
+// HTML-ALL: 
[[@LINE-44]]
template<typename T>
+// HTML-ALL: 
2
[[@LINE-44]]
int func(T x) {
+// HTML-ALL: 
2
[[@LINE-44]]
  if(x)
+// HTML-ALL: 
1
[[@LINE-44]]
    ret
+// HTML-ALL: 
2
[[@LINE-44]]
  else
+// HTML-ALL: 
1
[[@LINE-44]]
    ret
+// HTML-ALL: 
0
[[@LINE-44]]
+// HTML-ALL: 
2
[[@LINE-44]]
}
+
+// HTML-SHARED: 
_Z4funcIbEiT_
+// HTML-SHARED: "; +} + +void SourceCoverageViewHTML::renderLineSuffix(raw_ostream &OS, unsigned) { + // If this view has sub-views, renderLine() cannot close the view's cell. + // Take care of it here, after all sub-views have been rendered. + if (hasSubViews()) + OS << EndCodeTD; + OS << ""; +} + +void SourceCoverageViewHTML::renderViewDivider(raw_ostream &, unsigned) { + // The table-based output makes view dividers unnecessary. +} + +void SourceCoverageViewHTML::renderLine( + raw_ostream &OS, LineRef L, const coverage::CoverageSegment *WrappedSegment, + CoverageSegmentArray Segments, unsigned ExpansionCol, unsigned) { + StringRef Line = L.Line; + + // Steps for handling text-escaping, highlighting, and tooltip creation: + // + // 1. Split the line into N+1 snippets, where N = |Segments|. The first + // snippet starts from Col=1 and ends at the start of the first segment. + // The last snippet starts at the last mapped column in the line and ends + // at the end of the line. Both are required but may be empty. + + SmallVector Snippets; + + unsigned LCol = 1; + auto Snip = [&](unsigned Start, unsigned Len) { + assert(Start + Len <= Line.size() && "Snippet extends past the EOL"); + Snippets.push_back(Line.substr(Start, Len)); + LCol += Len; + }; + + Snip(LCol - 1, Segments.empty() ? 0 : (Segments.front()->Col - 1)); + + for (unsigned I = 1, E = Segments.size(); I < E; ++I) { + assert(LCol == Segments[I - 1]->Col && "Snippet start position is wrong"); + Snip(LCol - 1, Segments[I]->Col - LCol); + } + + // |Line| + 1 is needed to avoid underflow when, e.g |Line| = 0 and LCol = 1. + Snip(LCol - 1, Line.size() + 1 - LCol); + assert(LCol == Line.size() + 1 && "Final snippet doesn't reach the EOL"); + + // 2. Escape all of the snippets. + + for (unsigned I = 0, E = Snippets.size(); I < E; ++I) + Snippets[I] = escape(Snippets[I]); + + // 3. Use \p WrappedSegment to set the highlight for snippets 0 and 1. Use + // segment 1 to set the highlight for snippet 2, segment 2 to set the + // highlight for snippet 3, and so on. + + Optional Color; + auto Highlight = [&](const std::string &Snippet) { + return tag("span", Snippet, Color.getValue()); + }; + + auto CheckIfUncovered = [](const coverage::CoverageSegment *S) { + return S && S->HasCount && S->Count == 0; + }; + + if (CheckIfUncovered(WrappedSegment) || + CheckIfUncovered(Segments.empty() ? nullptr : Segments.front())) { + Color = "red"; + Snippets[0] = Highlight(Snippets[0]); + Snippets[1] = Highlight(Snippets[1]); + } + + for (unsigned I = 1, E = Segments.size(); I < E; ++I) { + const auto *CurSeg = Segments[I]; + if (CurSeg->Col == ExpansionCol) + Color = "cyan"; + else if (CheckIfUncovered(CurSeg)) + Color = "red"; + else + Color = None; + + if (Color.hasValue()) + Snippets[I + 1] = Highlight(Snippets[I + 1]); + } + + // 4. Snippets[1:N+1] correspond to \p Segments[0:N]: use these to generate + // sub-line region count tooltips if needed. + + bool HasMultipleRegions = [&] { + unsigned RegionCount = 0; + for (const auto *S : Segments) + if (S->HasCount && S->IsRegionEntry) + if (++RegionCount > 1) + return true; + return false; + }(); + + if (shouldRenderRegionMarkers(HasMultipleRegions)) { + for (unsigned I = 0, E = Segments.size(); I < E; ++I) { + const auto *CurSeg = Segments[I]; + if (!CurSeg->IsRegionEntry || !CurSeg->HasCount) + continue; + + Snippets[I + 1] = + tag("div", Snippets[I + 1] + tag("span", formatCount(CurSeg->Count), + "tooltip-content"), + "tooltip"); + } + } + + OS << BeginCodeTD; + OS << BeginPre; + for (const auto &Snippet : Snippets) + OS << Snippet; + OS << EndPre; + + // If there are no sub-views left to attach to this cell, end the cell. + // Otherwise, end it after the sub-views are rendered (renderLineSuffix()). + if (!hasSubViews()) + OS << EndCodeTD; +} + +void SourceCoverageViewHTML::renderLineCoverageColumn( + raw_ostream &OS, const LineCoverageStats &Line) { + std::string Count = ""; + if (Line.isMapped()) + Count = tag("pre", formatCount(Line.ExecutionCount)); + std::string CoverageClass = + (Line.ExecutionCount > 0) ? "covered-line" : "uncovered-line"; + OS << tag("td", Count, CoverageClass); +} + +void SourceCoverageViewHTML::renderLineNumberColumn(raw_ostream &OS, + unsigned LineNo) { + OS << tag("td", tag("pre", utostr(uint64_t(LineNo))), "line-number"); +} + +void SourceCoverageViewHTML::renderRegionMarkers(raw_ostream &, + CoverageSegmentArray, + unsigned) { + // Region markers are rendered in-line using tooltips. +} + +void SourceCoverageViewHTML::renderExpansionSite( + raw_ostream &OS, LineRef L, const coverage::CoverageSegment *WrappedSegment, + CoverageSegmentArray Segments, unsigned ExpansionCol, unsigned ViewDepth) { + // Render the line containing the expansion site. No extra formatting needed. + renderLine(OS, L, WrappedSegment, Segments, ExpansionCol, ViewDepth); +} + +void SourceCoverageViewHTML::renderExpansionView(raw_ostream &OS, + ExpansionView &ESV, + unsigned ViewDepth) { + OS << BeginExpansionDiv; + ESV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/false, + ViewDepth + 1); + OS << EndExpansionDiv; +} + +void SourceCoverageViewHTML::renderInstantiationView(raw_ostream &OS, + InstantiationView &ISV, + unsigned ViewDepth) { + OS << BeginExpansionDiv; + ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true, ViewDepth); + OS << EndExpansionDiv; +} diff --git a/tools/llvm-cov/SourceCoverageViewHTML.h b/tools/llvm-cov/SourceCoverageViewHTML.h new file mode 100644 index 0000000000000000000000000000000000000000..50ecf2bf899702ac04d7f535a1bf057f86f834b2 --- /dev/null +++ b/tools/llvm-cov/SourceCoverageViewHTML.h @@ -0,0 +1,83 @@ +//===- SourceCoverageViewHTML.h - A html code coverage view ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file This file defines the interface to the html coverage renderer. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_COV_SOURCECOVERAGEVIEWHTML_H +#define LLVM_COV_SOURCECOVERAGEVIEWHTML_H + +#include "SourceCoverageView.h" + +namespace llvm { + +/// \brief A coverage printer for html output. +class CoveragePrinterHTML : public CoveragePrinter { +public: + Expected createViewFile(StringRef Path, + bool InToplevel) override; + + void closeViewFile(OwnedStream OS) override; + + Error createIndexFile(ArrayRef SourceFiles) override; + + CoveragePrinterHTML(const CoverageViewOptions &Opts) + : CoveragePrinter(Opts) {} +}; + +/// \brief A code coverage view which supports html-based rendering. +class SourceCoverageViewHTML : public SourceCoverageView { + void renderViewHeader(raw_ostream &OS) override; + + void renderViewFooter(raw_ostream &OS) override; + + void renderSourceName(raw_ostream &OS) override; + + void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override; + + void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) override; + + void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) override; + + void renderLine(raw_ostream &OS, LineRef L, + const coverage::CoverageSegment *WrappedSegment, + CoverageSegmentArray Segments, unsigned ExpansionCol, + unsigned ViewDepth) override; + + void renderExpansionSite(raw_ostream &OS, LineRef L, + const coverage::CoverageSegment *WrappedSegment, + CoverageSegmentArray Segments, unsigned ExpansionCol, + unsigned ViewDepth) override; + + void renderExpansionView(raw_ostream &OS, ExpansionView &ESV, + unsigned ViewDepth) override; + + void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV, + unsigned ViewDepth) override; + + void renderLineCoverageColumn(raw_ostream &OS, + const LineCoverageStats &Line) override; + + void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) override; + + void renderRegionMarkers(raw_ostream &OS, CoverageSegmentArray Segments, + unsigned ViewDepth) override; + +public: + SourceCoverageViewHTML(StringRef SourceName, const MemoryBuffer &File, + const CoverageViewOptions &Options, + coverage::CoverageData &&CoverageInfo) + : SourceCoverageView(SourceName, File, Options, std::move(CoverageInfo)) { + } +}; + +} // namespace llvm + +#endif // LLVM_COV_SOURCECOVERAGEVIEWHTML_H diff --git a/tools/llvm-cov/SourceCoverageViewText.cpp b/tools/llvm-cov/SourceCoverageViewText.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae9d6daed08f763e5867713751a315bf7d613402 --- /dev/null +++ b/tools/llvm-cov/SourceCoverageViewText.cpp @@ -0,0 +1,213 @@ +//===- SourceCoverageViewText.cpp - A text-based code coverage view -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file This file implements the text-based coverage renderer. +/// +//===----------------------------------------------------------------------===// + +#include "SourceCoverageViewText.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" + +using namespace llvm; + +Expected +CoveragePrinterText::createViewFile(StringRef Path, bool InToplevel) { + return createOutputStream(Path, "txt", InToplevel); +} + +void CoveragePrinterText::closeViewFile(OwnedStream OS) { + OS->operator<<('\n'); +} + +Error CoveragePrinterText::createIndexFile(ArrayRef SourceFiles) { + auto OSOrErr = createOutputStream("index", "txt", /*InToplevel=*/true); + if (Error E = OSOrErr.takeError()) + return E; + auto OS = std::move(OSOrErr.get()); + raw_ostream &OSRef = *OS.get(); + + for (StringRef SF : SourceFiles) + OSRef << getOutputPath(SF, "txt", /*InToplevel=*/false) << '\n'; + + return Error::success(); +} + +namespace { + +static const unsigned LineCoverageColumnWidth = 7; +static const unsigned LineNumberColumnWidth = 5; + +/// \brief Get the width of the leading columns. +unsigned getCombinedColumnWidth(const CoverageViewOptions &Opts) { + return (Opts.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) + + (Opts.ShowLineNumbers ? LineNumberColumnWidth + 1 : 0); +} + +/// \brief The width of the line that is used to divide between the view and +/// the subviews. +unsigned getDividerWidth(const CoverageViewOptions &Opts) { + return getCombinedColumnWidth(Opts) + 4; +} + +} // anonymous namespace + +void SourceCoverageViewText::renderViewHeader(raw_ostream &) {} + +void SourceCoverageViewText::renderViewFooter(raw_ostream &) {} + +void SourceCoverageViewText::renderSourceName(raw_ostream &OS) { + getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName() + << ":\n"; +} + +void SourceCoverageViewText::renderLinePrefix(raw_ostream &OS, + unsigned ViewDepth) { + for (unsigned I = 0; I < ViewDepth; ++I) + OS << " |"; +} + +void SourceCoverageViewText::renderLineSuffix(raw_ostream &, unsigned) {} + +void SourceCoverageViewText::renderViewDivider(raw_ostream &OS, + unsigned ViewDepth) { + assert(ViewDepth != 0 && "Cannot render divider at top level"); + renderLinePrefix(OS, ViewDepth - 1); + OS.indent(2); + unsigned Length = getDividerWidth(getOptions()); + for (unsigned I = 0; I < Length; ++I) + OS << '-'; + OS << '\n'; +} + +void SourceCoverageViewText::renderLine( + raw_ostream &OS, LineRef L, + const coverage::CoverageSegment *WrappedSegment, + CoverageSegmentArray Segments, unsigned ExpansionCol, unsigned ViewDepth) { + StringRef Line = L.Line; + unsigned LineNumber = L.LineNo; + + Optional Highlight; + SmallVector, 2> HighlightedRanges; + + // The first segment overlaps from a previous line, so we treat it specially. + if (WrappedSegment && WrappedSegment->HasCount && WrappedSegment->Count == 0) + Highlight = raw_ostream::RED; + + // Output each segment of the line, possibly highlighted. + unsigned Col = 1; + for (const auto *S : Segments) { + unsigned End = std::min(S->Col, static_cast(Line.size()) + 1); + colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR, + getOptions().Colors && Highlight, /*Bold=*/false, + /*BG=*/true) + << Line.substr(Col - 1, End - Col); + if (getOptions().Debug && Highlight) + HighlightedRanges.push_back(std::make_pair(Col, End)); + Col = End; + if (Col == ExpansionCol) + Highlight = raw_ostream::CYAN; + else if (S->HasCount && S->Count == 0) + Highlight = raw_ostream::RED; + else + Highlight = None; + } + + // Show the rest of the line. + colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR, + getOptions().Colors && Highlight, /*Bold=*/false, /*BG=*/true) + << Line.substr(Col - 1, Line.size() - Col + 1); + OS << '\n'; + + if (getOptions().Debug) { + for (const auto &Range : HighlightedRanges) + errs() << "Highlighted line " << LineNumber << ", " << Range.first + << " -> " << Range.second << '\n'; + if (Highlight) + errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n"; + } +} + +void SourceCoverageViewText::renderLineCoverageColumn( + raw_ostream &OS, const LineCoverageStats &Line) { + if (!Line.isMapped()) { + OS.indent(LineCoverageColumnWidth) << '|'; + return; + } + std::string C = formatCount(Line.ExecutionCount); + OS.indent(LineCoverageColumnWidth - C.size()); + colored_ostream(OS, raw_ostream::MAGENTA, + Line.hasMultipleRegions() && getOptions().Colors) + << C; + OS << '|'; +} + +void SourceCoverageViewText::renderLineNumberColumn(raw_ostream &OS, + unsigned LineNo) { + SmallString<32> Buffer; + raw_svector_ostream BufferOS(Buffer); + BufferOS << LineNo; + auto Str = BufferOS.str(); + // Trim and align to the right. + Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth)); + OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|'; +} + +void SourceCoverageViewText::renderRegionMarkers( + raw_ostream &OS, CoverageSegmentArray Segments, unsigned ViewDepth) { + renderLinePrefix(OS, ViewDepth); + OS.indent(getCombinedColumnWidth(getOptions())); + + unsigned PrevColumn = 1; + for (const auto *S : Segments) { + if (!S->IsRegionEntry) + continue; + // Skip to the new region. + if (S->Col > PrevColumn) + OS.indent(S->Col - PrevColumn); + PrevColumn = S->Col + 1; + std::string C = formatCount(S->Count); + PrevColumn += C.size(); + OS << '^' << C; + } + OS << '\n'; + + if (getOptions().Debug) + for (const auto *S : Segments) + errs() << "Marker at " << S->Line << ":" << S->Col << " = " + << formatCount(S->Count) << (S->IsRegionEntry ? "\n" : " (pop)\n"); +} + +void SourceCoverageViewText::renderExpansionSite( + raw_ostream &OS, LineRef L, const coverage::CoverageSegment *WrappedSegment, + CoverageSegmentArray Segments, unsigned ExpansionCol, unsigned ViewDepth) { + renderLinePrefix(OS, ViewDepth); + OS.indent(getCombinedColumnWidth(getOptions()) + (ViewDepth == 0 ? 0 : 1)); + renderLine(OS, L, WrappedSegment, Segments, ExpansionCol, ViewDepth); +} + +void SourceCoverageViewText::renderExpansionView(raw_ostream &OS, + ExpansionView &ESV, + unsigned ViewDepth) { + // Render the child subview. + if (getOptions().Debug) + errs() << "Expansion at line " << ESV.getLine() << ", " << ESV.getStartCol() + << " -> " << ESV.getEndCol() << '\n'; + ESV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/false, + ViewDepth + 1); +} + +void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS, + InstantiationView &ISV, + unsigned ViewDepth) { + renderLinePrefix(OS, ViewDepth); + OS << ' '; + ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true, ViewDepth); +} diff --git a/tools/llvm-cov/SourceCoverageViewText.h b/tools/llvm-cov/SourceCoverageViewText.h new file mode 100644 index 0000000000000000000000000000000000000000..b2331247b37b71687e2868f6d88bb85751907093 --- /dev/null +++ b/tools/llvm-cov/SourceCoverageViewText.h @@ -0,0 +1,83 @@ +//===- SourceCoverageViewText.h - A text-based code coverage view ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file This file defines the interface to the text-based coverage renderer. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_COV_SOURCECOVERAGEVIEWTEXT_H +#define LLVM_COV_SOURCECOVERAGEVIEWTEXT_H + +#include "SourceCoverageView.h" + +namespace llvm { + +/// \brief A coverage printer for text output. +class CoveragePrinterText : public CoveragePrinter { +public: + Expected createViewFile(StringRef Path, + bool InToplevel) override; + + void closeViewFile(OwnedStream OS) override; + + Error createIndexFile(ArrayRef SourceFiles) override; + + CoveragePrinterText(const CoverageViewOptions &Opts) + : CoveragePrinter(Opts) {} +}; + +/// \brief A code coverage view which supports text-based rendering. +class SourceCoverageViewText : public SourceCoverageView { + void renderViewHeader(raw_ostream &OS) override; + + void renderViewFooter(raw_ostream &OS) override; + + void renderSourceName(raw_ostream &OS) override; + + void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override; + + void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) override; + + void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) override; + + void renderLine(raw_ostream &OS, LineRef L, + const coverage::CoverageSegment *WrappedSegment, + CoverageSegmentArray Segments, unsigned ExpansionCol, + unsigned ViewDepth) override; + + void renderExpansionSite(raw_ostream &OS, LineRef L, + const coverage::CoverageSegment *WrappedSegment, + CoverageSegmentArray Segments, unsigned ExpansionCol, + unsigned ViewDepth) override; + + void renderExpansionView(raw_ostream &OS, ExpansionView &ESV, + unsigned ViewDepth) override; + + void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV, + unsigned ViewDepth) override; + + void renderLineCoverageColumn(raw_ostream &OS, + const LineCoverageStats &Line) override; + + void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) override; + + void renderRegionMarkers(raw_ostream &OS, CoverageSegmentArray Segments, + unsigned ViewDepth) override; + +public: + SourceCoverageViewText(StringRef SourceName, const MemoryBuffer &File, + const CoverageViewOptions &Options, + coverage::CoverageData &&CoverageInfo) + : SourceCoverageView(SourceName, File, Options, std::move(CoverageInfo)) { + } +}; + +} // namespace llvm + +#endif // LLVM_COV_SOURCECOVERAGEVIEWTEXT_H diff --git a/tools/llvm-cov/TestingSupport.cpp b/tools/llvm-cov/TestingSupport.cpp index 6959897482ca2d4b32089ba2a6481d22ae7a9adf..72768f4fd583fc81970216cb6bd43b99258db122 100644 --- a/tools/llvm-cov/TestingSupport.cpp +++ b/tools/llvm-cov/TestingSupport.cpp @@ -8,11 +8,9 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/ObjectFile.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/LEB128.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -21,10 +19,6 @@ using namespace llvm; using namespace object; int convertForTestingMain(int argc, const char *argv[]) { - sys::PrintStackTraceOnErrorSignal(); - PrettyStackTraceProgram X(argc, argv); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - cl::opt InputSourceFile(cl::Positional, cl::Required, cl::desc("")); @@ -36,8 +30,12 @@ int convertForTestingMain(int argc, const char *argv[]) { cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); auto ObjErr = llvm::object::ObjectFile::createObjectFile(InputSourceFile); - if (auto Err = ObjErr.getError()) { - errs() << "error: " << Err.message() << "\n"; + if (!ObjErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(ObjErr.takeError(), OS, ""); + OS.flush(); + errs() << "error: " << Buf; return 1; } ObjectFile *OF = ObjErr.get().getBinary(); @@ -54,9 +52,9 @@ int convertForTestingMain(int argc, const char *argv[]) { StringRef Name; if (Section.getName(Name)) return 1; - if (Name == "__llvm_prf_names") { + if (Name == llvm::getInstrProfNameSectionName(false)) { ProfileNames = Section; - } else if (Name == "__llvm_covmap") { + } else if (Name == llvm::getInstrProfCoverageSectionName(false)) { CoverageMapping = Section; } else continue; @@ -84,7 +82,11 @@ int convertForTestingMain(int argc, const char *argv[]) { OS << "llvmcovmtestdata"; encodeULEB128(ProfileNamesData.size(), OS); encodeULEB128(ProfileNamesAddress, OS); - OS << ProfileNamesData << CoverageMappingData; + OS << ProfileNamesData; + // Coverage mapping data is expected to have an alignment of 8. + for (unsigned Pad = OffsetToAlignment(OS.tell(), 8); Pad; --Pad) + OS.write(uint8_t(0)); + OS << CoverageMappingData; return 0; } diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp index a5343fa29afc3a7ed55af5f748870cbc906e774b..4652fed2a384e21bd783285e9f16316b0da52d8b 100644 --- a/tools/llvm-cov/gcov.cpp +++ b/tools/llvm-cov/gcov.cpp @@ -16,10 +16,7 @@ #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/GCOV.h" -#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" #include using namespace llvm; @@ -85,11 +82,6 @@ static void reportCoverage(StringRef SourceFile, StringRef ObjectDir, } int gcovMain(int argc, const 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::list SourceFiles(cl::Positional, cl::OneOrMore, cl::desc("SOURCEFILE")); diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp index 8c5acaef63b2561ca8518d57fc1a7c22fd708727..ba60cd91da90661f46103b887dbb6d4faf967433 100644 --- a/tools/llvm-cov/llvm-cov.cpp +++ b/tools/llvm-cov/llvm-cov.cpp @@ -14,8 +14,11 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" +#include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include @@ -51,6 +54,11 @@ static int versionMain(int argc, const char *argv[]) { } int main(int argc, const char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(argv[0]); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + // If argv[0] is or ends with 'gcov', always be gcov compatible if (sys::path::stem(argv[0]).endswith_lower("gcov")) return gcovMain(argc, argv); diff --git a/tools/llvm-cxxdump/Error.cpp b/tools/llvm-cxxdump/Error.cpp index 16fed96e4834cc00bfff8ff90c88c489a9adc858..ff9f0f5790669e42a7ad736042e4a2ecd18fd657 100644 --- a/tools/llvm-cxxdump/Error.cpp +++ b/tools/llvm-cxxdump/Error.cpp @@ -17,6 +17,9 @@ using namespace llvm; namespace { +// FIXME: This class is only here to support the transition to llvm::Error. It +// will be removed once this transition is complete. Clients should prefer to +// deal with the Error value directly, rather than converting to error_code. class cxxdump_error_category : public std::error_category { public: const char *name() const LLVM_NOEXCEPT override { return "llvm.cxxdump"; } diff --git a/tools/llvm-cxxdump/llvm-cxxdump.cpp b/tools/llvm-cxxdump/llvm-cxxdump.cpp index 3dda69266a2d803778f3fc67485528ae24ccfab8..c92d20d6ccf170d719e5de3a79b1163b2e7e8cbd 100644 --- a/tools/llvm-cxxdump/llvm-cxxdump.cpp +++ b/tools/llvm-cxxdump/llvm-cxxdump.cpp @@ -50,6 +50,14 @@ static void error(std::error_code EC) { exit(1); } +static void error(Error Err) { + if (Err) { + logAllUnhandledErrors(std::move(Err), outs(), "Error reading file: "); + outs().flush(); + exit(1); + } +} + } // namespace llvm static void reportError(StringRef Input, StringRef Message) { @@ -79,8 +87,8 @@ static void collectRelocatedSymbols(const ObjectFile *Obj, const object::symbol_iterator RelocSymI = Reloc.getSymbol(); if (RelocSymI == Obj->symbol_end()) continue; - ErrorOr RelocSymName = RelocSymI->getName(); - error(RelocSymName.getError()); + Expected RelocSymName = RelocSymI->getName(); + error(errorToErrorCode(RelocSymName.takeError())); uint64_t Offset = Reloc.getOffset(); if (Offset >= SymOffset && Offset < SymEnd) { *I = *RelocSymName; @@ -101,8 +109,8 @@ static void collectRelocationOffsets( const object::symbol_iterator RelocSymI = Reloc.getSymbol(); if (RelocSymI == Obj->symbol_end()) continue; - ErrorOr RelocSymName = RelocSymI->getName(); - error(RelocSymName.getError()); + Expected RelocSymName = RelocSymI->getName(); + error(errorToErrorCode(RelocSymName.takeError())); uint64_t Offset = Reloc.getOffset(); if (Offset >= SymOffset && Offset < SymEnd) Collection[std::make_pair(SymName, Offset - SymOffset)] = *RelocSymName; @@ -175,11 +183,11 @@ static void dumpCXXData(const ObjectFile *Obj) { for (auto &P : SymAddr) { object::SymbolRef Sym = P.first; uint64_t SymSize = P.second; - ErrorOr SymNameOrErr = Sym.getName(); - error(SymNameOrErr.getError()); + Expected SymNameOrErr = Sym.getName(); + error(errorToErrorCode(SymNameOrErr.takeError())); StringRef SymName = *SymNameOrErr; - ErrorOr SecIOrErr = Sym.getSection(); - error(SecIOrErr.getError()); + Expected SecIOrErr = Sym.getSection(); + error(errorToErrorCode(SecIOrErr.takeError())); object::section_iterator SecI = *SecIOrErr; // Skip external symbols. if (SecI == Obj->section_end()) @@ -190,8 +198,8 @@ static void dumpCXXData(const ObjectFile *Obj) { continue; StringRef SecContents; error(Sec.getContents(SecContents)); - ErrorOr SymAddressOrErr = Sym.getAddress(); - error(SymAddressOrErr.getError()); + Expected SymAddressOrErr = Sym.getAddress(); + error(errorToErrorCode(SymAddressOrErr.takeError())); uint64_t SymAddress = *SymAddressOrErr; uint64_t SecAddress = Sec.getAddress(); uint64_t SecSize = Sec.getSize(); @@ -482,14 +490,19 @@ static void dumpCXXData(const ObjectFile *Obj) { } static void dumpArchive(const Archive *Arc) { - for (auto &ErrorOrChild : Arc->children()) { - error(ErrorOrChild.getError()); - const Archive::Child &ArcC = *ErrorOrChild; - ErrorOr> ChildOrErr = ArcC.getAsBinary(); - if (std::error_code EC = ChildOrErr.getError()) { + Error Err; + for (auto &ArcC : Arc->children(Err)) { + Expected> ChildOrErr = ArcC.getAsBinary(); + if (!ChildOrErr) { // Ignore non-object files. - if (EC != object_error::invalid_file_type) - reportError(Arc->getFileName(), EC.message()); + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS, ""); + OS.flush(); + reportError(Arc->getFileName(), Buf); + } + ChildOrErr.takeError(); continue; } @@ -498,12 +511,14 @@ static void dumpArchive(const Archive *Arc) { else reportError(Arc->getFileName(), cxxdump_error::unrecognized_file_format); } + error(std::move(Err)); } static void dumpInput(StringRef File) { // Attempt to open the binary. - ErrorOr> BinaryOrErr = createBinary(File); - if (std::error_code EC = BinaryOrErr.getError()) { + Expected> BinaryOrErr = createBinary(File); + if (!BinaryOrErr) { + auto EC = errorToErrorCode(BinaryOrErr.takeError()); reportError(File, EC); return; } @@ -518,7 +533,7 @@ static void dumpInput(StringRef File) { } int main(int argc, const char *argv[]) { - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; diff --git a/tools/llvm-diff/DiffConsumer.h b/tools/llvm-diff/DiffConsumer.h index 36d4a12311694af193d95f146ea047e6d5cf4901..82f5ce598b44374b675158db260dc19876a5bde7 100644 --- a/tools/llvm-diff/DiffConsumer.h +++ b/tools/llvm-diff/DiffConsumer.h @@ -17,12 +17,12 @@ #include "DiffLog.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" namespace llvm { +class StringRef; class Module; class Value; class Function; diff --git a/tools/llvm-diff/DiffLog.cpp b/tools/llvm-diff/DiffLog.cpp index ed86058f1af1061ad5d39fb5561215a7adafef74..898749e73bd20a9ec43c1f934a563427a67ad4b3 100644 --- a/tools/llvm-diff/DiffLog.cpp +++ b/tools/llvm-diff/DiffLog.cpp @@ -13,7 +13,6 @@ #include "DiffLog.h" #include "DiffConsumer.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/Instructions.h" diff --git a/tools/llvm-diff/DifferenceEngine.cpp b/tools/llvm-diff/DifferenceEngine.cpp index fc9ea99371fb3aedf62a7e22cc2338e07af5f25d..df208a26ab7dfdc8a3854b275b7250b6aafd03d2 100644 --- a/tools/llvm-diff/DifferenceEngine.cpp +++ b/tools/llvm-diff/DifferenceEngine.cpp @@ -16,7 +16,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/IR/CFG.h" #include "llvm/IR/CallSite.h" diff --git a/tools/llvm-diff/DifferenceEngine.h b/tools/llvm-diff/DifferenceEngine.h index f0d831144a4cb7caaf16e8ebe27d41c7067be935..7f084a377f0c7a1f4d127e19b20b73d5064d6bc5 100644 --- a/tools/llvm-diff/DifferenceEngine.h +++ b/tools/llvm-diff/DifferenceEngine.h @@ -17,7 +17,6 @@ #include "DiffConsumer.h" #include "DiffLog.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include diff --git a/tools/llvm-diff/llvm-diff.cpp b/tools/llvm-diff/llvm-diff.cpp index ae58f5caa913855d14844ac7bed46a74b6c16ccd..e449d6994784e7694bf07f1b8697fcfa2f932558 100644 --- a/tools/llvm-diff/llvm-diff.cpp +++ b/tools/llvm-diff/llvm-diff.cpp @@ -13,8 +13,6 @@ #include "DiffLog.h" #include "DifferenceEngine.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp index 9fdfcd4256c9a8cb6832b7153503638969be936d..88333aeb68892e578c91e1f496865d8cc1866599 100644 --- a/tools/llvm-dis/llvm-dis.cpp +++ b/tools/llvm-dis/llvm-dis.cpp @@ -27,6 +27,7 @@ #include "llvm/IR/Type.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DataStream.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/ManagedStatic.h" @@ -59,6 +60,11 @@ static cl::opt PreserveAssemblyUseListOrder( cl::desc("Preserve use-list order when writing LLVM assembly."), cl::init(false), cl::Hidden); +static cl::opt + MaterializeMetadata("materialize-metadata", + cl::desc("Load module without materializing metadata, " + "then materialize only the metadata")); + namespace { static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) { @@ -132,38 +138,59 @@ static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) { exit(1); } +static Expected> openInputFile(LLVMContext &Context) { + if (MaterializeMetadata) { + ErrorOr> MBOrErr = + MemoryBuffer::getFileOrSTDIN(InputFilename); + if (!MBOrErr) + return errorCodeToError(MBOrErr.getError()); + ErrorOr> MOrErr = + getLazyBitcodeModule(std::move(*MBOrErr), Context, + /*ShouldLazyLoadMetadata=*/true); + if (!MOrErr) + return errorCodeToError(MOrErr.getError()); + (*MOrErr)->materializeMetadata(); + return std::move(*MOrErr); + } else { + std::string ErrorMessage; + std::unique_ptr Streamer = + getDataFileStreamer(InputFilename, &ErrorMessage); + if (!Streamer) + return make_error(ErrorMessage, inconvertibleErrorCode()); + std::string DisplayFilename; + if (InputFilename == "-") + DisplayFilename = ""; + else + DisplayFilename = InputFilename; + ErrorOr> MOrErr = + getStreamedBitcodeModule(DisplayFilename, std::move(Streamer), Context); + (*MOrErr)->materializeAll(); + return std::move(*MOrErr); + } +} + int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); - LLVMContext &Context = getGlobalContext(); + LLVMContext Context; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. Context.setDiagnosticHandler(diagnosticHandler, argv[0]); cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n"); - std::string ErrorMessage; - std::unique_ptr M; - - // Use the bitcode streaming interface - std::unique_ptr Streamer = - getDataFileStreamer(InputFilename, &ErrorMessage); - if (Streamer) { - std::string DisplayFilename; - if (InputFilename == "-") - DisplayFilename = ""; - else - DisplayFilename = InputFilename; - ErrorOr> MOrErr = - getStreamedBitcodeModule(DisplayFilename, std::move(Streamer), Context); - M = std::move(*MOrErr); - M->materializeAll(); - } else { - errs() << argv[0] << ": " << ErrorMessage << '\n'; + Expected> MOrErr = openInputFile(Context); + if (!MOrErr) { + handleAllErrors(MOrErr.takeError(), [&](ErrorInfoBase &EIB) { + errs() << argv[0] << ": "; + EIB.log(errs()); + errs() << '\n'; + }); return 1; } + std::unique_ptr M = std::move(*MOrErr); // Just use stdout. We won't actually print anything on it. if (DontPrint) diff --git a/tools/llvm-dwarfdump/fuzzer/llvm-dwarfdump-fuzzer.cpp b/tools/llvm-dwarfdump/fuzzer/llvm-dwarfdump-fuzzer.cpp index af0ac3652287515b152cd020dee1f400e5f13cc0..32e173f9d1fce57c974126e0d3b5d90ccd430f50 100644 --- a/tools/llvm-dwarfdump/fuzzer/llvm-dwarfdump-fuzzer.cpp +++ b/tools/llvm-dwarfdump/fuzzer/llvm-dwarfdump-fuzzer.cpp @@ -24,10 +24,12 @@ extern "C" void LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { std::unique_ptr Buff = MemoryBuffer::getMemBuffer( StringRef((const char *)data, size), "", false); - ErrorOr> ObjOrErr = + Expected> ObjOrErr = ObjectFile::createObjectFile(Buff->getMemBufferRef()); - if (!ObjOrErr) + if (auto E = ObjOrErr.takeError()) { + consumeError(std::move(E)); return; + } ObjectFile &Obj = *ObjOrErr.get(); std::unique_ptr DICtx(new DWARFContextInMemory(Obj)); DICtx->dump(nulls(), DIDT_All); diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index eaacc7c5f21b79c626409fd66eeb4b515c74b108..4b3a011f861d107a8d42e7d6dfac08ca5fc27d7b 100644 --- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -29,7 +29,6 @@ #include "llvm/Support/raw_ostream.h" #include #include -#include #include #include @@ -96,16 +95,17 @@ static void DumpInput(StringRef Filename) { error(Filename, BuffOrErr.getError()); std::unique_ptr Buff = std::move(BuffOrErr.get()); - ErrorOr> BinOrErr = + Expected> BinOrErr = object::createBinary(Buff->getMemBufferRef()); - error(Filename, BinOrErr.getError()); + if (!BinOrErr) + error(Filename, errorToErrorCode(BinOrErr.takeError())); if (auto *Obj = dyn_cast(BinOrErr->get())) DumpObjectFile(*Obj, Filename); else if (auto *Fat = dyn_cast(BinOrErr->get())) for (auto &ObjForArch : Fat->objects()) { auto MachOOrErr = ObjForArch.getAsObjectFile(); - error(Filename, MachOOrErr.getError()); + error(Filename, errorToErrorCode(MachOOrErr.takeError())); DumpObjectFile(**MachOOrErr, Filename + " (" + ObjForArch.getArchTypeName() + ")"); } @@ -114,7 +114,7 @@ static void DumpInput(StringRef Filename) { /// If the input path is a .dSYM bundle (as created by the dsymutil tool), /// replace it with individual entries for each of the object files inside the /// bundle otherwise return the input path. -static std::vector expandBundle(std::string InputPath) { +static std::vector expandBundle(const std::string &InputPath) { std::vector BundlePaths; SmallString<256> BundlePath(InputPath); // Manually open up the bundle to avoid introducing additional dependencies. @@ -146,7 +146,7 @@ static std::vector expandBundle(std::string InputPath) { int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. @@ -158,7 +158,7 @@ int main(int argc, char **argv) { // Expand any .dSYM bundles to the individual object files contained therein. std::vector Objects; - for (auto F : InputFilenames) { + for (const auto &F : InputFilenames) { auto Objs = expandBundle(F); Objects.insert(Objects.end(), Objs.begin(), Objs.end()); } diff --git a/tools/llvm-dwp/CMakeLists.txt b/tools/llvm-dwp/CMakeLists.txt index b29c00d49c3d3a749d988edda7a0f262509c44eb..740ab5ca9040e465e721f4a43e24e94e17ed0cc8 100644 --- a/tools/llvm-dwp/CMakeLists.txt +++ b/tools/llvm-dwp/CMakeLists.txt @@ -10,4 +10,5 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-dwp llvm-dwp.cpp + DWPError.cpp ) diff --git a/tools/llvm-dwp/DWPError.cpp b/tools/llvm-dwp/DWPError.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21d53ed6d198c9407eeddf8489989a3e2eb52c98 --- /dev/null +++ b/tools/llvm-dwp/DWPError.cpp @@ -0,0 +1,3 @@ +#include "DWPError.h" +using namespace llvm; +char DWPError::ID; diff --git a/tools/llvm-dwp/DWPError.h b/tools/llvm-dwp/DWPError.h new file mode 100644 index 0000000000000000000000000000000000000000..62025ed4caa556ce663f4e8ef8257cceca649db7 --- /dev/null +++ b/tools/llvm-dwp/DWPError.h @@ -0,0 +1,23 @@ +#ifndef TOOLS_LLVM_DWP_DWPERROR +#define TOOLS_LLVM_DWP_DWPERROR + +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include + +namespace llvm { +class DWPError : public ErrorInfo { +public: + DWPError(std::string Info) : Info(std::move(Info)) {} + void log(raw_ostream &OS) const override { OS << Info; } + std::error_code convertToErrorCode() const override { + llvm_unreachable("Not implemented"); + } + static char ID; + +private: + std::string Info; +}; +} + +#endif diff --git a/tools/llvm-dwp/DWPStringPool.h b/tools/llvm-dwp/DWPStringPool.h new file mode 100644 index 0000000000000000000000000000000000000000..7d41176b56197ec24fbd23bd17aeb2bbcdec986e --- /dev/null +++ b/tools/llvm-dwp/DWPStringPool.h @@ -0,0 +1,56 @@ +#ifndef TOOLS_LLVM_DWP_DWPSTRINGPOOL +#define TOOLS_LLVM_DWP_DWPSTRINGPOOL + +#include "llvm/ADT/DenseMap.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCStreamer.h" +#include + +namespace llvm { +class DWPStringPool { + + struct CStrDenseMapInfo { + static inline const char *getEmptyKey() { + return reinterpret_cast(~static_cast(0)); + } + static inline const char *getTombstoneKey() { + return reinterpret_cast(~static_cast(1)); + } + static unsigned getHashValue(const char *Val) { + assert(Val != getEmptyKey() && "Cannot hash the empty key!"); + assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!"); + return (unsigned)hash_value(StringRef(Val)); + } + static bool isEqual(const char *LHS, const char *RHS) { + if (RHS == getEmptyKey()) + return LHS == getEmptyKey(); + if (RHS == getTombstoneKey()) + return LHS == getTombstoneKey(); + return strcmp(LHS, RHS) == 0; + } + }; + + MCStreamer &Out; + MCSection *Sec; + DenseMap Pool; + uint32_t Offset = 0; + +public: + DWPStringPool(MCStreamer &Out, MCSection *Sec) : Out(Out), Sec(Sec) {} + + uint32_t getOffset(const char *Str, unsigned Length) { + assert(strlen(Str) + 1 == Length && "Ensure length hint is correct"); + + auto Pair = Pool.insert(std::make_pair(Str, Offset)); + if (Pair.second) { + Out.SwitchSection(Sec); + Out.EmitBytes(StringRef(Str, Length)); + Offset += Length; + } + + return Pair.first->second; + } +}; +} + +#endif diff --git a/tools/llvm-dwp/llvm-dwp.cpp b/tools/llvm-dwp/llvm-dwp.cpp index 9fa22dcae3ea466276c402e16c386b727921303d..7bd3d3f3f4d08ecb503f8e88356e8207f7a1eefa 100644 --- a/tools/llvm-dwp/llvm-dwp.cpp +++ b/tools/llvm-dwp/llvm-dwp.cpp @@ -11,6 +11,8 @@ // package files). // //===----------------------------------------------------------------------===// +#include "DWPError.h" +#include "DWPStringPool.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSet.h" @@ -28,6 +30,7 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Compression.h" #include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" @@ -36,11 +39,9 @@ #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" -#include +#include #include #include -#include -#include using namespace llvm; using namespace llvm::object; @@ -55,21 +56,14 @@ static opt OutputFilename(Required, "o", value_desc("filename"), cat(DwpCategory)); -static int error(const Twine &Error, const Twine &Context) { - errs() << Twine("while processing ") + Context + ":\n"; - errs() << Twine("error: ") + Error + "\n"; - return 1; -} - -static std::error_code -writeStringsAndOffsets(MCStreamer &Out, StringMap &Strings, - uint32_t &StringOffset, MCSection *StrSection, - MCSection *StrOffsetSection, StringRef CurStrSection, - StringRef CurStrOffsetSection) { +static void writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings, + MCSection *StrOffsetSection, + StringRef CurStrSection, + StringRef CurStrOffsetSection) { // Could possibly produce an error or warning if one of these was non-null but // the other was null. if (CurStrSection.empty() || CurStrOffsetSection.empty()) - return std::error_code(); + return; DenseMap OffsetRemapping; @@ -77,15 +71,8 @@ writeStringsAndOffsets(MCStreamer &Out, StringMap &Strings, uint32_t LocalOffset = 0; uint32_t PrevOffset = 0; while (const char *s = Data.getCStr(&LocalOffset)) { - StringRef Str(s, LocalOffset - PrevOffset - 1); - auto Pair = Strings.insert(std::make_pair(Str, StringOffset)); - if (Pair.second) { - Out.SwitchSection(StrSection); - Out.EmitBytes( - StringRef(Pair.first->getKeyData(), Pair.first->getKeyLength() + 1)); - StringOffset += Str.size() + 1; - } - OffsetRemapping[PrevOffset] = Pair.first->second; + OffsetRemapping[PrevOffset] = + Strings.getOffset(s, LocalOffset - PrevOffset); PrevOffset = LocalOffset; } @@ -100,8 +87,6 @@ writeStringsAndOffsets(MCStreamer &Out, StringMap &Strings, auto NewOffset = OffsetRemapping[OldOffset]; Out.EmitIntValue(NewOffset, 4); } - - return std::error_code(); } static uint32_t getCUAbbrev(StringRef Abbrev, uint64_t AbbrCode) { @@ -126,8 +111,15 @@ struct CompileUnitIdentifiers { const char *DWOName = ""; }; -static const char *getIndexedString(uint32_t StrIndex, StringRef StrOffsets, - StringRef Str) { +static Expected +getIndexedString(uint32_t Form, DataExtractor InfoData, uint32_t &InfoOffset, + StringRef StrOffsets, StringRef Str) { + if (Form == dwarf::DW_FORM_string) + return InfoData.getCStr(&InfoOffset); + if (Form != dwarf::DW_FORM_GNU_str_index) + return make_error( + "string field encoded without DW_FORM_string or DW_FORM_GNU_str_index"); + auto StrIndex = InfoData.getULEB128(&InfoOffset); DataExtractor StrOffsetsData(StrOffsets, true, 0); uint32_t StrOffsetsOffset = 4 * StrIndex; uint32_t StrOffset = StrOffsetsData.getU32(&StrOffsetsOffset); @@ -135,9 +127,10 @@ static const char *getIndexedString(uint32_t StrIndex, StringRef StrOffsets, return StrData.getCStr(&StrOffset); } -static CompileUnitIdentifiers getCUIdentifiers(StringRef Abbrev, StringRef Info, - StringRef StrOffsets, - StringRef Str) { +static Expected getCUIdentifiers(StringRef Abbrev, + StringRef Info, + StringRef StrOffsets, + StringRef Str) { uint32_t Offset = 0; DataExtractor InfoData(Info, true, 0); InfoData.getU32(&Offset); // Length @@ -150,9 +143,8 @@ static CompileUnitIdentifiers getCUIdentifiers(StringRef Abbrev, StringRef Info, DataExtractor AbbrevData(Abbrev, true, 0); uint32_t AbbrevOffset = getCUAbbrev(Abbrev, AbbrCode); uint64_t Tag = AbbrevData.getULEB128(&AbbrevOffset); - (void)Tag; - // FIXME: Real error handling - assert(Tag == dwarf::DW_TAG_compile_unit); + if (Tag != dwarf::DW_TAG_compile_unit) + return make_error("top level DIE is not a compile unit"); // DW_CHILDREN AbbrevData.getU8(&AbbrevOffset); uint32_t Name; @@ -163,12 +155,19 @@ static CompileUnitIdentifiers getCUIdentifiers(StringRef Abbrev, StringRef Info, (Name != 0 || Form != 0)) { switch (Name) { case dwarf::DW_AT_name: { - ID.Name = getIndexedString(InfoData.getULEB128(&Offset), StrOffsets, Str); + Expected EName = + getIndexedString(Form, InfoData, Offset, StrOffsets, Str); + if (!EName) + return EName.takeError(); + ID.Name = *EName; break; } case dwarf::DW_AT_GNU_dwo_name: { - ID.DWOName = - getIndexedString(InfoData.getULEB128(&Offset), StrOffsets, Str); + Expected EName = + getIndexedString(Form, InfoData, Offset, StrOffsets, Str); + if (!EName) + return EName.takeError(); + ID.DWOName = *EName; break; } case dwarf::DW_AT_GNU_dwo_id: @@ -188,7 +187,9 @@ struct UnitIndexEntry { StringRef DWPName; }; -StringRef getSubsection(StringRef Section, const DWARFUnitIndex::Entry &Entry, DWARFSectionKind Kind) { +static StringRef getSubsection(StringRef Section, + const DWARFUnitIndex::Entry &Entry, + DWARFSectionKind Kind) { const auto *Off = Entry.getOffset(Kind); if (!Off) return StringRef(); @@ -227,36 +228,36 @@ static void addAllTypesFromDWP( static void addAllTypes(MCStreamer &Out, MapVector &TypeIndexEntries, - MCSection *OutputTypes, StringRef Types, + MCSection *OutputTypes, + const std::vector &TypesSections, const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) { - if (Types.empty()) - return; - - Out.SwitchSection(OutputTypes); - uint32_t Offset = 0; - DataExtractor Data(Types, true, 0); - while (Data.isValidOffset(Offset)) { - UnitIndexEntry Entry = CUEntry; - // Zero out the debug_info contribution - Entry.Contributions[0] = {}; - auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; - C.Offset = TypesOffset; - auto PrevOffset = Offset; - // Length of the unit, including the 4 byte length field. - C.Length = Data.getU32(&Offset) + 4; - - Data.getU16(&Offset); // Version - Data.getU32(&Offset); // Abbrev offset - Data.getU8(&Offset); // Address size - auto Signature = Data.getU64(&Offset); - Offset = PrevOffset + C.Length; - - auto P = TypeIndexEntries.insert(std::make_pair(Signature, Entry)); - if (!P.second) - continue; + for (StringRef Types : TypesSections) { + Out.SwitchSection(OutputTypes); + uint32_t Offset = 0; + DataExtractor Data(Types, true, 0); + while (Data.isValidOffset(Offset)) { + UnitIndexEntry Entry = CUEntry; + // Zero out the debug_info contribution + Entry.Contributions[0] = {}; + auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; + C.Offset = TypesOffset; + auto PrevOffset = Offset; + // Length of the unit, including the 4 byte length field. + C.Length = Data.getU32(&Offset) + 4; + + Data.getU16(&Offset); // Version + Data.getU32(&Offset); // Abbrev offset + Data.getU8(&Offset); // Address size + auto Signature = Data.getU64(&Offset); + Offset = PrevOffset + C.Length; + + auto P = TypeIndexEntries.insert(std::make_pair(Signature, Entry)); + if (!P.second) + continue; - Out.EmitBytes(Types.substr(PrevOffset, C.Length)); - TypesOffset += C.Length; + Out.EmitBytes(Types.substr(PrevOffset, C.Length)); + TypesOffset += C.Length; + } } } @@ -288,10 +289,11 @@ writeIndex(MCStreamer &Out, MCSection *Section, for (const auto &P : IndexEntries) { auto S = P.first; auto H = S & Mask; + auto HP = ((S >> 32) & Mask) | 1; while (Buckets[H]) { assert(S != IndexEntries.begin()[Buckets[H] - 1].first && "Duplicate unit"); - H = (H + (((S >> 32) & Mask) | 1)) % Buckets.size(); + H = (H + HP) & Mask; } Buckets[H] = i + 1; ++i; @@ -340,26 +342,127 @@ static bool consumeCompressedDebugSectionHeader(StringRef &data, return true; } -void printDuplicateError(const std::pair &PrevE, - const CompileUnitIdentifiers &ID, StringRef DWPName) { - errs() << "Duplicate DWO ID (" << PrevE.first << ") in '" << PrevE.second.Name - << '\''; - if (!PrevE.second.DWPName.empty()) { - errs() << " (from "; - if (!PrevE.second.DWOName.empty()) - errs() << '\'' << PrevE.second.DWOName << "' in "; - errs() << "'" << PrevE.second.DWPName.str() << "')"; - } - errs() << " and '" << ID.Name << '\''; +std::string buildDWODescription(StringRef Name, StringRef DWPName, StringRef DWOName) { + std::string Text = "\'"; + Text += Name; + Text += '\''; if (!DWPName.empty()) { - errs() << " (from "; - if (*ID.DWOName) - errs() << '\'' << ID.DWOName << "\' in "; - errs() << '\'' << DWPName << "')"; + Text += " (from "; + if (!DWOName.empty()) { + Text += '\''; + Text += DWOName; + Text += "' in "; + } + Text += '\''; + Text += DWPName; + Text += "')"; + } + return Text; +} + +static Error handleCompressedSection( + std::deque> &UncompressedSections, StringRef &Name, + StringRef &Contents) { + if (!Name.startswith("zdebug_")) + return Error(); + UncompressedSections.emplace_back(); + uint64_t OriginalSize; + if (!zlib::isAvailable()) + return make_error("zlib not available"); + if (!consumeCompressedDebugSectionHeader(Contents, OriginalSize) || + zlib::uncompress(Contents, UncompressedSections.back(), OriginalSize) != + zlib::StatusOK) + return make_error( + ("failure while decompressing compressed section: '" + Name + "\'") + .str()); + Name = Name.substr(1); + Contents = UncompressedSections.back(); + return Error(); +} + +static Error handleSection( + const StringMap> &KnownSections, + const MCSection *StrSection, const MCSection *StrOffsetSection, + const MCSection *TypesSection, const MCSection *CUIndexSection, + const MCSection *TUIndexSection, const SectionRef &Section, MCStreamer &Out, + std::deque> &UncompressedSections, + uint32_t (&ContributionOffsets)[8], UnitIndexEntry &CurEntry, + StringRef &CurStrSection, StringRef &CurStrOffsetSection, + std::vector &CurTypesSection, StringRef &InfoSection, + StringRef &AbbrevSection, StringRef &CurCUIndexSection, + StringRef &CurTUIndexSection) { + if (Section.isBSS()) + return Error(); + + if (Section.isVirtual()) + return Error(); + + StringRef Name; + if (std::error_code Err = Section.getName(Name)) + return errorCodeToError(Err); + + Name = Name.substr(Name.find_first_not_of("._")); + + StringRef Contents; + if (auto Err = Section.getContents(Contents)) + return errorCodeToError(Err); + + if (auto Err = handleCompressedSection(UncompressedSections, Name, Contents)) + return Err; + + auto SectionPair = KnownSections.find(Name); + if (SectionPair == KnownSections.end()) + return Error(); + + if (DWARFSectionKind Kind = SectionPair->second.second) { + auto Index = Kind - DW_SECT_INFO; + if (Kind != DW_SECT_TYPES) { + CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; + ContributionOffsets[Index] += + (CurEntry.Contributions[Index].Length = Contents.size()); + } + + switch (Kind) { + case DW_SECT_INFO: + InfoSection = Contents; + break; + case DW_SECT_ABBREV: + AbbrevSection = Contents; + break; + default: + break; + } } - errs() << '\n'; + + MCSection *OutSection = SectionPair->second.first; + if (OutSection == StrOffsetSection) + CurStrOffsetSection = Contents; + else if (OutSection == StrSection) + CurStrSection = Contents; + else if (OutSection == TypesSection) + CurTypesSection.push_back(Contents); + else if (OutSection == CUIndexSection) + CurCUIndexSection = Contents; + else if (OutSection == TUIndexSection) + CurTUIndexSection = Contents; + else { + Out.SwitchSection(OutSection); + Out.EmitBytes(Contents); + } + return Error(); } -static std::error_code write(MCStreamer &Out, ArrayRef Inputs) { + +static Error +buildDuplicateError(const std::pair &PrevE, + const CompileUnitIdentifiers &ID, StringRef DWPName) { + return make_error( + std::string("Duplicate DWO ID (") + utohexstr(PrevE.first) + ") in " + + buildDWODescription(PrevE.second.Name, PrevE.second.DWPName, + PrevE.second.DWOName) + + " and " + buildDWODescription(ID.Name, DWPName, ID.DWOName)); +} + +static Error write(MCStreamer &Out, ArrayRef Inputs) { const auto &MCOFI = *Out.getContext().getObjectFileInfo(); MCSection *const StrSection = MCOFI.getDwarfStrDWOSection(); MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection(); @@ -380,167 +483,107 @@ static std::error_code write(MCStreamer &Out, ArrayRef Inputs) { MapVector IndexEntries; MapVector TypeIndexEntries; - StringMap Strings; - uint32_t StringOffset = 0; - uint32_t ContributionOffsets[8] = {}; + DWPStringPool Strings(Out, StrSection); + + SmallVector, 128> Objects; + Objects.reserve(Inputs.size()); + + std::deque> UncompressedSections; + for (const auto &Input : Inputs) { auto ErrOrObj = object::ObjectFile::createObjectFile(Input); if (!ErrOrObj) - return ErrOrObj.getError(); + return ErrOrObj.takeError(); + + auto &Obj = *ErrOrObj->getBinary(); + Objects.push_back(std::move(*ErrOrObj)); UnitIndexEntry CurEntry = {}; StringRef CurStrSection; StringRef CurStrOffsetSection; - StringRef CurTypesSection; + std::vector CurTypesSection; StringRef InfoSection; StringRef AbbrevSection; StringRef CurCUIndexSection; StringRef CurTUIndexSection; - SmallVector, 4> UncompressedSections; - - for (const auto &Section : ErrOrObj->getBinary()->sections()) { - if (Section.isBSS()) - continue; - if (Section.isVirtual()) - continue; - - StringRef Name; - if (std::error_code Err = Section.getName(Name)) + for (const auto &Section : Obj.sections()) + if (auto Err = handleSection( + KnownSections, StrSection, StrOffsetSection, TypesSection, + CUIndexSection, TUIndexSection, Section, Out, + UncompressedSections, ContributionOffsets, CurEntry, + CurStrSection, CurStrOffsetSection, CurTypesSection, InfoSection, + AbbrevSection, CurCUIndexSection, CurTUIndexSection)) return Err; - Name = Name.substr(Name.find_first_not_of("._")); - - StringRef Contents; - if (auto Err = Section.getContents(Contents)) - return Err; - - if (Name.startswith("zdebug_")) { - uint64_t OriginalSize; - if (!zlib::isAvailable() || - !consumeCompressedDebugSectionHeader(Contents, OriginalSize)) - return make_error_code(std::errc::invalid_argument); - UncompressedSections.resize(UncompressedSections.size() + 1); - if (zlib::uncompress(Contents, UncompressedSections.back(), OriginalSize) != - zlib::StatusOK) { - UncompressedSections.pop_back(); - continue; - } - Name = Name.substr(1); - Contents = UncompressedSections.back(); - } - - auto SectionPair = KnownSections.find(Name); - if (SectionPair == KnownSections.end()) - continue; - - if (DWARFSectionKind Kind = SectionPair->second.second) { - auto Index = Kind - DW_SECT_INFO; - if (Kind != DW_SECT_TYPES) { - CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; - ContributionOffsets[Index] += - (CurEntry.Contributions[Index].Length = Contents.size()); - } - - switch (Kind) { - case DW_SECT_INFO: - InfoSection = Contents; - break; - case DW_SECT_ABBREV: - AbbrevSection = Contents; - break; - default: - break; - } - } - - MCSection *OutSection = SectionPair->second.first; - if (OutSection == StrOffsetSection) - CurStrOffsetSection = Contents; - else if (OutSection == StrSection) - CurStrSection = Contents; - else if (OutSection == TypesSection) - CurTypesSection = Contents; - else if (OutSection == CUIndexSection) - CurCUIndexSection = Contents; - else if (OutSection == TUIndexSection) - CurTUIndexSection = Contents; - else { - Out.SwitchSection(OutSection); - Out.EmitBytes(Contents); - } - } - if (InfoSection.empty()) continue; - if (!CurCUIndexSection.empty()) { - DWARFUnitIndex CUIndex(DW_SECT_INFO); - DataExtractor CUIndexData(CurCUIndexSection, - ErrOrObj->getBinary()->isLittleEndian(), 0); - if (!CUIndex.parse(CUIndexData)) - return make_error_code(std::errc::invalid_argument); - - for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) { - auto *I = E.getOffsets(); - if (!I) - continue; - auto P = - IndexEntries.insert(std::make_pair(E.getSignature(), CurEntry)); - CompileUnitIdentifiers ID = getCUIdentifiers( - getSubsection(AbbrevSection, E, DW_SECT_ABBREV), - getSubsection(InfoSection, E, DW_SECT_INFO), - getSubsection(CurStrOffsetSection, E, DW_SECT_STR_OFFSETS), - CurStrSection); - if (!P.second) { - printDuplicateError(*P.first, ID, Input); - return make_error_code(std::errc::invalid_argument); - } - auto &NewEntry = P.first->second; - NewEntry.Name = ID.Name; - NewEntry.DWOName = ID.DWOName; - NewEntry.DWPName = Input; - for (auto Kind : CUIndex.getColumnKinds()) { - auto &C = NewEntry.Contributions[Kind - DW_SECT_INFO]; - C.Offset += I->Offset; - C.Length = I->Length; - ++I; - } - } + writeStringsAndOffsets(Out, Strings, StrOffsetSection, CurStrSection, + CurStrOffsetSection); - if (!CurTypesSection.empty()) { - if (CurTUIndexSection.empty()) - return make_error_code(std::errc::invalid_argument); - DWARFUnitIndex TUIndex(DW_SECT_TYPES); - DataExtractor TUIndexData(CurTUIndexSection, - ErrOrObj->getBinary()->isLittleEndian(), 0); - if (!TUIndex.parse(TUIndexData)) - return make_error_code(std::errc::invalid_argument); - addAllTypesFromDWP(Out, TypeIndexEntries, TUIndex, TypesSection, - CurTypesSection, CurEntry, - ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); - } - } else { - CompileUnitIdentifiers ID = getCUIdentifiers( + if (CurCUIndexSection.empty()) { + Expected EID = getCUIdentifiers( AbbrevSection, InfoSection, CurStrOffsetSection, CurStrSection); + if (!EID) + return EID.takeError(); + const auto &ID = *EID; auto P = IndexEntries.insert(std::make_pair(ID.Signature, CurEntry)); - if (!P.second) { - printDuplicateError(*P.first, ID, ""); - return make_error_code(std::errc::invalid_argument); - } + if (!P.second) + return buildDuplicateError(*P.first, ID, ""); P.first->second.Name = ID.Name; P.first->second.DWOName = ID.DWOName; addAllTypes(Out, TypeIndexEntries, TypesSection, CurTypesSection, CurEntry, ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); + continue; + } + + DWARFUnitIndex CUIndex(DW_SECT_INFO); + DataExtractor CUIndexData(CurCUIndexSection, Obj.isLittleEndian(), 0); + if (!CUIndex.parse(CUIndexData)) + return make_error("Failed to parse cu_index"); + + for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) { + auto *I = E.getOffsets(); + if (!I) + continue; + auto P = IndexEntries.insert(std::make_pair(E.getSignature(), CurEntry)); + Expected EID = getCUIdentifiers( + getSubsection(AbbrevSection, E, DW_SECT_ABBREV), + getSubsection(InfoSection, E, DW_SECT_INFO), + getSubsection(CurStrOffsetSection, E, DW_SECT_STR_OFFSETS), + CurStrSection); + if (!EID) + return EID.takeError(); + const auto &ID = *EID; + if (!P.second) + return buildDuplicateError(*P.first, ID, Input); + auto &NewEntry = P.first->second; + NewEntry.Name = ID.Name; + NewEntry.DWOName = ID.DWOName; + NewEntry.DWPName = Input; + for (auto Kind : CUIndex.getColumnKinds()) { + auto &C = NewEntry.Contributions[Kind - DW_SECT_INFO]; + C.Offset += I->Offset; + C.Length = I->Length; + ++I; + } } - if (auto Err = writeStringsAndOffsets(Out, Strings, StringOffset, - StrSection, StrOffsetSection, - CurStrSection, CurStrOffsetSection)) - return Err; + if (!CurTypesSection.empty()) { + if (CurTypesSection.size() != 1) + return make_error("multiple type unit sections in .dwp file"); + DWARFUnitIndex TUIndex(DW_SECT_TYPES); + DataExtractor TUIndexData(CurTUIndexSection, Obj.isLittleEndian(), 0); + if (!TUIndex.parse(TUIndexData)) + return make_error("Failed to parse tu_index"); + addAllTypesFromDWP(Out, TypeIndexEntries, TUIndex, TypesSection, + CurTypesSection.front(), CurEntry, + ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); + } } // Lie about there being no info contributions so the TU index only includes @@ -557,7 +600,13 @@ static std::error_code write(MCStreamer &Out, ArrayRef Inputs) { writeIndex(Out, MCOFI.getDwarfCUIndexSection(), ContributionOffsets, IndexEntries); - return std::error_code(); + return Error(); +} + +static int error(const Twine &Error, const Twine &Context) { + errs() << Twine("while processing ") + Context + ":\n"; + errs() << Twine("error: ") + Error + "\n"; + return 1; } int main(int argc, char **argv) { @@ -592,7 +641,7 @@ int main(int argc, char **argv) { MCObjectFileInfo MOFI; MCContext MC(MAI.get(), MRI.get(), &MOFI); - MOFI.InitMCObjectFileInfo(TheTriple, Reloc::Default, CodeModel::Default, MC); + MOFI.InitMCObjectFileInfo(TheTriple, /*PIC*/ false, CodeModel::Default, MC); auto MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, ""); if (!MAB) @@ -625,8 +674,10 @@ int main(int argc, char **argv) { if (!MS) return error("no object streamer for target " + TripleName, Context); - if (auto Err = write(*MS, InputFiles)) - return error(Err.message(), "Writing DWP file"); + if (auto Err = write(*MS, InputFiles)) { + logAllUnhandledErrors(std::move(Err), errs(), "error: "); + return 1; + } MS->Finish(); } diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index 1da456d33f52dd832fb3ba966d42f8ba929e06f8..900c461ebd861a9cc584f9b976d8dcc58aec8556 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -102,10 +102,10 @@ static cl::opt PreserveAssemblyUseListOrder( int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); - LLVMContext &Context = getGlobalContext(); + LLVMContext Context; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n"); diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp index af1a59bdbd377298a650ec10bffecd70e1521501..6b72c17b1fede3b1c3b6b5f53f2f063c17db2938 100644 --- a/tools/llvm-jitlistener/llvm-jitlistener.cpp +++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp @@ -105,8 +105,6 @@ unsigned int GetNewMethodID(void) { class JitEventListenerTest { protected: void InitEE(const std::string &IRFile) { - LLVMContext &Context = getGlobalContext(); - // If we have a native target, initialize it to ensure it is linked in and // usable by the JIT. InitializeNativeTarget(); @@ -181,7 +179,7 @@ InputFilename(cl::Positional, cl::desc(""), int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index 729f8fd6449e61a1b10c796a5997de9f5fd410be..185ae2a82a17b36262ba6c5c1fc8c9fdb9715d97 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -36,6 +36,7 @@ #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include +#include using namespace llvm; static cl::list @@ -70,6 +71,10 @@ OutputFilename("o", cl::desc("Override output filename"), cl::init("-"), static cl::opt Internalize("internalize", cl::desc("Internalize linked symbols")); +static cl::opt + DisableDITypeMap("disable-debug-info-type-map", + cl::desc("Don't use a uniquing type map for debug info")); + static cl::opt OnlyNeeded("only-needed", cl::desc("Link only needed symbols")); @@ -142,7 +147,7 @@ public: ModuleLazyLoaderCache(std::function( const char *argv0, const std::string &FileName)> createLazyModule) - : createLazyModule(createLazyModule) {} + : createLazyModule(std::move(createLazyModule)) {} /// Retrieve a Module from the cache or lazily load it on demand. Module &operator()(const char *argv0, const std::string &FileName); @@ -272,8 +277,10 @@ static bool importFunctions(const char *argv0, LLVMContext &Context, if (renameModuleForThinLTO(*SrcModule, *Index, &GlobalsToImport)) return true; - if (L.linkInModule(std::move(SrcModule), Linker::Flags::None, - &GlobalsToImport)) + // Instruct the linker to not automatically import linkonce defintion. + unsigned Flags = Linker::Flags::DontForceLinkLinkonceODR; + + if (L.linkInModule(std::move(SrcModule), Flags, &GlobalsToImport)) return false; } @@ -292,7 +299,10 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L, return false; } - if (verifyModule(*M, &errs())) { + // Note that when ODR merging types cannot verify input files in here When + // doing that debug metadata in the src module might already be pointing to + // the destination. + if (DisableDITypeMap && verifyModule(*M, &errs())) { errs() << argv0 << ": " << File << ": error: input module is broken!\n"; return false; } @@ -328,15 +338,18 @@ static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L, int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); - LLVMContext &Context = getGlobalContext(); + LLVMContext Context; Context.setDiagnosticHandler(diagnosticHandlerWithContext, nullptr, true); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm linker\n"); + if (!DisableDITypeMap) + Context.enableDebugTypeODRUniquing(); + auto Composite = make_unique("llvm-link", Context); Linker L(*Composite); diff --git a/tools/llvm-lto/CMakeLists.txt b/tools/llvm-lto/CMakeLists.txt index 8a76b3b99f8eb8617df7397e10d4b2bd7f13f523..de888a74c530befe87f0b36803ed5aaf706440f7 100644 --- a/tools/llvm-lto/CMakeLists.txt +++ b/tools/llvm-lto/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} + BitReader BitWriter Core IRReader diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp index 1f7892de44b4df85b89e1fe3901c1c96ff88c647..b3b617b941d3375ed7e420cc92b8ed4f79f1b7d5 100644 --- a/tools/llvm-lto/llvm-lto.cpp +++ b/tools/llvm-lto/llvm-lto.cpp @@ -17,14 +17,16 @@ #include "llvm/CodeGen/CommandFlags.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" -#include "llvm/LTO/LTOCodeGenerator.h" -#include "llvm/LTO/LTOModule.h" -#include "llvm/LTO/ThinLTOCodeGenerator.h" +#include "llvm/LTO/legacy/LTOCodeGenerator.h" +#include "llvm/LTO/legacy/LTOModule.h" +#include "llvm/LTO/legacy/ThinLTOCodeGenerator.h" #include "llvm/Object/ModuleSummaryIndexObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" @@ -36,32 +38,28 @@ using namespace llvm; static cl::opt -OptLevel("O", - cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " - "(default = '-O2')"), - cl::Prefix, - cl::ZeroOrMore, - cl::init('2')); + OptLevel("O", cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " + "(default = '-O2')"), + cl::Prefix, cl::ZeroOrMore, cl::init('2')); static cl::opt DisableVerify( "disable-verify", cl::init(false), cl::desc("Do not run the verifier during the optimization pipeline")); -static cl::opt -DisableInline("disable-inlining", cl::init(false), - cl::desc("Do not run the inliner pass")); +static cl::opt DisableInline("disable-inlining", cl::init(false), + cl::desc("Do not run the inliner pass")); static cl::opt -DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), - cl::desc("Do not run the GVN load PRE pass")); + DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), + cl::desc("Do not run the GVN load PRE pass")); -static cl::opt -DisableLTOVectorization("disable-lto-vectorization", cl::init(false), - cl::desc("Do not run loop or slp vectorization during LTO")); +static cl::opt DisableLTOVectorization( + "disable-lto-vectorization", cl::init(false), + cl::desc("Do not run loop or slp vectorization during LTO")); -static cl::opt -UseDiagnosticHandler("use-diagnostic-handler", cl::init(false), - cl::desc("Use a diagnostic handler to test the handler interface")); +static cl::opt UseDiagnosticHandler( + "use-diagnostic-handler", cl::init(false), + cl::desc("Use a diagnostic handler to test the handler interface")); static cl::opt ThinLTO("thinlto", cl::init(false), @@ -69,8 +67,11 @@ static cl::opt enum ThinLTOModes { THINLINK, + THINDISTRIBUTE, + THINEMITIMPORTS, THINPROMOTE, THINIMPORT, + THININTERNALIZE, THINOPT, THINCODEGEN, THINALL @@ -82,11 +83,18 @@ cl::opt ThinLTOMode( clEnumValN( THINLINK, "thinlink", "ThinLink: produces the index by linking only the summaries."), + clEnumValN(THINDISTRIBUTE, "distributedindexes", + "Produces individual indexes for distributed backends."), + clEnumValN(THINEMITIMPORTS, "emitimports", + "Emit imports files for distributed backends."), clEnumValN(THINPROMOTE, "promote", "Perform pre-import promotion (requires -thinlto-index)."), clEnumValN(THINIMPORT, "import", "Perform both promotion and " "cross-module importing (requires " "-thinlto-index)."), + clEnumValN(THININTERNALIZE, "internalize", + "Perform internalization driven by -exported-symbol " + "(requires -thinlto-index)."), clEnumValN(THINOPT, "optimize", "Perform ThinLTO optimizations."), clEnumValN(THINCODEGEN, "codegen", "CodeGen (expected to match llc)"), clEnumValN(THINALL, "run", "Perform ThinLTO end-to-end"), @@ -97,28 +105,41 @@ static cl::opt cl::desc("Provide the index produced by a ThinLink, required " "to perform the promotion and/or importing.")); -static cl::opt -SaveModuleFile("save-merged-module", cl::init(false), - cl::desc("Write merged LTO module to file before CodeGen")); +static cl::opt ThinLTOPrefixReplace( + "thinlto-prefix-replace", + cl::desc("Control where files for distributed backends are " + "created. Expects 'oldprefix;newprefix' and if path " + "prefix of output file is oldprefix it will be " + "replaced with newprefix.")); -static cl::list -InputFilenames(cl::Positional, cl::OneOrMore, - cl::desc("")); +static cl::opt ThinLTOModuleId( + "thinlto-module-id", + cl::desc("For the module ID for the file to process, useful to " + "match what is in the index.")); static cl::opt -OutputFilename("o", cl::init(""), - cl::desc("Override output filename"), - cl::value_desc("filename")); + ThinLTOCacheDir("thinlto-cache-dir", cl::desc("Enable ThinLTO caching.")); -static cl::list -ExportedSymbols("exported-symbol", - cl::desc("Symbol to export from the resulting object file"), - cl::ZeroOrMore); +static cl::opt + SaveModuleFile("save-merged-module", cl::init(false), + cl::desc("Write merged LTO module to file before CodeGen")); + +static cl::list InputFilenames(cl::Positional, cl::OneOrMore, + cl::desc("")); + +static cl::opt OutputFilename("o", cl::init(""), + cl::desc("Override output filename"), + cl::value_desc("filename")); + +static cl::list ExportedSymbols( + "exported-symbol", + cl::desc("List of symbols to export from the resulting object file"), + cl::ZeroOrMore); static cl::list -DSOSymbols("dso-symbol", - cl::desc("Symbol to put in the symtab in the resulting dso"), - cl::ZeroOrMore); + DSOSymbols("dso-symbol", + cl::desc("Symbol to put in the symtab in the resulting dso"), + cl::ZeroOrMore); static cl::opt ListSymbolsOnly( "list-symbols-only", cl::init(false), @@ -135,6 +156,10 @@ static cl::opt RestoreGlobalsLinkage( "restore-linkage", cl::init(false), cl::desc("Restore original linkage of globals prior to CodeGen")); +static cl::opt CheckHasObjC( + "check-for-objc", cl::init(false), + cl::desc("Only check if the module has objective-C defined in it")); + namespace { struct ModuleInfo { std::vector CanBeHidden; @@ -211,6 +236,11 @@ static void error(const ErrorOr &V, const Twine &Prefix) { error(V.getError(), Prefix); } +static void maybeVerifyModule(const Module &Mod) { + if (!DisableVerify && verifyModule(Mod)) + error("Broken Module"); +} + static std::unique_ptr getLocalLTOModule(StringRef Path, std::unique_ptr &Buffer, const TargetOptions &Options) { @@ -225,6 +255,7 @@ getLocalLTOModule(StringRef Path, std::unique_ptr &Buffer, std::move(Context), Buffer->getBufferStart(), Buffer->getBufferSize(), Options, Path); CurrentActivity = ""; + maybeVerifyModule((*Ret)->getModule()); return std::move(*Ret); } @@ -275,6 +306,37 @@ static void createCombinedModuleSummaryIndex() { OS.close(); } +/// Parse the thinlto_prefix_replace option into the \p OldPrefix and +/// \p NewPrefix strings, if it was specified. +static void getThinLTOOldAndNewPrefix(std::string &OldPrefix, + std::string &NewPrefix) { + assert(ThinLTOPrefixReplace.empty() || + ThinLTOPrefixReplace.find(";") != StringRef::npos); + StringRef PrefixReplace = ThinLTOPrefixReplace; + std::pair Split = PrefixReplace.split(";"); + OldPrefix = Split.first.str(); + NewPrefix = Split.second.str(); +} + +/// Given the original \p Path to an output file, replace any path +/// prefix matching \p OldPrefix with \p NewPrefix. Also, create the +/// resulting directory if it does not yet exist. +static std::string getThinLTOOutputFile(const std::string &Path, + const std::string &OldPrefix, + const std::string &NewPrefix) { + if (OldPrefix.empty() && NewPrefix.empty()) + return Path; + SmallString<128> NewPath(Path); + llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix); + StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str()); + if (!ParentPath.empty()) { + // Make sure the new directory exists, creating it if necessary. + if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath)) + error(EC, "error creating the directory '" + ParentPath + "'"); + } + return NewPath.str(); +} + namespace thinlto { std::vector> @@ -309,6 +371,13 @@ static std::unique_ptr loadModule(StringRef Filename, Err.print("llvm-lto", errs()); report_fatal_error("Can't load module for file " + Filename); } + maybeVerifyModule(*M); + + if (ThinLTOModuleId.getNumOccurrences()) { + if (InputFilenames.size() != 1) + report_fatal_error("Can't override the module id for multiple files"); + M->setModuleIdentifier(ThinLTOModuleId); + } return M; } @@ -316,7 +385,8 @@ static void writeModuleToFile(Module &TheModule, StringRef Filename) { std::error_code EC; raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::F_None); error(EC, "error opening the file '" + Filename + "'"); - WriteBitcodeToFile(&TheModule, OS, true, false); + maybeVerifyModule(TheModule); + WriteBitcodeToFile(&TheModule, OS, /* ShouldPreserveUseListOrder */ true); } class ThinLTOProcessing { @@ -324,18 +394,29 @@ public: ThinLTOCodeGenerator ThinGenerator; ThinLTOProcessing(const TargetOptions &Options) { - ThinGenerator.setCodePICModel(RelocModel); + ThinGenerator.setCodePICModel(getRelocModel()); ThinGenerator.setTargetOptions(Options); + ThinGenerator.setCacheDir(ThinLTOCacheDir); + + // Add all the exported symbols to the table of symbols to preserve. + for (unsigned i = 0; i < ExportedSymbols.size(); ++i) + ThinGenerator.preserveSymbol(ExportedSymbols[i]); } void run() { switch (ThinLTOMode) { case THINLINK: return thinLink(); + case THINDISTRIBUTE: + return distributedIndexes(); + case THINEMITIMPORTS: + return emitImports(); case THINPROMOTE: return promote(); case THINIMPORT: return import(); + case THININTERNALIZE: + return internalize(); case THINOPT: return optimize(); case THINCODEGEN: @@ -372,6 +453,63 @@ private: return; } + /// Load the combined index from disk, then compute and generate + /// individual index files suitable for ThinLTO distributed backend builds + /// on the files mentioned on the command line (these must match the index + /// content). + void distributedIndexes() { + if (InputFilenames.size() != 1 && !OutputFilename.empty()) + report_fatal_error("Can't handle a single output filename and multiple " + "input files, do not provide an output filename and " + "the output files will be suffixed from the input " + "ones."); + + std::string OldPrefix, NewPrefix; + getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix); + + auto Index = loadCombinedIndex(); + for (auto &Filename : InputFilenames) { + // Build a map of module to the GUIDs and summary objects that should + // be written to its index. + std::map ModuleToSummariesForIndex; + ThinLTOCodeGenerator::gatherImportedSummariesForModule( + Filename, *Index, ModuleToSummariesForIndex); + + std::string OutputName = OutputFilename; + if (OutputName.empty()) { + OutputName = Filename + ".thinlto.bc"; + } + OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix); + std::error_code EC; + raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::F_None); + error(EC, "error opening the file '" + OutputName + "'"); + WriteIndexToFile(*Index, OS, &ModuleToSummariesForIndex); + } + } + + /// Load the combined index from disk, compute the imports, and emit + /// the import file lists for each module to disk. + void emitImports() { + if (InputFilenames.size() != 1 && !OutputFilename.empty()) + report_fatal_error("Can't handle a single output filename and multiple " + "input files, do not provide an output filename and " + "the output files will be suffixed from the input " + "ones."); + + std::string OldPrefix, NewPrefix; + getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix); + + auto Index = loadCombinedIndex(); + for (auto &Filename : InputFilenames) { + std::string OutputName = OutputFilename; + if (OutputName.empty()) { + OutputName = Filename + ".imports"; + } + OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix); + ThinLTOCodeGenerator::emitImports(Filename, OutputName, *Index); + } + } + /// Load the combined index from disk, then load every file referenced by /// the index and add them to the generator, finally perform the promotion /// on the files mentioned on the command line (these must match the index @@ -429,6 +567,37 @@ private: } } + void internalize() { + if (InputFilenames.size() != 1 && !OutputFilename.empty()) + report_fatal_error("Can't handle a single output filename and multiple " + "input files, do not provide an output filename and " + "the output files will be suffixed from the input " + "ones."); + + if (ExportedSymbols.empty()) + errs() << "Warning: -internalize will not perform without " + "-exported-symbol\n"; + + auto Index = loadCombinedIndex(); + auto InputBuffers = loadAllFilesForIndex(*Index); + for (auto &MemBuffer : InputBuffers) + ThinGenerator.addModule(MemBuffer->getBufferIdentifier(), + MemBuffer->getBuffer()); + + for (auto &Filename : InputFilenames) { + LLVMContext Ctx; + auto TheModule = loadModule(Filename, Ctx); + + ThinGenerator.internalize(*TheModule, *Index); + + std::string OutputName = OutputFilename; + if (OutputName.empty()) { + OutputName = Filename + ".thinlto.internalized.bc"; + } + writeModuleToFile(*TheModule, OutputName); + } + } + void optimize() { if (InputFilenames.size() != 1 && !OutputFilename.empty()) report_fatal_error("Can't handle a single output filename and multiple " @@ -526,7 +695,7 @@ private: int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. @@ -549,6 +718,21 @@ int main(int argc, char **argv) { return 0; } + if (CheckHasObjC) { + for (auto &Filename : InputFilenames) { + ErrorOr> BufferOrErr = + MemoryBuffer::getFile(Filename); + error(BufferOrErr, "error loading file '" + Filename + "'"); + auto Buffer = std::move(BufferOrErr.get()); + LLVMContext Ctx; + if (llvm::isBitcodeContainingObjCCategory(*Buffer, Ctx)) + outs() << "Bitcode " << Filename << " contains ObjC\n"; + else + outs() << "Bitcode " << Filename << " does not contain ObjC\n"; + } + return 0; + } + if (ThinLTOMode.getNumOccurrences()) { if (ThinLTOMode.getNumOccurrences() > 1) report_fatal_error("You can't specify more than one -thinlto-action"); @@ -572,7 +756,7 @@ int main(int argc, char **argv) { if (UseDiagnosticHandler) CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr); - CodeGen.setCodePICModel(RelocModel); + CodeGen.setCodePICModel(getRelocModel()); CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF); CodeGen.setTargetOptions(Options); @@ -609,8 +793,7 @@ int main(int argc, char **argv) { CodeGen.setModule(std::move(Module)); } else if (!CodeGen.addModule(Module.get())) { // Print a message here so that we know addModule() did not abort. - errs() << argv[0] << ": error adding file '" << InputFilenames[i] << "'\n"; - return 1; + error("error adding file '" + InputFilenames[i] + "'"); } } @@ -644,8 +827,7 @@ int main(int argc, char **argv) { if (!CodeGen.optimize(DisableVerify, DisableInline, DisableGVNLoadPRE, DisableLTOVectorization)) { // Diagnostic messages should have been printed by the handler. - errs() << argv[0] << ": error optimizing the code\n"; - return 1; + error("error optimizing the code"); } if (SaveModuleFile) { @@ -653,10 +835,8 @@ int main(int argc, char **argv) { ModuleFilename += ".merged.bc"; std::string ErrMsg; - if (!CodeGen.writeMergedModules(ModuleFilename.c_str())) { - errs() << argv[0] << ": writing merged module failed.\n"; - return 1; - } + if (!CodeGen.writeMergedModules(ModuleFilename.c_str())) + error("writing merged module failed."); } std::list OSs; @@ -667,40 +847,29 @@ int main(int argc, char **argv) { PartFilename += "." + utostr(I); std::error_code EC; OSs.emplace_back(PartFilename, EC, sys::fs::F_None); - if (EC) { - errs() << argv[0] << ": error opening the file '" << PartFilename - << "': " << EC.message() << "\n"; - return 1; - } + if (EC) + error("error opening the file '" + PartFilename + "': " + EC.message()); OSPtrs.push_back(&OSs.back().os()); } - if (!CodeGen.compileOptimized(OSPtrs)) { + if (!CodeGen.compileOptimized(OSPtrs)) // Diagnostic messages should have been printed by the handler. - errs() << argv[0] << ": error compiling the code\n"; - return 1; - } + error("error compiling the code"); for (tool_output_file &OS : OSs) OS.keep(); } else { - if (Parallelism != 1) { - errs() << argv[0] << ": -j must be specified together with -o\n"; - return 1; - } + if (Parallelism != 1) + error("-j must be specified together with -o"); - if (SaveModuleFile) { - errs() << argv[0] << ": -save-merged-module must be specified with -o\n"; - return 1; - } + if (SaveModuleFile) + error(": -save-merged-module must be specified with -o"); const char *OutputName = nullptr; if (!CodeGen.compile_to_file(&OutputName, DisableVerify, DisableInline, - DisableGVNLoadPRE, DisableLTOVectorization)) { + DisableGVNLoadPRE, DisableLTOVectorization)) + error("error compiling the code"); // Diagnostic messages should have been printed by the handler. - errs() << argv[0] << ": error compiling the code\n"; - return 1; - } outs() << "Wrote native object file '" << OutputName << "'\n"; } diff --git a/tools/llvm-mc-fuzzer/CMakeLists.txt b/tools/llvm-mc-fuzzer/CMakeLists.txt index 0d6432b23dfa5dca9f66d8a4694f7ee31781e73a..b42b3eee3c981decd36d2237a5825f079e66854e 100644 --- a/tools/llvm-mc-fuzzer/CMakeLists.txt +++ b/tools/llvm-mc-fuzzer/CMakeLists.txt @@ -13,6 +13,6 @@ if( LLVM_USE_SANITIZE_COVERAGE ) add_llvm_tool(llvm-mc-fuzzer llvm-mc-fuzzer.cpp) target_link_libraries(llvm-mc-fuzzer - LLVMFuzzerNoMain + LLVMFuzzer ) endif() diff --git a/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp b/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp index 3f80e4582ee1bc2e275a8677d4f535395c936717..df8e0112af5bf50e5afe2fd1e46a88992097a4d7 100644 --- a/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp +++ b/tools/llvm-mc-fuzzer/llvm-mc-fuzzer.cpp @@ -9,13 +9,12 @@ // //===----------------------------------------------------------------------===// +#include "FuzzerInterface.h" #include "llvm-c/Disassembler.h" #include "llvm-c/Target.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" -#include "FuzzerInterface.h" using namespace llvm; @@ -58,9 +57,10 @@ static cl::list std::string FeaturesStr; static cl::list - FuzzerArgv("fuzzer-args", cl::Positional, + FuzzerArgs("fuzzer-args", cl::Positional, cl::desc("Options to pass to the fuzzer"), cl::ZeroOrMore, cl::PositionalEatsArgs); +static std::vector ModifiedArgv; int DisassembleOneInput(const uint8_t *Data, size_t Size) { char AssemblyText[AssemblyTextBufSize]; @@ -88,7 +88,17 @@ int DisassembleOneInput(const uint8_t *Data, size_t Size) { return 0; } -int main(int argc, char **argv) { +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Action == AC_Assemble) + errs() << "error: -assemble is not implemented\n"; + else if (Action == AC_Disassemble) + return DisassembleOneInput(Data, Size); + + llvm_unreachable("Unknown action"); + return 0; +} + +int LLVMFuzzerInitialize(int *argc, char ***argv) { // The command line is unusual compared to other fuzzers due to the need to // specify the target. Options like -triple, -mcpu, and -mattr work like // their counterparts in llvm-mc, while -fuzzer-args collects options for the @@ -112,11 +122,29 @@ int main(int argc, char **argv) { // individual instructions that test unique paths. Without this constraint, // there will be considerable redundancy in the corpus. + char **OriginalArgv = *argv; + LLVMInitializeAllTargetInfos(); LLVMInitializeAllTargetMCs(); LLVMInitializeAllDisassemblers(); - cl::ParseCommandLineOptions(argc, argv); + cl::ParseCommandLineOptions(*argc, OriginalArgv); + + // Rebuild the argv without the arguments llvm-mc-fuzzer consumed so that + // the driver can parse its arguments. + // + // FuzzerArgs cannot provide the non-const pointer that OriginalArgv needs. + // Re-use the strings from OriginalArgv instead of copying FuzzerArg to a + // non-const buffer to avoid the need to clean up when the fuzzer terminates. + ModifiedArgv.push_back(OriginalArgv[0]); + for (const auto &FuzzerArg : FuzzerArgs) { + for (int i = 1; i < *argc; ++i) { + if (FuzzerArg == OriginalArgv[i]) + ModifiedArgv.push_back(OriginalArgv[i]); + } + } + *argc = ModifiedArgv.size(); + *argv = ModifiedArgv.data(); // Package up features to be passed to target/subtarget // We have to pass it via a global since the callback doesn't @@ -128,11 +156,5 @@ int main(int argc, char **argv) { FeaturesStr = Features.getString(); } - if (Action == AC_Assemble) - errs() << "error: -assemble is not implemented\n"; - else if (Action == AC_Disassemble) - return fuzzer::FuzzerDriver(argc, argv, DisassembleOneInput); - - llvm_unreachable("Unknown action"); - return 1; + return 0; } diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index b706c53299f655d844fe4c0c0354e7508256fbd6..00f19cb328c371ec1e22fe626ee8926bf909261a 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -52,9 +52,22 @@ OutputFilename("o", cl::desc("Output filename"), static cl::opt ShowEncoding("show-encoding", cl::desc("Show instruction encodings")); -static cl::opt -CompressDebugSections("compress-debug-sections", - cl::desc("Compress DWARF debug sections")); +static cl::opt RelaxELFRel( + "relax-relocations", cl::init(true), + cl::desc("Emit R_X86_64_GOTPCRELX instead of R_X86_64_GOTPCREL")); + +static cl::opt +CompressDebugSections("compress-debug-sections", cl::ValueOptional, + cl::init(DebugCompressionType::DCT_None), + cl::desc("Choose DWARF debug sections compression:"), + cl::values( + clEnumValN(DebugCompressionType::DCT_None, "none", + "No compression"), + clEnumValN(DebugCompressionType::DCT_Zlib, "zlib", + "Use zlib compression"), + clEnumValN(DebugCompressionType::DCT_ZlibGnu, "zlib-gnu", + "Use zlib-gnu compression (depricated)"), + clEnumValEnd)); static cl::opt ShowInst("show-inst", cl::desc("Show internal instruction representation")); @@ -74,6 +87,10 @@ PrintImmHex("print-imm-hex", cl::init(false), static cl::list DefineSymbol("defsym", cl::desc("Defines a symbol to be an integer constant")); +static cl::opt + PreserveComments("preserve-comments", + cl::desc("Preserve Comments in outputted assembly")); + enum OutputFileType { OFT_Null, OFT_AssemblyFile, @@ -115,20 +132,8 @@ MAttrs("mattr", cl::desc("Target specific attributes (-mattr=help for details)"), cl::value_desc("a1,+a2,-a3,...")); -static cl::opt -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 PIC("position-independent", + cl::desc("Position independent"), cl::init(false)); static cl::opt CMModel("code-model", @@ -249,7 +254,7 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, bool Error = false; while (Lexer.Lex().isNot(AsmToken::Eof)) { - AsmToken Tok = Lexer.getTok(); + const AsmToken &Tok = Lexer.getTok(); switch (Tok.getKind()) { default: @@ -368,7 +373,7 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget, int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. @@ -419,20 +424,23 @@ int main(int argc, char **argv) { std::unique_ptr MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); assert(MAI && "Unable to create target asm info!"); - if (CompressDebugSections) { + MAI->setRelaxELFRelocations(RelaxELFRel); + + if (CompressDebugSections != DebugCompressionType::DCT_None) { if (!zlib::isAvailable()) { errs() << ProgName << ": build tools with zlib to enable -compress-debug-sections"; return 1; } - MAI->setCompressDebugSections(true); + MAI->setCompressDebugSections(CompressDebugSections); } + MAI->setPreserveAsmComments(PreserveComments); // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and // MCObjectFileInfo needs a MCContext reference in order to initialize itself. MCObjectFileInfo MOFI; MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr); - MOFI.InitMCObjectFileInfo(TheTriple, RelocModel, CMModel, Ctx); + MOFI.InitMCObjectFileInfo(TheTriple, PIC, CMModel, Ctx); if (SaveTempLabels) Ctx.setAllowTemporaryLabels(false); diff --git a/tools/llvm-mcmarkup/llvm-mcmarkup.cpp b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp index 56543139d6faccad5cc56a6f12c8223f078348e3..0be3c715eee4ee08466d26f4e013ff0e83ae038a 100644 --- a/tools/llvm-mcmarkup/llvm-mcmarkup.cpp +++ b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp @@ -208,7 +208,7 @@ static void parseMCMarkup(StringRef Filename) { int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 65e9156a74d10ae341c3a757beb32cc80bcb47d9..9b2f5220badbc969eee68ce8177cb5e341758ea1 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -16,6 +16,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringSwitch.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalVariable.h" @@ -189,6 +190,52 @@ static bool error(std::error_code EC, Twine Path = Twine()) { return false; } +// This version of error() prints the archive name and member name, for example: +// "libx.a(foo.o)" after the ToolName before the error message. It sets +// HadError but returns allowing the code to move on to other archive members. +static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, + StringRef ArchitectureName = StringRef()) { + HadError = true; + errs() << ToolName << ": " << FileName; + + ErrorOr NameOrErr = C.getName(); + // TODO: if we have a error getting the name then it would be nice to print + // the index of which archive member this is and or its offset in the + // archive instead of "???" as the name. + if (NameOrErr.getError()) + errs() << "(" << "???" << ")"; + else + errs() << "(" << NameOrErr.get() << ")"; + + if (!ArchitectureName.empty()) + errs() << " (for architecture " << ArchitectureName << ") "; + + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS, ""); + OS.flush(); + errs() << " " << Buf << "\n"; +} + +// This version of error() prints the file name and which architecture slice it +// is from, for example: "foo.o (for architecture i386)" after the ToolName +// before the error message. It sets HadError but returns allowing the code to +// move on to other architecture slices. +static void error(llvm::Error E, StringRef FileName, + StringRef ArchitectureName = StringRef()) { + HadError = true; + errs() << ToolName << ": " << FileName; + + if (!ArchitectureName.empty()) + errs() << " (for architecture " << ArchitectureName << ") "; + + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS, ""); + OS.flush(); + errs() << " " << Buf << "\n"; +} + namespace { struct NMSymbol { uint64_t Address; @@ -343,7 +390,7 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I, MachO::REFERENCE_FLAG_UNDEFINED_LAZY) outs() << "undefined [lazy bound]) "; else if ((NDesc & MachO::REFERENCE_TYPE) == - MachO::REFERENCE_FLAG_UNDEFINED_LAZY) + MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY) outs() << "undefined [private lazy bound]) "; else if ((NDesc & MachO::REFERENCE_TYPE) == MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY) @@ -372,9 +419,10 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I, outs() << "(?,?) "; break; } - ErrorOr SecOrErr = + Expected SecOrErr = MachO->getSymbolSection(I->Sym.getRawDataRefImpl()); - if (SecOrErr.getError()) { + if (!SecOrErr) { + consumeError(SecOrErr.takeError()); outs() << "(?,?) "; break; } @@ -549,8 +597,8 @@ static void darwinPrintStab(MachOObjectFile *MachO, SymbolListT::iterator I) { } static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, - std::string ArchiveName, - std::string ArchitectureName) { + const std::string &ArchiveName, + const std::string &ArchitectureName) { if (!NoSort) { std::function Cmp; if (NumericSort) @@ -583,26 +631,26 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, printDashes = "----------------"; switch (AddressRadix) { case Radix::o: - printFormat = "%016" PRIo64; + printFormat = OutputFormat == posix ? "%" PRIo64 : "%016" PRIo64; break; case Radix::x: - printFormat = "%016" PRIx64; + printFormat = OutputFormat == posix ? "%" PRIx64 : "%016" PRIx64; break; default: - printFormat = "%016" PRId64; + printFormat = OutputFormat == posix ? "%" PRId64 : "%016" PRId64; } } else { printBlanks = " "; printDashes = "--------"; switch (AddressRadix) { case Radix::o: - printFormat = "%08" PRIo64; + printFormat = OutputFormat == posix ? "%" PRIo64 : "%08" PRIo64; break; case Radix::x: - printFormat = "%08" PRIx64; + printFormat = OutputFormat == posix ? "%" PRIx64 : "%08" PRIx64; break; default: - printFormat = "%08" PRId64; + printFormat = OutputFormat == posix ? "%" PRId64 : "%08" PRId64; } } @@ -617,9 +665,13 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, if (PrintFileName) { if (!ArchitectureName.empty()) outs() << "(for architecture " << ArchitectureName << "):"; - if (!ArchiveName.empty()) - outs() << ArchiveName << ":"; - outs() << CurrentFilename << ": "; + if (OutputFormat == posix && !ArchiveName.empty()) + outs() << ArchiveName << "[" << CurrentFilename << "]: "; + else { + if (!ArchiveName.empty()) + outs() << ArchiveName << ":"; + outs() << CurrentFilename << ": "; + } } if ((JustSymbolName || (UndefinedOnly && isa(Obj) && OutputFormat != darwin)) && OutputFormat != posix) { @@ -630,8 +682,13 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, char SymbolAddrStr[18] = ""; char SymbolSizeStr[18] = ""; - if (OutputFormat == sysv || I->TypeChar == 'U') - strcpy(SymbolAddrStr, printBlanks); + if (OutputFormat == sysv || I->TypeChar == 'U') { + if (OutputFormat == posix) + format(printFormat, I->Address) + .print(SymbolAddrStr, sizeof(SymbolAddrStr)); + else + strcpy(SymbolAddrStr, printBlanks); + } if (OutputFormat == sysv) strcpy(SymbolSizeStr, printBlanks); @@ -656,7 +713,7 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, } else if (OutputFormat == posix) { outs() << I->Name << " " << I->TypeChar << " "; if (MachO) - outs() << I->Address << " " << "0" /* SymbolSizeStr */ << "\n"; + outs() << SymbolAddrStr << " " << "0" /* SymbolSizeStr */ << "\n"; else outs() << SymbolAddrStr << " " << SymbolSizeStr << "\n"; } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) { @@ -687,9 +744,11 @@ static char getSymbolNMTypeChar(ELFObjectFileBase &Obj, // OK, this is ELF elf_symbol_iterator SymI(I); - ErrorOr SecIOrErr = SymI->getSection(); - if (error(SecIOrErr.getError())) + Expected SecIOrErr = SymI->getSection(); + if (!SecIOrErr) { + consumeError(SecIOrErr.takeError()); return '?'; + } elf_section_iterator SecI = *SecIOrErr; if (SecI != Obj.section_end()) { @@ -714,9 +773,11 @@ static char getSymbolNMTypeChar(ELFObjectFileBase &Obj, } if (SymI->getELFType() == ELF::STT_SECTION) { - ErrorOr Name = SymI->getName(); - if (error(Name.getError())) + Expected Name = SymI->getName(); + if (!Name) { + consumeError(Name.takeError()); return '?'; + } return StringSwitch(*Name) .StartsWith(".debug", 'N') .StartsWith(".note", 'n') @@ -731,9 +792,11 @@ static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) { // OK, this is COFF. symbol_iterator SymI(I); - ErrorOr Name = SymI->getName(); - if (error(Name.getError())) + Expected Name = SymI->getName(); + if (!Name) { + consumeError(Name.takeError()); return '?'; + } char Ret = StringSwitch(*Name) .StartsWith(".debug", 'N') @@ -745,9 +808,11 @@ static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) { uint32_t Characteristics = 0; if (!COFF::isReservedSectionNumber(Symb.getSectionNumber())) { - ErrorOr SecIOrErr = SymI->getSection(); - if (error(SecIOrErr.getError())) + Expected SecIOrErr = SymI->getSection(); + if (!SecIOrErr) { + consumeError(SecIOrErr.takeError()); return '?'; + } section_iterator SecI = *SecIOrErr; const coff_section *Section = Obj.getCOFFSection(*SecI); Characteristics = Section->Characteristics; @@ -788,9 +853,11 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) { case MachO::N_INDR: return 'i'; case MachO::N_SECT: { - ErrorOr SecOrErr = Obj.getSymbolSection(Symb); - if (SecOrErr.getError()) + Expected SecOrErr = Obj.getSymbolSection(Symb); + if (!SecOrErr) { + consumeError(SecOrErr.takeError()); return 's'; + } section_iterator Sec = *SecOrErr; DataRefImpl Ref = Sec->getRawDataRefImpl(); StringRef SectionName; @@ -896,10 +963,10 @@ static unsigned getNsectInMachO(MachOObjectFile &Obj, BasicSymbolRef Sym) { return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0; } -static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName, - std::string ArchiveName = std::string(), - std::string ArchitectureName = - std::string()) { +static void +dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName, + const std::string &ArchiveName = std::string(), + const std::string &ArchitectureName = std::string()) { auto Symbols = Obj.symbols(); if (DynamicSyms) { const auto *E = dyn_cast(&Obj); @@ -948,9 +1015,11 @@ static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName, } if (PrintAddress && isa(Obj)) { SymbolRef SymRef(Sym); - ErrorOr AddressOrErr = SymRef.getAddress(); - if (error(AddressOrErr.getError())) + Expected AddressOrErr = SymRef.getAddress(); + if (!AddressOrErr) { + consumeError(AddressOrErr.takeError()); break; + } S.Address = *AddressOrErr; } S.TypeChar = getNMTypeChar(Obj, Sym); @@ -991,10 +1060,10 @@ static bool checkMachOAndArchFlags(SymbolicFile *O, std::string &Filename) { Triple T; if (MachO->is64Bit()) { H_64 = MachO->MachOObjectFile::getHeader64(); - T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype); + T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); } else { H = MachO->MachOObjectFile::getHeader(); - T = MachOObjectFile::getArch(H.cputype, H.cpusubtype); + T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); } if (std::none_of( ArchFlags.begin(), ArchFlags.end(), @@ -1011,11 +1080,13 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { if (error(BufferOrErr.getError(), Filename)) return; - LLVMContext &Context = getGlobalContext(); - ErrorOr> BinaryOrErr = createBinary( + LLVMContext Context; + Expected> BinaryOrErr = createBinary( BufferOrErr.get()->getMemBufferRef(), NoLLVMBitcode ? nullptr : &Context); - if (error(BinaryOrErr.getError(), Filename)) + if (!BinaryOrErr) { + error(errorToErrorCode(BinaryOrErr.takeError()), Filename); return; + } Binary &Bin = *BinaryOrErr.get(); if (Archive *A = dyn_cast(&Bin)) { @@ -1038,27 +1109,31 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { } } - for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); - I != E; ++I) { - if (error(I->getError())) - return; - auto &C = I->get(); - ErrorOr> ChildOrErr = C.getAsBinary(&Context); - if (ChildOrErr.getError()) - continue; - if (SymbolicFile *O = dyn_cast(&*ChildOrErr.get())) { - if (!checkMachOAndArchFlags(O, Filename)) - return; - if (!PrintFileName) { - outs() << "\n"; - if (isa(O)) { - outs() << Filename << "(" << O->getFileName() << ")"; - } else - outs() << O->getFileName(); - outs() << ":\n"; + { + Error Err; + for (auto &C : A->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(&Context); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + error(std::move(E), Filename, C); + continue; + } + if (SymbolicFile *O = dyn_cast(&*ChildOrErr.get())) { + if (!checkMachOAndArchFlags(O, Filename)) + return; + if (!PrintFileName) { + outs() << "\n"; + if (isa(O)) { + outs() << Filename << "(" << O->getFileName() << ")"; + } else + outs() << O->getFileName(); + outs() << ":\n"; + } + dumpSymbolNamesFromObject(*O, false, Filename); } - dumpSymbolNamesFromObject(*O, false, Filename); } + if (Err) + error(std::move(Err), A->getFileName()); } return; } @@ -1074,7 +1149,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { I != E; ++I) { if (ArchFlags[i] == I->getArchTypeName()) { ArchFound = true; - ErrorOr> ObjOrErr = + Expected> ObjOrErr = I->getAsObjectFile(); std::string ArchiveName; std::string ArchitectureName; @@ -1092,19 +1167,26 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { } dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName); - } else if (ErrorOr> AOrErr = + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + error(std::move(E), Filename, ArchFlags.size() > 1 ? + StringRef(I->getArchTypeName()) : StringRef()); + continue; + } else if (Expected> AOrErr = I->getAsArchive()) { std::unique_ptr &A = *AOrErr; - for (Archive::child_iterator AI = A->child_begin(), - AE = A->child_end(); - AI != AE; ++AI) { - if (error(AI->getError())) - return; - auto &C = AI->get(); - ErrorOr> ChildOrErr = + Error Err; + for (auto &C : A->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(&Context); - if (ChildOrErr.getError()) + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) { + error(std::move(E), Filename, C, ArchFlags.size() > 1 ? + StringRef(I->getArchTypeName()) : StringRef()); + } continue; + } if (SymbolicFile *O = dyn_cast(&*ChildOrErr.get())) { if (PrintFileName) { @@ -1124,6 +1206,14 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { ArchitectureName); } } + if (Err) + error(std::move(Err), A->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error(Filename + " for architecture " + + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file", + "Mach-O universal file"); } } } @@ -1143,25 +1233,29 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { E = UB->end_objects(); I != E; ++I) { if (HostArchName == I->getArchTypeName()) { - ErrorOr> ObjOrErr = I->getAsObjectFile(); + Expected> ObjOrErr = I->getAsObjectFile(); std::string ArchiveName; ArchiveName.clear(); if (ObjOrErr) { ObjectFile &Obj = *ObjOrErr.get(); dumpSymbolNamesFromObject(Obj, false); - } else if (ErrorOr> AOrErr = + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + error(std::move(E), Filename); + return; + } else if (Expected> AOrErr = I->getAsArchive()) { std::unique_ptr &A = *AOrErr; - for (Archive::child_iterator AI = A->child_begin(), - AE = A->child_end(); - AI != AE; ++AI) { - if (error(AI->getError())) - return; - auto &C = AI->get(); - ErrorOr> ChildOrErr = + Error Err; + for (auto &C : A->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(&Context); - if (ChildOrErr.getError()) + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), Filename, C); continue; + } if (SymbolicFile *O = dyn_cast(&*ChildOrErr.get())) { if (PrintFileName) @@ -1173,6 +1267,14 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { dumpSymbolNamesFromObject(*O, false, ArchiveName); } } + if (Err) + error(std::move(Err), A->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error(Filename + " for architecture " + + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file", + "Mach-O universal file"); } return; } @@ -1184,7 +1286,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), E = UB->end_objects(); I != E; ++I) { - ErrorOr> ObjOrErr = I->getAsObjectFile(); + Expected> ObjOrErr = I->getAsObjectFile(); std::string ArchiveName; std::string ArchitectureName; ArchiveName.clear(); @@ -1203,16 +1305,25 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { outs() << ":\n"; } dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName); - } else if (ErrorOr> AOrErr = I->getAsArchive()) { + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + error(std::move(E), Filename, moreThanOneArch ? + StringRef(I->getArchTypeName()) : StringRef()); + continue; + } else if (Expected> AOrErr = + I->getAsArchive()) { std::unique_ptr &A = *AOrErr; - for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); - AI != AE; ++AI) { - if (error(AI->getError())) - return; - auto &C = AI->get(); - ErrorOr> ChildOrErr = C.getAsBinary(&Context); - if (ChildOrErr.getError()) + Error Err; + for (auto &C : A->children(Err)) { + Expected> ChildOrErr = + C.getAsBinary(&Context); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), Filename, C, moreThanOneArch ? + StringRef(ArchitectureName) : StringRef()); continue; + } if (SymbolicFile *O = dyn_cast(&*ChildOrErr.get())) { if (PrintFileName) { ArchiveName = A->getFileName(); @@ -1232,6 +1343,14 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { dumpSymbolNamesFromObject(*O, false, ArchiveName, ArchitectureName); } } + if (Err) + error(std::move(Err), A->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error(Filename + " for architecture " + + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file", + "Mach-O universal file"); } } return; @@ -1245,7 +1364,7 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt index d0dd4ac0182c3358509766608ecdb57957d393cf..551847f34eef09a66709f623b73e49f4c8cc9d1a 100644 --- a/tools/llvm-objdump/CMakeLists.txt +++ b/tools/llvm-objdump/CMakeLists.txt @@ -17,3 +17,7 @@ add_llvm_tool(llvm-objdump ELFDump.cpp MachODump.cpp ) + +if(HAVE_LIBXAR) + target_link_libraries(llvm-objdump ${XAR_LIB}) +endif() diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp index aee771e42a2dd2c2c615dee2854baa6a7b7c5938..3ec6a1f73750e4ee6579605ed4940a108de7eeba 100644 --- a/tools/llvm-objdump/COFFDump.cpp +++ b/tools/llvm-objdump/COFFDump.cpp @@ -161,13 +161,13 @@ static std::error_code resolveSectionAndAddress(const COFFObjectFile *Obj, const SymbolRef &Sym, const coff_section *&ResolvedSection, uint64_t &ResolvedAddr) { - ErrorOr ResolvedAddrOrErr = Sym.getAddress(); - if (std::error_code EC = ResolvedAddrOrErr.getError()) - return EC; + Expected ResolvedAddrOrErr = Sym.getAddress(); + if (!ResolvedAddrOrErr) + return errorToErrorCode(ResolvedAddrOrErr.takeError()); ResolvedAddr = *ResolvedAddrOrErr; - ErrorOr Iter = Sym.getSection(); - if (std::error_code EC = Iter.getError()) - return EC; + Expected Iter = Sym.getSection(); + if (!Iter) + return errorToErrorCode(Iter.takeError()); ResolvedSection = Obj->getCOFFSection(**Iter); return std::error_code(); } @@ -215,9 +215,9 @@ static std::error_code resolveSymbolName(const std::vector &Rels, SymbolRef Sym; if (std::error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC; - ErrorOr NameOrErr = Sym.getName(); - if (std::error_code EC = NameOrErr.getError()) - return EC; + Expected NameOrErr = Sym.getName(); + if (!NameOrErr) + return errorToErrorCode(NameOrErr.takeError()); Name = *NameOrErr; return std::error_code(); } @@ -352,11 +352,11 @@ static void printImportTables(const COFFObjectFile *Obj) { if (I == E) return; outs() << "The Import Tables:\n"; - for (; I != E; I = ++I) { + for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) { const import_directory_table_entry *Dir; StringRef Name; - if (I->getImportTableEntry(Dir)) return; - if (I->getName(Name)) return; + if (DirRef.getImportTableEntry(Dir)) return; + if (DirRef.getName(Name)) return; outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n", static_cast(Dir->ImportLookupTableRVA), @@ -366,17 +366,23 @@ static void printImportTables(const COFFObjectFile *Obj) { static_cast(Dir->ImportAddressTableRVA)); outs() << " DLL Name: " << Name << "\n"; outs() << " Hint/Ord Name\n"; - const import_lookup_table_entry32 *entry; - if (I->getImportLookupEntry(entry)) - return; - for (; entry->Data; ++entry) { - if (entry->isOrdinal()) { - outs() << format(" % 6d\n", entry->getOrdinal()); + for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) { + bool IsOrdinal; + if (Entry.isOrdinal(IsOrdinal)) + return; + if (IsOrdinal) { + uint16_t Ordinal; + if (Entry.getOrdinal(Ordinal)) + return; + outs() << format(" % 6d\n", Ordinal); continue; } + uint32_t HintNameRVA; + if (Entry.getHintNameRVA(HintNameRVA)) + return; uint16_t Hint; StringRef Name; - if (Obj->getHintName(entry->getHintNameRVA(), Hint, Name)) + if (Obj->getHintName(HintNameRVA, Hint, Name)) return; outs() << format(" % 6d ", Hint) << Name << "\n"; } @@ -653,6 +659,13 @@ void llvm::printCOFFSymbolTable(const COFFObjectFile *coff) { SI = SI + Symbol->getNumberOfAuxSymbols(); break; + } else if (Symbol->isWeakExternal()) { + const coff_aux_weak_external *awe; + error(coff->getAuxSymbol(SI + 1, awe)); + + outs() << "AUX " << format("indx %d srch %d\n", + static_cast(awe->TagIndex), + static_cast(awe->Characteristics)); } else { outs() << "AUX Unknown\n"; } diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 000ee3ff0d2ef5ba98bff18e421acbbc551d9fc5..08bc1f48240764001757f764fb47c3c4e4cd71d9 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Object/MachO.h" #include "llvm-objdump.h" #include "llvm-c/Disassembler.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" @@ -29,7 +29,6 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" @@ -43,6 +42,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -52,6 +52,12 @@ #include #endif +#ifdef HAVE_LIBXAR +extern "C" { +#include +} +#endif + using namespace llvm; using namespace object; @@ -143,11 +149,18 @@ static const Target *GetTarget(const MachOObjectFile *MachOObj, const char **McpuDefault, const Target **ThumbTarget) { // Figure out the target triple. + llvm::Triple TT(TripleName); if (TripleName.empty()) { - llvm::Triple TT("unknown-unknown-unknown"); - llvm::Triple ThumbTriple = Triple(); - TT = MachOObj->getArch(McpuDefault, &ThumbTriple); + TT = MachOObj->getArchTriple(McpuDefault); TripleName = TT.str(); + } + + if (TT.getArch() == Triple::arm) { + // We've inferred a 32-bit ARM target from the object file. All MachO CPUs + // that support ARM are also capable of Thumb mode. + llvm::Triple ThumbTriple = TT; + std::string ThumbName = (Twine("thumb") + TT.getArchName().substr(3)).str(); + ThumbTriple.setArchName(ThumbName); ThumbTripleName = ThumbTriple.str(); } @@ -172,13 +185,23 @@ static const Target *GetTarget(const MachOObjectFile *MachOObj, struct SymbolSorter { bool operator()(const SymbolRef &A, const SymbolRef &B) { - ErrorOr ATypeOrErr = A.getType(); - if (std::error_code EC = ATypeOrErr.getError()) - report_fatal_error(EC.message()); + Expected ATypeOrErr = A.getType(); + if (!ATypeOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(ATypeOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } SymbolRef::Type AType = *ATypeOrErr; - ErrorOr BTypeOrErr = B.getType(); - if (std::error_code EC = BTypeOrErr.getError()) - report_fatal_error(EC.message()); + Expected BTypeOrErr = B.getType(); + if (!BTypeOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(BTypeOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } SymbolRef::Type BType = *BTypeOrErr; uint64_t AAddr = (AType != SymbolRef::ST_Function) ? 0 : A.getValue(); uint64_t BAddr = (BType != SymbolRef::ST_Function) ? 0 : B.getValue(); @@ -274,9 +297,14 @@ static void getSectionsAndSymbols(MachOObjectFile *MachOObj, SmallVectorImpl &FoundFns, uint64_t &BaseSegmentAddress) { for (const SymbolRef &Symbol : MachOObj->symbols()) { - ErrorOr SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } if (!SymName->startswith("ltmp")) Symbols.push_back(Symbol); } @@ -332,7 +360,7 @@ static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose, if (cputype & MachO::CPU_ARCH_ABI64) outs() << format("0x%016" PRIx64, addr + j * stride) << " "; else - outs() << format("0x%08" PRIx32, addr + j * stride) << " "; + outs() << format("0x%08" PRIx32, (uint32_t)addr + j * stride) << " "; MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand(); uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j); if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) { @@ -354,9 +382,14 @@ static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose, if (indirect_symbol < Symtab.nsyms) { symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol); SymbolRef Symbol = *Sym; - ErrorOr SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } outs() << *SymName; } else { outs() << "?"; @@ -581,16 +614,26 @@ static void CreateSymbolAddressMap(MachOObjectFile *O, SymbolAddressMap *AddrMap) { // Create a map of symbol addresses to symbol names. for (const SymbolRef &Symbol : O->symbols()) { - ErrorOr STOrErr = Symbol.getType(); - if (std::error_code EC = STOrErr.getError()) - report_fatal_error(EC.message()); + Expected STOrErr = Symbol.getType(); + if (!STOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(STOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } SymbolRef::Type ST = *STOrErr; if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data || ST == SymbolRef::ST_Other) { uint64_t Address = Symbol.getValue(); - ErrorOr SymNameOrErr = Symbol.getName(); - if (std::error_code EC = SymNameOrErr.getError()) - report_fatal_error(EC.message()); + Expected SymNameOrErr = Symbol.getName(); + if (!SymNameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymNameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } StringRef SymName = *SymNameOrErr; if (!SymName.startswith(".objc")) (*AddrMap)[Address] = SymName; @@ -824,9 +867,14 @@ static void DumpLiteralPointerSection(MachOObjectFile *O, [&](const std::pair &P) { return P.first == i; }); if (Reloc != Relocs.end()) { symbol_iterator RelocSym = Reloc->second; - ErrorOr SymName = RelocSym->getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected SymName = RelocSym->getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } outs() << "external relocation entry for symbol:" << *SymName << "\n"; continue; } @@ -975,10 +1023,10 @@ static void DumpRawSectionContents(MachOObjectFile *O, const char *sect, if (O->is64Bit()) outs() << format("%016" PRIx64, addr) << "\t"; else - outs() << format("%08" PRIx64, sect) << "\t"; + outs() << format("%08" PRIx64, addr) << "\t"; for (j = 0; j < 4 * sizeof(int32_t) && i + j < size; j += sizeof(int32_t)) { - if (i + j + sizeof(int32_t) < size) { + if (i + j + sizeof(int32_t) <= size) { uint32_t long_word; memcpy(&long_word, sect + i + j, sizeof(int32_t)); if (O->isLittleEndian() != sys::IsLittleEndianHost) @@ -986,7 +1034,7 @@ static void DumpRawSectionContents(MachOObjectFile *O, const char *sect, outs() << format("%08" PRIx32, long_word) << " "; } else { for (uint32_t k = 0; i + j + k < size; k++) { - uint8_t byte_word = *(sect + i + j); + uint8_t byte_word = *(sect + i + j + k); outs() << format("%02" PRIx32, (uint32_t)byte_word) << " "; } } @@ -1000,6 +1048,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, StringRef DisSegName, StringRef DisSectName); static void DumpProtocolSection(MachOObjectFile *O, const char *sect, uint32_t size, uint32_t addr); +#ifdef HAVE_LIBXAR +static void DumpBitcodeSection(MachOObjectFile *O, const char *sect, + uint32_t size, bool verbose, + bool PrintXarHeader, bool PrintXarFileHeaders, + std::string XarMemberName); +#endif // defined(HAVE_LIBXAR) static void DumpSectionContents(StringRef Filename, MachOObjectFile *O, bool verbose) { @@ -1061,6 +1115,13 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O, DumpProtocolSection(O, sect, sect_size, sect_addr); continue; } +#ifdef HAVE_LIBXAR + if (SegName == "__LLVM" && SectName == "__bundle") { + DumpBitcodeSection(O, sect, sect_size, verbose, !NoSymbolicOperands, + ArchiveHeaders, ""); + continue; + } +#endif // defined(HAVE_LIBXAR) switch (section_type) { case MachO::S_REGULAR: DumpRawSectionContents(O, sect, sect_size, sect_addr); @@ -1138,10 +1199,10 @@ static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { Triple T; if (MachO->is64Bit()) { H_64 = MachO->MachOObjectFile::getHeader64(); - T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype); + T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); } else { H = MachO->MachOObjectFile::getHeader(); - T = MachOObjectFile::getArch(H.cputype, H.cpusubtype); + T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); } unsigned i; for (i = 0; i < ArchFlags.size(); ++i) { @@ -1170,7 +1231,7 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, // If we are doing some processing here on the Mach-O file print the header // info. And don't print it otherwise like in the case of printing the // UniversalHeaders or ArchiveHeaders. - if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind || + if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints || DylibsUsed || DylibId || ObjcMetaData || (FilterSections.size() != 0)) { outs() << Filename; @@ -1203,8 +1264,10 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, PrintDylibs(MachOOF, false); if (DylibId) PrintDylibs(MachOOF, true); - if (SymbolTable) - PrintSymbolTable(MachOOF); + if (SymbolTable) { + StringRef ArchiveName = ArchiveMemberName == StringRef() ? "" : Filename; + PrintSymbolTable(MachOOF, ArchiveName, ArchitectureName); + } if (UnwindInfo) printMachOUnwindInfo(MachOOF); if (PrivateHeaders) { @@ -1340,9 +1403,12 @@ static void printCPUType(uint32_t cputype, uint32_t cpusubtype) { static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB, bool verbose) { outs() << "Fat headers\n"; - if (verbose) - outs() << "fat_magic FAT_MAGIC\n"; - else + if (verbose) { + if (UB->getMagic() == MachO::FAT_MAGIC) + outs() << "fat_magic FAT_MAGIC\n"; + else // UB->getMagic() == MachO::FAT_MAGIC_64 + outs() << "fat_magic FAT_MAGIC_64\n"; + } else outs() << "fat_magic " << format("0x%" PRIx32, MachO::FAT_MAGIC) << "\n"; uint32_t nfat_arch = UB->getNumberOfObjects(); @@ -1469,13 +1535,11 @@ static void printArchiveChild(const Archive::Child &C, bool verbose, } static void printArchiveHeaders(Archive *A, bool verbose, bool print_offset) { - for (Archive::child_iterator I = A->child_begin(false), E = A->child_end(); - I != E; ++I) { - if (std::error_code EC = I->getError()) - report_fatal_error(EC.message()); - const Archive::Child &C = **I; + Error Err; + for (const auto &C : A->children(Err, false)) printArchiveChild(C, verbose, print_offset); - } + if (Err) + report_fatal_error(std::move(Err)); } // ParseInputMachO() parses the named Mach-O file in Filename and handles the @@ -1497,29 +1561,31 @@ void llvm::ParseInputMachO(StringRef Filename) { } // Attempt to open the binary. - ErrorOr> BinaryOrErr = createBinary(Filename); - if (std::error_code EC = BinaryOrErr.getError()) - report_error(Filename, EC); + Expected> BinaryOrErr = createBinary(Filename); + if (!BinaryOrErr) + report_error(Filename, BinaryOrErr.takeError()); Binary &Bin = *BinaryOrErr.get().getBinary(); if (Archive *A = dyn_cast(&Bin)) { outs() << "Archive : " << Filename << "\n"; if (ArchiveHeaders) printArchiveHeaders(A, !NonVerbose, ArchiveMemberOffsets); - for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); - I != E; ++I) { - if (std::error_code EC = I->getError()) - report_error(Filename, EC); - auto &C = I->get(); - ErrorOr> ChildOrErr = C.getAsBinary(); - if (ChildOrErr.getError()) + Error Err; + for (auto &C : A->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + report_error(Filename, C, std::move(E)); continue; + } if (MachOObjectFile *O = dyn_cast(&*ChildOrErr.get())) { if (!checkMachOAndArchFlags(O, Filename)) return; ProcessMachO(Filename, O, O->getFileName()); } } + if (Err) + report_error(Filename, std::move(Err)); return; } if (UniversalHeaders) { @@ -1538,7 +1604,7 @@ void llvm::ParseInputMachO(StringRef Filename) { I != E; ++I) { if (ArchFlags[i] == I->getArchTypeName()) { ArchFound = true; - ErrorOr> ObjOrErr = + Expected> ObjOrErr = I->getAsObjectFile(); std::string ArchitectureName = ""; if (ArchFlags.size() > 1) @@ -1547,7 +1613,12 @@ void llvm::ParseInputMachO(StringRef Filename) { ObjectFile &O = *ObjOrErr.get(); if (MachOObjectFile *MachOOF = dyn_cast(&O)) ProcessMachO(Filename, MachOOF, "", ArchitectureName); - } else if (ErrorOr> AOrErr = + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + report_error(Filename, StringRef(), std::move(E), + ArchitectureName); + continue; + } else if (Expected> AOrErr = I->getAsArchive()) { std::unique_ptr &A = *AOrErr; outs() << "Archive : " << Filename; @@ -1556,19 +1627,25 @@ void llvm::ParseInputMachO(StringRef Filename) { outs() << "\n"; if (ArchiveHeaders) printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets); - for (Archive::child_iterator AI = A->child_begin(), - AE = A->child_end(); - AI != AE; ++AI) { - if (std::error_code EC = AI->getError()) - report_error(Filename, EC); - auto &C = AI->get(); - ErrorOr> ChildOrErr = C.getAsBinary(); - if (ChildOrErr.getError()) + Error Err; + for (auto &C : A->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + report_error(Filename, C, std::move(E), ArchitectureName); continue; + } if (MachOObjectFile *O = dyn_cast(&*ChildOrErr.get())) ProcessMachO(Filename, O, O->getFileName(), ArchitectureName); } + if (Err) + report_error(Filename, std::move(Err)); + } else { + consumeError(AOrErr.takeError()); + error("Mach-O universal file: " + Filename + " for " + + "architecture " + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file"); } } } @@ -1588,32 +1665,42 @@ void llvm::ParseInputMachO(StringRef Filename) { I != E; ++I) { if (MachOObjectFile::getHostArch().getArchName() == I->getArchTypeName()) { - ErrorOr> ObjOrErr = I->getAsObjectFile(); + Expected> ObjOrErr = I->getAsObjectFile(); std::string ArchiveName; ArchiveName.clear(); if (ObjOrErr) { ObjectFile &O = *ObjOrErr.get(); if (MachOObjectFile *MachOOF = dyn_cast(&O)) ProcessMachO(Filename, MachOOF); - } else if (ErrorOr> AOrErr = + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + report_error(Filename, std::move(E)); + continue; + } else if (Expected> AOrErr = I->getAsArchive()) { std::unique_ptr &A = *AOrErr; outs() << "Archive : " << Filename << "\n"; if (ArchiveHeaders) printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets); - for (Archive::child_iterator AI = A->child_begin(), - AE = A->child_end(); - AI != AE; ++AI) { - if (std::error_code EC = AI->getError()) - report_error(Filename, EC); - auto &C = AI->get(); - ErrorOr> ChildOrErr = C.getAsBinary(); - if (ChildOrErr.getError()) + Error Err; + for (auto &C : A->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + report_error(Filename, C, std::move(E)); continue; + } if (MachOObjectFile *O = dyn_cast(&*ChildOrErr.get())) ProcessMachO(Filename, O, O->getFileName()); } + if (Err) + report_error(Filename, std::move(Err)); + } else { + consumeError(AOrErr.takeError()); + error("Mach-O universal file: " + Filename + " for architecture " + + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file"); } return; } @@ -1625,7 +1712,7 @@ void llvm::ParseInputMachO(StringRef Filename) { for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), E = UB->end_objects(); I != E; ++I) { - ErrorOr> ObjOrErr = I->getAsObjectFile(); + Expected> ObjOrErr = I->getAsObjectFile(); std::string ArchitectureName = ""; if (moreThanOneArch) ArchitectureName = I->getArchTypeName(); @@ -1633,7 +1720,12 @@ void llvm::ParseInputMachO(StringRef Filename) { ObjectFile &Obj = *ObjOrErr.get(); if (MachOObjectFile *MachOOF = dyn_cast(&Obj)) ProcessMachO(Filename, MachOOF, "", ArchitectureName); - } else if (ErrorOr> AOrErr = I->getAsArchive()) { + } else if (auto E = isNotObjectErrorInvalidFileType( + ObjOrErr.takeError())) { + report_error(StringRef(), Filename, std::move(E), ArchitectureName); + continue; + } else if (Expected> AOrErr = + I->getAsArchive()) { std::unique_ptr &A = *AOrErr; outs() << "Archive : " << Filename; if (!ArchitectureName.empty()) @@ -1641,14 +1733,14 @@ void llvm::ParseInputMachO(StringRef Filename) { outs() << "\n"; if (ArchiveHeaders) printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets); - for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); - AI != AE; ++AI) { - if (std::error_code EC = AI->getError()) - report_error(Filename, EC); - auto &C = AI->get(); - ErrorOr> ChildOrErr = C.getAsBinary(); - if (ChildOrErr.getError()) + Error Err; + for (auto &C : A->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + report_error(Filename, C, std::move(E), ArchitectureName); continue; + } if (MachOObjectFile *O = dyn_cast(&*ChildOrErr.get())) { if (MachOObjectFile *MachOOF = dyn_cast(O)) @@ -1656,6 +1748,13 @@ void llvm::ParseInputMachO(StringRef Filename) { ArchitectureName); } } + if (Err) + report_error(Filename, std::move(Err)); + } else { + consumeError(AOrErr.takeError()); + error("Mach-O universal file: " + Filename + " for architecture " + + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file"); } } return; @@ -1779,9 +1878,14 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, } } if (reloc_found && isExtern) { - ErrorOr SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); op_info->AddSymbol.Present = 1; op_info->AddSymbol.Name = name; @@ -1849,9 +1953,14 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, // is the offset from the external symbol. if (info->O->getAnyRelocationPCRel(RE)) op_info->Value -= Pc + Offset + Size; - ErrorOr SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); unsigned Type = info->O->getAnyRelocationType(RE); if (Type == MachO::X86_64_RELOC_SUBTRACTOR) { @@ -1866,9 +1975,14 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, op_info->SubtractSymbol.Name = name; symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum); Symbol = *RelocSymNext; - ErrorOr SymNameNext = Symbol.getName(); - if (std::error_code EC = SymNameNext.getError()) - report_fatal_error(EC.message()); + Expected SymNameNext = Symbol.getName(); + if (!SymNameNext) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymNameNext.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } name = SymNameNext->data(); } } @@ -1939,9 +2053,14 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, } if (isExtern) { - ErrorOr SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); op_info->AddSymbol.Present = 1; op_info->AddSymbol.Name = name; @@ -2059,9 +2178,14 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, // NOTE: Scattered relocations don't exist on arm64. if (!info->O->getPlainRelocationExternal(RE)) return 0; - ErrorOr SymName = Reloc->getSymbol()->getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected SymName = Reloc->getSymbol()->getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); op_info->AddSymbol.Present = 1; op_info->AddSymbol.Name = name; @@ -2189,9 +2313,14 @@ static const char *GuessIndirectSymbol(uint64_t ReferenceValue, if (indirect_symbol < Symtab.nsyms) { symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol); SymbolRef Symbol = *Sym; - ErrorOr SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); return name; } @@ -2224,9 +2353,14 @@ static const char *GuessIndirectSymbol(uint64_t ReferenceValue, if (indirect_symbol < Symtab.nsyms) { symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol); SymbolRef Symbol = *Sym; - ErrorOr SymName = Symbol.getName(); - if (std::error_code EC = SymName.getError()) - report_fatal_error(EC.message()); + Expected SymName = Symbol.getName(); + if (!SymName) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymName.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } const char *name = SymName->data(); return name; } @@ -2453,9 +2587,14 @@ static const char *get_symbol_64(uint32_t sect_offset, SectionRef S, const char *SymbolName = nullptr; if (reloc_found && isExtern) { n_value = Symbol.getValue(); - ErrorOr NameOrError = Symbol.getName(); - if (std::error_code EC = NameOrError.getError()) - report_fatal_error(EC.message()); + Expected NameOrError = Symbol.getName(); + if (!NameOrError) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(NameOrError.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } StringRef Name = *NameOrError; if (!Name.empty()) { SymbolName = Name.data(); @@ -5075,6 +5214,9 @@ static void print_image_info32(SectionRef S, struct DisassembleInfo *info) { struct objc_image_info32 o; const char *r; + if (S == SectionRef()) + return; + StringRef SectName; S.getName(SectName); DataRefImpl Ref = S.getRawDataRefImpl(); @@ -5547,6 +5689,373 @@ static void DumpProtocolSection(MachOObjectFile *O, const char *sect, } } +#ifdef HAVE_LIBXAR +inline void swapStruct(struct xar_header &xar) { + sys::swapByteOrder(xar.magic); + sys::swapByteOrder(xar.size); + sys::swapByteOrder(xar.version); + sys::swapByteOrder(xar.toc_length_compressed); + sys::swapByteOrder(xar.toc_length_uncompressed); + sys::swapByteOrder(xar.cksum_alg); +} + +static void PrintModeVerbose(uint32_t mode) { + switch(mode & S_IFMT){ + case S_IFDIR: + outs() << "d"; + break; + case S_IFCHR: + outs() << "c"; + break; + case S_IFBLK: + outs() << "b"; + break; + case S_IFREG: + outs() << "-"; + break; + case S_IFLNK: + outs() << "l"; + break; + case S_IFSOCK: + outs() << "s"; + break; + default: + outs() << "?"; + break; + } + + /* owner permissions */ + if(mode & S_IREAD) + outs() << "r"; + else + outs() << "-"; + if(mode & S_IWRITE) + outs() << "w"; + else + outs() << "-"; + if(mode & S_ISUID) + outs() << "s"; + else if(mode & S_IEXEC) + outs() << "x"; + else + outs() << "-"; + + /* group permissions */ + if(mode & (S_IREAD >> 3)) + outs() << "r"; + else + outs() << "-"; + if(mode & (S_IWRITE >> 3)) + outs() << "w"; + else + outs() << "-"; + if(mode & S_ISGID) + outs() << "s"; + else if(mode & (S_IEXEC >> 3)) + outs() << "x"; + else + outs() << "-"; + + /* other permissions */ + if(mode & (S_IREAD >> 6)) + outs() << "r"; + else + outs() << "-"; + if(mode & (S_IWRITE >> 6)) + outs() << "w"; + else + outs() << "-"; + if(mode & S_ISVTX) + outs() << "t"; + else if(mode & (S_IEXEC >> 6)) + outs() << "x"; + else + outs() << "-"; +} + +static void PrintXarFilesSummary(const char *XarFilename, xar_t xar) { + xar_iter_t xi; + xar_file_t xf; + xar_iter_t xp; + const char *key, *type, *mode, *user, *group, *size, *mtime, *name, *m; + char *endp; + uint32_t mode_value; + + xi = xar_iter_new(); + if (!xi) { + errs() << "Can't obtain an xar iterator for xar archive " + << XarFilename << "\n"; + return; + } + + // Go through the xar's files. + for (xf = xar_file_first(xar, xi); xf; xf = xar_file_next(xi)) { + xp = xar_iter_new(); + if(!xp){ + errs() << "Can't obtain an xar iterator for xar archive " + << XarFilename << "\n"; + return; + } + type = nullptr; + mode = nullptr; + user = nullptr; + group = nullptr; + size = nullptr; + mtime = nullptr; + name = nullptr; + for(key = xar_prop_first(xf, xp); key; key = xar_prop_next(xp)){ + const char *val = nullptr; + xar_prop_get(xf, key, &val); +#if 0 // Useful for debugging. + outs() << "key: " << key << " value: " << val << "\n"; +#endif + if(strcmp(key, "type") == 0) + type = val; + if(strcmp(key, "mode") == 0) + mode = val; + if(strcmp(key, "user") == 0) + user = val; + if(strcmp(key, "group") == 0) + group = val; + if(strcmp(key, "data/size") == 0) + size = val; + if(strcmp(key, "mtime") == 0) + mtime = val; + if(strcmp(key, "name") == 0) + name = val; + } + if(mode != nullptr){ + mode_value = strtoul(mode, &endp, 8); + if(*endp != '\0') + outs() << "(mode: \"" << mode << "\" contains non-octal chars) "; + if(strcmp(type, "file") == 0) + mode_value |= S_IFREG; + PrintModeVerbose(mode_value); + outs() << " "; + } + if(user != nullptr) + outs() << format("%10s/", user); + if(group != nullptr) + outs() << format("%-10s ", group); + if(size != nullptr) + outs() << format("%7s ", size); + if(mtime != nullptr){ + for(m = mtime; *m != 'T' && *m != '\0'; m++) + outs() << *m; + if(*m == 'T') + m++; + outs() << " "; + for( ; *m != 'Z' && *m != '\0'; m++) + outs() << *m; + outs() << " "; + } + if(name != nullptr) + outs() << name; + outs() << "\n"; + } +} + +static void DumpBitcodeSection(MachOObjectFile *O, const char *sect, + uint32_t size, bool verbose, + bool PrintXarHeader, bool PrintXarFileHeaders, + std::string XarMemberName) { + if(size < sizeof(struct xar_header)) { + outs() << "size of (__LLVM,__bundle) section too small (smaller than size " + "of struct xar_header)\n"; + return; + } + struct xar_header XarHeader; + memcpy(&XarHeader, sect, sizeof(struct xar_header)); + if (sys::IsLittleEndianHost) + swapStruct(XarHeader); + if (PrintXarHeader) { + if (!XarMemberName.empty()) + outs() << "In xar member " << XarMemberName << ": "; + else + outs() << "For (__LLVM,__bundle) section: "; + outs() << "xar header\n"; + if (XarHeader.magic == XAR_HEADER_MAGIC) + outs() << " magic XAR_HEADER_MAGIC\n"; + else + outs() << " magic " + << format_hex(XarHeader.magic, 10, true) + << " (not XAR_HEADER_MAGIC)\n"; + outs() << " size " << XarHeader.size << "\n"; + outs() << " version " << XarHeader.version << "\n"; + outs() << " toc_length_compressed " << XarHeader.toc_length_compressed + << "\n"; + outs() << "toc_length_uncompressed " << XarHeader.toc_length_uncompressed + << "\n"; + outs() << " cksum_alg "; + switch (XarHeader.cksum_alg) { + case XAR_CKSUM_NONE: + outs() << "XAR_CKSUM_NONE\n"; + break; + case XAR_CKSUM_SHA1: + outs() << "XAR_CKSUM_SHA1\n"; + break; + case XAR_CKSUM_MD5: + outs() << "XAR_CKSUM_MD5\n"; + break; +#ifdef XAR_CKSUM_SHA256 + case XAR_CKSUM_SHA256: + outs() << "XAR_CKSUM_SHA256\n"; + break; +#endif +#ifdef XAR_CKSUM_SHA512 + case XAR_CKSUM_SHA512: + outs() << "XAR_CKSUM_SHA512\n"; + break; +#endif + default: + outs() << XarHeader.cksum_alg << "\n"; + } + } + + SmallString<128> XarFilename; + int FD; + std::error_code XarEC = + sys::fs::createTemporaryFile("llvm-objdump", "xar", FD, XarFilename); + if (XarEC) { + errs() << XarEC.message() << "\n"; + return; + } + tool_output_file XarFile(XarFilename, FD); + raw_fd_ostream &XarOut = XarFile.os(); + StringRef XarContents(sect, size); + XarOut << XarContents; + XarOut.close(); + if (XarOut.has_error()) + return; + + xar_t xar = xar_open(XarFilename.c_str(), READ); + if (!xar) { + errs() << "Can't create temporary xar archive " << XarFilename << "\n"; + return; + } + + SmallString<128> TocFilename; + std::error_code TocEC = + sys::fs::createTemporaryFile("llvm-objdump", "toc", TocFilename); + if (TocEC) { + errs() << TocEC.message() << "\n"; + return; + } + xar_serialize(xar, TocFilename.c_str()); + + if (PrintXarFileHeaders) { + if (!XarMemberName.empty()) + outs() << "In xar member " << XarMemberName << ": "; + else + outs() << "For (__LLVM,__bundle) section: "; + outs() << "xar archive files:\n"; + PrintXarFilesSummary(XarFilename.c_str(), xar); + } + + ErrorOr> FileOrErr = + MemoryBuffer::getFileOrSTDIN(TocFilename.c_str()); + if (std::error_code EC = FileOrErr.getError()) { + errs() << EC.message() << "\n"; + return; + } + std::unique_ptr &Buffer = FileOrErr.get(); + + if (!XarMemberName.empty()) + outs() << "In xar member " << XarMemberName << ": "; + else + outs() << "For (__LLVM,__bundle) section: "; + outs() << "xar table of contents:\n"; + outs() << Buffer->getBuffer() << "\n"; + + // TODO: Go through the xar's files. + xar_iter_t xi = xar_iter_new(); + if(!xi){ + errs() << "Can't obtain an xar iterator for xar archive " + << XarFilename.c_str() << "\n"; + xar_close(xar); + return; + } + for(xar_file_t xf = xar_file_first(xar, xi); xf; xf = xar_file_next(xi)){ + const char *key; + xar_iter_t xp; + const char *member_name, *member_type, *member_size_string; + size_t member_size; + + xp = xar_iter_new(); + if(!xp){ + errs() << "Can't obtain an xar iterator for xar archive " + << XarFilename.c_str() << "\n"; + xar_close(xar); + return; + } + member_name = NULL; + member_type = NULL; + member_size_string = NULL; + for(key = xar_prop_first(xf, xp); key; key = xar_prop_next(xp)){ + const char *val = nullptr; + xar_prop_get(xf, key, &val); +#if 0 // Useful for debugging. + outs() << "key: " << key << " value: " << val << "\n"; +#endif + if(strcmp(key, "name") == 0) + member_name = val; + if(strcmp(key, "type") == 0) + member_type = val; + if(strcmp(key, "data/size") == 0) + member_size_string = val; + } + /* + * If we find a file with a name, date/size and type properties + * and with the type being "file" see if that is a xar file. + */ + if (member_name != NULL && member_type != NULL && + strcmp(member_type, "file") == 0 && + member_size_string != NULL){ + // Extract the file into a buffer. + char *endptr; + member_size = strtoul(member_size_string, &endptr, 10); + if (*endptr == '\0' && member_size != 0) { + char *buffer = (char *) ::operator new (member_size); + if (xar_extract_tobuffersz(xar, xf, &buffer, &member_size) == 0) { +#if 0 // Useful for debugging. + outs() << "xar member: " << member_name << " extracted\n"; +#endif + // Set the XarMemberName we want to see printed in the header. + std::string OldXarMemberName; + // If XarMemberName is already set this is nested. So + // save the old name and create the nested name. + if (!XarMemberName.empty()) { + OldXarMemberName = XarMemberName; + XarMemberName = + (Twine("[") + XarMemberName + "]" + member_name).str(); + } else { + OldXarMemberName = ""; + XarMemberName = member_name; + } + // See if this is could be a xar file (nested). + if (member_size >= sizeof(struct xar_header)) { +#if 0 // Useful for debugging. + outs() << "could be a xar file: " << member_name << "\n"; +#endif + memcpy((char *)&XarHeader, buffer, sizeof(struct xar_header)); + if (sys::IsLittleEndianHost) + swapStruct(XarHeader); + if(XarHeader.magic == XAR_HEADER_MAGIC) + DumpBitcodeSection(O, buffer, member_size, verbose, + PrintXarHeader, PrintXarFileHeaders, + XarMemberName); + } + XarMemberName = OldXarMemberName; + } + delete buffer; + } + } + xar_iter_free(xp); + } + xar_close(xar); +} +#endif // defined(HAVE_LIBXAR) + static void printObjcMetaData(MachOObjectFile *O, bool verbose) { if (O->is64Bit()) printObjc2_64bit_MetaData(O, verbose); @@ -5965,7 +6474,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, return; } - // Set up thumb disassembler. + // Set up separate thumb disassembler if needed. std::unique_ptr ThumbMRI; std::unique_ptr ThumbAsmInfo; std::unique_ptr ThumbSTI; @@ -6094,16 +6603,26 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, SymbolAddressMap AddrMap; bool DisSymNameFound = false; for (const SymbolRef &Symbol : MachOOF->symbols()) { - ErrorOr STOrErr = Symbol.getType(); - if (std::error_code EC = STOrErr.getError()) - report_fatal_error(EC.message()); + Expected STOrErr = Symbol.getType(); + if (!STOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(STOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } SymbolRef::Type ST = *STOrErr; if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data || ST == SymbolRef::ST_Other) { uint64_t Address = Symbol.getValue(); - ErrorOr SymNameOrErr = Symbol.getName(); - if (std::error_code EC = SymNameOrErr.getError()) - report_fatal_error(EC.message()); + Expected SymNameOrErr = Symbol.getName(); + if (!SymNameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymNameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } StringRef SymName = *SymNameOrErr; AddrMap[Address] = SymName; if (!DisSymName.empty() && DisSymName == SymName) @@ -6141,23 +6660,55 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, ThumbSymbolizerInfo.adrp_addr = 0; ThumbSymbolizerInfo.adrp_inst = 0; + unsigned int Arch = MachOOF->getArch(); + // Disassemble symbol by symbol. for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) { - ErrorOr SymNameOrErr = Symbols[SymIdx].getName(); - if (std::error_code EC = SymNameOrErr.getError()) - report_fatal_error(EC.message()); + Expected SymNameOrErr = Symbols[SymIdx].getName(); + if (!SymNameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymNameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } StringRef SymName = *SymNameOrErr; - ErrorOr STOrErr = Symbols[SymIdx].getType(); - if (std::error_code EC = STOrErr.getError()) - report_fatal_error(EC.message()); + Expected STOrErr = Symbols[SymIdx].getType(); + if (!STOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(STOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } SymbolRef::Type ST = *STOrErr; if (ST != SymbolRef::ST_Function && ST != SymbolRef::ST_Data) continue; // Make sure the symbol is defined in this section. bool containsSym = Sections[SectIdx].containsSymbol(Symbols[SymIdx]); - if (!containsSym) + if (!containsSym) { + if (!DisSymName.empty() && DisSymName == SymName) { + outs() << "-dis-symname: " << DisSymName << " not in the section\n"; + return; + } + continue; + } + // The __mh_execute_header is special and we need to deal with that fact + // this symbol is before the start of the (__TEXT,__text) section and at the + // address of the start of the __TEXT segment. This is because this symbol + // is an N_SECT symbol in the (__TEXT,__text) but its address is before the + // start of the section in a standard MH_EXECUTE filetype. + if (!DisSymName.empty() && DisSymName == "__mh_execute_header") { + outs() << "-dis-symname: __mh_execute_header not in any section\n"; + return; + } + // When this code is trying to disassemble a symbol at a time and in the case + // there is only the __mh_execute_header symbol left as in a stripped + // executable, we need to deal with this by ignoring this symbol so the whole + // section is disassembled and this symbol is then not displayed. + if (SymName == "__mh_execute_header") continue; // If we are only disassembling one symbol see if this is that symbol. @@ -6175,9 +6726,14 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, uint64_t NextSym = 0; uint64_t NextSymIdx = SymIdx + 1; while (Symbols.size() > NextSymIdx) { - ErrorOr STOrErr = Symbols[NextSymIdx].getType(); - if (std::error_code EC = STOrErr.getError()) - report_fatal_error(EC.message()); + Expected STOrErr = Symbols[NextSymIdx].getType(); + if (!STOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(STOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } SymbolRef::Type NextSymType = *STOrErr; if (NextSymType == SymbolRef::ST_Function) { containsNextSym = @@ -6196,8 +6752,11 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, symbolTableWorked = true; DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl(); - bool isThumb = - (MachOOF->getSymbolFlags(Symb) & SymbolRef::SF_Thumb) && ThumbTarget; + bool IsThumb = MachOOF->getSymbolFlags(Symb) & SymbolRef::SF_Thumb; + + // We only need the dedicated Thumb target if there's a real choice + // (i.e. we're not targeting M-class) and the function is Thumb. + bool UseThumbTarget = IsThumb && ThumbTarget; outs() << SymName << ":\n"; DILineInfo lastLine; @@ -6215,7 +6774,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, outs() << format("%8" PRIx64 ":", PC); } } - if (!NoShowRawInsn) + if (!NoShowRawInsn || Arch == Triple::arm) outs() << "\t"; // Check the data in code table here to see if this is data not an @@ -6241,19 +6800,19 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, raw_svector_ostream Annotations(AnnotationsBytes); bool gotInst; - if (isThumb) + if (UseThumbTarget) gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC, DebugOut, Annotations); else gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC, DebugOut, Annotations); if (gotInst) { - if (!NoShowRawInsn) { + if (!NoShowRawInsn || Arch == Triple::arm) { dumpBytes(makeArrayRef(Bytes.data() + Index, Size), outs()); } formatted_raw_ostream FormattedOS(outs()); StringRef AnnotationsStr = Annotations.str(); - if (isThumb) + if (UseThumbTarget) ThumbIP->printInst(&Inst, FormattedOS, AnnotationsStr, *ThumbSTI); else IP->printInst(&Inst, FormattedOS, AnnotationsStr, *STI); @@ -6275,14 +6834,21 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, outs() << format("\t.byte 0x%02x #bad opcode\n", *(Bytes.data() + Index) & 0xff); Size = 1; // skip exactly one illegible byte and move on. - } else if (Arch == Triple::aarch64) { + } else if (Arch == Triple::aarch64 || + (Arch == Triple::arm && !IsThumb)) { uint32_t opcode = (*(Bytes.data() + Index) & 0xff) | (*(Bytes.data() + Index + 1) & 0xff) << 8 | (*(Bytes.data() + Index + 2) & 0xff) << 16 | (*(Bytes.data() + Index + 3) & 0xff) << 24; outs() << format("\t.long\t0x%08x\n", opcode); Size = 4; - } else { + } else if (Arch == Triple::arm) { + assert(IsThumb && "ARM mode should have been dealt with above"); + uint32_t opcode = (*(Bytes.data() + Index) & 0xff) | + (*(Bytes.data() + Index + 1) & 0xff) << 8; + outs() << format("\t.short\t0x%04x\n", opcode); + Size = 2; + } else{ errs() << "llvm-objdump: warning: invalid instruction encoding\n"; if (Size == 0) Size = 1; // skip illegible bytes @@ -6311,7 +6877,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, outs() << format("%8" PRIx64 ":", PC); } } - if (!NoShowRawInsn) { + if (!NoShowRawInsn || Arch == Triple::arm) { outs() << "\t"; dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs()); } @@ -6413,9 +6979,14 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj, const RelocationRef &Reloc, uint64_t Addr, StringRef &Name, uint64_t &Addend) { if (Reloc.getSymbol() != Obj->symbol_end()) { - ErrorOr NameOrErr = Reloc.getSymbol()->getName(); - if (std::error_code EC = NameOrErr.getError()) - report_fatal_error(EC.message()); + Expected NameOrErr = Reloc.getSymbol()->getName(); + if (!NameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(NameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } Name = *NameOrErr; Addend = Addr; return; @@ -6438,12 +7009,25 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj, // Go back one so that SymbolAddress <= Addr. --Sym; - section_iterator SymSection = *Sym->second.getSection(); + auto SectOrErr = Sym->second.getSection(); + if (!SectOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SectOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } + section_iterator SymSection = *SectOrErr; if (RelocSection == *SymSection) { // There's a valid symbol in the same section before this reference. - ErrorOr NameOrErr = Sym->second.getName(); - if (std::error_code EC = NameOrErr.getError()) - report_fatal_error(EC.message()); + Expected NameOrErr = Sym->second.getName(); + if (!NameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(NameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } Name = *NameOrErr; Addend = Addr - Sym->first; return; @@ -6781,7 +7365,13 @@ void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) { for (const SymbolRef &SymRef : Obj->symbols()) { // Discard any undefined or absolute symbols. They're not going to take part // in the convenience lookup for unwind info and just take up resources. - section_iterator Section = *SymRef.getSection(); + auto SectOrErr = SymRef.getSection(); + if (!SectOrErr) { + // TODO: Actually report errors helpfully. + consumeError(SectOrErr.takeError()); + continue; + } + section_iterator Section = *SectOrErr; if (Section == Obj->section_end()) continue; @@ -8260,7 +8850,7 @@ static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) { static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld, uint32_t object_size) { if (ld.cmd == MachO::LC_CODE_SIGNATURE) - outs() << " cmd LC_FUNCTION_STARTS\n"; + outs() << " cmd LC_CODE_SIGNATURE\n"; else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO) outs() << " cmd LC_SEGMENT_SPLIT_INFO\n"; else if (ld.cmd == MachO::LC_FUNCTION_STARTS) diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 28d667a486e70147416b368c26ee6ad3247c9176..8414239cb506ec70211f7a2de7f8d38809e8c157 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -59,6 +59,7 @@ #include #include #include +#include using namespace llvm; using namespace object; @@ -197,7 +198,7 @@ public: SectionFilterIterator(FilterPredicate P, llvm::object::section_iterator const &I, llvm::object::section_iterator const &E) - : Predicate(P), Iterator(I), End(E) { + : Predicate(std::move(P)), Iterator(I), End(E) { ScanPredicate(); } const llvm::object::SectionRef &operator*() const { return *Iterator; } @@ -224,7 +225,7 @@ private: class SectionFilter { public: SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O) - : Predicate(P), Object(O) {} + : Predicate(std::move(P)), Object(O) {} SectionFilterIterator begin() { return SectionFilterIterator(Predicate, Object.section_begin(), Object.section_end()); @@ -263,6 +264,12 @@ void llvm::error(std::error_code EC) { exit(1); } +LLVM_ATTRIBUTE_NORETURN void llvm::error(Twine Message) { + errs() << ToolName << ": " << Message << ".\n"; + errs().flush(); + exit(1); +} + LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File, std::error_code EC) { assert(EC); @@ -270,6 +277,52 @@ LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File, exit(1); } +LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File, + llvm::Error E) { + assert(E); + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS, ""); + OS.flush(); + errs() << ToolName << ": '" << File << "': " << Buf; + exit(1); +} + +LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef ArchiveName, + StringRef FileName, + llvm::Error E, + StringRef ArchitectureName) { + assert(E); + errs() << ToolName << ": "; + if (ArchiveName != "") + errs() << ArchiveName << "(" << FileName << ")"; + else + errs() << FileName; + if (!ArchitectureName.empty()) + errs() << " (for architecture " << ArchitectureName << ")"; + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS, ""); + OS.flush(); + errs() << " " << Buf; + exit(1); +} + +LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef ArchiveName, + const object::Archive::Child &C, + llvm::Error E, + StringRef ArchitectureName) { + ErrorOr NameOrErr = C.getName(); + // TODO: if we have a error getting the name then it would be nice to print + // the index of which archive member this is and or its offset in the + // archive instead of "???" as the name. + if (NameOrErr.getError()) + llvm::report_error(ArchiveName, "???", std::move(E), ArchitectureName); + else + llvm::report_error(ArchiveName, NameOrErr.get(), std::move(E), + ArchitectureName); +} + static const Target *getTarget(const ObjectFile *Obj = nullptr) { // Figure out the target triple. llvm::Triple TheTriple("unknown-unknown-unknown"); @@ -384,12 +437,48 @@ public: } }; HexagonPrettyPrinter HexagonPrettyPrinterInst; + +class AMDGCNPrettyPrinter : public PrettyPrinter { +public: + void printInst(MCInstPrinter &IP, + const MCInst *MI, + ArrayRef Bytes, + uint64_t Address, + raw_ostream &OS, + StringRef Annot, + MCSubtargetInfo const &STI) override { + if (!MI) { + OS << " "; + return; + } + + SmallString<40> InstStr; + raw_svector_ostream IS(InstStr); + + IP.printInst(MI, IS, "", STI); + + OS << left_justify(IS.str(), 60) << format("// %012" PRIX64 ": ", Address); + typedef support::ulittle32_t U32; + for (auto D : makeArrayRef(reinterpret_cast(Bytes.data()), + Bytes.size() / sizeof(U32))) + // D should be explicitly casted to uint32_t here as it is passed + // by format to snprintf as vararg. + OS << format("%08" PRIX32 " ", static_cast(D)); + + if (!Annot.empty()) + OS << "// " << Annot; + } +}; +AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst; + PrettyPrinter &selectPrettyPrinter(Triple const &Triple) { switch(Triple.getArch()) { default: return PrettyPrinterInst; case Triple::hexagon: return HexagonPrettyPrinterInst; + case Triple::amdgcn: + return AMDGCNPrettyPrinterInst; } } } @@ -443,18 +532,18 @@ static std::error_code getRelocationValueString(const ELFObjectFile *Obj, const Elf_Sym *symb = Obj->getSymbol(SI->getRawDataRefImpl()); StringRef Target; if (symb->getType() == ELF::STT_SECTION) { - ErrorOr SymSI = SI->getSection(); - if (std::error_code EC = SymSI.getError()) - return EC; + Expected SymSI = SI->getSection(); + if (!SymSI) + return errorToErrorCode(SymSI.takeError()); const Elf_Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl()); ErrorOr SecName = EF.getSectionName(SymSec); if (std::error_code EC = SecName.getError()) return EC; Target = *SecName; } else { - ErrorOr SymName = symb->getName(StrTab); + Expected SymName = symb->getName(StrTab); if (!SymName) - return SymName.getError(); + return errorToErrorCode(SymName.takeError()); Target = *SymName; } switch (EF.getHeader()->e_machine) { @@ -544,9 +633,9 @@ static std::error_code getRelocationValueString(const COFFObjectFile *Obj, const RelocationRef &Rel, SmallVectorImpl &Result) { symbol_iterator SymI = Rel.getSymbol(); - ErrorOr SymNameOrErr = SymI->getName(); - if (std::error_code EC = SymNameOrErr.getError()) - return EC; + Expected SymNameOrErr = SymI->getName(); + if (!SymNameOrErr) + return errorToErrorCode(SymNameOrErr.takeError()); StringRef SymName = *SymNameOrErr; Result.append(SymName.begin(), SymName.end()); return std::error_code(); @@ -566,14 +655,24 @@ static void printRelocationTargetName(const MachOObjectFile *O, for (const SymbolRef &Symbol : O->symbols()) { std::error_code ec; - ErrorOr Addr = Symbol.getAddress(); - if ((ec = Addr.getError())) - report_fatal_error(ec.message()); + Expected Addr = Symbol.getAddress(); + if (!Addr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(Addr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } if (*Addr != Val) continue; - ErrorOr Name = Symbol.getName(); - if (std::error_code EC = Name.getError()) - report_fatal_error(EC.message()); + Expected Name = Symbol.getName(); + if (!Name) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(Name.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } fmt << *Name; return; } @@ -604,8 +703,8 @@ static void printRelocationTargetName(const MachOObjectFile *O, if (isExtern) { symbol_iterator SI = O->symbol_begin(); advance(SI, Val); - ErrorOr SOrErr = SI->getName(); - error(SOrErr.getError()); + Expected SOrErr = SI->getName(); + error(errorToErrorCode(SOrErr.takeError())); S = *SOrErr; } else { section_iterator SI = O->section_begin(); @@ -843,12 +942,10 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { const Target *TheTarget = getTarget(Obj); // Package up features to be passed to target/subtarget - std::string FeaturesStr; + SubtargetFeatures Features = Obj->getFeatures(); if (MAttrs.size()) { - SubtargetFeatures Features; for (unsigned i = 0; i != MAttrs.size(); ++i) Features.AddFeature(MAttrs[i]); - FeaturesStr = Features.getString(); } std::unique_ptr MRI( @@ -862,7 +959,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (!AsmInfo) report_fatal_error("error: no assembly info for target " + TripleName); std::unique_ptr STI( - TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr)); + TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString())); if (!STI) report_fatal_error("error: no subtarget info for target " + TripleName); std::unique_ptr MII(TheTarget->createMCInstrInfo()); @@ -906,17 +1003,17 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { typedef std::vector> SectionSymbolsTy; std::map AllSymbols; for (const SymbolRef &Symbol : Obj->symbols()) { - ErrorOr AddressOrErr = Symbol.getAddress(); - error(AddressOrErr.getError()); + Expected AddressOrErr = Symbol.getAddress(); + error(errorToErrorCode(AddressOrErr.takeError())); uint64_t Address = *AddressOrErr; - ErrorOr Name = Symbol.getName(); - error(Name.getError()); + Expected Name = Symbol.getName(); + error(errorToErrorCode(Name.takeError())); if (Name->empty()) continue; - ErrorOr SectionOrErr = Symbol.getSection(); - error(SectionOrErr.getError()); + Expected SectionOrErr = Symbol.getSection(); + error(errorToErrorCode(SectionOrErr.takeError())); section_iterator SecI = *SectionOrErr; if (SecI == Obj->section_end()) continue; @@ -1046,6 +1143,18 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (Start >= End) continue; + if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) { + // make size 4 bytes folded + End = Start + ((End - Start) & ~0x3ull); + Start += 256; // add sizeof(amd_kernel_code_t) + // cut trailing zeroes - up to 256 bytes (align) + const uint64_t EndAlign = 256; + const auto Limit = End - (std::min)(EndAlign, End - Start); + while (End > Limit && + *reinterpret_cast(&Bytes[End - 4]) == 0) + End -= 4; + } + outs() << '\n' << Symbols[si].second << ":\n"; #ifndef NDEBUG @@ -1282,7 +1391,8 @@ void llvm::PrintSectionContents(const ObjectFile *Obj) { } } -void llvm::PrintSymbolTable(const ObjectFile *o) { +void llvm::PrintSymbolTable(const ObjectFile *o, StringRef ArchiveName, + StringRef ArchitectureName) { outs() << "SYMBOL TABLE:\n"; if (const COFFObjectFile *coff = dyn_cast(o)) { @@ -1290,22 +1400,26 @@ void llvm::PrintSymbolTable(const ObjectFile *o) { return; } for (const SymbolRef &Symbol : o->symbols()) { - ErrorOr AddressOrError = Symbol.getAddress(); - error(AddressOrError.getError()); + Expected AddressOrError = Symbol.getAddress(); + if (!AddressOrError) + report_error(ArchiveName, o->getFileName(), AddressOrError.takeError()); uint64_t Address = *AddressOrError; - ErrorOr TypeOrError = Symbol.getType(); - error(TypeOrError.getError()); + Expected TypeOrError = Symbol.getType(); + if (!TypeOrError) + report_error(ArchiveName, o->getFileName(), TypeOrError.takeError()); SymbolRef::Type Type = *TypeOrError; uint32_t Flags = Symbol.getFlags(); - ErrorOr SectionOrErr = Symbol.getSection(); - error(SectionOrErr.getError()); + Expected SectionOrErr = Symbol.getSection(); + error(errorToErrorCode(SectionOrErr.takeError())); section_iterator Section = *SectionOrErr; StringRef Name; if (Type == SymbolRef::ST_Debug && Section != o->section_end()) { Section->getName(Name); } else { - ErrorOr NameOrErr = Symbol.getName(); - error(NameOrErr.getError()); + Expected NameOrErr = Symbol.getName(); + if (!NameOrErr) + report_error(ArchiveName, o->getFileName(), NameOrErr.takeError(), + ArchitectureName); Name = *NameOrErr; } @@ -1537,12 +1651,16 @@ static void printFirstPrivateFileHeader(const ObjectFile *o) { report_fatal_error("Invalid/Unsupported object file format"); } -static void DumpObject(const ObjectFile *o) { +static void DumpObject(const ObjectFile *o, const Archive *a = nullptr) { + StringRef ArchiveName = a != nullptr ? a->getFileName() : ""; // Avoid other output when using a raw option. if (!RawClangAST) { outs() << '\n'; - outs() << o->getFileName() - << ":\tfile format " << o->getFileFormatName() << "\n\n"; + if (a) + outs() << a->getFileName() << "(" << o->getFileName() << ")"; + else + outs() << o->getFileName(); + outs() << ":\tfile format " << o->getFileFormatName() << "\n\n"; } if (Disassemble) @@ -1554,7 +1672,7 @@ static void DumpObject(const ObjectFile *o) { if (SectionContents) PrintSectionContents(o); if (SymbolTable) - PrintSymbolTable(o); + PrintSymbolTable(o, ArchiveName); if (UnwindInfo) PrintUnwindInfo(o); if (PrivateHeaders) @@ -1584,19 +1702,21 @@ static void DumpObject(const ObjectFile *o) { /// @brief Dump each object file in \a a; static void DumpArchive(const Archive *a) { - for (auto &ErrorOrChild : a->children()) { - if (std::error_code EC = ErrorOrChild.getError()) - report_error(a->getFileName(), EC); - const Archive::Child &C = *ErrorOrChild; - ErrorOr> ChildOrErr = C.getAsBinary(); - if (std::error_code EC = ChildOrErr.getError()) - if (EC != object_error::invalid_file_type) - report_error(a->getFileName(), EC); + Error Err; + for (auto &C : a->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + report_error(a->getFileName(), C, std::move(E)); + continue; + } if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) - DumpObject(o); + DumpObject(o, a); else report_error(a->getFileName(), object_error::invalid_file_type); } + if (Err) + report_error(a->getFileName(), std::move(Err)); } /// @brief Open file and figure out how to dump it. @@ -1611,9 +1731,9 @@ static void DumpInput(StringRef file) { } // Attempt to open the binary. - ErrorOr> BinaryOrErr = createBinary(file); - if (std::error_code EC = BinaryOrErr.getError()) - report_error(file, EC); + Expected> BinaryOrErr = createBinary(file); + if (!BinaryOrErr) + report_error(file, BinaryOrErr.takeError()); Binary &Binary = *BinaryOrErr.get().getBinary(); if (Archive *a = dyn_cast(&Binary)) @@ -1626,7 +1746,7 @@ static void DumpInput(StringRef file) { int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index c50caae5b58cedae5b76975616ad3204412c8d64..5b10ee87ca86381e9d71e33fddeab086648b5e0e 100644 --- a/tools/llvm-objdump/llvm-objdump.h +++ b/tools/llvm-objdump/llvm-objdump.h @@ -9,17 +9,20 @@ #ifndef LLVM_TOOLS_LLVM_OBJDUMP_LLVM_OBJDUMP_H #define LLVM_TOOLS_LLVM_OBJDUMP_LLVM_OBJDUMP_H -#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Object/Archive.h" namespace llvm { +class StringRef; + namespace object { class COFFObjectFile; class MachOObjectFile; class ObjectFile; + class Archive; class RelocationRef; } @@ -83,8 +86,21 @@ void printRawClangAST(const object::ObjectFile *o); void PrintRelocations(const object::ObjectFile *o); void PrintSectionHeaders(const object::ObjectFile *o); void PrintSectionContents(const object::ObjectFile *o); -void PrintSymbolTable(const object::ObjectFile *o); +void PrintSymbolTable(const object::ObjectFile *o, StringRef ArchiveName, + StringRef ArchitectureName = StringRef()); +LLVM_ATTRIBUTE_NORETURN void error(Twine Message); LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, std::error_code EC); +LLVM_ATTRIBUTE_NORETURN void report_error(StringRef File, llvm::Error E); +LLVM_ATTRIBUTE_NORETURN void report_error(StringRef FileName, + StringRef ArchiveName, + llvm::Error E, + StringRef ArchitectureName + = StringRef()); +LLVM_ATTRIBUTE_NORETURN void report_error(StringRef ArchiveName, + const object::Archive::Child &C, + llvm::Error E, + StringRef ArchitectureName + = StringRef()); } // end namespace llvm diff --git a/tools/llvm-pdbdump/BuiltinDumper.cpp b/tools/llvm-pdbdump/BuiltinDumper.cpp index 43270540f4534af89237c05a53831157deca21ec..2ce1a78391102d1d2951c60f457c8cad5927bf96 100644 --- a/tools/llvm-pdbdump/BuiltinDumper.cpp +++ b/tools/llvm-pdbdump/BuiltinDumper.cpp @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" using namespace llvm; +using namespace llvm::pdb; BuiltinDumper::BuiltinDumper(LinePrinter &P) : PDBSymDumper(false), Printer(P) {} @@ -30,13 +31,31 @@ StringRef BuiltinDumper::getTypeName(const PDBSymbolTypeBuiltin &Symbol) { return "float"; return "double"; case PDB_BuiltinType::UInt: - if (Symbol.getLength() == 8) + switch (Symbol.getLength()) { + case 8: return "unsigned __int64"; - return "unsigned"; + case 4: + return "unsigned int"; + case 2: + return "unsigned short"; + case 1: + return "unsigned char"; + default: + return "unsigned"; + } case PDB_BuiltinType::Int: - if (Symbol.getLength() == 4) + switch (Symbol.getLength()) { + case 8: + return "__int64"; + case 4: + return "int"; + case 2: + return "short"; + case 1: + return "char"; + default: return "int"; - return "__int64"; + } case PDB_BuiltinType::Char: return "char"; case PDB_BuiltinType::WCharT: diff --git a/tools/llvm-pdbdump/BuiltinDumper.h b/tools/llvm-pdbdump/BuiltinDumper.h index ac666dbd059b7fcb36c585824be05d783c5e5810..7a2f1438669c3a251e8b699a38afb68706f02d08 100644 --- a/tools/llvm-pdbdump/BuiltinDumper.h +++ b/tools/llvm-pdbdump/BuiltinDumper.h @@ -10,9 +10,11 @@ #ifndef LLVM_TOOLS_LLVMPDBDUMP_BUILTINDUMPER_H #define LLVM_TOOLS_LLVMPDBDUMP_BUILTINDUMPER_H +#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/PDB/PDBSymDumper.h" namespace llvm { +namespace pdb { class LinePrinter; @@ -28,5 +30,6 @@ private: LinePrinter &Printer; }; } +} #endif diff --git a/tools/llvm-pdbdump/CMakeLists.txt b/tools/llvm-pdbdump/CMakeLists.txt index 1907f917079ae6284f6804287297a177301d6bac..f725edfaf3dae3e3f6050cb045d2553755c377e3 100644 --- a/tools/llvm-pdbdump/CMakeLists.txt +++ b/tools/llvm-pdbdump/CMakeLists.txt @@ -1,6 +1,8 @@ set(LLVM_LINK_COMPONENTS - Support + DebugInfoCodeView DebugInfoPDB + Object + Support ) add_llvm_tool(llvm-pdbdump @@ -12,7 +14,14 @@ add_llvm_tool(llvm-pdbdump ExternalSymbolDumper.cpp FunctionDumper.cpp LinePrinter.cpp + LLVMOutputStyle.cpp + PdbYaml.cpp TypeDumper.cpp TypedefDumper.cpp VariableDumper.cpp + YAMLOutputStyle.cpp ) + +if(LLVM_USE_SANITIZE_COVERAGE) + add_subdirectory(fuzzer) +endif() diff --git a/tools/llvm-pdbdump/ClassDefinitionDumper.cpp b/tools/llvm-pdbdump/ClassDefinitionDumper.cpp index 8abf3fa3912af4c831cac60829004e0c0e89a7b6..553bc0b267c2ef7beca2dea63e917cb72d3f3180 100644 --- a/tools/llvm-pdbdump/ClassDefinitionDumper.cpp +++ b/tools/llvm-pdbdump/ClassDefinitionDumper.cpp @@ -28,6 +28,7 @@ #include "llvm/Support/Format.h" using namespace llvm; +using namespace llvm::pdb; ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} @@ -84,7 +85,7 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { auto &AccessGroup = Groups.find((int)Access)->second; if (auto Func = dyn_cast(Child.get())) { - if (Func->isCompilerGenerated() && opts::ExcludeCompilerGenerated) + if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) continue; if (Func->getLength() == 0 && !Func->isPureVirtual() && !Func->isIntroVirtualFunction()) diff --git a/tools/llvm-pdbdump/ClassDefinitionDumper.h b/tools/llvm-pdbdump/ClassDefinitionDumper.h index 5b48ba879cf7beece61b90e9f63d46211598f190..304e11dcb6c997c99158dc8b029455e70afae186 100644 --- a/tools/llvm-pdbdump/ClassDefinitionDumper.h +++ b/tools/llvm-pdbdump/ClassDefinitionDumper.h @@ -19,6 +19,7 @@ #include namespace llvm { +namespace pdb { class LinePrinter; @@ -58,5 +59,5 @@ private: int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group); }; } - +} #endif diff --git a/tools/llvm-pdbdump/CompilandDumper.cpp b/tools/llvm-pdbdump/CompilandDumper.cpp index 7d80f3234d1f65aa6d0bc9ca418d50df98af684c..5ec37cbbb5a065526cbf3716cb152a8cdeb240fe 100644 --- a/tools/llvm-pdbdump/CompilandDumper.cpp +++ b/tools/llvm-pdbdump/CompilandDumper.cpp @@ -33,9 +33,9 @@ #include "FunctionDumper.h" #include -#include using namespace llvm; +using namespace llvm::pdb; CompilandDumper::CompilandDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} @@ -158,9 +158,9 @@ void CompilandDumper::dump(const PDBSymbolThunk &Symbol) { Printer.NewLine(); Printer << "thunk "; - PDB_ThunkOrdinal Ordinal = Symbol.getThunkOrdinal(); + codeview::ThunkOrdinal Ordinal = Symbol.getThunkOrdinal(); uint64_t VA = Symbol.getVirtualAddress(); - if (Ordinal == PDB_ThunkOrdinal::TrampIncremental) { + if (Ordinal == codeview::ThunkOrdinal::TrampIncremental) { uint64_t Target = Symbol.getTargetVirtualAddress(); WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(VA, 10); Printer << " -> "; diff --git a/tools/llvm-pdbdump/CompilandDumper.h b/tools/llvm-pdbdump/CompilandDumper.h index 204d34acf1bfc0b0328a2676b77e59a3e9f84f06..462aaeb2611fe6bff35b66a618070895a30bfc30 100644 --- a/tools/llvm-pdbdump/CompilandDumper.h +++ b/tools/llvm-pdbdump/CompilandDumper.h @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/PDB/PDBSymDumper.h" namespace llvm { +namespace pdb { class LinePrinter; @@ -38,5 +39,6 @@ private: LinePrinter &Printer; }; } +} #endif diff --git a/tools/llvm-pdbdump/EnumDumper.cpp b/tools/llvm-pdbdump/EnumDumper.cpp index 3514c39f6e03362a4731078af1477a933e925092..43b6018ffedf38e0fef19028b1b72a152babef7b 100644 --- a/tools/llvm-pdbdump/EnumDumper.cpp +++ b/tools/llvm-pdbdump/EnumDumper.cpp @@ -18,13 +18,14 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" using namespace llvm; +using namespace llvm::pdb; EnumDumper::EnumDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} void EnumDumper::start(const PDBSymbolTypeEnum &Symbol) { WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); - if (!opts::NoEnumDefs) { + if (!opts::pretty::NoEnumDefs) { auto BuiltinType = Symbol.getUnderlyingType(); if (BuiltinType->getBuiltinType() != PDB_BuiltinType::Int || BuiltinType->getLength() != 4) { diff --git a/tools/llvm-pdbdump/EnumDumper.h b/tools/llvm-pdbdump/EnumDumper.h index 23de0614247fed4f1b918cb27e958b61b4236040..0a34e1f89ada0bb2b4ebabc735b7b9076b0d2806 100644 --- a/tools/llvm-pdbdump/EnumDumper.h +++ b/tools/llvm-pdbdump/EnumDumper.h @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/PDB/PDBSymDumper.h" namespace llvm { +namespace pdb { class LinePrinter; @@ -26,5 +27,5 @@ private: LinePrinter &Printer; }; } - +} #endif diff --git a/tools/llvm-pdbdump/ExternalSymbolDumper.cpp b/tools/llvm-pdbdump/ExternalSymbolDumper.cpp index c4e9f474880e3ad543e278f8bbd221703cc25a38..508a2405772e48c18c994dcfe111980d0f7111c0 100644 --- a/tools/llvm-pdbdump/ExternalSymbolDumper.cpp +++ b/tools/llvm-pdbdump/ExternalSymbolDumper.cpp @@ -15,6 +15,7 @@ #include "llvm/Support/Format.h" using namespace llvm; +using namespace llvm::pdb; ExternalSymbolDumper::ExternalSymbolDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} diff --git a/tools/llvm-pdbdump/ExternalSymbolDumper.h b/tools/llvm-pdbdump/ExternalSymbolDumper.h index d77b09cdebf17a17034800040e879109ebe83114..b44b8a6fe98ae10a353c3ae77aee0067c563777e 100644 --- a/tools/llvm-pdbdump/ExternalSymbolDumper.h +++ b/tools/llvm-pdbdump/ExternalSymbolDumper.h @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/PDB/PDBSymDumper.h" namespace llvm { +namespace pdb { class LinePrinter; @@ -28,5 +29,6 @@ private: LinePrinter &Printer; }; } +} #endif diff --git a/tools/llvm-pdbdump/FunctionDumper.cpp b/tools/llvm-pdbdump/FunctionDumper.cpp index 7f4181722e7c355af6326c9fecfa5c3ae9f1f8a7..29ba15d521f0e213b0bc63efa3e9917730c9dba1 100644 --- a/tools/llvm-pdbdump/FunctionDumper.cpp +++ b/tools/llvm-pdbdump/FunctionDumper.cpp @@ -13,6 +13,7 @@ #include "llvm-pdbdump.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" @@ -28,11 +29,12 @@ using namespace llvm; using namespace llvm::codeview; +using namespace llvm::pdb; namespace { template void dumpClassParentWithScopeOperator(const T &Symbol, LinePrinter &Printer, - llvm::FunctionDumper &Dumper) { + FunctionDumper &Dumper) { uint32_t ClassParentId = Symbol.getClassParentId(); auto ClassParent = Symbol.getSession().template getConcreteSymbolById( @@ -58,7 +60,7 @@ void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol, Symbol.getSession().getConcreteSymbolById( ClassParentId); - CallingConvention CC = Symbol.getCallingConvention(); + PDB_CallingConv CC = Symbol.getCallingConvention(); bool ShouldDumpCallingConvention = true; if ((ClassParent && CC == CallingConvention::ThisCall) || (!ClassParent && CC == CallingConvention::NearStdCall)) { diff --git a/tools/llvm-pdbdump/FunctionDumper.h b/tools/llvm-pdbdump/FunctionDumper.h index 19a00145a1fd79657f20ada39fcfa39019903d14..c71fafa18ed3b9e70c2a7b7bb668c0d88dc93b99 100644 --- a/tools/llvm-pdbdump/FunctionDumper.h +++ b/tools/llvm-pdbdump/FunctionDumper.h @@ -13,7 +13,7 @@ #include "llvm/DebugInfo/PDB/PDBSymDumper.h" namespace llvm { - +namespace pdb { class LinePrinter; class FunctionDumper : public PDBSymDumper { @@ -38,5 +38,6 @@ private: LinePrinter &Printer; }; } +} #endif diff --git a/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/tools/llvm-pdbdump/LLVMOutputStyle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d8eefa0837746c55a78614081707858b8c0ee72e --- /dev/null +++ b/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -0,0 +1,776 @@ +//===- LLVMOutputStyle.cpp ------------------------------------ *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LLVMOutputStyle.h" + +#include "llvm-pdbdump.h" +#include "llvm/DebugInfo/CodeView/EnumTables.h" +#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" +#include "llvm/DebugInfo/CodeView/SymbolDumper.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" +#include "llvm/DebugInfo/PDB/Raw/EnumTables.h" +#include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/InfoStream.h" +#include "llvm/DebugInfo/PDB/Raw/ModInfo.h" +#include "llvm/DebugInfo/PDB/Raw/ModStream.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" +#include "llvm/Object/COFF.h" + +#include + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static void printSectionOffset(llvm::raw_ostream &OS, + const SectionOffset &Off) { + OS << Off.Off << ", " << Off.Isect; +} + +LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) + : File(File), P(outs()), TD(&P, false) {} + +Error LLVMOutputStyle::dump() { + if (auto EC = dumpFileHeaders()) + return EC; + + if (auto EC = dumpStreamSummary()) + return EC; + + if (auto EC = dumpStreamBlocks()) + return EC; + + if (auto EC = dumpStreamData()) + return EC; + + if (auto EC = dumpInfoStream()) + return EC; + + if (auto EC = dumpNamedStream()) + return EC; + + if (auto EC = dumpTpiStream(StreamTPI)) + return EC; + + if (auto EC = dumpTpiStream(StreamIPI)) + return EC; + + if (auto EC = dumpDbiStream()) + return EC; + + if (auto EC = dumpSectionContribs()) + return EC; + + if (auto EC = dumpSectionMap()) + return EC; + + if (auto EC = dumpPublicsStream()) + return EC; + + if (auto EC = dumpSectionHeaders()) + return EC; + + if (auto EC = dumpFpoStream()) + return EC; + + flush(); + + return Error::success(); +} + +Error LLVMOutputStyle::dumpFileHeaders() { + if (!opts::raw::DumpHeaders) + return Error::success(); + + DictScope D(P, "FileHeaders"); + P.printNumber("BlockSize", File.getBlockSize()); + P.printNumber("Unknown0", File.getUnknown0()); + P.printNumber("NumBlocks", File.getBlockCount()); + P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes()); + P.printNumber("Unknown1", File.getUnknown1()); + P.printNumber("BlockMapAddr", File.getBlockMapIndex()); + P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks()); + P.printNumber("BlockMapOffset", File.getBlockMapOffset()); + + // The directory is not contiguous. Instead, the block map contains a + // contiguous list of block numbers whose contents, when concatenated in + // order, make up the directory. + P.printList("DirectoryBlocks", File.getDirectoryBlockArray()); + P.printNumber("NumStreams", File.getNumStreams()); + return Error::success(); +} + +Error LLVMOutputStyle::dumpStreamSummary() { + if (!opts::raw::DumpStreamSummary) + return Error::success(); + + // It's OK if we fail to load some of these streams, we still attempt to print + // what we can. + auto Dbi = File.getPDBDbiStream(); + auto Tpi = File.getPDBTpiStream(); + auto Ipi = File.getPDBIpiStream(); + auto Info = File.getPDBInfoStream(); + + ListScope L(P, "Streams"); + uint32_t StreamCount = File.getNumStreams(); + std::unordered_map ModStreams; + std::unordered_map NamedStreams; + + if (Dbi) { + for (auto &ModI : Dbi->modules()) { + uint16_t SN = ModI.Info.getModuleStreamIndex(); + ModStreams[SN] = &ModI; + } + } + if (Info) { + for (auto &NSE : Info->named_streams()) { + NamedStreams[NSE.second] = NSE.first(); + } + } + + for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { + std::string Label("Stream "); + Label += to_string(StreamIdx); + std::string Value; + if (StreamIdx == OldMSFDirectory) + Value = "Old MSF Directory"; + else if (StreamIdx == StreamPDB) + Value = "PDB Stream"; + else if (StreamIdx == StreamDBI) + Value = "DBI Stream"; + else if (StreamIdx == StreamTPI) + Value = "TPI Stream"; + else if (StreamIdx == StreamIPI) + Value = "IPI Stream"; + else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex()) + Value = "Global Symbol Hash"; + else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex()) + Value = "Public Symbol Hash"; + else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex()) + Value = "Public Symbol Records"; + else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex()) + Value = "TPI Hash"; + else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex()) + Value = "TPI Aux Hash"; + else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex()) + Value = "IPI Hash"; + else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex()) + Value = "IPI Aux Hash"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception)) + Value = "Exception Data"; + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup)) + Value = "Fixup Data"; + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO)) + Value = "FPO Data"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO)) + Value = "New FPO Data"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc)) + Value = "Omap From Source Data"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc)) + Value = "Omap To Source Data"; + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata)) + Value = "Pdata"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr)) + Value = "Section Header Data"; + else if (Dbi && + StreamIdx == + Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig)) + Value = "Section Header Original Data"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap)) + Value = "Token Rid Data"; + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata)) + Value = "Xdata"; + else { + auto ModIter = ModStreams.find(StreamIdx); + auto NSIter = NamedStreams.find(StreamIdx); + if (ModIter != ModStreams.end()) { + Value = "Module \""; + Value += ModIter->second->Info.getModuleName().str(); + Value += "\""; + } else if (NSIter != NamedStreams.end()) { + Value = "Named Stream \""; + Value += NSIter->second; + Value += "\""; + } else { + Value = "???"; + } + } + Value = "[" + Value + "]"; + Value = + Value + " (" + to_string(File.getStreamByteSize(StreamIdx)) + " bytes)"; + + P.printString(Label, Value); + } + + // Consume errors from missing streams. + if (!Dbi) + consumeError(Dbi.takeError()); + if (!Tpi) + consumeError(Tpi.takeError()); + if (!Ipi) + consumeError(Ipi.takeError()); + if (!Info) + consumeError(Info.takeError()); + + P.flush(); + return Error::success(); +} + +Error LLVMOutputStyle::dumpStreamBlocks() { + if (!opts::raw::DumpStreamBlocks) + return Error::success(); + + ListScope L(P, "StreamBlocks"); + uint32_t StreamCount = File.getNumStreams(); + for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { + std::string Name("Stream "); + Name += to_string(StreamIdx); + auto StreamBlocks = File.getStreamBlockList(StreamIdx); + P.printList(Name, StreamBlocks); + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpStreamData() { + uint32_t StreamCount = File.getNumStreams(); + StringRef DumpStreamStr = opts::raw::DumpStreamDataIdx; + uint32_t DumpStreamNum; + if (DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum)) + return Error::success(); + + if (DumpStreamNum >= StreamCount) + return make_error(raw_error_code::no_stream); + + auto S = MappedBlockStream::createIndexedStream(DumpStreamNum, File); + if (!S) + return S.takeError(); + codeview::StreamReader R(**S); + while (R.bytesRemaining() > 0) { + ArrayRef Data; + uint32_t BytesToReadInBlock = std::min( + R.bytesRemaining(), static_cast(File.getBlockSize())); + if (auto EC = R.readBytes(Data, BytesToReadInBlock)) + return EC; + P.printBinaryBlock( + "Data", + StringRef(reinterpret_cast(Data.begin()), Data.size())); + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpInfoStream() { + if (!opts::raw::DumpHeaders) + return Error::success(); + auto IS = File.getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + DictScope D(P, "PDB Stream"); + P.printNumber("Version", IS->getVersion()); + P.printHex("Signature", IS->getSignature()); + P.printNumber("Age", IS->getAge()); + P.printObject("Guid", IS->getGuid()); + return Error::success(); +} + +Error LLVMOutputStyle::dumpNamedStream() { + if (opts::raw::DumpStreamDataName.empty()) + return Error::success(); + + auto IS = File.getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + uint32_t NameStreamIndex = + IS->getNamedStreamIndex(opts::raw::DumpStreamDataName); + if (NameStreamIndex == 0 || NameStreamIndex >= File.getNumStreams()) + return make_error(raw_error_code::no_stream); + + if (NameStreamIndex != 0) { + std::string Name("Stream '"); + Name += opts::raw::DumpStreamDataName; + Name += "'"; + DictScope D(P, Name); + P.printNumber("Index", NameStreamIndex); + + auto NameStream = + MappedBlockStream::createIndexedStream(NameStreamIndex, File); + if (!NameStream) + return NameStream.takeError(); + codeview::StreamReader Reader(**NameStream); + + NameHashTable NameTable; + if (auto EC = NameTable.load(Reader)) + return EC; + + P.printHex("Signature", NameTable.getSignature()); + P.printNumber("Version", NameTable.getHashVersion()); + P.printNumber("Name Count", NameTable.getNameCount()); + ListScope L(P, "Names"); + for (uint32_t ID : NameTable.name_ids()) { + StringRef Str = NameTable.getStringForID(ID); + if (!Str.empty()) + P.printString(to_string(ID), Str); + } + } + return Error::success(); +} + +static void printTypeIndexOffset(raw_ostream &OS, + const TypeIndexOffset &TIOff) { + OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}"; +} + +static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) { + if (!opts::raw::DumpTpiHash) + return; + DictScope DD(P, "Hash"); + P.printNumber("Number of Hash Buckets", Tpi.NumHashBuckets()); + P.printNumber("Hash Key Size", Tpi.getHashKeySize()); + P.printList("Values", Tpi.getHashValues()); + P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets(), + printTypeIndexOffset); + P.printList("Hash Adjustments", Tpi.getHashAdjustments(), + printTypeIndexOffset); +} + +Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { + assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); + + bool DumpRecordBytes = false; + bool DumpRecords = false; + StringRef Label; + StringRef VerLabel; + if (StreamIdx == StreamTPI) { + DumpRecordBytes = opts::raw::DumpTpiRecordBytes; + DumpRecords = opts::raw::DumpTpiRecords; + Label = "Type Info Stream (TPI)"; + VerLabel = "TPI Version"; + } else if (StreamIdx == StreamIPI) { + DumpRecordBytes = opts::raw::DumpIpiRecordBytes; + DumpRecords = opts::raw::DumpIpiRecords; + Label = "Type Info Stream (IPI)"; + VerLabel = "IPI Version"; + } + if (!DumpRecordBytes && !DumpRecords && !opts::raw::DumpModuleSyms) + return Error::success(); + + auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream() + : File.getPDBIpiStream(); + if (!Tpi) + return Tpi.takeError(); + + if (DumpRecords || DumpRecordBytes) { + DictScope D(P, Label); + + P.printNumber(VerLabel, Tpi->getTpiVersion()); + P.printNumber("Record count", Tpi->NumTypeRecords()); + + ListScope L(P, "Records"); + + bool HadError = false; + for (auto &Type : Tpi->types(&HadError)) { + DictScope DD(P, ""); + + if (DumpRecords) { + if (auto EC = TD.dump(Type)) + return EC; + } + + if (DumpRecordBytes) + P.printBinaryBlock("Bytes", Type.Data); + } + dumpTpiHash(P, *Tpi); + if (HadError) + return make_error(raw_error_code::corrupt_file, + "TPI stream contained corrupt record"); + } else if (opts::raw::DumpModuleSyms) { + // Even if the user doesn't want to dump type records, we still need to + // iterate them in order to build the list of types so that we can print + // them when dumping module symbols. So when they want to dump symbols + // but not types, use a null output stream. + ScopedPrinter *OldP = TD.getPrinter(); + TD.setPrinter(nullptr); + + bool HadError = false; + for (auto &Type : Tpi->types(&HadError)) { + if (auto EC = TD.dump(Type)) + return EC; + } + + TD.setPrinter(OldP); + dumpTpiHash(P, *Tpi); + if (HadError) + return make_error(raw_error_code::corrupt_file, + "TPI stream contained corrupt record"); + } + P.flush(); + return Error::success(); +} + +Error LLVMOutputStyle::dumpDbiStream() { + bool DumpModules = opts::raw::DumpModules || opts::raw::DumpModuleSyms || + opts::raw::DumpModuleFiles || opts::raw::DumpLineInfo; + if (!opts::raw::DumpHeaders && !DumpModules) + return Error::success(); + + auto DS = File.getPDBDbiStream(); + if (!DS) + return DS.takeError(); + + DictScope D(P, "DBI Stream"); + P.printNumber("Dbi Version", DS->getDbiVersion()); + P.printNumber("Age", DS->getAge()); + P.printBoolean("Incremental Linking", DS->isIncrementallyLinked()); + P.printBoolean("Has CTypes", DS->hasCTypes()); + P.printBoolean("Is Stripped", DS->isStripped()); + P.printObject("Machine Type", DS->getMachineType()); + P.printNumber("Symbol Record Stream Index", DS->getSymRecordStreamIndex()); + P.printNumber("Public Symbol Stream Index", DS->getPublicSymbolStreamIndex()); + P.printNumber("Global Symbol Stream Index", DS->getGlobalSymbolStreamIndex()); + + uint16_t Major = DS->getBuildMajorVersion(); + uint16_t Minor = DS->getBuildMinorVersion(); + P.printVersion("Toolchain Version", Major, Minor); + + std::string DllName; + raw_string_ostream DllStream(DllName); + DllStream << "mspdb" << Major << Minor << ".dll version"; + DllStream.flush(); + P.printVersion(DllName, Major, Minor, DS->getPdbDllVersion()); + + if (DumpModules) { + ListScope L(P, "Modules"); + for (auto &Modi : DS->modules()) { + DictScope DD(P); + P.printString("Name", Modi.Info.getModuleName().str()); + P.printNumber("Debug Stream Index", Modi.Info.getModuleStreamIndex()); + P.printString("Object File Name", Modi.Info.getObjFileName().str()); + P.printNumber("Num Files", Modi.Info.getNumberOfFiles()); + P.printNumber("Source File Name Idx", Modi.Info.getSourceFileNameIndex()); + P.printNumber("Pdb File Name Idx", Modi.Info.getPdbFilePathNameIndex()); + P.printNumber("Line Info Byte Size", Modi.Info.getLineInfoByteSize()); + P.printNumber("C13 Line Info Byte Size", + Modi.Info.getC13LineInfoByteSize()); + P.printNumber("Symbol Byte Size", Modi.Info.getSymbolDebugInfoByteSize()); + P.printNumber("Type Server Index", Modi.Info.getTypeServerIndex()); + P.printBoolean("Has EC Info", Modi.Info.hasECInfo()); + if (opts::raw::DumpModuleFiles) { + std::string FileListName = + to_string(Modi.SourceFiles.size()) + " Contributing Source Files"; + ListScope LL(P, FileListName); + for (auto File : Modi.SourceFiles) + P.printString(File.str()); + } + bool HasModuleDI = + (Modi.Info.getModuleStreamIndex() < File.getNumStreams()); + bool ShouldDumpSymbols = + (opts::raw::DumpModuleSyms || opts::raw::DumpSymRecordBytes); + if (HasModuleDI && (ShouldDumpSymbols || opts::raw::DumpLineInfo)) { + auto ModStreamData = MappedBlockStream::createIndexedStream( + Modi.Info.getModuleStreamIndex(), File); + if (!ModStreamData) + return ModStreamData.takeError(); + ModStream ModS(Modi.Info, std::move(*ModStreamData)); + if (auto EC = ModS.reload()) + return EC; + + if (ShouldDumpSymbols) { + ListScope SS(P, "Symbols"); + codeview::CVSymbolDumper SD(P, TD, nullptr, false); + bool HadError = false; + for (const auto &S : ModS.symbols(&HadError)) { + DictScope DD(P, ""); + + if (opts::raw::DumpModuleSyms) + SD.dump(S); + if (opts::raw::DumpSymRecordBytes) + P.printBinaryBlock("Bytes", S.Data); + } + if (HadError) + return make_error( + raw_error_code::corrupt_file, + "DBI stream contained corrupt symbol record"); + } + if (opts::raw::DumpLineInfo) { + ListScope SS(P, "LineInfo"); + bool HadError = false; + // Define a locally scoped visitor to print the different + // substream types types. + class RecordVisitor : public codeview::IModuleSubstreamVisitor { + public: + RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {} + Error visitUnknown(ModuleSubstreamKind Kind, + StreamRef Stream) override { + DictScope DD(P, "Unknown"); + ArrayRef Data; + StreamReader R(Stream); + if (auto EC = R.readBytes(Data, R.bytesRemaining())) { + return make_error( + raw_error_code::corrupt_file, + "DBI stream contained corrupt line info record"); + } + P.printBinaryBlock("Data", Data); + return Error::success(); + } + Error + visitFileChecksums(StreamRef Data, + const FileChecksumArray &Checksums) override { + DictScope DD(P, "FileChecksums"); + for (const auto &C : Checksums) { + DictScope DDD(P, "Checksum"); + if (auto Result = getFileNameForOffset(C.FileNameOffset)) + P.printString("FileName", Result.get()); + else + return Result.takeError(); + P.flush(); + P.printEnum("Kind", uint8_t(C.Kind), getFileChecksumNames()); + P.printBinaryBlock("Checksum", C.Checksum); + } + return Error::success(); + } + + Error visitLines(StreamRef Data, const LineSubstreamHeader *Header, + const LineInfoArray &Lines) override { + DictScope DD(P, "Lines"); + for (const auto &L : Lines) { + if (auto Result = getFileNameForOffset2(L.NameIndex)) + P.printString("FileName", Result.get()); + else + return Result.takeError(); + P.flush(); + for (const auto &N : L.LineNumbers) { + DictScope DDD(P, "Line"); + LineInfo LI(N.Flags); + P.printNumber("Offset", N.Offset); + if (LI.isAlwaysStepInto()) + P.printString("StepInto", StringRef("Always")); + else if (LI.isNeverStepInto()) + P.printString("StepInto", StringRef("Never")); + else + P.printNumber("LineNumberStart", LI.getStartLine()); + P.printNumber("EndDelta", LI.getLineDelta()); + P.printBoolean("IsStatement", LI.isStatement()); + } + for (const auto &C : L.Columns) { + DictScope DDD(P, "Column"); + P.printNumber("Start", C.StartColumn); + P.printNumber("End", C.EndColumn); + } + } + return Error::success(); + } + + private: + Expected getFileNameForOffset(uint32_t Offset) { + auto ST = F.getStringTable(); + if (!ST) + return ST.takeError(); + + return ST->getStringForID(Offset); + } + Expected getFileNameForOffset2(uint32_t Offset) { + auto DS = F.getPDBDbiStream(); + if (!DS) + return DS.takeError(); + return DS->getFileNameForIndex(Offset); + } + ScopedPrinter &P; + PDBFile &F; + }; + + RecordVisitor V(P, File); + for (const auto &L : ModS.lines(&HadError)) { + if (auto EC = codeview::visitModuleSubstream(L, V)) + return EC; + } + } + } + } + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpSectionContribs() { + if (!opts::raw::DumpSectionContribs) + return Error::success(); + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + ListScope L(P, "Section Contributions"); + class Visitor : public ISectionContribVisitor { + public: + Visitor(ScopedPrinter &P, DbiStream &DS) : P(P), DS(DS) {} + void visit(const SectionContrib &SC) override { + DictScope D(P, "Contribution"); + P.printNumber("ISect", SC.ISect); + P.printNumber("Off", SC.Off); + P.printNumber("Size", SC.Size); + P.printFlags("Characteristics", SC.Characteristics, + codeview::getImageSectionCharacteristicNames(), + COFF::SectionCharacteristics(0x00F00000)); + { + DictScope DD(P, "Module"); + P.printNumber("Index", SC.Imod); + auto M = DS.modules(); + if (M.size() > SC.Imod) { + P.printString("Name", M[SC.Imod].Info.getModuleName()); + } + } + P.printNumber("Data CRC", SC.DataCrc); + P.printNumber("Reloc CRC", SC.RelocCrc); + P.flush(); + } + void visit(const SectionContrib2 &SC) override { + visit(SC.Base); + P.printNumber("ISect Coff", SC.ISectCoff); + P.flush(); + } + + private: + ScopedPrinter &P; + DbiStream &DS; + }; + Visitor V(P, *Dbi); + Dbi->visitSectionContributions(V); + return Error::success(); +} + +Error LLVMOutputStyle::dumpSectionMap() { + if (!opts::raw::DumpSectionMap) + return Error::success(); + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + ListScope L(P, "Section Map"); + for (auto &M : Dbi->getSectionMap()) { + DictScope D(P, "Entry"); + P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames()); + P.printNumber("Flags", M.Flags); + P.printNumber("Ovl", M.Ovl); + P.printNumber("Group", M.Group); + P.printNumber("Frame", M.Frame); + P.printNumber("SecName", M.SecName); + P.printNumber("ClassName", M.ClassName); + P.printNumber("Offset", M.Offset); + P.printNumber("SecByteLength", M.SecByteLength); + P.flush(); + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpPublicsStream() { + if (!opts::raw::DumpPublics) + return Error::success(); + + DictScope D(P, "Publics Stream"); + auto Publics = File.getPDBPublicsStream(); + if (!Publics) + return Publics.takeError(); + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + P.printNumber("Stream number", Dbi->getPublicSymbolStreamIndex()); + P.printNumber("SymHash", Publics->getSymHash()); + P.printNumber("AddrMap", Publics->getAddrMap()); + P.printNumber("Number of buckets", Publics->getNumBuckets()); + P.printList("Hash Buckets", Publics->getHashBuckets()); + P.printList("Address Map", Publics->getAddressMap()); + P.printList("Thunk Map", Publics->getThunkMap()); + P.printList("Section Offsets", Publics->getSectionOffsets(), + printSectionOffset); + ListScope L(P, "Symbols"); + codeview::CVSymbolDumper SD(P, TD, nullptr, false); + bool HadError = false; + for (auto S : Publics->getSymbols(&HadError)) { + DictScope DD(P, ""); + + SD.dump(S); + if (opts::raw::DumpSymRecordBytes) + P.printBinaryBlock("Bytes", S.Data); + } + if (HadError) + return make_error( + raw_error_code::corrupt_file, + "Public symbol stream contained corrupt record"); + + return Error::success(); +} + +Error LLVMOutputStyle::dumpSectionHeaders() { + if (!opts::raw::DumpSectionHeaders) + return Error::success(); + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + ListScope D(P, "Section Headers"); + for (const object::coff_section &Section : Dbi->getSectionHeaders()) { + DictScope DD(P, ""); + + // If a name is 8 characters long, there is no NUL character at end. + StringRef Name(Section.Name, strnlen(Section.Name, sizeof(Section.Name))); + P.printString("Name", Name); + P.printNumber("Virtual Size", Section.VirtualSize); + P.printNumber("Virtual Address", Section.VirtualAddress); + P.printNumber("Size of Raw Data", Section.SizeOfRawData); + P.printNumber("File Pointer to Raw Data", Section.PointerToRawData); + P.printNumber("File Pointer to Relocations", Section.PointerToRelocations); + P.printNumber("File Pointer to Linenumbers", Section.PointerToLinenumbers); + P.printNumber("Number of Relocations", Section.NumberOfRelocations); + P.printNumber("Number of Linenumbers", Section.NumberOfLinenumbers); + P.printFlags("Characteristics", Section.Characteristics, + getImageSectionCharacteristicNames()); + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpFpoStream() { + if (!opts::raw::DumpFpo) + return Error::success(); + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + ListScope D(P, "New FPO"); + for (const object::FpoData &Fpo : Dbi->getFpoRecords()) { + DictScope DD(P, ""); + P.printNumber("Offset", Fpo.Offset); + P.printNumber("Size", Fpo.Size); + P.printNumber("Number of locals", Fpo.NumLocals); + P.printNumber("Number of params", Fpo.NumParams); + P.printNumber("Size of Prolog", Fpo.getPrologSize()); + P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs()); + P.printBoolean("Has SEH", Fpo.hasSEH()); + P.printBoolean("Use BP", Fpo.useBP()); + P.printNumber("Frame Pointer", Fpo.getFP()); + } + return Error::success(); +} + +void LLVMOutputStyle::flush() { P.flush(); } diff --git a/tools/llvm-pdbdump/LLVMOutputStyle.h b/tools/llvm-pdbdump/LLVMOutputStyle.h new file mode 100644 index 0000000000000000000000000000000000000000..77935d102205e18ab703aabece4f3b93b38dec60 --- /dev/null +++ b/tools/llvm-pdbdump/LLVMOutputStyle.h @@ -0,0 +1,50 @@ +//===- LLVMOutputStyle.h -------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H + +#include "OutputStyle.h" + +#include "llvm/DebugInfo/CodeView/TypeDumper.h" +#include "llvm/Support/ScopedPrinter.h" + +namespace llvm { +namespace pdb { +class LLVMOutputStyle : public OutputStyle { +public: + LLVMOutputStyle(PDBFile &File); + + Error dump() override; + +private: + Error dumpFileHeaders(); + Error dumpStreamSummary(); + Error dumpStreamBlocks(); + Error dumpStreamData(); + Error dumpInfoStream(); + Error dumpNamedStream(); + Error dumpTpiStream(uint32_t StreamIdx); + Error dumpDbiStream(); + Error dumpSectionContribs(); + Error dumpSectionMap(); + Error dumpPublicsStream(); + Error dumpSectionHeaders(); + Error dumpFpoStream(); + + void flush(); + + PDBFile &File; + ScopedPrinter P; + codeview::CVTypeDumper TD; +}; +} +} + +#endif diff --git a/tools/llvm-pdbdump/LinePrinter.cpp b/tools/llvm-pdbdump/LinePrinter.cpp index a43727f02b5e5aa98579c7f1c3a886b035c4eb5c..47c7d3e3c0e74ff24ebb7eb25ee9a554bf63a032 100644 --- a/tools/llvm-pdbdump/LinePrinter.cpp +++ b/tools/llvm-pdbdump/LinePrinter.cpp @@ -16,6 +16,9 @@ #include +using namespace llvm; +using namespace llvm::pdb; + namespace { bool IsItemExcluded(llvm::StringRef Item, std::list &IncludeFilters, @@ -41,19 +44,19 @@ using namespace llvm; LinePrinter::LinePrinter(int Indent, llvm::raw_ostream &Stream) : OS(Stream), IndentSpaces(Indent), CurrentIndent(0) { - SetFilters(ExcludeTypeFilters, opts::ExcludeTypes.begin(), - opts::ExcludeTypes.end()); - SetFilters(ExcludeSymbolFilters, opts::ExcludeSymbols.begin(), - opts::ExcludeSymbols.end()); - SetFilters(ExcludeCompilandFilters, opts::ExcludeCompilands.begin(), - opts::ExcludeCompilands.end()); - - SetFilters(IncludeTypeFilters, opts::IncludeTypes.begin(), - opts::IncludeTypes.end()); - SetFilters(IncludeSymbolFilters, opts::IncludeSymbols.begin(), - opts::IncludeSymbols.end()); - SetFilters(IncludeCompilandFilters, opts::IncludeCompilands.begin(), - opts::IncludeCompilands.end()); + SetFilters(ExcludeTypeFilters, opts::pretty::ExcludeTypes.begin(), + opts::pretty::ExcludeTypes.end()); + SetFilters(ExcludeSymbolFilters, opts::pretty::ExcludeSymbols.begin(), + opts::pretty::ExcludeSymbols.end()); + SetFilters(ExcludeCompilandFilters, opts::pretty::ExcludeCompilands.begin(), + opts::pretty::ExcludeCompilands.end()); + + SetFilters(IncludeTypeFilters, opts::pretty::IncludeTypes.begin(), + opts::pretty::IncludeTypes.end()); + SetFilters(IncludeSymbolFilters, opts::pretty::IncludeSymbols.begin(), + opts::pretty::IncludeSymbols.end()); + SetFilters(IncludeCompilandFilters, opts::pretty::IncludeCompilands.begin(), + opts::pretty::IncludeCompilands.end()); } void LinePrinter::Indent() { CurrentIndent += IndentSpaces; } diff --git a/tools/llvm-pdbdump/LinePrinter.h b/tools/llvm-pdbdump/LinePrinter.h index b0a9d2cfc4e82ad97c455292d3167e2f564573b3..a4401f8af9552c9947335b9a5166b383c2316067 100644 --- a/tools/llvm-pdbdump/LinePrinter.h +++ b/tools/llvm-pdbdump/LinePrinter.h @@ -18,6 +18,7 @@ #include namespace llvm { +namespace pdb { class LinePrinter { friend class WithColor; @@ -88,5 +89,6 @@ private: raw_ostream &OS; }; } +} #endif diff --git a/tools/llvm-pdbdump/OutputStyle.h b/tools/llvm-pdbdump/OutputStyle.h new file mode 100644 index 0000000000000000000000000000000000000000..dfefc25a215e88f08d1302fd84559c3aa57eec32 --- /dev/null +++ b/tools/llvm-pdbdump/OutputStyle.h @@ -0,0 +1,28 @@ +//===- OutputStyle.h ------------------------------------------ *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_OUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_OUTPUTSTYLE_H + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class OutputStyle { +public: + virtual ~OutputStyle() {} + + virtual Error dump() = 0; +}; +} +} + +#endif diff --git a/tools/llvm-pdbdump/PdbYaml.cpp b/tools/llvm-pdbdump/PdbYaml.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a341ab073081693f8914f72a51430280b11d143b --- /dev/null +++ b/tools/llvm-pdbdump/PdbYaml.cpp @@ -0,0 +1,157 @@ +//===- PdbYAML.cpp -------------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PdbYaml.h" + +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" + +using namespace llvm; +using namespace llvm::yaml; +using namespace llvm::pdb; +using namespace llvm::pdb::yaml; + +namespace llvm { +namespace yaml { +template <> struct ScalarTraits { + static void output(const llvm::pdb::PDB_UniqueId &S, void *, + llvm::raw_ostream &OS) { + OS << S; + } + + static StringRef input(StringRef Scalar, void *Ctx, + llvm::pdb::PDB_UniqueId &S) { + if (Scalar.size() != 38) + return "GUID strings are 38 characters long"; + if (Scalar[0] != '{' || Scalar[37] != '}') + return "GUID is not enclosed in {}"; + if (Scalar[9] != '-' || Scalar[14] != '-' || Scalar[19] != '-' || + Scalar[24] != '-') + return "GUID sections are not properly delineated with dashes"; + + char *OutBuffer = S.Guid; + for (auto Iter = Scalar.begin(); Iter != Scalar.end();) { + if (*Iter == '-' || *Iter == '{' || *Iter == '}') { + ++Iter; + continue; + } + uint8_t Value = (llvm::hexDigitValue(*Iter) << 4); + ++Iter; + Value |= llvm::hexDigitValue(*Iter); + ++Iter; + *OutBuffer++ = Value; + } + + return ""; + } + + static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); } +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, llvm::pdb::PDB_Machine &Value) { + io.enumCase(Value, "Invalid", PDB_Machine::Invalid); + io.enumCase(Value, "Am33", PDB_Machine::Am33); + io.enumCase(Value, "Amd64", PDB_Machine::Amd64); + io.enumCase(Value, "Arm", PDB_Machine::Arm); + io.enumCase(Value, "ArmNT", PDB_Machine::ArmNT); + io.enumCase(Value, "Ebc", PDB_Machine::Ebc); + io.enumCase(Value, "x86", PDB_Machine::x86); + io.enumCase(Value, "Ia64", PDB_Machine::Ia64); + io.enumCase(Value, "M32R", PDB_Machine::M32R); + io.enumCase(Value, "Mips16", PDB_Machine::Mips16); + io.enumCase(Value, "MipsFpu", PDB_Machine::MipsFpu); + io.enumCase(Value, "MipsFpu16", PDB_Machine::MipsFpu16); + io.enumCase(Value, "PowerPCFP", PDB_Machine::PowerPCFP); + io.enumCase(Value, "R4000", PDB_Machine::R4000); + io.enumCase(Value, "SH3", PDB_Machine::SH3); + io.enumCase(Value, "SH3DSP", PDB_Machine::SH3DSP); + io.enumCase(Value, "Thumb", PDB_Machine::Thumb); + io.enumCase(Value, "WceMipsV2", PDB_Machine::WceMipsV2); + } +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, llvm::pdb::PdbRaw_DbiVer &Value) { + io.enumCase(Value, "V41", llvm::pdb::PdbRaw_DbiVer::PdbDbiVC41); + io.enumCase(Value, "V50", llvm::pdb::PdbRaw_DbiVer::PdbDbiV50); + io.enumCase(Value, "V60", llvm::pdb::PdbRaw_DbiVer::PdbDbiV60); + io.enumCase(Value, "V70", llvm::pdb::PdbRaw_DbiVer::PdbDbiV70); + io.enumCase(Value, "V110", llvm::pdb::PdbRaw_DbiVer::PdbDbiV110); + } +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, llvm::pdb::PdbRaw_ImplVer &Value) { + io.enumCase(Value, "VC2", llvm::pdb::PdbRaw_ImplVer::PdbImplVC2); + io.enumCase(Value, "VC4", llvm::pdb::PdbRaw_ImplVer::PdbImplVC4); + io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_ImplVer::PdbImplVC41); + io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_ImplVer::PdbImplVC50); + io.enumCase(Value, "VC98", llvm::pdb::PdbRaw_ImplVer::PdbImplVC98); + io.enumCase(Value, "VC70Dep", llvm::pdb::PdbRaw_ImplVer::PdbImplVC70Dep); + io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_ImplVer::PdbImplVC70); + io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_ImplVer::PdbImplVC80); + io.enumCase(Value, "VC110", llvm::pdb::PdbRaw_ImplVer::PdbImplVC110); + io.enumCase(Value, "VC140", llvm::pdb::PdbRaw_ImplVer::PdbImplVC140); + } +}; +} +} + +void MappingTraits::mapping(IO &IO, PdbObject &Obj) { + IO.mapOptional("MSF", Obj.Headers); + IO.mapOptional("StreamSizes", Obj.StreamSizes); + IO.mapOptional("StreamMap", Obj.StreamMap); + IO.mapOptional("PdbStream", Obj.PdbStream); + IO.mapOptional("DbiStream", Obj.DbiStream); +} + +void MappingTraits::mapping(IO &IO, MsfHeaders &Obj) { + IO.mapRequired("SuperBlock", Obj.SuperBlock); + IO.mapRequired("NumDirectoryBlocks", Obj.NumDirectoryBlocks); + IO.mapRequired("BlockMapOffset", Obj.BlockMapOffset); + IO.mapRequired("DirectoryBlocks", Obj.DirectoryBlocks); + IO.mapRequired("NumStreams", Obj.NumStreams); + IO.mapRequired("FileSize", Obj.FileSize); +} + +void MappingTraits::mapping(IO &IO, + PDBFile::SuperBlock &SB) { + if (!IO.outputting()) { + ::memcpy(SB.MagicBytes, MsfMagic, sizeof(MsfMagic)); + } + + IO.mapRequired("BlockSize", SB.BlockSize); + IO.mapRequired("Unknown0", SB.Unknown0); + IO.mapRequired("NumBlocks", SB.NumBlocks); + IO.mapRequired("NumDirectoryBytes", SB.NumDirectoryBytes); + IO.mapRequired("Unknown1", SB.Unknown1); + IO.mapRequired("BlockMapAddr", SB.BlockMapAddr); +} + +void MappingTraits::mapping(IO &IO, StreamBlockList &SB) { + IO.mapRequired("Stream", SB.Blocks); +} + +void MappingTraits::mapping(IO &IO, PdbInfoStream &Obj) { + IO.mapRequired("Age", Obj.Age); + IO.mapRequired("Guid", Obj.Guid); + IO.mapRequired("Signature", Obj.Signature); + IO.mapRequired("Version", Obj.Version); +} + +void MappingTraits::mapping(IO &IO, PdbDbiStream &Obj) { + IO.mapRequired("VerHeader", Obj.VerHeader); + IO.mapRequired("Age", Obj.Age); + IO.mapRequired("BuildNumber", Obj.BuildNumber); + IO.mapRequired("PdbDllVersion", Obj.PdbDllVersion); + IO.mapRequired("PdbDllRbld", Obj.PdbDllRbld); + IO.mapRequired("Flags", Obj.Flags); + IO.mapRequired("MachineType", Obj.MachineType); +} diff --git a/tools/llvm-pdbdump/PdbYaml.h b/tools/llvm-pdbdump/PdbYaml.h new file mode 100644 index 0000000000000000000000000000000000000000..91c0a585926bd09a0716f2f362900c63a7feefd6 --- /dev/null +++ b/tools/llvm-pdbdump/PdbYaml.h @@ -0,0 +1,101 @@ +//===- PdbYAML.h ---------------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H +#define LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H + +#include "OutputStyle.h" + +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/YAMLTraits.h" + +#include + +namespace llvm { +namespace pdb { + +namespace yaml { +struct MsfHeaders { + PDBFile::SuperBlock SuperBlock; + uint32_t NumDirectoryBlocks; + uint32_t BlockMapOffset; + std::vector DirectoryBlocks; + uint32_t NumStreams; + uint32_t FileSize; +}; + +struct StreamBlockList { + std::vector Blocks; +}; + +struct PdbInfoStream { + PdbRaw_ImplVer Version; + uint32_t Signature; + uint32_t Age; + PDB_UniqueId Guid; +}; + +struct PdbDbiStream { + PdbRaw_DbiVer VerHeader; + uint32_t Age; + uint16_t BuildNumber; + uint32_t PdbDllVersion; + uint16_t PdbDllRbld; + uint16_t Flags; + PDB_Machine MachineType; +}; + +struct PdbObject { + Optional Headers; + Optional> StreamSizes; + Optional> StreamMap; + Optional PdbStream; + Optional DbiStream; +}; +} +} +} + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits { + static void mapping(IO &IO, pdb::yaml::PdbObject &Obj); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, pdb::yaml::MsfHeaders &Obj); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, pdb::PDBFile::SuperBlock &SB); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, pdb::yaml::StreamBlockList &SB); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, pdb::yaml::PdbInfoStream &Obj); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, pdb::yaml::PdbDbiStream &Obj); +}; +} +} + +LLVM_YAML_IS_SEQUENCE_VECTOR(support::ulittle32_t) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) + +#endif // LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H diff --git a/tools/llvm-pdbdump/TypeDumper.cpp b/tools/llvm-pdbdump/TypeDumper.cpp index 88c0bd65697ede96444d642076599aa037ee1550..a49d6404555392585015faf3dc3588bb93eecb20 100644 --- a/tools/llvm-pdbdump/TypeDumper.cpp +++ b/tools/llvm-pdbdump/TypeDumper.cpp @@ -24,6 +24,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" using namespace llvm; +using namespace llvm::pdb; TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} @@ -62,7 +63,7 @@ void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) { if (Printer.IsTypeExcluded(Symbol.getName())) return; // Dump member enums when dumping their class definition. - if (Symbol.isNested()) + if (nullptr != Symbol.getClassParent()) return; Printer.NewLine(); @@ -87,7 +88,7 @@ void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) { Printer.NewLine(); - if (opts::NoClassDefs) { + if (opts::pretty::NoClassDefs) { WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); } else { diff --git a/tools/llvm-pdbdump/TypeDumper.h b/tools/llvm-pdbdump/TypeDumper.h index 5c0832eccaf98c393dc49fd795a367bdd3164327..76a477964f1f78031ced86c7d7fa5ff175e9ab5b 100644 --- a/tools/llvm-pdbdump/TypeDumper.h +++ b/tools/llvm-pdbdump/TypeDumper.h @@ -13,7 +13,7 @@ #include "llvm/DebugInfo/PDB/PDBSymDumper.h" namespace llvm { - +namespace pdb { class LinePrinter; class TypeDumper : public PDBSymDumper { @@ -30,5 +30,5 @@ private: LinePrinter &Printer; }; } - +} #endif diff --git a/tools/llvm-pdbdump/TypedefDumper.cpp b/tools/llvm-pdbdump/TypedefDumper.cpp index a6b5c53a6b3a939bef11f313ec1bbfa12f812747..b1e017613ce12834387369ef444ff8412a1c52e3 100644 --- a/tools/llvm-pdbdump/TypedefDumper.cpp +++ b/tools/llvm-pdbdump/TypedefDumper.cpp @@ -23,6 +23,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" using namespace llvm; +using namespace llvm::pdb; TypedefDumper::TypedefDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} diff --git a/tools/llvm-pdbdump/TypedefDumper.h b/tools/llvm-pdbdump/TypedefDumper.h index 8cd578cc6d296de62dc86670779858bcc4c2c75e..c22b58a7e41e4dea29f4fbb778ee02314f0a028b 100644 --- a/tools/llvm-pdbdump/TypedefDumper.h +++ b/tools/llvm-pdbdump/TypedefDumper.h @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/PDB/PDBSymDumper.h" namespace llvm { +namespace pdb { class LinePrinter; @@ -33,5 +34,6 @@ private: LinePrinter &Printer; }; } +} #endif diff --git a/tools/llvm-pdbdump/VariableDumper.cpp b/tools/llvm-pdbdump/VariableDumper.cpp index e5665b5fcafa4a42f1c8ad9087a027724dd1248e..284d7e9b731f93d966da6a85f41789ad083746ed 100644 --- a/tools/llvm-pdbdump/VariableDumper.cpp +++ b/tools/llvm-pdbdump/VariableDumper.cpp @@ -27,12 +27,13 @@ #include "llvm/Support/Format.h" using namespace llvm; +using namespace llvm::pdb; VariableDumper::VariableDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} void VariableDumper::start(const PDBSymbolData &Var) { - if (Var.isCompilerGenerated() && opts::ExcludeCompilerGenerated) + if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) return; if (Printer.IsSymbolExcluded(Var.getName())) return; diff --git a/tools/llvm-pdbdump/VariableDumper.h b/tools/llvm-pdbdump/VariableDumper.h index db8d8ea0e43054fee1e9029c30a8b11cd989a414..4f00358878c94678e39e04fccac7c4a39d0e40f7 100644 --- a/tools/llvm-pdbdump/VariableDumper.h +++ b/tools/llvm-pdbdump/VariableDumper.h @@ -11,10 +11,13 @@ #define LLVM_TOOLS_LLVMPDBDUMP_VARIABLEDUMPER_H #include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/ADT/StringRef.h" namespace llvm { +class StringRef; + +namespace pdb { + class LinePrinter; class VariableDumper : public PDBSymDumper { @@ -37,5 +40,5 @@ private: LinePrinter &Printer; }; } - +} #endif diff --git a/tools/llvm-pdbdump/YAMLOutputStyle.cpp b/tools/llvm-pdbdump/YAMLOutputStyle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa68128cd80aa18604d5a1578e5d3ee9abd03523 --- /dev/null +++ b/tools/llvm-pdbdump/YAMLOutputStyle.cpp @@ -0,0 +1,136 @@ +//===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "YAMLOutputStyle.h" + +#include "PdbYaml.h" +#include "llvm-pdbdump.h" + +#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" +#include "llvm/DebugInfo/PDB/Raw/InfoStream.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" + +using namespace llvm; +using namespace llvm::pdb; + +YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) : File(File), Out(outs()) {} + +Error YAMLOutputStyle::dump() { + if (opts::pdb2yaml::StreamDirectory || opts::pdb2yaml::PdbStream || + opts::pdb2yaml::DbiStream) + opts::pdb2yaml::StreamMetadata = true; + + if (auto EC = dumpFileHeaders()) + return EC; + + if (auto EC = dumpStreamMetadata()) + return EC; + + if (auto EC = dumpStreamDirectory()) + return EC; + + if (auto EC = dumpPDBStream()) + return EC; + + if (auto EC = dumpDbiStream()) + return EC; + + flush(); + return Error::success(); +} + +Error YAMLOutputStyle::dumpFileHeaders() { + if (opts::pdb2yaml::NoFileHeaders) + return Error::success(); + + yaml::MsfHeaders Headers; + Obj.Headers.emplace(); + Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount(); + Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex(); + Obj.Headers->BlockMapOffset = File.getBlockMapOffset(); + Obj.Headers->SuperBlock.BlockSize = File.getBlockSize(); + auto Blocks = File.getDirectoryBlockArray(); + Obj.Headers->DirectoryBlocks.assign(Blocks.begin(), Blocks.end()); + Obj.Headers->NumDirectoryBlocks = File.getNumDirectoryBlocks(); + Obj.Headers->SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes(); + Obj.Headers->NumStreams = + opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0; + Obj.Headers->SuperBlock.Unknown0 = File.getUnknown0(); + Obj.Headers->SuperBlock.Unknown1 = File.getUnknown1(); + Obj.Headers->FileSize = File.getFileSize(); + + return Error::success(); +} + +Error YAMLOutputStyle::dumpStreamMetadata() { + if (!opts::pdb2yaml::StreamMetadata) + return Error::success(); + + Obj.StreamSizes = File.getStreamSizes(); + return Error::success(); +} + +Error YAMLOutputStyle::dumpStreamDirectory() { + if (!opts::pdb2yaml::StreamDirectory) + return Error::success(); + + auto StreamMap = File.getStreamMap(); + Obj.StreamMap.emplace(); + for (auto &Stream : StreamMap) { + pdb::yaml::StreamBlockList BlockList; + BlockList.Blocks = Stream; + Obj.StreamMap->push_back(BlockList); + } + + return Error::success(); +} + +Error YAMLOutputStyle::dumpPDBStream() { + if (!opts::pdb2yaml::PdbStream) + return Error::success(); + + auto IS = File.getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + auto &InfoS = IS.get(); + Obj.PdbStream.emplace(); + Obj.PdbStream->Age = InfoS.getAge(); + Obj.PdbStream->Guid = InfoS.getGuid(); + Obj.PdbStream->Signature = InfoS.getSignature(); + Obj.PdbStream->Version = InfoS.getVersion(); + + return Error::success(); +} + +Error YAMLOutputStyle::dumpDbiStream() { + if (!opts::pdb2yaml::DbiStream) + return Error::success(); + + auto DbiS = File.getPDBDbiStream(); + if (!DbiS) + return DbiS.takeError(); + + auto &DS = DbiS.get(); + Obj.DbiStream.emplace(); + Obj.DbiStream->Age = DS.getAge(); + Obj.DbiStream->BuildNumber = DS.getBuildNumber(); + Obj.DbiStream->Flags = DS.getFlags(); + Obj.DbiStream->MachineType = DS.getMachineType(); + Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld(); + Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion(); + Obj.DbiStream->VerHeader = DS.getDbiVersion(); + return Error::success(); +} + +void YAMLOutputStyle::flush() { + Out << Obj; + outs().flush(); +} diff --git a/tools/llvm-pdbdump/YAMLOutputStyle.h b/tools/llvm-pdbdump/YAMLOutputStyle.h new file mode 100644 index 0000000000000000000000000000000000000000..d36dfec5f25ad0243af0afebc1a052cd9e548d4d --- /dev/null +++ b/tools/llvm-pdbdump/YAMLOutputStyle.h @@ -0,0 +1,45 @@ +//===- YAMLOutputStyle.h -------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H + +#include "OutputStyle.h" +#include "PdbYaml.h" + +#include "llvm/DebugInfo/CodeView/TypeDumper.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/YAMLTraits.h" + +namespace llvm { +namespace pdb { +class YAMLOutputStyle : public OutputStyle { +public: + YAMLOutputStyle(PDBFile &File); + + Error dump() override; + +private: + Error dumpFileHeaders(); + Error dumpStreamMetadata(); + Error dumpStreamDirectory(); + Error dumpPDBStream(); + Error dumpDbiStream(); + + void flush(); + + PDBFile &File; + llvm::yaml::Output Out; + + yaml::PdbObject Obj; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H diff --git a/tools/llvm-pdbdump/fuzzer/CMakeLists.txt b/tools/llvm-pdbdump/fuzzer/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cf5a0f70aab38a3cb40a6693d870793c0d8c3105 --- /dev/null +++ b/tools/llvm-pdbdump/fuzzer/CMakeLists.txt @@ -0,0 +1,15 @@ +set(LLVM_LINK_COMPONENTS + DebugInfoCodeView + DebugInfoPDB + Object + Support + ) + +add_llvm_executable(llvm-pdbdump-fuzzer + EXCLUDE_FROM_ALL + llvm-pdbdump-fuzzer.cpp + ) + +target_link_libraries(llvm-pdbdump-fuzzer + LLVMFuzzer + ) diff --git a/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp b/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e818dda32fc027320f7d5e0a3f6d0bc74407f290 --- /dev/null +++ b/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp @@ -0,0 +1,104 @@ +//===-- llvm-pdbdump-fuzzer.cpp - Fuzz the llvm-pdbdump tool --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements a function that runs llvm-pdbdump +/// on a single input. This function is then linked into the Fuzzer library. +/// +//===----------------------------------------------------------------------===// +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/ByteStream.h" +#include "llvm/DebugInfo/CodeView/SymbolDumper.h" +#include "llvm/DebugInfo/CodeView/TypeDumper.h" +#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/ModStream.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawSession.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; + +namespace { +// We need a class which behaves like an immutable ByteStream, but whose data +// is backed by an llvm::MemoryBuffer. It also needs to own the underlying +// MemoryBuffer, so this simple adapter is a good way to achieve that. +class InputByteStream : public codeview::ByteStream { +public: + explicit InputByteStream(std::unique_ptr Buffer) + : ByteStream(ArrayRef(Buffer->getBuffer().bytes_begin(), + Buffer->getBuffer().bytes_end())), + MemBuffer(std::move(Buffer)) {} + + std::unique_ptr MemBuffer; +}; +} + +extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { + std::unique_ptr Buff = MemoryBuffer::getMemBuffer( + StringRef((const char *)data, size), "", false); + + ScopedPrinter P(nulls()); + codeview::CVTypeDumper TD(&P, false); + + auto InputStream = llvm::make_unique(std::move(Buff)); + std::unique_ptr File(new pdb::PDBFile(std::move(InputStream))); + if (auto E = File->parseFileHeaders()) { + consumeError(std::move(E)); + return 0; + } + if (auto E = File->parseStreamData()) { + consumeError(std::move(E)); + return 0; + } + + auto DbiS = File->getPDBDbiStream(); + if (auto E = DbiS.takeError()) { + consumeError(std::move(E)); + return 0; + } + auto TpiS = File->getPDBTpiStream(); + if (auto E = TpiS.takeError()) { + consumeError(std::move(E)); + return 0; + } + auto IpiS = File->getPDBIpiStream(); + if (auto E = IpiS.takeError()) { + consumeError(std::move(E)); + return 0; + } + auto InfoS = File->getPDBInfoStream(); + if (auto E = InfoS.takeError()) { + consumeError(std::move(E)); + return 0; + } + pdb::DbiStream &DS = DbiS.get(); + + for (auto &Modi : DS.modules()) { + auto ModStreamData = pdb::MappedBlockStream::createIndexedStream( + Modi.Info.getModuleStreamIndex(), *File); + if (!ModStreamData) { + consumeError(ModStreamData.takeError()); + return 0; + } + pdb::ModStream ModS(Modi.Info, std::move(*ModStreamData)); + if (auto E = ModS.reload()) { + consumeError(std::move(E)); + return 0; + } + codeview::CVSymbolDumper SD(P, TD, nullptr, false); + bool HadError = false; + for (auto &S : ModS.symbols(&HadError)) { + SD.dump(S); + } + } + return 0; +} diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp index 940ef1b6399b3203038cd7b81af25037075b8464..5a3ced37a9d0b74522d624554bdaa4aa8b972e8f 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -17,15 +17,20 @@ #include "CompilandDumper.h" #include "ExternalSymbolDumper.h" #include "FunctionDumper.h" +#include "LLVMOutputStyle.h" #include "LinePrinter.h" +#include "OutputStyle.h" #include "TypeDumper.h" #include "VariableDumper.h" +#include "YAMLOutputStyle.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" +#include "llvm/DebugInfo/CodeView/ByteStream.h" +#include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" @@ -35,613 +40,362 @@ #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" +#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" +#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Raw/InfoStream.h" +#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/PDB/Raw/RawSession.h" +#include "llvm/Support/COM.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/FileOutputBuffer.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/Process.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/Signals.h" - -#if defined(HAVE_DIA_SDK) -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -#endif +#include "llvm/Support/raw_ostream.h" using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +namespace { +// A simple adapter that acts like a ByteStream but holds ownership over +// and underlying FileOutputBuffer. +class FileBufferByteStream : public ByteStream { +public: + FileBufferByteStream(std::unique_ptr Buffer) + : ByteStream(MutableArrayRef(Buffer->getBufferStart(), + Buffer->getBufferEnd())), + FileBuffer(std::move(Buffer)) {} + + Error commit() const override { + if (FileBuffer->commit()) + return llvm::make_error(raw_error_code::not_writable); + return Error::success(); + } -namespace opts { +private: + std::unique_ptr FileBuffer; +}; +} -enum class PDB_DumpType { ByType, ByObjFile, Both }; +namespace opts { -cl::list InputFilenames(cl::Positional, - cl::desc(""), - cl::OneOrMore); +cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file"); +cl::SubCommand + PrettySubcommand("pretty", + "Dump semantic information about types and symbols"); +cl::SubCommand + YamlToPdbSubcommand("yaml2pdb", + "Generate a PDB file from a YAML description"); +cl::SubCommand + PdbToYamlSubcommand("pdb2yaml", + "Generate a detailed YAML description of a PDB File"); cl::OptionCategory TypeCategory("Symbol Type Options"); cl::OptionCategory FilterCategory("Filtering Options"); cl::OptionCategory OtherOptions("Other Options"); +namespace pretty { +cl::list InputFilenames(cl::Positional, + cl::desc(""), + cl::OneOrMore, cl::sub(PrettySubcommand)); + cl::opt Compilands("compilands", cl::desc("Display compilands"), - cl::cat(TypeCategory)); + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt Symbols("symbols", cl::desc("Display symbols for each compiland"), - cl::cat(TypeCategory)); + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt Globals("globals", cl::desc("Dump global symbols"), - cl::cat(TypeCategory)); + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt Externals("externals", cl::desc("Dump external symbols"), - cl::cat(TypeCategory)); -cl::opt Types("types", cl::desc("Display types"), cl::cat(TypeCategory)); -cl::opt Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory)); + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt Types("types", cl::desc("Display types"), cl::cat(TypeCategory), + cl::sub(PrettySubcommand)); +cl::opt Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory), + cl::sub(PrettySubcommand)); cl::opt All("all", cl::desc("Implies all other options in 'Symbol Types' category"), - cl::cat(TypeCategory)); + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt LoadAddress( "load-address", cl::desc("Assume the module is loaded at the specified address"), - cl::cat(OtherOptions)); - -cl::opt DumpHeaders("dump-headers", cl::desc("dump PDB headers"), - cl::cat(OtherOptions)); -cl::opt DumpStreamSizes("dump-stream-sizes", - cl::desc("dump PDB stream sizes"), - cl::cat(OtherOptions)); -cl::opt DumpStreamBlocks("dump-stream-blocks", - cl::desc("dump PDB stream blocks"), - cl::cat(OtherOptions)); -cl::opt DumpStreamData("dump-stream", cl::desc("dump stream data"), - cl::cat(OtherOptions)); - -cl::list - ExcludeTypes("exclude-types", - cl::desc("Exclude types by regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory)); -cl::list - ExcludeSymbols("exclude-symbols", - cl::desc("Exclude symbols by regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory)); -cl::list - ExcludeCompilands("exclude-compilands", - cl::desc("Exclude compilands by regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory)); + cl::cat(OtherOptions), cl::sub(PrettySubcommand)); +cl::list ExcludeTypes( + "exclude-types", cl::desc("Exclude types by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::list ExcludeSymbols( + "exclude-symbols", cl::desc("Exclude symbols by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::list ExcludeCompilands( + "exclude-compilands", cl::desc("Exclude compilands by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); cl::list IncludeTypes( "include-types", cl::desc("Include only types which match a regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory)); + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); cl::list IncludeSymbols( "include-symbols", cl::desc("Include only symbols which match a regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory)); + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); cl::list IncludeCompilands( "include-compilands", cl::desc("Include only compilands those which match a regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory)); + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); cl::opt ExcludeCompilerGenerated( "no-compiler-generated", cl::desc("Don't show compiler generated types and symbols"), - cl::cat(FilterCategory)); + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); cl::opt ExcludeSystemLibraries("no-system-libs", cl::desc("Don't show symbols from system libraries"), - cl::cat(FilterCategory)); + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); cl::opt NoClassDefs("no-class-definitions", cl::desc("Don't display full class definitions"), - cl::cat(FilterCategory)); + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); cl::opt NoEnumDefs("no-enum-definitions", cl::desc("Don't display full enum definitions"), - cl::cat(FilterCategory)); + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); } +namespace raw { -static void reportError(StringRef Input, StringRef Message) { - if (Input == "-") - Input = ""; - errs() << Input << ": " << Message << "\n"; - errs().flush(); - exit(1); -} +cl::OptionCategory MsfOptions("MSF Container Options"); +cl::OptionCategory TypeOptions("Type Record Options"); +cl::OptionCategory FileOptions("Module & File Options"); +cl::OptionCategory SymbolOptions("Symbol Options"); +cl::OptionCategory MiscOptions("Miscellaneous Options"); -static void reportError(StringRef Input, std::error_code EC) { - reportError(Input, EC.message()); -} +// MSF OPTIONS +cl::opt DumpHeaders("headers", cl::desc("dump PDB headers"), + cl::cat(MsfOptions), cl::sub(RawSubcommand)); +cl::opt DumpStreamBlocks("stream-blocks", + cl::desc("dump PDB stream blocks"), + cl::cat(MsfOptions), cl::sub(RawSubcommand)); +cl::opt DumpStreamSummary("stream-summary", + cl::desc("dump summary of the PDB streams"), + cl::cat(MsfOptions), cl::sub(RawSubcommand)); -static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, - const uint64_t Size) { - if (Addr + Size < Addr || Addr + Size < Size || - Addr + Size > uintptr_t(M.getBufferEnd()) || - Addr < uintptr_t(M.getBufferStart())) { - return std::make_error_code(std::errc::bad_address); - } - return std::error_code(); -} +// TYPE OPTIONS +cl::opt + DumpTpiRecords("tpi-records", + cl::desc("dump CodeView type records from TPI stream"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); +cl::opt DumpTpiRecordBytes( + "tpi-record-bytes", + cl::desc("dump CodeView type record raw bytes from TPI stream"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); +cl::opt DumpTpiHash("tpi-hash", cl::desc("dump CodeView TPI hash stream"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); +cl::opt + DumpIpiRecords("ipi-records", + cl::desc("dump CodeView type records from IPI stream"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); +cl::opt DumpIpiRecordBytes( + "ipi-record-bytes", + cl::desc("dump CodeView type record raw bytes from IPI stream"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); + +// MODULE & FILE OPTIONS +cl::opt DumpModules("modules", cl::desc("dump compiland information"), + cl::cat(FileOptions), cl::sub(RawSubcommand)); +cl::opt DumpModuleFiles("module-files", cl::desc("dump file information"), + cl::cat(FileOptions), cl::sub(RawSubcommand)); +cl::opt DumpLineInfo("line-info", + cl::desc("dump file and line information"), + cl::cat(FileOptions), cl::sub(RawSubcommand)); + +// SYMBOL OPTIONS +cl::opt DumpModuleSyms("module-syms", cl::desc("dump module symbols"), + cl::cat(SymbolOptions), cl::sub(RawSubcommand)); +cl::opt DumpPublics("publics", cl::desc("dump Publics stream data"), + cl::cat(SymbolOptions), cl::sub(RawSubcommand)); +cl::opt + DumpSymRecordBytes("sym-record-bytes", + cl::desc("dump CodeView symbol record raw bytes"), + cl::cat(SymbolOptions), cl::sub(RawSubcommand)); + +// MISCELLANEOUS OPTIONS +cl::opt DumpSectionContribs("section-contribs", + cl::desc("dump section contributions"), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); +cl::opt DumpSectionMap("section-map", cl::desc("dump section map"), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); +cl::opt DumpSectionHeaders("section-headers", + cl::desc("dump section headers"), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); +cl::opt DumpFpo("fpo", cl::desc("dump FPO records"), cl::cat(MiscOptions), + cl::sub(RawSubcommand)); + +cl::opt DumpStreamDataIdx("stream", cl::desc("dump stream data"), + cl::cat(MiscOptions), + cl::sub(RawSubcommand)); +cl::opt DumpStreamDataName("stream-name", + cl::desc("dump stream data"), + cl::cat(MiscOptions), + cl::sub(RawSubcommand)); + +cl::opt RawAll("all", cl::desc("Implies most other options."), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); -template -static std::error_code checkOffset(MemoryBufferRef M, ArrayRef AR) { - return checkOffset(M, uintptr_t(AR.data()), (uint64_t)AR.size() * sizeof(T)); +cl::list InputFilenames(cl::Positional, + cl::desc(""), + cl::OneOrMore, cl::sub(RawSubcommand)); } -static std::error_code checkOffset(MemoryBufferRef M, StringRef SR) { - return checkOffset(M, uintptr_t(SR.data()), SR.size()); -} +namespace yaml2pdb { +cl::opt + YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), + cl::sub(YamlToPdbSubcommand)); -// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. -// Returns unexpected_eof if error. -template -static std::error_code getObject(const T *&Obj, MemoryBufferRef M, - const void *Ptr, - const uint64_t Size = sizeof(T)) { - uintptr_t Addr = uintptr_t(Ptr); - if (std::error_code EC = checkOffset(M, Addr, Size)) - return EC; - Obj = reinterpret_cast(Addr); - return std::error_code(); +cl::list InputFilename(cl::Positional, + cl::desc(""), cl::Required, + cl::sub(YamlToPdbSubcommand)); } -static uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) { - return alignTo(NumBytes, BlockSize) / BlockSize; +namespace pdb2yaml { +cl::opt + NoFileHeaders("no-file-headers", + cl::desc("Do not dump MSF file headers (you will not be able " + "to generate a fresh PDB from the resulting YAML)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt StreamMetadata( + "stream-metadata", + cl::desc("Dump the number of streams and each stream's size"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt StreamDirectory( + "stream-directory", + cl::desc("Dump each stream's block map (implies -stream-metadata)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt PdbStream( + "pdb-stream", + cl::desc("Dump the PDB Stream (Stream 1) (implies -stream-metadata)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt DbiStream( + "dbi-stream", + cl::desc("Dump the DBI Stream (Stream 2) (implies -stream-metadata)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::list InputFilename(cl::Positional, + cl::desc(""), cl::Required, + cl::sub(PdbToYamlSubcommand)); } - -static uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) { - return BlockNumber * BlockSize; } -struct PDBStructureContext { - const PDB::SuperBlock *SB; - MemoryBufferRef M; - std::vector StreamSizes; - DenseMap> StreamMap; - - SmallVector Scratch; - - // getObject tries to stitch together non-contiguous blocks into a contiguous - // value. The storage for the value comes from the memory mapped file if the - // memory would be contiguous. Otherwise, it uses 'Scratch' to buffer the - // data. - template - void getObject(const T *&Obj, uint32_t StreamIdx, uint32_t &Offset) { - // Make sure the stream index is valid. - auto StreamBlockI = StreamMap.find(StreamIdx); - if (StreamBlockI == StreamMap.end()) - reportError(M.getBufferIdentifier(), - std::make_error_code(std::errc::bad_address)); - - auto &StreamBlocks = StreamBlockI->second; - uint32_t BlockNum = Offset / SB->BlockSize; - uint32_t OffsetInBlock = Offset % SB->BlockSize; - - // Make sure we aren't trying to read beyond the end of the stream. - if (Offset + sizeof(T) > StreamSizes[StreamIdx]) - reportError(M.getBufferIdentifier(), - std::make_error_code(std::errc::bad_address)); - - // Modify the passed in offset to point to the data after the object. - Offset += sizeof(T); - - // Handle the contiguous case: the offset + size stays within a block. - if (OffsetInBlock + sizeof(T) <= SB->BlockSize) { - uint32_t StreamBlockAddr = StreamBlocks[BlockNum]; - uint64_t StreamBlockOffset = - blockToOffset(StreamBlockAddr, SB->BlockSize) + OffsetInBlock; - // Return a pointer to the memory buffer. - Obj = reinterpret_cast(M.getBufferStart() + StreamBlockOffset); - return; - } - - // The non-contiguous case: we will stitch together non-contiguous chunks - // into the scratch buffer. - Scratch.clear(); - - uint32_t BytesLeft = sizeof(T); - while (BytesLeft > 0) { - uint32_t StreamBlockAddr = StreamBlocks[BlockNum]; - uint64_t StreamBlockOffset = - blockToOffset(StreamBlockAddr, SB->BlockSize) + OffsetInBlock; - - const char *ChunkStart = - M.getBufferStart() + StreamBlockOffset; - uint32_t BytesInChunk = - std::min(BytesLeft, SB->BlockSize - OffsetInBlock); - Scratch.append(ChunkStart, ChunkStart + BytesInChunk); - - BytesLeft -= BytesInChunk; - ++BlockNum; - OffsetInBlock = 0; - } - - // Return a pointer to the scratch buffer. - Obj = reinterpret_cast(Scratch.data()); - } - - template - T getInt(uint32_t StreamIdx, uint32_t &Offset) { - const support::detail::packed_endian_specific_integral< - T, support::little, support::unaligned> *P; - getObject(P, StreamIdx, Offset); - return *P; - } - - template - T getObject(uint32_t StreamIdx, uint32_t &Offset) { - const T *P; - getObject(P, StreamIdx, Offset); - return *P; - } -}; - -static void dumpStructure(MemoryBufferRef M) { - const PDB::SuperBlock *SB; +static ExitOnError ExitOnErr; - auto Error = [&](std::error_code EC) { - if (EC) - reportError(M.getBufferIdentifier(), EC); - }; +static void yamlToPdb(StringRef Path) { + ErrorOr> ErrorOrBuffer = + MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); - Error(getObject(SB, M, M.getBufferStart())); - - if (opts::DumpHeaders) { - outs() << "BlockSize: " << SB->BlockSize << '\n'; - outs() << "Unknown0: " << SB->Unknown0 << '\n'; - outs() << "NumBlocks: " << SB->NumBlocks << '\n'; - outs() << "NumDirectoryBytes: " << SB->NumDirectoryBytes << '\n'; - outs() << "Unknown1: " << SB->Unknown1 << '\n'; - outs() << "BlockMapAddr: " << SB->BlockMapAddr << '\n'; + if (ErrorOrBuffer.getError()) { + ExitOnErr(make_error(generic_error_code::invalid_path, Path)); } - // We don't support blocksizes which aren't a multiple of four bytes. - if (SB->BlockSize % sizeof(support::ulittle32_t) != 0) - Error(std::make_error_code(std::errc::not_supported)); - - // We don't support directories whose sizes aren't a multiple of four bytes. - if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) - Error(std::make_error_code(std::errc::not_supported)); - - // The number of blocks which comprise the directory is a simple function of - // the number of bytes it contains. - uint64_t NumDirectoryBlocks = - bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize); - if (opts::DumpHeaders) - outs() << "NumDirectoryBlocks: " << NumDirectoryBlocks << '\n'; - - // The block map, as we understand it, is a block which consists of a list of - // block numbers. - // It is unclear what would happen if the number of blocks couldn't fit on a - // single block. - if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t)) - Error(std::make_error_code(std::errc::illegal_byte_sequence)); - - uint64_t BlockMapOffset = (uint64_t)SB->BlockMapAddr * SB->BlockSize; - if (opts::DumpHeaders) - outs() << "BlockMapOffset: " << BlockMapOffset << '\n'; - - // The directory is not contiguous. Instead, the block map contains a - // contiguous list of block numbers whose contents, when concatenated in - // order, make up the directory. - auto DirectoryBlocks = - makeArrayRef(reinterpret_cast( - M.getBufferStart() + BlockMapOffset), - NumDirectoryBlocks); - Error(checkOffset(M, DirectoryBlocks)); - - if (opts::DumpHeaders) { - outs() << "DirectoryBlocks: ["; - for (const support::ulittle32_t &DirectoryBlockAddr : DirectoryBlocks) { - if (&DirectoryBlockAddr != &DirectoryBlocks.front()) - outs() << ", "; - outs() << DirectoryBlockAddr; - } - outs() << "]\n"; - } + std::unique_ptr &Buffer = ErrorOrBuffer.get(); - bool SeenNumStreams = false; - uint32_t NumStreams = 0; - uint32_t StreamIdx = 0; - uint64_t DirectoryBytesRead = 0; - PDBStructureContext Ctx; - Ctx.SB = SB; - Ctx.M = M; - // The structure of the directory is as follows: - // struct PDBDirectory { - // uint32_t NumStreams; - // uint32_t StreamSizes[NumStreams]; - // uint32_t StreamMap[NumStreams][]; - // }; - // - // Empty streams don't consume entries in the StreamMap. - for (uint32_t DirectoryBlockAddr : DirectoryBlocks) { - uint64_t DirectoryBlockOffset = - blockToOffset(DirectoryBlockAddr, SB->BlockSize); - auto DirectoryBlock = - makeArrayRef(reinterpret_cast( - M.getBufferStart() + DirectoryBlockOffset), - SB->BlockSize / sizeof(support::ulittle32_t)); - Error(checkOffset(M, DirectoryBlock)); - - // We read data out of the directory four bytes at a time. Depending on - // where we are in the directory, the contents may be: the number of streams - // in the directory, a stream's size, or a block in the stream map. - for (uint32_t Data : DirectoryBlock) { - // Don't read beyond the end of the directory. - if (DirectoryBytesRead == SB->NumDirectoryBytes) - break; - - DirectoryBytesRead += sizeof(Data); - - // This data must be the number of streams if we haven't seen it yet. - if (!SeenNumStreams) { - NumStreams = Data; - SeenNumStreams = true; - continue; - } - // This data must be a stream size if we have not seen them all yet. - if (Ctx.StreamSizes.size() < NumStreams) { - // It seems like some streams have their set to -1 when their contents - // are not present. Treat them like empty streams for now. - if (Data == UINT32_MAX) - Ctx.StreamSizes.push_back(0); - else - Ctx.StreamSizes.push_back(Data); - continue; - } + llvm::yaml::Input In(Buffer->getBuffer()); + pdb::yaml::PdbObject YamlObj; + In >> YamlObj; + if (!YamlObj.Headers.hasValue()) + ExitOnErr(make_error(generic_error_code::unspecified, + "Yaml does not contain MSF headers")); - // This data must be a stream block number if we have seen all of the - // stream sizes. - std::vector *StreamBlocks = nullptr; - // Figure out which stream this block number belongs to. - while (StreamIdx < NumStreams) { - uint64_t NumExpectedStreamBlocks = - bytesToBlocks(Ctx.StreamSizes[StreamIdx], SB->BlockSize); - StreamBlocks = &Ctx.StreamMap[StreamIdx]; - if (NumExpectedStreamBlocks > StreamBlocks->size()) - break; - ++StreamIdx; - } - // It seems this block doesn't belong to any stream? The stream is either - // corrupt or something more mysterious is going on. - if (StreamIdx == NumStreams) - Error(std::make_error_code(std::errc::illegal_byte_sequence)); + auto OutFileOrError = FileOutputBuffer::create( + opts::yaml2pdb::YamlPdbOutputFile, YamlObj.Headers->FileSize); + if (OutFileOrError.getError()) + ExitOnErr(make_error(generic_error_code::invalid_path, + opts::yaml2pdb::YamlPdbOutputFile)); - StreamBlocks->push_back(Data); - } - } + auto FileByteStream = + llvm::make_unique(std::move(*OutFileOrError)); + PDBFileBuilder Builder(std::move(FileByteStream)); - // We should have read exactly SB->NumDirectoryBytes bytes. - assert(DirectoryBytesRead == SB->NumDirectoryBytes); - - if (opts::DumpHeaders) - outs() << "NumStreams: " << NumStreams << '\n'; - if (opts::DumpStreamSizes) - for (uint32_t StreamIdx = 0; StreamIdx < NumStreams; ++StreamIdx) - outs() << "StreamSizes[" << StreamIdx - << "]: " << Ctx.StreamSizes[StreamIdx] << '\n'; - - if (opts::DumpStreamBlocks) { - for (uint32_t StreamIdx = 0; StreamIdx < NumStreams; ++StreamIdx) { - outs() << "StreamBlocks[" << StreamIdx << "]: ["; - std::vector &StreamBlocks = Ctx.StreamMap[StreamIdx]; - for (uint32_t &StreamBlock : StreamBlocks) { - if (&StreamBlock != &StreamBlocks.front()) - outs() << ", "; - outs() << StreamBlock; - } - outs() << "]\n"; - } + ExitOnErr(Builder.setSuperBlock(YamlObj.Headers->SuperBlock)); + if (YamlObj.StreamSizes.hasValue()) { + Builder.setStreamSizes(YamlObj.StreamSizes.getValue()); } + Builder.setDirectoryBlocks(YamlObj.Headers->DirectoryBlocks); - StringRef DumpStreamStr = opts::DumpStreamData; - uint32_t DumpStreamNum; - if (!DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum) && - DumpStreamNum < NumStreams) { - uint32_t StreamBytesRead = 0; - uint32_t StreamSize = Ctx.StreamSizes[DumpStreamNum]; - std::vector &StreamBlocks = Ctx.StreamMap[DumpStreamNum]; - for (uint32_t &StreamBlockAddr : StreamBlocks) { - uint64_t StreamBlockOffset = blockToOffset(StreamBlockAddr, SB->BlockSize); - uint32_t BytesLeftToReadInStream = StreamSize - StreamBytesRead; - if (BytesLeftToReadInStream == 0) - break; - - uint32_t BytesToReadInBlock = std::min( - BytesLeftToReadInStream, static_cast(SB->BlockSize)); - auto StreamBlockData = - StringRef(M.getBufferStart() + StreamBlockOffset, BytesToReadInBlock); - Error(checkOffset(M, StreamBlockData)); - - outs() << StreamBlockData; - StreamBytesRead += StreamBlockData.size(); + if (YamlObj.StreamMap.hasValue()) { + std::vector> StreamMap; + for (auto &E : YamlObj.StreamMap.getValue()) { + StreamMap.push_back(E.Blocks); } + Builder.setStreamMap(StreamMap); + } else { + ExitOnErr(Builder.generateSimpleStreamMap()); } - uint32_t Offset = 0; - - // Stream 1 starts with the following header: - // uint32_t Version; - // uint32_t Signature; - // uint32_t Age; - // GUID Guid; - auto Version = Ctx.getInt(/*PDBStream=*/1, Offset); - outs() << "Version: " << Version << '\n'; - - // PDB's with versions before PDBImpvVC70 might not have the Guid field, we - // don't support them. - if (Version < 20000404) - Error(std::make_error_code(std::errc::not_supported)); - - // This appears to be the time the PDB was last opened by an MSVC tool? - // It is definitely a timestamp of some sort. - auto Signature = Ctx.getInt(/*PDBStream=*/1, Offset); - outs() << "Signature: "; - outs().write_hex(Signature) << '\n'; - - // This appears to be a number which is used to determine that the PDB is kept - // in sync with the EXE. - auto Age = Ctx.getInt(/*PDBStream=*/1, Offset); - outs() << "Age: " << Age << '\n'; - - // I'm not sure what the purpose of the GUID is. - using GuidTy = char[16]; - const GuidTy *Guid; - Ctx.getObject(Guid, /*PDBStream=*/1, Offset); - outs() << "Guid: "; - for (char C : *Guid) - outs().write_hex(C & 0xff) << ' '; - outs() << '\n'; - - // This is some sort of weird string-set/hash table encoded in the stream. - // It starts with the number of bytes in the table. - auto NumberOfBytes = Ctx.getInt(/*PDBStream=*/1, Offset); - outs() << "NumberOfBytes: " << NumberOfBytes << '\n'; - - // Following that field is the starting offset of strings in the name table. - uint32_t StringsOffset = Offset; - Offset += NumberOfBytes; - - // This appears to be equivalent to the total number of strings *actually* - // in the name table. - auto HashSize = Ctx.getInt(/*PDBStream=*/1, Offset); - outs() << "HashSize: " << HashSize << '\n'; - - // This appears to be an upper bound on the number of strings in the name - // table. - auto MaxNumberOfStrings = Ctx.getInt(/*PDBStream=*/1, Offset); - outs() << "MaxNumberOfStrings: " << MaxNumberOfStrings << '\n'; - - // This appears to be a hash table which uses bitfields to determine whether - // or not a bucket is 'present'. - auto NumPresentWords = Ctx.getInt(/*PDBStream=*/1, Offset); - outs() << "NumPresentWords: " << NumPresentWords << '\n'; - - // Store all the 'present' bits in a vector for later processing. - SmallVector PresentWords; - for (uint32_t I = 0; I != NumPresentWords; ++I) { - auto Word = Ctx.getInt(/*PDBStream=*/1, Offset); - PresentWords.push_back(Word); - outs() << "Word: " << Word << '\n'; - } - - // This appears to be a hash table which uses bitfields to determine whether - // or not a bucket is 'deleted'. - auto NumDeletedWords = Ctx.getInt(/*PDBStream=*/1, Offset); - outs() << "NumDeletedWords: " << NumDeletedWords << '\n'; - - // Store all the 'deleted' bits in a vector for later processing. - SmallVector DeletedWords; - for (uint32_t I = 0; I != NumDeletedWords; ++I) { - auto Word = Ctx.getInt(/*PDBStream=*/1, Offset); - DeletedWords.push_back(Word); - outs() << "Word: " << Word << '\n'; + if (YamlObj.PdbStream.hasValue()) { + auto &InfoBuilder = Builder.getInfoBuilder(); + InfoBuilder.setAge(YamlObj.PdbStream->Age); + InfoBuilder.setGuid(YamlObj.PdbStream->Guid); + InfoBuilder.setSignature(YamlObj.PdbStream->Signature); + InfoBuilder.setVersion(YamlObj.PdbStream->Version); } - BitVector Present(MaxNumberOfStrings, false); - if (!PresentWords.empty()) - Present.setBitsInMask(PresentWords.data(), PresentWords.size()); - BitVector Deleted(MaxNumberOfStrings, false); - if (!DeletedWords.empty()) - Deleted.setBitsInMask(DeletedWords.data(), DeletedWords.size()); - - StringMap NamedStreams; - for (uint32_t I = 0; I < MaxNumberOfStrings; ++I) { - if (!Present.test(I)) - continue; - - // For all present entries, dump out their mapping. - - // This appears to be an offset relative to the start of the strings. - // It tells us where the null-terminated string begins. - auto NameOffset = Ctx.getInt(/*PDBStream=*/1, Offset); - outs() << "NameOffset: " << NameOffset << '\n'; - - // This appears to be a stream number into the stream directory. - auto NameIndex = Ctx.getInt(/*PDBStream=*/1, Offset); - outs() << "NameIndex: " << NameIndex << '\n'; - - // Compute the offset of the start of the string relative to the stream. - uint32_t StringOffset = StringsOffset + NameOffset; - - // Pump out our c-string from the stream. - SmallString<8> Str; - char C; - do { - C = Ctx.getObject(/*PDBStream=*/1, StringOffset); - if (C != '\0') - Str += C; - } while (C != '\0'); - outs() << "String: " << Str << "\n\n"; - - // Add this to a string-map from name to stream number. - NamedStreams.insert({Str, NameIndex}); + if (YamlObj.DbiStream.hasValue()) { + auto &DbiBuilder = Builder.getDbiBuilder(); + DbiBuilder.setAge(YamlObj.DbiStream->Age); + DbiBuilder.setBuildNumber(YamlObj.DbiStream->BuildNumber); + DbiBuilder.setFlags(YamlObj.DbiStream->Flags); + DbiBuilder.setMachineType(YamlObj.DbiStream->MachineType); + DbiBuilder.setPdbDllRbld(YamlObj.DbiStream->PdbDllRbld); + DbiBuilder.setPdbDllVersion(YamlObj.DbiStream->PdbDllVersion); + DbiBuilder.setVersionHeader(YamlObj.DbiStream->VerHeader); } - // Let's try to dump out the named stream "/names". - auto NameI = NamedStreams.find("/names"); - if (NameI != NamedStreams.end()) { - uint32_t NameStream = NameI->second; - outs() << "NameStream: " << NameStream << '\n'; + auto Pdb = Builder.build(); + ExitOnErr(Pdb.takeError()); - uint32_t NameStreamOffset = 0; + auto &PdbFile = *Pdb; + ExitOnErr(PdbFile->commit()); +} - // The name stream appears to start with a signature and version. - auto NameStreamSignature = - Ctx.getInt(/*PDBStream=*/NameStream, NameStreamOffset); - outs() << "NameStreamSignature: "; - outs().write_hex(NameStreamSignature) << '\n'; +static void pdb2Yaml(StringRef Path) { + std::unique_ptr Session; + ExitOnErr(loadDataForPDB(PDB_ReaderType::Raw, Path, Session)); - auto NameStreamVersion = - Ctx.getInt(/*PDBStream=*/NameStream, NameStreamOffset); - outs() << "NameStreamVersion: " << NameStreamVersion << '\n'; + RawSession *RS = static_cast(Session.get()); + PDBFile &File = RS->getPDBFile(); + auto O = llvm::make_unique(File); + O = llvm::make_unique(File); - // We only support this particular version of the name stream. - if (NameStreamSignature != 0xeffeeffe || NameStreamVersion != 1) - Error(std::make_error_code(std::errc::not_supported)); - } + ExitOnErr(O->dump()); } -static void dumpInput(StringRef Path) { - if (opts::DumpHeaders || !opts::DumpStreamData.empty()) { - ErrorOr> ErrorOrBuffer = - MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, - /*RequiresNullTerminator=*/false); +static void dumpRaw(StringRef Path) { + std::unique_ptr Session; + ExitOnErr(loadDataForPDB(PDB_ReaderType::Raw, Path, Session)); - if (std::error_code EC = ErrorOrBuffer.getError()) - reportError(Path, EC); + RawSession *RS = static_cast(Session.get()); + PDBFile &File = RS->getPDBFile(); + auto O = llvm::make_unique(File); - std::unique_ptr &Buffer = ErrorOrBuffer.get(); + ExitOnErr(O->dump()); +} - dumpStructure(Buffer->getMemBufferRef()); +static void dumpPretty(StringRef Path) { + std::unique_ptr Session; - outs().flush(); - return; - } + ExitOnErr(loadDataForPDB(PDB_ReaderType::DIA, Path, Session)); - std::unique_ptr Session; - PDB_ErrorCode Error = loadDataForPDB(PDB_ReaderType::DIA, Path, Session); - switch (Error) { - case PDB_ErrorCode::Success: - break; - case PDB_ErrorCode::NoPdbImpl: - outs() << "Reading PDBs is not supported on this platform.\n"; - return; - case PDB_ErrorCode::InvalidPath: - outs() << "Unable to load PDB at '" << Path - << "'. Check that the file exists and is readable.\n"; - return; - case PDB_ErrorCode::InvalidFileFormat: - outs() << "Unable to load PDB at '" << Path - << "'. The file has an unrecognized format.\n"; - return; - default: - outs() << "Unable to load PDB at '" << Path - << "'. An unknown error occured.\n"; - return; - } - if (opts::LoadAddress) - Session->setLoadAddress(opts::LoadAddress); + if (opts::pretty::LoadAddress) + Session->setLoadAddress(opts::pretty::LoadAddress); LinePrinter Printer(2, outs()); @@ -678,7 +432,7 @@ static void dumpInput(StringRef Path) { outs() << "HasPrivateSymbols "; Printer.Unindent(); - if (opts::Compilands) { + if (opts::pretty::Compilands) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---COMPILANDS---"; @@ -686,14 +440,14 @@ static void dumpInput(StringRef Path) { auto Compilands = GlobalScope->findAllChildren(); CompilandDumper Dumper(Printer); CompilandDumpFlags options = CompilandDumper::Flags::None; - if (opts::Lines) + if (opts::pretty::Lines) options = options | CompilandDumper::Flags::Lines; while (auto Compiland = Compilands->getNext()) Dumper.start(*Compiland, options); Printer.Unindent(); } - if (opts::Types) { + if (opts::pretty::Types) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---"; Printer.Indent(); @@ -702,7 +456,7 @@ static void dumpInput(StringRef Path) { Printer.Unindent(); } - if (opts::Symbols) { + if (opts::pretty::Symbols) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---"; Printer.Indent(); @@ -713,7 +467,7 @@ static void dumpInput(StringRef Path) { Printer.Unindent(); } - if (opts::Globals) { + if (opts::pretty::Globals) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---"; Printer.Indent(); @@ -739,14 +493,14 @@ static void dumpInput(StringRef Path) { } Printer.Unindent(); } - if (opts::Externals) { + if (opts::pretty::Externals) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---"; Printer.Indent(); ExternalSymbolDumper Dumper(Printer); Dumper.start(*GlobalScope); } - if (opts::Lines) { + if (opts::pretty::Lines) { Printer.NewLine(); } outs().flush(); @@ -754,59 +508,83 @@ static void dumpInput(StringRef Path) { int main(int argc_, const char *argv_[]) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv_[0]); PrettyStackTraceProgram X(argc_, argv_); + ExitOnErr.setBanner("llvm-pdbdump: "); + SmallVector argv; SpecificBumpPtrAllocator ArgAllocator; - std::error_code EC = sys::Process::GetArgumentVector( - argv, makeArrayRef(argv_, argc_), ArgAllocator); - if (EC) { - errs() << "error: couldn't get arguments: " << EC.message() << '\n'; - return 1; - } + ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector( + argv, makeArrayRef(argv_, argc_), ArgAllocator))); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n"); - if (opts::Lines) - opts::Compilands = true; - - if (opts::All) { - opts::Compilands = true; - opts::Symbols = true; - opts::Globals = true; - opts::Types = true; - opts::Externals = true; - opts::Lines = true; - } - // When adding filters for excluded compilands and types, we need to remember - // that these are regexes. So special characters such as * and \ need to be - // escaped in the regex. In the case of a literal \, this means it needs to - // be escaped again in the C++. So matching a single \ in the input requires - // 4 \es in the C++. - if (opts::ExcludeCompilerGenerated) { - opts::ExcludeTypes.push_back("__vc_attributes"); - opts::ExcludeCompilands.push_back("\\* Linker \\*"); - } - if (opts::ExcludeSystemLibraries) { - opts::ExcludeCompilands.push_back( - "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld"); - opts::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt"); - opts::ExcludeCompilands.push_back("d:\\\\th.obj.x86fre\\\\minkernel"); + // These options are shared by two subcommands. + if ((opts::PdbToYamlSubcommand || opts::RawSubcommand) && opts::raw::RawAll) { + opts::raw::DumpHeaders = true; + opts::raw::DumpModules = true; + opts::raw::DumpModuleFiles = true; + opts::raw::DumpModuleSyms = true; + opts::raw::DumpPublics = true; + opts::raw::DumpSectionHeaders = true; + opts::raw::DumpStreamSummary = true; + opts::raw::DumpStreamBlocks = true; + opts::raw::DumpTpiRecords = true; + opts::raw::DumpTpiHash = true; + opts::raw::DumpIpiRecords = true; + opts::raw::DumpSectionMap = true; + opts::raw::DumpSectionContribs = true; + opts::raw::DumpLineInfo = true; + opts::raw::DumpFpo = true; } -#if defined(HAVE_DIA_SDK) - CoInitializeEx(nullptr, COINIT_MULTITHREADED); -#endif - - std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), - dumpInput); + llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); + + if (opts::PdbToYamlSubcommand) { + pdb2Yaml(opts::pdb2yaml::InputFilename.front()); + } else if (opts::YamlToPdbSubcommand) { + yamlToPdb(opts::yaml2pdb::InputFilename.front()); + } else if (opts::PrettySubcommand) { + if (opts::pretty::Lines) + opts::pretty::Compilands = true; + + if (opts::pretty::All) { + opts::pretty::Compilands = true; + opts::pretty::Symbols = true; + opts::pretty::Globals = true; + opts::pretty::Types = true; + opts::pretty::Externals = true; + opts::pretty::Lines = true; + } -#if defined(HAVE_DIA_SDK) - CoUninitialize(); -#endif + // When adding filters for excluded compilands and types, we need to + // remember + // that these are regexes. So special characters such as * and \ need to be + // escaped in the regex. In the case of a literal \, this means it needs to + // be escaped again in the C++. So matching a single \ in the input + // requires + // 4 \es in the C++. + if (opts::pretty::ExcludeCompilerGenerated) { + opts::pretty::ExcludeTypes.push_back("__vc_attributes"); + opts::pretty::ExcludeCompilands.push_back("\\* Linker \\*"); + } + if (opts::pretty::ExcludeSystemLibraries) { + opts::pretty::ExcludeCompilands.push_back( + "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld"); + opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt"); + opts::pretty::ExcludeCompilands.push_back( + "d:\\\\th.obj.x86fre\\\\minkernel"); + } + std::for_each(opts::pretty::InputFilenames.begin(), + opts::pretty::InputFilenames.end(), dumpPretty); + } else if (opts::RawSubcommand) { + std::for_each(opts::raw::InputFilenames.begin(), + opts::raw::InputFilenames.end(), dumpRaw); + } + outs().flush(); return 0; } diff --git a/tools/llvm-pdbdump/llvm-pdbdump.h b/tools/llvm-pdbdump/llvm-pdbdump.h index cb5bec64dec81531151100cd108ec44c0405309d..0a66515f4a015833f9df22533373f98463c6e0dc 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/tools/llvm-pdbdump/llvm-pdbdump.h @@ -14,12 +14,13 @@ #include "llvm/Support/raw_ostream.h" namespace opts { + +namespace pretty { extern llvm::cl::opt Compilands; extern llvm::cl::opt Symbols; extern llvm::cl::opt Globals; extern llvm::cl::opt Types; extern llvm::cl::opt All; - extern llvm::cl::opt ExcludeCompilerGenerated; extern llvm::cl::opt NoClassDefs; @@ -32,4 +33,37 @@ extern llvm::cl::list IncludeSymbols; extern llvm::cl::list IncludeCompilands; } -#endif \ No newline at end of file +namespace raw { +extern llvm::cl::opt DumpHeaders; +extern llvm::cl::opt DumpStreamBlocks; +extern llvm::cl::opt DumpStreamSummary; +extern llvm::cl::opt DumpTpiHash; +extern llvm::cl::opt DumpTpiRecordBytes; +extern llvm::cl::opt DumpTpiRecords; +extern llvm::cl::opt DumpIpiRecords; +extern llvm::cl::opt DumpIpiRecordBytes; +extern llvm::cl::opt DumpStreamDataIdx; +extern llvm::cl::opt DumpStreamDataName; +extern llvm::cl::opt DumpModules; +extern llvm::cl::opt DumpModuleFiles; +extern llvm::cl::opt DumpModuleSyms; +extern llvm::cl::opt DumpPublics; +extern llvm::cl::opt DumpSectionContribs; +extern llvm::cl::opt DumpLineInfo; +extern llvm::cl::opt DumpSectionMap; +extern llvm::cl::opt DumpSymRecordBytes; +extern llvm::cl::opt DumpSectionHeaders; +extern llvm::cl::opt DumpFpo; +} + +namespace pdb2yaml { +extern llvm::cl::opt NoFileHeaders; +extern llvm::cl::opt StreamMetadata; +extern llvm::cl::opt StreamDirectory; +extern llvm::cl::opt PdbStream; +extern llvm::cl::opt DbiStream; +extern llvm::cl::list InputFilename; +} +} + +#endif diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp index 046e82fa6eda17a850f18e8f303012455fdaf316..8e4b4c3d4ed5535d58408bb2cdefcf92c4cd45bd 100644 --- a/tools/llvm-profdata/llvm-profdata.cpp +++ b/tools/llvm-profdata/llvm-profdata.cpp @@ -31,7 +31,6 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include -#include using namespace llvm; @@ -48,38 +47,50 @@ static void exitWithError(const Twine &Message, StringRef Whence = "", ::exit(1); } -static void exitWithErrorCode(const std::error_code &Error, - StringRef Whence = "") { - if (Error.category() == instrprof_category()) { - instrprof_error instrError = static_cast(Error.value()); - if (instrError == instrprof_error::unrecognized_format) { - // Hint for common error of forgetting -sample for sample profiles. - exitWithError(Error.message(), Whence, - "Perhaps you forgot to use the -sample option?"); - } +static void exitWithError(Error E, StringRef Whence = "") { + if (E.isA()) { + handleAllErrors(std::move(E), [&](const InstrProfError &IPE) { + instrprof_error instrError = IPE.get(); + StringRef Hint = ""; + if (instrError == instrprof_error::unrecognized_format) { + // Hint for common error of forgetting -sample for sample profiles. + Hint = "Perhaps you forgot to use the -sample option?"; + } + exitWithError(IPE.message(), Whence, Hint); + }); } - exitWithError(Error.message(), Whence); + + exitWithError(toString(std::move(E)), Whence); +} + +static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") { + exitWithError(EC.message(), Whence); } namespace { enum ProfileKinds { instr, sample }; } -static void handleMergeWriterError(std::error_code &Error, - StringRef WhenceFile = "", +static void handleMergeWriterError(Error E, StringRef WhenceFile = "", StringRef WhenceFunction = "", bool ShowHint = true) { if (!WhenceFile.empty()) errs() << WhenceFile << ": "; if (!WhenceFunction.empty()) errs() << WhenceFunction << ": "; - errs() << Error.message() << "\n"; + + auto IPE = instrprof_error::success; + E = handleErrors(std::move(E), + [&IPE](std::unique_ptr E) -> Error { + IPE = E->get(); + return Error(std::move(E)); + }); + errs() << toString(std::move(E)) << "\n"; if (ShowHint) { StringRef Hint = ""; - if (Error.category() == instrprof_category()) { - instrprof_error instrError = static_cast(Error.value()); - switch (instrError) { + if (IPE != instrprof_error::success) { + switch (IPE) { case instrprof_error::hash_mismatch: case instrprof_error::count_mismatch: case instrprof_error::value_site_count_mismatch: @@ -121,11 +132,11 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs, exitWithErrorCode(EC, OutputFilename); InstrProfWriter Writer(OutputSparse); - SmallSet WriterErrorCodes; + SmallSet WriterErrorCodes; for (const auto &Input : Inputs) { auto ReaderOrErr = InstrProfReader::create(Input.Filename); - if (std::error_code ec = ReaderOrErr.getError()) - exitWithErrorCode(ec, Input.Filename); + if (Error E = ReaderOrErr.takeError()) + exitWithError(std::move(E), Input.Filename); auto Reader = std::move(ReaderOrErr.get()); bool IsIRProfile = Reader->isIRLevelProfile(); @@ -133,14 +144,16 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs, exitWithError("Merge IR generated profile with Clang generated profile."); for (auto &I : *Reader) { - if (std::error_code EC = Writer.addRecord(std::move(I), Input.Weight)) { + if (Error E = Writer.addRecord(std::move(I), Input.Weight)) { // Only show hint the first time an error occurs. - bool firstTime = WriterErrorCodes.insert(EC).second; - handleMergeWriterError(EC, Input.Filename, I.Name, firstTime); + instrprof_error IPE = InstrProfError::take(std::move(E)); + bool firstTime = WriterErrorCodes.insert(IPE).second; + handleMergeWriterError(make_error(IPE), Input.Filename, + I.Name, firstTime); } } if (Reader->hasError()) - exitWithErrorCode(Reader->getError(), Input.Filename); + exitWithError(Reader->getError(), Input.Filename); } if (OutputFormat == PF_Text) Writer.writeText(Output); @@ -164,9 +177,9 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs, auto Writer = std::move(WriterOrErr.get()); StringMap ProfileMap; SmallVector, 5> Readers; + LLVMContext Context; for (const auto &Input : Inputs) { - auto ReaderOrErr = - SampleProfileReader::create(Input.Filename, getGlobalContext()); + auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context); if (std::error_code EC = ReaderOrErr.getError()) exitWithErrorCode(EC, Input.Filename); @@ -188,7 +201,7 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs, sampleprof_error Result = ProfileMap[FName].merge(Samples, Input.Weight); if (Result != sampleprof_error::success) { std::error_code EC = make_error_code(Result); - handleMergeWriterError(EC, Input.Filename, FName); + handleMergeWriterError(errorCodeToError(EC), Input.Filename, FName); } } } @@ -210,11 +223,53 @@ static WeightedFile parseWeightedFile(const StringRef &WeightedFilename) { return WeightedFile(FileName, Weight); } +static std::unique_ptr +getInputFilenamesFileBuf(const StringRef &InputFilenamesFile) { + if (InputFilenamesFile == "") + return {}; + + auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFilenamesFile); + if (!BufOrError) + exitWithErrorCode(BufOrError.getError(), InputFilenamesFile); + + return std::move(*BufOrError); +} + +static void parseInputFilenamesFile(MemoryBuffer *Buffer, + WeightedFileVector &WFV) { + if (!Buffer) + return; + + SmallVector Entries; + StringRef Data = Buffer->getBuffer(); + Data.split(Entries, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/false); + for (const StringRef &FileWeightEntry : Entries) { + StringRef SanitizedEntry = FileWeightEntry.trim(" \t\v\f\r"); + // Skip comments. + if (SanitizedEntry.startswith("#")) + continue; + // If there's no comma, it's an unweighted profile. + else if (SanitizedEntry.find(',') == StringRef::npos) + WFV.emplace_back(SanitizedEntry, 1); + else + WFV.emplace_back(parseWeightedFile(SanitizedEntry)); + } +} + static int merge_main(int argc, const char *argv[]) { cl::list InputFilenames(cl::Positional, cl::desc("")); cl::list WeightedInputFilenames("weighted-input", cl::desc(",")); + cl::opt InputFilenamesFile( + "input-files", cl::init(""), + cl::desc("Path to file containing newline-separated " + "[,] entries")); + cl::alias InputFilenamesFileA("f", cl::desc("Alias for --input-files"), + cl::aliasopt(InputFilenamesFile)); + cl::opt DumpInputFileList( + "dump-input-file-list", cl::init(false), cl::Hidden, + cl::desc("Dump the list of input files and their weights, then exit")); cl::opt OutputFilename("output", cl::value_desc("output"), cl::init("-"), cl::Required, cl::desc("Output file")); @@ -224,7 +279,6 @@ static int merge_main(int argc, const char *argv[]) { cl::desc("Profile kind:"), cl::init(instr), cl::values(clEnumVal(instr, "Instrumentation profile (default)"), clEnumVal(sample, "Sample profile"), clEnumValEnd)); - cl::opt OutputFormat( cl::desc("Format of output profile"), cl::init(PF_Binary), cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"), @@ -232,21 +286,31 @@ static int merge_main(int argc, const char *argv[]) { clEnumValN(PF_GCC, "gcc", "GCC encoding (only meaningful for -sample)"), clEnumValEnd)); - cl::opt OutputSparse("sparse", cl::init(false), cl::desc("Generate a sparse profile (only meaningful for -instr)")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); - if (InputFilenames.empty() && WeightedInputFilenames.empty()) - exitWithError("No input files specified. See " + - sys::path::filename(argv[0]) + " -help"); - WeightedFileVector WeightedInputs; for (StringRef Filename : InputFilenames) - WeightedInputs.push_back(WeightedFile(Filename, 1)); + WeightedInputs.emplace_back(Filename, 1); for (StringRef WeightedFilename : WeightedInputFilenames) - WeightedInputs.push_back(parseWeightedFile(WeightedFilename)); + WeightedInputs.emplace_back(parseWeightedFile(WeightedFilename)); + + // Make sure that the file buffer stays alive for the duration of the + // weighted input vector's lifetime. + auto Buffer = getInputFilenamesFileBuf(InputFilenamesFile); + parseInputFilenamesFile(Buffer.get(), WeightedInputs); + + if (WeightedInputs.empty()) + exitWithError("No input files specified. See " + + sys::path::filename(argv[0]) + " -help"); + + if (DumpInputFileList) { + for (auto &WF : WeightedInputs) + outs() << WF.Weight << "," << WF.Filename << "\n"; + return 0; + } if (ProfileKind == instr) mergeInstrProfile(WeightedInputs, OutputFilename, OutputFormat, @@ -257,24 +321,28 @@ static int merge_main(int argc, const char *argv[]) { return 0; } -static int showInstrProfile(std::string Filename, bool ShowCounts, +static int showInstrProfile(const std::string &Filename, bool ShowCounts, bool ShowIndirectCallTargets, bool ShowDetailedSummary, std::vector DetailedSummaryCutoffs, - bool ShowAllFunctions, std::string ShowFunction, - bool TextFormat, raw_fd_ostream &OS) { + bool ShowAllFunctions, + const std::string &ShowFunction, bool TextFormat, + raw_fd_ostream &OS) { auto ReaderOrErr = InstrProfReader::create(Filename); - std::vector Cutoffs(DetailedSummaryCutoffs); - if (ShowDetailedSummary && DetailedSummaryCutoffs.empty()) { + std::vector Cutoffs = std::move(DetailedSummaryCutoffs); + if (ShowDetailedSummary && Cutoffs.empty()) { Cutoffs = {800000, 900000, 950000, 990000, 999000, 999900, 999990}; } - InstrProfSummary PS(Cutoffs); - if (std::error_code EC = ReaderOrErr.getError()) - exitWithErrorCode(EC, Filename); + InstrProfSummaryBuilder Builder(std::move(Cutoffs)); + if (Error E = ReaderOrErr.takeError()) + exitWithError(std::move(E), Filename); auto Reader = std::move(ReaderOrErr.get()); bool IsIRInstr = Reader->isIRLevelProfile(); size_t ShownFunctions = 0; + uint64_t TotalNumValueSites = 0; + uint64_t TotalNumValueSitesWithValueProfile = 0; + uint64_t TotalNumValues = 0; for (const auto &Func : *Reader) { bool Show = ShowAllFunctions || (!ShowFunction.empty() && @@ -289,7 +357,7 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, } assert(Func.Counts.size() > 0 && "function missing entry counter"); - PS.addRecord(Func); + Builder.addRecord(Func); if (Show) { @@ -321,10 +389,14 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, InstrProfSymtab &Symtab = Reader->getSymtab(); uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget); OS << " Indirect Target Results: \n"; + TotalNumValueSites += NS; for (size_t I = 0; I < NS; ++I) { uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I); std::unique_ptr VD = Func.getValueForSite(IPVK_IndirectCallTarget, I); + TotalNumValues += NV; + if (NV) + TotalNumValueSitesWithValueProfile++; for (uint32_t V = 0; V < NV; V++) { OS << "\t[ " << I << ", "; OS << Symtab.getFuncName(VD[V].Value) << ", " << VD[V].Count @@ -334,24 +406,30 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, } } } - if (Reader->hasError()) - exitWithErrorCode(Reader->getError(), Filename); + exitWithError(Reader->getError(), Filename); if (ShowCounts && TextFormat) return 0; - + std::unique_ptr PS(Builder.getSummary()); if (ShowAllFunctions || !ShowFunction.empty()) OS << "Functions shown: " << ShownFunctions << "\n"; - OS << "Total functions: " << PS.getNumFunctions() << "\n"; - OS << "Maximum function count: " << PS.getMaxFunctionCount() << "\n"; - OS << "Maximum internal block count: " << PS.getMaxInternalBlockCount() << "\n"; + OS << "Total functions: " << PS->getNumFunctions() << "\n"; + OS << "Maximum function count: " << PS->getMaxFunctionCount() << "\n"; + OS << "Maximum internal block count: " << PS->getMaxInternalCount() << "\n"; + if (ShownFunctions && ShowIndirectCallTargets) { + OS << "Total Number of Indirect Call Sites : " << TotalNumValueSites + << "\n"; + OS << "Total Number of Sites With Values : " + << TotalNumValueSitesWithValueProfile << "\n"; + OS << "Total Number of Profiled Values : " << TotalNumValues << "\n"; + } if (ShowDetailedSummary) { OS << "Detailed summary:\n"; - OS << "Total number of blocks: " << PS.getNumBlocks() << "\n"; - OS << "Total count: " << PS.getTotalCount() << "\n"; - for (auto Entry : PS.getDetailedSummary()) { + OS << "Total number of blocks: " << PS->getNumCounts() << "\n"; + OS << "Total count: " << PS->getTotalCount() << "\n"; + for (auto Entry : PS->getDetailedSummary()) { OS << Entry.NumCounts << " blocks with count >= " << Entry.MinCount << " account for " << format("%0.6g", (float)Entry.Cutoff / ProfileSummary::Scale * 100) @@ -361,11 +439,13 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, return 0; } -static int showSampleProfile(std::string Filename, bool ShowCounts, - bool ShowAllFunctions, std::string ShowFunction, +static int showSampleProfile(const std::string &Filename, bool ShowCounts, + bool ShowAllFunctions, + const std::string &ShowFunction, raw_fd_ostream &OS) { using namespace sampleprof; - auto ReaderOrErr = SampleProfileReader::create(Filename, getGlobalContext()); + LLVMContext Context; + auto ReaderOrErr = SampleProfileReader::create(Filename, Context); if (std::error_code EC = ReaderOrErr.getError()) exitWithErrorCode(EC, Filename); @@ -440,7 +520,7 @@ static int show_main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. diff --git a/tools/llvm-readobj/ARMAttributeParser.cpp b/tools/llvm-readobj/ARMAttributeParser.cpp index d490510abe7b05bde484065dfd2baf17fd7dbadf..877dd71c907060d5a56294e976abf942096b0976 100644 --- a/tools/llvm-readobj/ARMAttributeParser.cpp +++ b/tools/llvm-readobj/ARMAttributeParser.cpp @@ -8,10 +8,10 @@ //===----------------------------------------------------------------------===// #include "ARMAttributeParser.h" -#include "StreamWriter.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/ScopedPrinter.h" using namespace llvm; using namespace llvm::ARMBuildAttrs; @@ -341,7 +341,7 @@ void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data, if (Value < array_lengthof(Strings)) Description = std::string(Strings[Value]); else if (Value <= 12) - Description = std::string("8-byte alignment, ") + utostr(1 << Value) + Description = std::string("8-byte alignment, ") + utostr(1ULL << Value) + std::string("-byte extended alignment"); else Description = "Invalid"; @@ -362,8 +362,8 @@ void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data, if (Value < array_lengthof(Strings)) Description = std::string(Strings[Value]); else if (Value <= 12) - Description = std::string("8-byte stack alignment, ") + utostr(1 << Value) - + std::string("-byte data alignment"); + Description = std::string("8-byte stack alignment, ") + + utostr(1ULL << Value) + std::string("-byte data alignment"); else Description = "Invalid"; diff --git a/tools/llvm-readobj/ARMAttributeParser.h b/tools/llvm-readobj/ARMAttributeParser.h index a58285688f25c397a8d0bdcd4fd8ea11e45b40d8..6936b70ca123069fa08cbe7f5c86bdd618bc51f8 100644 --- a/tools/llvm-readobj/ARMAttributeParser.h +++ b/tools/llvm-readobj/ARMAttributeParser.h @@ -10,14 +10,14 @@ #ifndef LLVM_TOOLS_LLVM_READOBJ_ARMATTRIBUTEPARSER_H #define LLVM_TOOLS_LLVM_READOBJ_ARMATTRIBUTEPARSER_H -#include "StreamWriter.h" #include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/Support/ScopedPrinter.h" namespace llvm { class StringRef; class ARMAttributeParser { - StreamWriter &SW; + ScopedPrinter &SW; struct DisplayHandler { ARMBuildAttrs::AttrType Attribute; @@ -115,7 +115,7 @@ class ARMAttributeParser { SmallVectorImpl &IndexList); void ParseSubsection(const uint8_t *Data, uint32_t Length); public: - ARMAttributeParser(StreamWriter &SW) : SW(SW) {} + ARMAttributeParser(ScopedPrinter &SW) : SW(SW) {} void Parse(ArrayRef Section); }; diff --git a/tools/llvm-readobj/ARMEHABIPrinter.h b/tools/llvm-readobj/ARMEHABIPrinter.h index 42f2a12367d0a35193d88b51da3724e18f6dc4a5..59c9b713d85e1fe5b0b7850ed37ac1f181013a59 100644 --- a/tools/llvm-readobj/ARMEHABIPrinter.h +++ b/tools/llvm-readobj/ARMEHABIPrinter.h @@ -11,7 +11,6 @@ #define LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H #include "Error.h" -#include "StreamWriter.h" #include "llvm-readobj.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Object/ELF.h" @@ -20,6 +19,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Format.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/type_traits.h" namespace llvm { @@ -27,7 +27,7 @@ namespace ARM { namespace EHABI { class OpcodeDecoder { - StreamWriter &SW; + ScopedPrinter &SW; raw_ostream &OS; struct RingEntry { @@ -64,7 +64,7 @@ class OpcodeDecoder { void PrintRegisters(uint32_t Mask, StringRef Prefix); public: - OpcodeDecoder(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {} + OpcodeDecoder(ScopedPrinter &SW) : SW(SW), OS(SW.getOStream()) {} void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length); }; @@ -311,7 +311,7 @@ class PrinterContext { typedef typename object::ELFFile::Elf_Rel Elf_Rel; typedef typename object::ELFFile::Elf_Word Elf_Word; - StreamWriter &SW; + ScopedPrinter &SW; const object::ELFFile *ELF; const Elf_Shdr *Symtab; ArrayRef ShndxTable; @@ -335,7 +335,7 @@ class PrinterContext { void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const; public: - PrinterContext(StreamWriter &SW, const object::ELFFile *ELF, + PrinterContext(ScopedPrinter &SW, const object::ELFFile *ELF, const Elf_Shdr *Symtab) : SW(SW), ELF(ELF), Symtab(Symtab) {} @@ -355,8 +355,15 @@ PrinterContext::FunctionAtAddress(unsigned Section, for (const Elf_Sym &Sym : ELF->symbols(Symtab)) if (Sym.st_shndx == Section && Sym.st_value == Address && - Sym.getType() == ELF::STT_FUNC) - return Sym.getName(StrTable); + Sym.getType() == ELF::STT_FUNC) { + auto NameOrErr = Sym.getName(StrTable); + if (!NameOrErr) { + // TODO: Actually report errors helpfully. + consumeError(NameOrErr.takeError()); + return readobj_error::unknown_symbol; + } + return *NameOrErr; + } return readobj_error::unknown_symbol; } diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp index 0f74a9987070582dc5f90a59df7e04c18fa83bac..1a033b1eb42e84f31cc166d8a13f5ee1b8207d5c 100644 --- a/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -198,15 +198,15 @@ Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { ErrorOr Decoder::getSymbol(const COFFObjectFile &COFF, uint64_t VA, bool FunctionOnly) { for (const auto &Symbol : COFF.symbols()) { - ErrorOr Type = Symbol.getType(); - if (std::error_code EC = Type.getError()) - return EC; + Expected Type = Symbol.getType(); + if (!Type) + return errorToErrorCode(Type.takeError()); if (FunctionOnly && *Type != SymbolRef::ST_Function) continue; - ErrorOr Address = Symbol.getAddress(); - if (std::error_code EC = Address.getError()) - return EC; + Expected Address = Symbol.getAddress(); + if (!Address) + return errorToErrorCode(Address.takeError()); if (*Address == VA) return Symbol; } @@ -570,9 +570,14 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, if (!Symbol) Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true); - ErrorOr Name = Symbol->getName(); - if (std::error_code EC = Name.getError()) - report_fatal_error(EC.message()); + Expected Name = Symbol->getName(); + if (!Name) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(Name.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } ListScope EHS(SW, "ExceptionHandler"); SW.printString("Routine", formatSymbol(*Name, Address)); @@ -604,13 +609,23 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, StringRef FunctionName; uint64_t FunctionAddress; if (Function) { - ErrorOr FunctionNameOrErr = Function->getName(); - if (std::error_code EC = FunctionNameOrErr.getError()) - report_fatal_error(EC.message()); + Expected FunctionNameOrErr = Function->getName(); + if (!FunctionNameOrErr) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } FunctionName = *FunctionNameOrErr; - ErrorOr FunctionAddressOrErr = Function->getAddress(); - if (std::error_code EC = FunctionAddressOrErr.getError()) - report_fatal_error(EC.message()); + Expected FunctionAddressOrErr = Function->getAddress(); + if (!FunctionAddressOrErr) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } FunctionAddress = *FunctionAddressOrErr; } else { const pe32_header *PEHeader; @@ -622,20 +637,33 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); if (XDataRecord) { - ErrorOr Name = XDataRecord->getName(); - if (std::error_code EC = Name.getError()) - report_fatal_error(EC.message()); + Expected Name = XDataRecord->getName(); + if (!Name) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(Name.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } - ErrorOr AddressOrErr = XDataRecord->getAddress(); - if (std::error_code EC = AddressOrErr.getError()) - report_fatal_error(EC.message()); + Expected AddressOrErr = XDataRecord->getAddress(); + if (!AddressOrErr) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(AddressOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } uint64_t Address = *AddressOrErr; SW.printString("ExceptionRecord", formatSymbol(*Name, Address)); - ErrorOr SIOrErr = XDataRecord->getSection(); - if (!SIOrErr) + Expected SIOrErr = XDataRecord->getSection(); + if (!SIOrErr) { + // TODO: Actually report errors helpfully. + consumeError(SIOrErr.takeError()); return false; + } section_iterator SI = *SIOrErr; return dumpXDataRecord(COFF, *SI, FunctionAddress, Address); @@ -671,11 +699,23 @@ bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, StringRef FunctionName; uint64_t FunctionAddress; if (Function) { - ErrorOr FunctionNameOrErr = Function->getName(); - if (std::error_code EC = FunctionNameOrErr.getError()) - report_fatal_error(EC.message()); + Expected FunctionNameOrErr = Function->getName(); + if (!FunctionNameOrErr) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } FunctionName = *FunctionNameOrErr; - ErrorOr FunctionAddressOrErr = Function->getAddress(); + Expected FunctionAddressOrErr = Function->getAddress(); + if (!FunctionAddressOrErr) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } FunctionAddress = *FunctionAddressOrErr; } else { const pe32_header *PEHeader; diff --git a/tools/llvm-readobj/ARMWinEHPrinter.h b/tools/llvm-readobj/ARMWinEHPrinter.h index 274ef114841c19cb907259f2b8c497bb3bd79af9..95f521702268a89e56d3ef49d13219a4c4e0e5ee 100644 --- a/tools/llvm-readobj/ARMWinEHPrinter.h +++ b/tools/llvm-readobj/ARMWinEHPrinter.h @@ -10,9 +10,9 @@ #ifndef LLVM_TOOLS_LLVM_READOBJ_ARMWINEHPRINTER_H #define LLVM_TOOLS_LLVM_READOBJ_ARMWINEHPRINTER_H -#include "StreamWriter.h" #include "llvm/Object/COFF.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/ScopedPrinter.h" namespace llvm { namespace ARM { @@ -22,7 +22,7 @@ class RuntimeFunction; class Decoder { static const size_t PDataEntrySize; - StreamWriter &SW; + ScopedPrinter &SW; raw_ostream &OS; struct RingEntry { @@ -107,7 +107,7 @@ class Decoder { const object::SectionRef Section); public: - Decoder(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {} + Decoder(ScopedPrinter &SW) : SW(SW), OS(SW.getOStream()) {} std::error_code dumpProcedureData(const object::COFFObjectFile &COFF); }; } diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index a06b678780cb470c37158f6a652d27f0137be75f..7477f5b035d0c7289916294f0107ca569b44712d 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -1,6 +1,8 @@ set(LLVM_LINK_COMPONENTS + DebugInfoCodeView Object Support + DebugInfoCodeView ) add_llvm_tool(llvm-readobj @@ -13,6 +15,5 @@ add_llvm_tool(llvm-readobj llvm-readobj.cpp MachODumper.cpp ObjDumper.cpp - StreamWriter.cpp Win64EHDumper.cpp ) diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 781185af849d58fa6cfbf61b3aad6a3ff2bc56bc..348f5b43556438aa4ee6f06d495b2de1852abce8 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -12,23 +12,28 @@ /// //===----------------------------------------------------------------------===// -#include "llvm-readobj.h" #include "ARMWinEHPrinter.h" #include "CodeView.h" #include "Error.h" #include "ObjDumper.h" #include "StackMapPrinter.h" -#include "StreamWriter.h" #include "Win64EHDumper.h" +#include "llvm-readobj.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSet.h" +#include "llvm/DebugInfo/CodeView/ByteStream.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" +#include "llvm/DebugInfo/CodeView/SymbolDumper.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeDumper.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/COFF.h" @@ -36,6 +41,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/Win64EH.h" #include "llvm/Support/raw_ostream.h" @@ -54,10 +60,10 @@ namespace { class COFFDumper : public ObjDumper { public: - COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer) - : ObjDumper(Writer) - , Obj(Obj) { - } + friend class COFFObjectDumpDelegate; + COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer) + : ObjDumper(Writer), Obj(Obj), + CVTD(&Writer, opts::CodeViewSubsectionBytes) {} void printFileHeaders() override; void printSections() override; @@ -69,7 +75,10 @@ public: void printCOFFExports() override; void printCOFFDirectives() override; void printCOFFBaseReloc() override; + void printCOFFDebugDirectory() override; void printCodeViewDebugInfo() override; + void + mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) override; void printStackMap() const override; private: void printSymbol(const SymbolRef &Sym); @@ -84,15 +93,13 @@ private: void printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section); void printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section); - void printCodeViewFieldList(StringRef FieldData); StringRef getTypeName(TypeIndex Ty); StringRef getFileNameForFileOffset(uint32_t FileOffset); void printFileNameForOffset(StringRef Label, uint32_t FileOffset); - void printTypeIndex(StringRef FieldName, TypeIndex TI); - void printLocalVariableAddrRange(const LocalVariableAddrRange &Range, - const coff_section *Sec, - StringRef SectionContents); - void printLocalVariableAddrGap(StringRef &SymData); + void printTypeIndex(StringRef FieldName, TypeIndex TI) { + // Forward to CVTypeDumper for simplicity. + CVTD.printTypeIndex(FieldName, TI); + } void printCodeViewSymbolsSubsection(StringRef Subsection, const SectionRef &Section, @@ -102,10 +109,8 @@ private: void printCodeViewInlineeLines(StringRef Subsection); - void printMemberAttributes(MemberAttributes Attrs); - void printRelocatedField(StringRef Label, const coff_section *Sec, - StringRef SectionContents, const ulittle32_t *Field, + uint32_t RelocOffset, uint32_t Offset, StringRef *RelocSym = nullptr); void printBinaryBlockWithRelocs(StringRef Label, const SectionRef &Sec, @@ -136,21 +141,53 @@ private: StringRef CVFileChecksumTable; StringRef CVStringTable; - /// All user defined type records in .debug$T live in here. Type indices - /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to - /// index into this vector. - SmallVector CVUDTNames; - - StringSet<> TypeNames; + CVTypeDumper CVTD; }; -} // namespace +class COFFObjectDumpDelegate : public SymbolDumpDelegate { +public: + COFFObjectDumpDelegate(COFFDumper &CD, const SectionRef &SR, + const COFFObjectFile *Obj, StringRef SectionContents) + : CD(CD), SR(SR), SectionContents(SectionContents) { + Sec = Obj->getCOFFSection(SR); + } + + uint32_t getRecordOffset(ArrayRef Record) override { + return Record.data() - SectionContents.bytes_begin(); + } + + void printRelocatedField(StringRef Label, uint32_t RelocOffset, + uint32_t Offset, StringRef *RelocSym) override { + CD.printRelocatedField(Label, Sec, RelocOffset, Offset, RelocSym); + } + + void printBinaryBlockWithRelocs(StringRef Label, + ArrayRef Block) override { + StringRef SBlock(reinterpret_cast(Block.data()), + Block.size()); + if (opts::CodeViewSubsectionBytes) + CD.printBinaryBlockWithRelocs(Label, SR, SectionContents, SBlock); + } + + StringRef getFileNameForFileOffset(uint32_t FileOffset) override { + return CD.getFileNameForFileOffset(FileOffset); + } + + StringRef getStringTable() override { return CD.CVStringTable; } + +private: + COFFDumper &CD; + const SectionRef &SR; + const coff_section *Sec; + StringRef SectionContents; +}; +} // end namespace namespace llvm { std::error_code createCOFFDumper(const object::ObjectFile *Obj, - StreamWriter &Writer, + ScopedPrinter &Writer, std::unique_ptr &Result) { const COFFObjectFile *COFFObj = dyn_cast(Obj); if (!COFFObj) @@ -168,15 +205,19 @@ std::error_code COFFDumper::resolveSymbol(const coff_section *Section, uint64_t Offset, SymbolRef &Sym) { cacheRelocations(); const auto &Relocations = RelocMap[Section]; + auto SymI = Obj->symbol_end(); for (const auto &Relocation : Relocations) { uint64_t RelocationOffset = Relocation.getOffset(); if (RelocationOffset == Offset) { - Sym = *Relocation.getSymbol(); - return readobj_error::success; + SymI = Relocation.getSymbol(); + break; } } - return readobj_error::unknown_symbol; + if (SymI == Obj->symbol_end()) + return readobj_error::unknown_symbol; + Sym = *SymI; + return readobj_error::success; } // Given a section and an offset into this section the function returns the name @@ -187,9 +228,9 @@ std::error_code COFFDumper::resolveSymbolName(const coff_section *Section, SymbolRef Symbol; if (std::error_code EC = resolveSymbol(Section, Offset, Symbol)) return EC; - ErrorOr NameOrErr = Symbol.getName(); - if (std::error_code EC = NameOrErr.getError()) - return EC; + Expected NameOrErr = Symbol.getName(); + if (!NameOrErr) + return errorToErrorCode(NameOrErr.takeError()); Name = *NameOrErr; return std::error_code(); } @@ -209,15 +250,14 @@ std::error_code COFFDumper::resolveSymbolName(const coff_section *Section, } void COFFDumper::printRelocatedField(StringRef Label, const coff_section *Sec, - StringRef SectionContents, - const ulittle32_t *Field, + uint32_t RelocOffset, uint32_t Offset, StringRef *RelocSym) { StringRef SymStorage; StringRef &Symbol = RelocSym ? *RelocSym : SymStorage; - if (!resolveSymbolName(Sec, SectionContents, Field, Symbol)) - W.printSymbolOffset(Label, Symbol, *Field); + if (!resolveSymbolName(Sec, RelocOffset, Symbol)) + W.printSymbolOffset(Label, Symbol, Offset); else - W.printHex(Label, *Field); + W.printHex(Label, RelocOffset); } void COFFDumper::printBinaryBlockWithRelocs(StringRef Label, @@ -232,6 +272,7 @@ void COFFDumper::printBinaryBlockWithRelocs(StringRef Label, uint64_t OffsetStart = Block.data() - SectionContents.data(); uint64_t OffsetEnd = OffsetStart + Block.size(); + W.flush(); cacheRelocations(); ListScope D(W, "BlockRelocations"); const coff_section *Section = Obj->getCOFFSection(Sec); @@ -419,6 +460,26 @@ static const EnumEntry ImageCOMDATSelect[] = { { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST } }; +static const EnumEntry ImageDebugType[] = { + { "Unknown" , COFF::IMAGE_DEBUG_TYPE_UNKNOWN }, + { "COFF" , COFF::IMAGE_DEBUG_TYPE_COFF }, + { "CodeView" , COFF::IMAGE_DEBUG_TYPE_CODEVIEW }, + { "FPO" , COFF::IMAGE_DEBUG_TYPE_FPO }, + { "Misc" , COFF::IMAGE_DEBUG_TYPE_MISC }, + { "Exception" , COFF::IMAGE_DEBUG_TYPE_EXCEPTION }, + { "Fixup" , COFF::IMAGE_DEBUG_TYPE_FIXUP }, + { "OmapToSrc" , COFF::IMAGE_DEBUG_TYPE_OMAP_TO_SRC }, + { "OmapFromSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC }, + { "Borland" , COFF::IMAGE_DEBUG_TYPE_BORLAND }, + { "Reserved10" , COFF::IMAGE_DEBUG_TYPE_RESERVED10 }, + { "CLSID" , COFF::IMAGE_DEBUG_TYPE_CLSID }, + { "VCFeature" , COFF::IMAGE_DEBUG_TYPE_VC_FEATURE }, + { "POGO" , COFF::IMAGE_DEBUG_TYPE_POGO }, + { "ILTCG" , COFF::IMAGE_DEBUG_TYPE_ILTCG }, + { "MPX" , COFF::IMAGE_DEBUG_TYPE_MPX }, + { "Repro" , COFF::IMAGE_DEBUG_TYPE_REPRO }, +}; + static const EnumEntry WeakExternalCharacteristics[] = { { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY }, @@ -426,41 +487,6 @@ WeakExternalCharacteristics[] = { { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS } }; -static const EnumEntry CompileSym3Flags[] = { - LLVM_READOBJ_ENUM_ENT(CompileSym3, EC), - LLVM_READOBJ_ENUM_ENT(CompileSym3, NoDbgInfo), - LLVM_READOBJ_ENUM_ENT(CompileSym3, LTCG), - LLVM_READOBJ_ENUM_ENT(CompileSym3, NoDataAlign), - LLVM_READOBJ_ENUM_ENT(CompileSym3, ManagedPresent), - LLVM_READOBJ_ENUM_ENT(CompileSym3, SecurityChecks), - LLVM_READOBJ_ENUM_ENT(CompileSym3, HotPatch), - LLVM_READOBJ_ENUM_ENT(CompileSym3, CVTCIL), - LLVM_READOBJ_ENUM_ENT(CompileSym3, MSILModule), - LLVM_READOBJ_ENUM_ENT(CompileSym3, Sdl), - LLVM_READOBJ_ENUM_ENT(CompileSym3, PGO), - LLVM_READOBJ_ENUM_ENT(CompileSym3, Exp), -}; - -static const EnumEntry SourceLanguages[] = { - LLVM_READOBJ_ENUM_ENT(SourceLanguage, C), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, Cpp), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, Fortran), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, Masm), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, Pascal), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, Basic), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, Cobol), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, Link), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, Cvtres), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, Cvtpgd), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, CSharp), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, VB), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, ILAsm), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, Java), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, JScript), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, MSIL), - LLVM_READOBJ_ENUM_ENT(SourceLanguage, HLSL), -}; - static const EnumEntry SubSectionTypes[] = { LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, Symbols), LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, Lines), @@ -477,302 +503,12 @@ static const EnumEntry SubSectionTypes[] = { LLVM_READOBJ_ENUM_CLASS_ENT(ModuleSubstreamKind, CoffSymbolRVA), }; -static const EnumEntry CPUTypeNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Intel8080), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Intel8086), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Intel80286), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Intel80386), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Intel80486), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Pentium), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PentiumPro), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Pentium3), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPS), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPS16), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPS32), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPS64), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPSI), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPSII), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPSIII), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPSIV), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, MIPSV), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M68000), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M68010), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M68020), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M68030), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M68040), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Alpha), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Alpha21164), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Alpha21164A), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Alpha21264), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Alpha21364), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPC601), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPC603), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPC604), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPC620), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPCFP), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, PPCBE), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, SH3), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, SH3E), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, SH3DSP), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, SH4), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, SHMedia), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM3), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM4), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM4T), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM5), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM5T), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM6), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM_XMAC), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM_WMMX), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARM7), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Omni), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Ia64), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Ia64_2), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, CEE), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, AM33), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, M32R), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, TriCore), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, X64), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, EBC), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, Thumb), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, ARMNT), - LLVM_READOBJ_ENUM_CLASS_ENT(CPUType, D3D11_Shader), -}; - -static const EnumEntry ProcSymFlags[] = { - LLVM_READOBJ_ENUM_ENT(ProcFlags, HasFP), - LLVM_READOBJ_ENUM_ENT(ProcFlags, HasIRET), - LLVM_READOBJ_ENUM_ENT(ProcFlags, HasFRET), - LLVM_READOBJ_ENUM_ENT(ProcFlags, IsNoReturn), - LLVM_READOBJ_ENUM_ENT(ProcFlags, IsUnreachable), - LLVM_READOBJ_ENUM_ENT(ProcFlags, HasCustomCallingConv), - LLVM_READOBJ_ENUM_ENT(ProcFlags, IsNoInline), - LLVM_READOBJ_ENUM_ENT(ProcFlags, HasOptimizedDebugInfo), -}; - -static const EnumEntry FrameProcSymFlags[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, HasAlloca), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, HasSetJmp), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, HasLongJmp), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, HasInlineAssembly), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, HasExceptionHandling), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, MarkedInline), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, - HasStructuredExceptionHandling), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, Naked), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, SecurityChecks), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, - AsynchronousExceptionHandling), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, - NoStackOrderingForSecurityChecks), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, Inlined), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, StrictSecurityChecks), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, SafeBuffers), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, - ProfileGuidedOptimization), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, ValidProfileCounts), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, OptimizedForSpeed), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfg), - LLVM_READOBJ_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfw), -}; - static const EnumEntry FrameDataFlags[] = { LLVM_READOBJ_ENUM_ENT(FrameData, HasSEH), LLVM_READOBJ_ENUM_ENT(FrameData, HasEH), LLVM_READOBJ_ENUM_ENT(FrameData, IsFunctionStart), }; -static const EnumEntry LocalFlags[] = { - LLVM_READOBJ_ENUM_ENT(LocalSym, IsParameter), - LLVM_READOBJ_ENUM_ENT(LocalSym, IsAddressTaken), - LLVM_READOBJ_ENUM_ENT(LocalSym, IsCompilerGenerated), - LLVM_READOBJ_ENUM_ENT(LocalSym, IsAggregate), - LLVM_READOBJ_ENUM_ENT(LocalSym, IsAggregated), - LLVM_READOBJ_ENUM_ENT(LocalSym, IsAliased), - LLVM_READOBJ_ENUM_ENT(LocalSym, IsAlias), - LLVM_READOBJ_ENUM_ENT(LocalSym, IsReturnValue), - LLVM_READOBJ_ENUM_ENT(LocalSym, IsOptimizedOut), - LLVM_READOBJ_ENUM_ENT(LocalSym, IsEnregisteredGlobal), - LLVM_READOBJ_ENUM_ENT(LocalSym, IsEnregisteredStatic), -}; - -static const EnumEntry FrameCookieKinds[] = { - LLVM_READOBJ_ENUM_ENT(FrameCookieSym, Copy), - LLVM_READOBJ_ENUM_ENT(FrameCookieSym, XorStackPointer), - LLVM_READOBJ_ENUM_ENT(FrameCookieSym, XorFramePointer), - LLVM_READOBJ_ENUM_ENT(FrameCookieSym, XorR13), -}; - -static const EnumEntry ClassOptionNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Packed), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasConstructorOrDestructor), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasOverloadedOperator), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Nested), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, ContainsNestedClass), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasOverloadedAssignmentOperator), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasConversionOperator), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, ForwardReference), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Scoped), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, HasUniqueName), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Sealed), - LLVM_READOBJ_ENUM_CLASS_ENT(ClassOptions, Intrinsic), -}; - -static const EnumEntry MemberAccessNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, None), - LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, Private), - LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, Protected), - LLVM_READOBJ_ENUM_CLASS_ENT(MemberAccess, Public), -}; - -static const EnumEntry MethodOptionNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(MethodOptions, Pseudo), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodOptions, NoInherit), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodOptions, NoConstruct), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodOptions, CompilerGenerated), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodOptions, Sealed), -}; - -static const EnumEntry MemberKindNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Vanilla), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Virtual), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Static), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, Friend), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, IntroducingVirtual), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, PureVirtual), - LLVM_READOBJ_ENUM_CLASS_ENT(MethodKind, PureIntroducingVirtual), -}; - -/// The names here all end in "*". If the simple type is a pointer type, we -/// return the whole name. Otherwise we lop off the last character in our -/// StringRef. -static const EnumEntry SimpleTypeNames[] = { - {"void*", SimpleTypeKind::Void}, - {"*", SimpleTypeKind::NotTranslated}, - {"HRESULT*", SimpleTypeKind::HResult}, - {"signed char*", SimpleTypeKind::SignedCharacter}, - {"unsigned char*", SimpleTypeKind::UnsignedCharacter}, - {"char*", SimpleTypeKind::NarrowCharacter}, - {"wchar_t*", SimpleTypeKind::WideCharacter}, - {"__int8*", SimpleTypeKind::SByte}, - {"unsigned __int8*", SimpleTypeKind::Byte}, - {"short*", SimpleTypeKind::Int16Short}, - {"unsigned short*", SimpleTypeKind::UInt16Short}, - {"__int16*", SimpleTypeKind::Int16}, - {"unsigned __int16*", SimpleTypeKind::UInt16}, - {"long*", SimpleTypeKind::Int32Long}, - {"unsigned long*", SimpleTypeKind::UInt32Long}, - {"int*", SimpleTypeKind::Int32}, - {"unsigned*", SimpleTypeKind::UInt32}, - {"__int64*", SimpleTypeKind::Int64Quad}, - {"unsigned __int64*", SimpleTypeKind::UInt64Quad}, - {"__int64*", SimpleTypeKind::Int64}, - {"unsigned __int64*", SimpleTypeKind::UInt64}, - {"__int128*", SimpleTypeKind::Int128}, - {"unsigned __int128*", SimpleTypeKind::UInt128}, - {"__half*", SimpleTypeKind::Float16}, - {"float*", SimpleTypeKind::Float32}, - {"float*", SimpleTypeKind::Float32PartialPrecision}, - {"__float48*", SimpleTypeKind::Float48}, - {"double*", SimpleTypeKind::Float64}, - {"long double*", SimpleTypeKind::Float80}, - {"__float128*", SimpleTypeKind::Float128}, - {"_Complex float*", SimpleTypeKind::Complex32}, - {"_Complex double*", SimpleTypeKind::Complex64}, - {"_Complex long double*", SimpleTypeKind::Complex80}, - {"_Complex __float128*", SimpleTypeKind::Complex128}, - {"bool*", SimpleTypeKind::Boolean8}, - {"__bool16*", SimpleTypeKind::Boolean16}, - {"__bool32*", SimpleTypeKind::Boolean32}, - {"__bool64*", SimpleTypeKind::Boolean64}, -}; - -static const EnumEntry LeafTypeNames[] = { -#define LEAF_TYPE(name, val) LLVM_READOBJ_ENUM_ENT(TypeLeafKind, name), -#include "llvm/DebugInfo/CodeView/CVLeafTypes.def" -}; - -static const EnumEntry PtrKindNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Near16), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Far16), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Huge16), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnSegment), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnValue), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnSegmentValue), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnAddress), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnSegmentAddress), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnType), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, BasedOnSelf), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Near32), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Far32), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerKind, Near64), -}; - -static const EnumEntry PtrModeNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(PointerMode, Pointer), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerMode, LValueReference), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerMode, PointerToDataMember), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerMode, PointerToMemberFunction), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerMode, RValueReference), -}; - -static const EnumEntry PtrMemberRepNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, Unknown), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - SingleInheritanceData), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - MultipleInheritanceData), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - VirtualInheritanceData), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, GeneralData), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - SingleInheritanceFunction), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - MultipleInheritanceFunction), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, - VirtualInheritanceFunction), - LLVM_READOBJ_ENUM_CLASS_ENT(PointerToMemberRepresentation, GeneralFunction), -}; - -static const EnumEntry TypeModifierNames[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(ModifierOptions, Const), - LLVM_READOBJ_ENUM_CLASS_ENT(ModifierOptions, Volatile), - LLVM_READOBJ_ENUM_CLASS_ENT(ModifierOptions, Unaligned), -}; - -static const EnumEntry CallingConventions[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearC), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarC), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearPascal), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarPascal), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearFast), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarFast), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearStdCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarStdCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearSysCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, FarSysCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, ThisCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, MipsCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, Generic), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, AlphaCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, PpcCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, SHCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, ArmCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, AM33Call), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, TriCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, SH5Call), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, M32RCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, ClrCall), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, Inline), - LLVM_READOBJ_ENUM_CLASS_ENT(CallingConvention, NearVector), -}; - -static const EnumEntry FunctionOptionEnum[] = { - LLVM_READOBJ_ENUM_CLASS_ENT(FunctionOptions, CxxReturnUdt), - LLVM_READOBJ_ENUM_CLASS_ENT(FunctionOptions, Constructor), - LLVM_READOBJ_ENUM_CLASS_ENT(FunctionOptions, ConstructorWithVirtualBases), -}; - static const EnumEntry FileChecksumKindNames[] = { LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, None), LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, MD5), @@ -912,8 +648,42 @@ void COFFDumper::printPEHeader(const PEHeader *Hdr) { "DelayImportDescriptor", "CLRRuntimeHeader", "Reserved" }; - for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) { + for (uint32_t i = 0; i < Hdr->NumberOfRvaAndSize; ++i) printDataDirectory(i, directory[i]); + } +} + +void COFFDumper::printCOFFDebugDirectory() { + ListScope LS(W, "DebugDirectory"); + for (const debug_directory &D : Obj->debug_directories()) { + char FormattedTime[20] = {}; + time_t TDS = D.TimeDateStamp; + strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS)); + DictScope S(W, "DebugEntry"); + W.printHex("Characteristics", D.Characteristics); + W.printHex("TimeDateStamp", FormattedTime, D.TimeDateStamp); + W.printHex("MajorVersion", D.MajorVersion); + W.printHex("MinorVersion", D.MinorVersion); + W.printEnum("Type", D.Type, makeArrayRef(ImageDebugType)); + W.printHex("SizeOfData", D.SizeOfData); + W.printHex("AddressOfRawData", D.AddressOfRawData); + W.printHex("PointerToRawData", D.PointerToRawData); + if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW) { + const debug_pdb_info *PDBInfo; + StringRef PDBFileName; + error(Obj->getDebugPDBInfo(&D, PDBInfo, PDBFileName)); + DictScope PDBScope(W, "PDBInfo"); + W.printHex("PDBSignature", PDBInfo->Signature); + W.printBinary("PDBGUID", makeArrayRef(PDBInfo->Guid)); + W.printNumber("PDBAge", PDBInfo->Age); + W.printString("PDBFileName", PDBFileName); + } else { + // FIXME: Type values of 12 and 13 are commonly observed but are not in + // the documented type enum. Figure out what they mean. + ArrayRef RawData; + error( + Obj->getRvaAndSizeAsBytes(D.AddressOfRawData, D.SizeOfData, RawData)); + W.printBinaryBlock("RawData", RawData); } } } @@ -940,34 +710,14 @@ void COFFDumper::printCodeViewDebugInfo() { } } -/// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if -/// there are not enough bytes remaining. Reinterprets the consumed bytes as a -/// T object and points 'Res' at them. -template -static std::error_code consumeObject(StringRef &Data, const T *&Res) { - if (Data.size() < sizeof(*Res)) - return object_error::parse_failed; - Res = reinterpret_cast(Data.data()); - Data = Data.drop_front(sizeof(*Res)); - return std::error_code(); -} - -static std::error_code consumeUInt32(StringRef &Data, uint32_t &Res) { - const ulittle32_t *IntPtr; - if (auto EC = consumeObject(Data, IntPtr)) - return EC; - Res = *IntPtr; - return std::error_code(); -} - void COFFDumper::initializeFileAndStringTables(StringRef Data) { while (!Data.empty() && (CVFileChecksumTable.data() == nullptr || CVStringTable.data() == nullptr)) { // The section consists of a number of subsection in the following format: // |SubSectionType|SubSectionSize|Contents...| uint32_t SubType, SubSectionSize; - error(consumeUInt32(Data, SubType)); - error(consumeUInt32(Data, SubSectionSize)); + error(consume(Data, SubType)); + error(consume(Data, SubSectionSize)); if (SubSectionSize > Data.size()) return error(object_error::parse_failed); switch (ModuleSubstreamKind(SubType)) { @@ -980,7 +730,10 @@ void COFFDumper::initializeFileAndStringTables(StringRef Data) { default: break; } - Data = Data.drop_front(alignTo(SubSectionSize, 4)); + uint32_t PaddedSize = alignTo(SubSectionSize, 4); + if (PaddedSize > Data.size()) + error(object_error::parse_failed); + Data = Data.drop_front(PaddedSize); } } @@ -998,19 +751,20 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, W.printNumber("Section", SectionName, Obj->getSectionID(Section)); uint32_t Magic; - error(consumeUInt32(Data, Magic)); + error(consume(Data, Magic)); W.printHex("Magic", Magic); if (Magic != COFF::DEBUG_SECTION_MAGIC) return error(object_error::parse_failed); initializeFileAndStringTables(Data); + // TODO: Convert this over to using ModuleSubstreamVisitor. while (!Data.empty()) { // The section consists of a number of subsection in the following format: // |SubSectionType|SubSectionSize|Contents...| uint32_t SubType, SubSectionSize; - error(consumeUInt32(Data, SubType)); - error(consumeUInt32(Data, SubSectionSize)); + error(consume(Data, SubType)); + error(consume(Data, SubSectionSize)); ListScope S(W, "Subsection"); W.printEnum("SubSectionType", SubType, makeArrayRef(SubSectionTypes)); @@ -1026,6 +780,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, size_t SectionOffset = Data.data() - SectionContents.data(); size_t NextOffset = SectionOffset + SubSectionSize; NextOffset = alignTo(NextOffset, 4); + if (NextOffset > SectionContents.size()) + return error(object_error::parse_failed); Data = SectionContents.drop_front(NextOffset); // Optionally print the subsection bytes in case our parsing gets confused @@ -1087,14 +843,20 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, while (!Contents.empty()) { const FrameData *FD; error(consumeObject(Contents, FD)); + + if (FD->FrameFunc >= CVStringTable.size()) + error(object_error::parse_failed); + + StringRef FrameFunc = + CVStringTable.drop_front(FD->FrameFunc).split('\0').first; + DictScope S(W, "FrameData"); W.printHex("RvaStart", FD->RvaStart); W.printHex("CodeSize", FD->CodeSize); W.printHex("LocalSize", FD->LocalSize); W.printHex("ParamsSize", FD->ParamsSize); W.printHex("MaxStackSize", FD->MaxStackSize); - W.printString("FrameFunc", - CVStringTable.drop_front(FD->FrameFunc).split('\0').first); + W.printString("FrameFunc", FrameFunc); W.printHex("PrologSize", FD->PrologSize); W.printHex("SavedRegsSize", FD->SavedRegsSize); W.printFlags("Flags", FD->Flags, makeArrayRef(FrameDataFlags)); @@ -1182,616 +944,27 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, } } -static std::error_code decodeNumerictLeaf(StringRef &Data, APSInt &Num) { - // Used to avoid overload ambiguity on APInt construtor. - bool FalseVal = false; - if (Data.size() < 2) - return object_error::parse_failed; - uint16_t Short = *reinterpret_cast(Data.data()); - Data = Data.drop_front(2); - if (Short < LF_NUMERIC) { - Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false), - /*isUnsigned=*/true); - return std::error_code(); - } - switch (Short) { - case LF_CHAR: - Num = APSInt(APInt(/*numBits=*/8, - *reinterpret_cast(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(1); - return std::error_code(); - case LF_SHORT: - Num = APSInt(APInt(/*numBits=*/16, - *reinterpret_cast(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(2); - return std::error_code(); - case LF_USHORT: - Num = APSInt(APInt(/*numBits=*/16, - *reinterpret_cast(Data.data()), - /*isSigned=*/false), - /*isUnsigned=*/true); - Data = Data.drop_front(2); - return std::error_code(); - case LF_LONG: - Num = APSInt(APInt(/*numBits=*/32, - *reinterpret_cast(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(4); - return std::error_code(); - case LF_ULONG: - Num = APSInt(APInt(/*numBits=*/32, - *reinterpret_cast(Data.data()), - /*isSigned=*/FalseVal), - /*isUnsigned=*/true); - Data = Data.drop_front(4); - return std::error_code(); - case LF_QUADWORD: - Num = APSInt(APInt(/*numBits=*/64, - *reinterpret_cast(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(8); - return std::error_code(); - case LF_UQUADWORD: - Num = APSInt(APInt(/*numBits=*/64, - *reinterpret_cast(Data.data()), - /*isSigned=*/false), - /*isUnsigned=*/true); - Data = Data.drop_front(8); - return std::error_code(); - } - return object_error::parse_failed; -} - -/// Decode an unsigned integer numeric leaf value. -std::error_code decodeUIntLeaf(StringRef &Data, uint64_t &Num) { - APSInt N; - if (std::error_code err = decodeNumerictLeaf(Data, N)) - return err; - if (N.isSigned() || !N.isIntN(64)) - return object_error::parse_failed; - Num = N.getLimitedValue(); - return std::error_code(); -} - void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, const SectionRef &Section, StringRef SectionContents) { - if (Subsection.size() < sizeof(SymRecord)) - return error(object_error::parse_failed); - - const coff_section *Sec = Obj->getCOFFSection(Section); - - // This holds the remaining data to parse. - StringRef Data = Subsection; - - bool InFunctionScope = false; - while (!Data.empty()) { - const SymRecord *Rec; - error(consumeObject(Data, Rec)); - - StringRef SymData = Data.substr(0, Rec->RecordLength - 2); - StringRef OrigSymData = SymData; - - Data = Data.drop_front(Rec->RecordLength - 2); - - SymbolRecordKind Kind = Rec->getKind(); - switch (Kind) { - case S_LPROC32: - case S_GPROC32: - case S_GPROC32_ID: - case S_LPROC32_ID: - case S_LPROC32_DPC: - case S_LPROC32_DPC_ID: { - DictScope S(W, "ProcStart"); - const ProcSym *Proc; - error(consumeObject(SymData, Proc)); - if (InFunctionScope) - return error(object_error::parse_failed); - InFunctionScope = true; - - StringRef LinkageName; - StringRef DisplayName = SymData.split('\0').first; - W.printHex("PtrParent", Proc->PtrParent); - W.printHex("PtrEnd", Proc->PtrEnd); - W.printHex("PtrNext", Proc->PtrNext); - W.printHex("CodeSize", Proc->CodeSize); - W.printHex("DbgStart", Proc->DbgStart); - W.printHex("DbgEnd", Proc->DbgEnd); - printTypeIndex("FunctionType", Proc->FunctionType); - printRelocatedField("CodeOffset", Sec, SectionContents, &Proc->CodeOffset, - &LinkageName); - W.printHex("Segment", Proc->Segment); - W.printFlags("Flags", Proc->Flags, makeArrayRef(ProcSymFlags)); - W.printString("DisplayName", DisplayName); - W.printString("LinkageName", LinkageName); - break; - } - - case S_PROC_ID_END: { - W.startLine() << "ProcEnd\n"; - InFunctionScope = false; - break; - } - - case S_BLOCK32: { - DictScope S(W, "BlockStart"); - const BlockSym *Block; - error(consumeObject(SymData, Block)); - - StringRef BlockName = SymData.split('\0').first; - StringRef LinkageName; - W.printHex("PtrParent", Block->PtrParent); - W.printHex("PtrEnd", Block->PtrEnd); - W.printHex("CodeSize", Block->CodeSize); - printRelocatedField("CodeOffset", Sec, SectionContents, - &Block->CodeOffset, &LinkageName); - W.printHex("Segment", Block->Segment); - W.printString("BlockName", BlockName); - W.printString("LinkageName", LinkageName); - break; - } - - case S_END: { - W.startLine() << "BlockEnd\n"; - InFunctionScope = false; - break; - } - - case S_LABEL32: { - DictScope S(W, "Label"); - const LabelSym *Label; - error(consumeObject(SymData, Label)); - - StringRef DisplayName = SymData.split('\0').first; - StringRef LinkageName; - printRelocatedField("CodeOffset", Sec, SectionContents, - &Label->CodeOffset, &LinkageName); - W.printHex("Segment", Label->Segment); - W.printHex("Flags", Label->Flags); - W.printFlags("Flags", Label->Flags, makeArrayRef(ProcSymFlags)); - W.printString("DisplayName", DisplayName); - W.printString("LinkageName", LinkageName); - break; - } - - case S_INLINESITE: { - DictScope S(W, "InlineSite"); - const InlineSiteSym *InlineSite; - error(consumeObject(SymData, InlineSite)); - W.printHex("PtrParent", InlineSite->PtrParent); - W.printHex("PtrEnd", InlineSite->PtrEnd); - printTypeIndex("Inlinee", InlineSite->Inlinee); - - auto GetCompressedAnnotation = [&]() -> uint32_t { - if (SymData.empty()) - return -1; - - uint8_t FirstByte = SymData.front(); - SymData = SymData.drop_front(); - - if ((FirstByte & 0x80) == 0x00) - return FirstByte; - - if (SymData.empty()) - return -1; - - uint8_t SecondByte = SymData.front(); - SymData = SymData.drop_front(); - - if ((FirstByte & 0xC0) == 0x80) - return ((FirstByte & 0x3F) << 8) | SecondByte; - - if (SymData.empty()) - return -1; - - uint8_t ThirdByte = SymData.front(); - SymData = SymData.drop_front(); - - if (SymData.empty()) - return -1; - - uint8_t FourthByte = SymData.front(); - SymData = SymData.drop_front(); - - if ((FirstByte & 0xE0) == 0xC0) - return ((FirstByte & 0x1F) << 24) | (SecondByte << 16) | - (ThirdByte << 8) | FourthByte; - - return -1; - }; - auto DecodeSignedOperand = [](uint32_t Operand) -> int32_t { - if (Operand & 1) - return -(Operand >> 1); - return Operand >> 1; - }; - - ListScope BinaryAnnotations(W, "BinaryAnnotations"); - while (!SymData.empty()) { - uint32_t OpCode = GetCompressedAnnotation(); - switch (OpCode) { - default: - case Invalid: - return error(object_error::parse_failed); - case CodeOffset: - W.printHex("CodeOffset", GetCompressedAnnotation()); - break; - case ChangeCodeOffsetBase: - W.printNumber("ChangeCodeOffsetBase", GetCompressedAnnotation()); - break; - case ChangeCodeOffset: - W.printHex("ChangeCodeOffset", GetCompressedAnnotation()); - break; - case ChangeCodeLength: - W.printHex("ChangeCodeLength", GetCompressedAnnotation()); - break; - case ChangeFile: - printFileNameForOffset("ChangeFile", GetCompressedAnnotation()); - break; - case ChangeLineOffset: - W.printNumber("ChangeLineOffset", - DecodeSignedOperand(GetCompressedAnnotation())); - break; - case ChangeLineEndDelta: - W.printNumber("ChangeLineEndDelta", GetCompressedAnnotation()); - break; - case ChangeRangeKind: - W.printNumber("ChangeRangeKind", GetCompressedAnnotation()); - break; - case ChangeColumnStart: - W.printNumber("ChangeColumnStart", GetCompressedAnnotation()); - break; - case ChangeColumnEndDelta: - W.printNumber("ChangeColumnEndDelta", - DecodeSignedOperand(GetCompressedAnnotation())); - break; - case ChangeCodeOffsetAndLineOffset: { - uint32_t Annotation = GetCompressedAnnotation(); - int32_t LineOffset = DecodeSignedOperand(Annotation >> 4); - uint32_t CodeOffset = Annotation & 0xf; - W.startLine() << "ChangeCodeOffsetAndLineOffset: {CodeOffset: " - << W.hex(CodeOffset) << ", LineOffset: " << LineOffset - << "}\n"; - break; - } - case ChangeCodeLengthAndCodeOffset: { - uint32_t Length = GetCompressedAnnotation(); - uint32_t CodeOffset = GetCompressedAnnotation(); - W.startLine() << "ChangeCodeLengthAndCodeOffset: {CodeOffset: " - << W.hex(CodeOffset) << ", Length: " << W.hex(Length) - << "}\n"; - break; - } - case ChangeColumnEnd: - W.printNumber("ChangeColumnEnd", GetCompressedAnnotation()); - break; - } - } - break; - } - - case S_INLINESITE_END: { - DictScope S(W, "InlineSiteEnd"); - break; - } - - case S_CALLERS: - case S_CALLEES: { - ListScope S(W, Kind == S_CALLEES ? "Callees" : "Callers"); - uint32_t Count; - error(consumeUInt32(SymData, Count)); - for (uint32_t I = 0; I < Count; ++I) { - const TypeIndex *FuncID; - error(consumeObject(SymData, FuncID)); - printTypeIndex("FuncID", *FuncID); - } - break; - } - - case S_LOCAL: { - DictScope S(W, "Local"); - const LocalSym *Local; - error(consumeObject(SymData, Local)); - printTypeIndex("Type", Local->Type); - W.printFlags("Flags", uint16_t(Local->Flags), makeArrayRef(LocalFlags)); - StringRef VarName = SymData.split('\0').first; - W.printString("VarName", VarName); - break; - } - - case S_DEFRANGE: { - DictScope S(W, "DefRange"); - const DefRangeSym *DefRange; - error(consumeObject(SymData, DefRange)); - W.printString( - "Program", - CVStringTable.drop_front(DefRange->Program).split('\0').first); - printLocalVariableAddrRange(DefRange->Range, Sec, SectionContents); - printLocalVariableAddrGap(SymData); - break; - } - case S_DEFRANGE_SUBFIELD: { - DictScope S(W, "DefRangeSubfield"); - const DefRangeSubfieldSym *DefRangeSubfield; - error(consumeObject(SymData, DefRangeSubfield)); - W.printString("Program", - CVStringTable.drop_front(DefRangeSubfield->Program) - .split('\0') - .first); - W.printNumber("OffsetInParent", DefRangeSubfield->OffsetInParent); - printLocalVariableAddrRange(DefRangeSubfield->Range, Sec, - SectionContents); - printLocalVariableAddrGap(SymData); - break; - } - case S_DEFRANGE_REGISTER: { - DictScope S(W, "DefRangeRegister"); - const DefRangeRegisterSym *DefRangeRegister; - error(consumeObject(SymData, DefRangeRegister)); - W.printNumber("Register", DefRangeRegister->Register); - W.printNumber("MayHaveNoName", DefRangeRegister->MayHaveNoName); - printLocalVariableAddrRange(DefRangeRegister->Range, Sec, - SectionContents); - printLocalVariableAddrGap(SymData); - break; - } - case S_DEFRANGE_SUBFIELD_REGISTER: { - DictScope S(W, "DefRangeSubfieldRegister"); - const DefRangeSubfieldRegisterSym *DefRangeSubfieldRegisterSym; - error(consumeObject(SymData, DefRangeSubfieldRegisterSym)); - W.printNumber("Register", DefRangeSubfieldRegisterSym->Register); - W.printNumber("MayHaveNoName", - DefRangeSubfieldRegisterSym->MayHaveNoName); - W.printNumber("OffsetInParent", - DefRangeSubfieldRegisterSym->OffsetInParent); - printLocalVariableAddrRange(DefRangeSubfieldRegisterSym->Range, Sec, - SectionContents); - printLocalVariableAddrGap(SymData); - break; - } - case S_DEFRANGE_FRAMEPOINTER_REL: { - DictScope S(W, "DefRangeFramePointerRel"); - const DefRangeFramePointerRelSym *DefRangeFramePointerRel; - error(consumeObject(SymData, DefRangeFramePointerRel)); - W.printNumber("Offset", DefRangeFramePointerRel->Offset); - printLocalVariableAddrRange(DefRangeFramePointerRel->Range, Sec, - SectionContents); - printLocalVariableAddrGap(SymData); - break; - } - case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: { - DictScope S(W, "DefRangeFramePointerRelFullScope"); - const DefRangeFramePointerRelFullScopeSym - *DefRangeFramePointerRelFullScope; - error(consumeObject(SymData, DefRangeFramePointerRelFullScope)); - W.printNumber("Offset", DefRangeFramePointerRelFullScope->Offset); - break; - } - case S_DEFRANGE_REGISTER_REL: { - DictScope S(W, "DefRangeRegisterRel"); - const DefRangeRegisterRelSym *DefRangeRegisterRel; - error(consumeObject(SymData, DefRangeRegisterRel)); - W.printNumber("BaseRegister", DefRangeRegisterRel->BaseRegister); - W.printBoolean("HasSpilledUDTMember", - DefRangeRegisterRel->hasSpilledUDTMember()); - W.printNumber("OffsetInParent", DefRangeRegisterRel->offsetInParent()); - W.printNumber("BasePointerOffset", - DefRangeRegisterRel->BasePointerOffset); - printLocalVariableAddrRange(DefRangeRegisterRel->Range, Sec, - SectionContents); - printLocalVariableAddrGap(SymData); - break; - } - - case S_CALLSITEINFO: { - DictScope S(W, "CallSiteInfo"); - const CallSiteInfoSym *CallSiteInfo; - error(consumeObject(SymData, CallSiteInfo)); - - StringRef LinkageName; - printRelocatedField("CodeOffset", Sec, SectionContents, - &CallSiteInfo->CodeOffset, &LinkageName); - W.printHex("Segment", CallSiteInfo->Segment); - W.printHex("Reserved", CallSiteInfo->Reserved); - printTypeIndex("Type", CallSiteInfo->Type); - W.printString("LinkageName", LinkageName); - break; - } - - case S_HEAPALLOCSITE: { - DictScope S(W, "HeapAllocationSite"); - const HeapAllocationSiteSym *HeapAllocationSite; - error(consumeObject(SymData, HeapAllocationSite)); - - StringRef LinkageName; - printRelocatedField("CodeOffset", Sec, SectionContents, - &HeapAllocationSite->CodeOffset, &LinkageName); - W.printHex("Segment", HeapAllocationSite->Segment); - W.printHex("CallInstructionSize", - HeapAllocationSite->CallInstructionSize); - printTypeIndex("Type", HeapAllocationSite->Type); - W.printString("LinkageName", LinkageName); - break; - } - - case S_FRAMECOOKIE: { - DictScope S(W, "FrameCookie"); - const FrameCookieSym *FrameCookie; - error(consumeObject(SymData, FrameCookie)); - - StringRef LinkageName; - printRelocatedField("CodeOffset", Sec, SectionContents, - &FrameCookie->CodeOffset, &LinkageName); - W.printHex("Register", FrameCookie->Register); - W.printEnum("CookieKind", uint16_t(FrameCookie->CookieKind), - makeArrayRef(FrameCookieKinds)); - break; - } - - case S_LDATA32: - case S_GDATA32: - case S_LMANDATA: - case S_GMANDATA: { - DictScope S(W, "DataSym"); - const DataSym *Data; - error(consumeObject(SymData, Data)); - - StringRef DisplayName = SymData.split('\0').first; - StringRef LinkageName; - printRelocatedField("DataOffset", Sec, SectionContents, &Data->DataOffset, - &LinkageName); - printTypeIndex("Type", Data->Type); - W.printString("DisplayName", DisplayName); - W.printString("LinkageName", LinkageName); - break; - } - - case S_LTHREAD32: - case S_GTHREAD32: { - DictScope S(W, "ThreadLocalDataSym"); - const ThreadLocalDataSym *Data; - error(consumeObject(SymData, Data)); - - StringRef DisplayName = SymData.split('\0').first; - StringRef LinkageName; - printRelocatedField("DataOffset", Sec, SectionContents, &Data->DataOffset, - &LinkageName); - printTypeIndex("Type", Data->Type); - W.printString("DisplayName", DisplayName); - W.printString("LinkageName", LinkageName); - break; - } - - case S_OBJNAME: { - DictScope S(W, "ObjectName"); - const ObjNameSym *ObjName; - error(consumeObject(SymData, ObjName)); - W.printHex("Signature", ObjName->Signature); - StringRef ObjectName = SymData.split('\0').first; - W.printString("ObjectName", ObjectName); - break; - } - - case S_COMPILE3: { - DictScope S(W, "CompilerFlags"); - const CompileSym3 *CompFlags; - error(consumeObject(SymData, CompFlags)); - W.printEnum("Language", CompFlags->getLanguage(), - makeArrayRef(SourceLanguages)); - W.printFlags("Flags", CompFlags->flags & ~0xff, - makeArrayRef(CompileSym3Flags)); - W.printEnum("Machine", unsigned(CompFlags->Machine), - makeArrayRef(CPUTypeNames)); - std::string FrontendVersion; - { - raw_string_ostream Out(FrontendVersion); - Out << CompFlags->VersionFrontendMajor << '.' - << CompFlags->VersionFrontendMinor << '.' - << CompFlags->VersionFrontendBuild << '.' - << CompFlags->VersionFrontendQFE; - } - std::string BackendVersion; - { - raw_string_ostream Out(BackendVersion); - Out << CompFlags->VersionBackendMajor << '.' - << CompFlags->VersionBackendMinor << '.' - << CompFlags->VersionBackendBuild << '.' - << CompFlags->VersionBackendQFE; - } - W.printString("FrontendVersion", FrontendVersion); - W.printString("BackendVersion", BackendVersion); - StringRef VersionName = SymData.split('\0').first; - W.printString("VersionName", VersionName); - break; - } - - case S_FRAMEPROC: { - DictScope S(W, "FrameProc"); - const FrameProcSym *FrameProc; - error(consumeObject(SymData, FrameProc)); - W.printHex("TotalFrameBytes", FrameProc->TotalFrameBytes); - W.printHex("PaddingFrameBytes", FrameProc->PaddingFrameBytes); - W.printHex("OffsetToPadding", FrameProc->OffsetToPadding); - W.printHex("BytesOfCalleeSavedRegisters", FrameProc->BytesOfCalleeSavedRegisters); - W.printHex("OffsetOfExceptionHandler", FrameProc->OffsetOfExceptionHandler); - W.printHex("SectionIdOfExceptionHandler", FrameProc->SectionIdOfExceptionHandler); - W.printFlags("Flags", FrameProc->Flags, makeArrayRef(FrameProcSymFlags)); - break; - } - - case S_UDT: - case S_COBOLUDT: { - DictScope S(W, "UDT"); - const UDTSym *UDT; - error(consumeObject(SymData, UDT)); - printTypeIndex("Type", UDT->Type); - StringRef UDTName = SymData.split('\0').first; - W.printString("UDTName", UDTName); - break; - } - - case S_BPREL32: { - DictScope S(W, "BPRelativeSym"); - const BPRelativeSym *BPRel; - error(consumeObject(SymData, BPRel)); - W.printNumber("Offset", BPRel->Offset); - printTypeIndex("Type", BPRel->Type); - StringRef VarName = SymData.split('\0').first; - W.printString("VarName", VarName); - break; - } - - case S_REGREL32: { - DictScope S(W, "RegRelativeSym"); - const RegRelativeSym *RegRel; - error(consumeObject(SymData, RegRel)); - W.printHex("Offset", RegRel->Offset); - printTypeIndex("Type", RegRel->Type); - W.printHex("Register", RegRel->Register); - StringRef VarName = SymData.split('\0').first; - W.printString("VarName", VarName); - break; - } - - case S_BUILDINFO: { - DictScope S(W, "BuildInfo"); - const BuildInfoSym *BuildInfo; - error(consumeObject(SymData, BuildInfo)); - W.printNumber("BuildId", BuildInfo->BuildId); - break; - } - - case S_CONSTANT: - case S_MANCONSTANT: { - DictScope S(W, "Constant"); - const ConstantSym *Constant; - error(consumeObject(SymData, Constant)); - printTypeIndex("Type", Constant->Type); - APSInt Value; - error(decodeNumerictLeaf(SymData, Value)); - W.printNumber("Value", Value); - StringRef Name = SymData.split('\0').first; - W.printString("Name", Name); - break; - } - - default: { - DictScope S(W, "UnknownSym"); - W.printHex("Kind", unsigned(Kind)); - W.printHex("Size", Rec->RecordLength); - break; - } - } + ArrayRef BinaryData(Subsection.bytes_begin(), + Subsection.bytes_end()); + auto CODD = llvm::make_unique(*this, Section, Obj, + SectionContents); + + CVSymbolDumper CVSD(W, CVTD, std::move(CODD), opts::CodeViewSubsectionBytes); + ByteStream<> Stream(BinaryData); + CVSymbolArray Symbols; + StreamReader Reader(Stream); + if (auto EC = Reader.readArray(Symbols, Reader.getLength())) { + consumeError(std::move(EC)); + W.flush(); + error(object_error::parse_failed); + } - if (opts::CodeViewSubsectionBytes) - printBinaryBlockWithRelocs("SymData", Section, SectionContents, - OrigSymData); + if (!CVSD.dump(Symbols)) { W.flush(); + error(object_error::parse_failed); } W.flush(); } @@ -1816,6 +989,8 @@ void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) { W.printBinary("ChecksumBytes", ChecksumBytes); unsigned PaddedSize = alignTo(FC->ChecksumSize + sizeof(FileChecksum), 4) - sizeof(FileChecksum); + if (PaddedSize > Data.size()) + error(object_error::parse_failed); Data = Data.drop_front(PaddedSize); } } @@ -1823,7 +998,7 @@ void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) { void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { StringRef Data = Subsection; uint32_t Signature; - error(consumeUInt32(Data, Signature)); + error(consume(Data, Signature)); bool HasExtraFiles = Signature == unsigned(InlineeLinesSignature::ExtraFiles); while (!Data.empty()) { @@ -1836,90 +1011,18 @@ void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { if (HasExtraFiles) { uint32_t ExtraFileCount; - error(consumeUInt32(Data, ExtraFileCount)); + error(consume(Data, ExtraFileCount)); W.printNumber("ExtraFileCount", ExtraFileCount); ListScope ExtraFiles(W, "ExtraFiles"); for (unsigned I = 0; I < ExtraFileCount; ++I) { uint32_t FileID; - error(consumeUInt32(Data, FileID)); + error(consume(Data, FileID)); printFileNameForOffset("FileID", FileID); } } } } -StringRef getRemainingTypeBytes(const TypeRecordPrefix *Rec, const char *Start) { - ptrdiff_t StartOffset = Start - reinterpret_cast(Rec); - size_t RecSize = Rec->Len + 2; - assert(StartOffset >= 0 && "negative start-offset!"); - assert(static_cast(StartOffset) <= RecSize && - "Start beyond the end of Rec"); - return StringRef(Start, RecSize - StartOffset); -} - -StringRef getRemainingBytesAsString(const TypeRecordPrefix *Rec, const char *Start) { - StringRef Remaining = getRemainingTypeBytes(Rec, Start); - StringRef Leading, Trailing; - std::tie(Leading, Trailing) = Remaining.split('\0'); - return Leading; -} - -StringRef COFFDumper::getTypeName(TypeIndex TI) { - if (TI.isNoType()) - return ""; - - if (TI.isSimple()) { - // This is a simple type. - for (const auto &SimpleTypeName : SimpleTypeNames) { - if (SimpleTypeName.Value == TI.getSimpleKind()) { - if (TI.getSimpleMode() == SimpleTypeMode::Direct) - return SimpleTypeName.Name.drop_back(1); - // Otherwise, this is a pointer type. We gloss over the distinction - // between near, far, 64, 32, etc, and just give a pointer type. - return SimpleTypeName.Name; - } - } - return ""; - } - - // User-defined type. - StringRef UDTName; - unsigned UDTIndex = TI.getIndex() - 0x1000; - if (UDTIndex < CVUDTNames.size()) - return CVUDTNames[UDTIndex]; - - return ""; -} - -void COFFDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { - StringRef TypeName; - if (!TI.isNoType()) - TypeName = getTypeName(TI); - if (!TypeName.empty()) - W.printHex(FieldName, TypeName, TI.getIndex()); - else - W.printHex(FieldName, TI.getIndex()); -} - -void COFFDumper::printLocalVariableAddrRange( - const LocalVariableAddrRange &Range, const coff_section *Sec, - StringRef SectionContents) { - DictScope S(W, "LocalVariableAddrRange"); - printRelocatedField("OffsetStart", Sec, SectionContents, &Range.OffsetStart); - W.printHex("ISectStart", Range.ISectStart); - W.printHex("Range", Range.Range); -} - -void COFFDumper::printLocalVariableAddrGap(StringRef &SymData) { - while (!SymData.empty()) { - const LocalVariableAddrGap *Gap; - error(consumeObject(SymData, Gap)); - ListScope S(W, "LocalVariableAddrGap"); - W.printHex("GapStartOffset", Gap->GapStartOffset); - W.printHex("Range", Gap->Range); - } -} - StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) { // The file checksum subsection should precede all references to it. if (!CVFileChecksumTable.data() || !CVStringTable.data()) @@ -1931,7 +1034,7 @@ StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) { // The string table offset comes first before the file checksum. StringRef Data = CVFileChecksumTable.drop_front(FileOffset); uint32_t StringOffset; - error(consumeUInt32(Data, StringOffset)); + error(consume(Data, StringOffset)); // Check if the string table offset is valid. if (StringOffset >= CVStringTable.size()) @@ -1945,574 +1048,53 @@ void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) { W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset); } -static StringRef getLeafTypeName(TypeLeafKind LT) { - switch (LT) { - case LF_STRING_ID: return "StringId"; - case LF_FIELDLIST: return "FieldList"; - case LF_ARGLIST: - case LF_SUBSTR_LIST: return "ArgList"; - case LF_CLASS: - case LF_STRUCTURE: - case LF_INTERFACE: return "ClassType"; - case LF_UNION: return "UnionType"; - case LF_ENUM: return "EnumType"; - case LF_ARRAY: return "ArrayType"; - case LF_VFTABLE: return "VFTableType"; - case LF_MFUNC_ID: return "MemberFuncId"; - case LF_PROCEDURE: return "ProcedureType"; - case LF_MFUNCTION: return "MemberFunctionType"; - case LF_METHODLIST: return "MethodListEntry"; - case LF_FUNC_ID: return "FuncId"; - case LF_TYPESERVER2: return "TypeServer2"; - case LF_POINTER: return "PointerType"; - case LF_MODIFIER: return "TypeModifier"; - case LF_VTSHAPE: return "VTableShape"; - case LF_UDT_SRC_LINE: return "UDTSrcLine"; - case LF_BUILDINFO: return "BuildInfo"; - default: break; +void COFFDumper::mergeCodeViewTypes(MemoryTypeTableBuilder &CVTypes) { + for (const SectionRef &S : Obj->sections()) { + StringRef SectionName; + error(S.getName(SectionName)); + if (SectionName == ".debug$T") { + StringRef Data; + error(S.getContents(Data)); + uint32_t Magic; + error(consume(Data, Magic)); + if (Magic != 4) + error(object_error::parse_failed); + ArrayRef Bytes(reinterpret_cast(Data.data()), + Data.size()); + ByteStream<> Stream(Bytes); + CVTypeArray Types; + StreamReader Reader(Stream); + if (auto EC = Reader.readArray(Types, Reader.getLength())) { + consumeError(std::move(EC)); + W.flush(); + error(object_error::parse_failed); + } + + if (!mergeTypeStreams(CVTypes, Types)) + return error(object_error::parse_failed); + } } - return "UnknownLeaf"; } void COFFDumper::printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section) { ListScope D(W, "CodeViewTypes"); W.printNumber("Section", SectionName, Obj->getSectionID(Section)); + StringRef Data; error(Section.getContents(Data)); - W.printBinaryBlock("Data", Data); + if (opts::CodeViewSubsectionBytes) + W.printBinaryBlock("Data", Data); - unsigned Magic = *reinterpret_cast(Data.data()); + uint32_t Magic; + error(consume(Data, Magic)); W.printHex("Magic", Magic); + if (Magic != COFF::DEBUG_SECTION_MAGIC) + return error(object_error::parse_failed); - Data = Data.drop_front(4); - - while (!Data.empty()) { - const TypeRecordPrefix *Rec; - error(consumeObject(Data, Rec)); - auto Leaf = static_cast(uint16_t(Rec->Leaf)); - - // This record is 'Len - 2' bytes, and the next one starts immediately - // afterwards. - StringRef LeafData = Data.substr(0, Rec->Len - 2); - StringRef RemainingData = Data.drop_front(LeafData.size()); - - // Find the name of this leaf type. - StringRef LeafName = getLeafTypeName(Leaf); - DictScope S(W, LeafName); - unsigned NextTypeIndex = 0x1000 + CVUDTNames.size(); - W.printEnum("TypeLeafKind", unsigned(Leaf), makeArrayRef(LeafTypeNames)); - W.printHex("TypeIndex", NextTypeIndex); - - // Fill this in inside the switch to get something in CVUDTNames. - StringRef Name; - - switch (Leaf) { - default: { - W.printHex("Size", Rec->Len); - break; - } - - case LF_STRING_ID: { - const StringId *String; - error(consumeObject(LeafData, String)); - W.printHex("Id", String->id.getIndex()); - StringRef StringData = getRemainingBytesAsString(Rec, LeafData.data()); - W.printString("StringData", StringData); - // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. - Name = StringData; - break; - } - - case LF_FIELDLIST: { - W.printHex("Size", Rec->Len); - // FieldList has no fixed prefix that can be described with a struct. All - // the bytes must be interpreted as more records. - printCodeViewFieldList(LeafData); - break; - } - - case LF_ARGLIST: - case LF_SUBSTR_LIST: { - const ArgList *Args; - error(consumeObject(LeafData, Args)); - W.printNumber("NumArgs", Args->NumArgs); - ListScope Arguments(W, "Arguments"); - SmallString<256> TypeName("("); - for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) { - const TypeIndex *Type; - error(consumeObject(LeafData, Type)); - printTypeIndex("ArgType", *Type); - StringRef ArgTypeName = getTypeName(*Type); - TypeName.append(ArgTypeName); - if (ArgI + 1 != Args->NumArgs) - TypeName.append(", "); - } - TypeName.push_back(')'); - Name = TypeNames.insert(TypeName).first->getKey(); - break; - } - - case LF_CLASS: - case LF_STRUCTURE: - case LF_INTERFACE: { - const ClassType *Class; - error(consumeObject(LeafData, Class)); - W.printNumber("MemberCount", Class->MemberCount); - uint16_t Props = Class->Properties; - W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); - printTypeIndex("FieldList", Class->FieldList); - printTypeIndex("DerivedFrom", Class->DerivedFrom); - printTypeIndex("VShape", Class->VShape); - uint64_t SizeOf; - error(decodeUIntLeaf(LeafData, SizeOf)); - W.printNumber("SizeOf", SizeOf); - StringRef LinkageName; - std::tie(Name, LinkageName) = LeafData.split('\0'); - W.printString("Name", Name); - if (Props & uint16_t(ClassOptions::HasUniqueName)) { - LinkageName = getRemainingBytesAsString(Rec, LinkageName.data()); - if (LinkageName.empty()) - return error(object_error::parse_failed); - W.printString("LinkageName", LinkageName); - } - break; - } - - case LF_UNION: { - const UnionType *Union; - error(consumeObject(LeafData, Union)); - W.printNumber("MemberCount", Union->MemberCount); - uint16_t Props = Union->Properties; - W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); - printTypeIndex("FieldList", Union->FieldList); - uint64_t SizeOf; - error(decodeUIntLeaf(LeafData, SizeOf)); - W.printNumber("SizeOf", SizeOf); - StringRef LinkageName; - std::tie(Name, LinkageName) = LeafData.split('\0'); - W.printString("Name", Name); - if (Props & uint16_t(ClassOptions::HasUniqueName)) { - LinkageName = getRemainingBytesAsString(Rec, LinkageName.data()); - if (LinkageName.empty()) - return error(object_error::parse_failed); - W.printString("LinkageName", LinkageName); - } - break; - } - - case LF_ENUM: { - const EnumType *Enum; - error(consumeObject(LeafData, Enum)); - W.printNumber("NumEnumerators", Enum->NumEnumerators); - W.printFlags("Properties", uint16_t(Enum->Properties), - makeArrayRef(ClassOptionNames)); - printTypeIndex("UnderlyingType", Enum->UnderlyingType); - printTypeIndex("FieldListType", Enum->FieldListType); - Name = LeafData.split('\0').first; - W.printString("Name", Name); - break; - } - - case LF_ARRAY: { - const ArrayType *AT; - error(consumeObject(LeafData, AT)); - printTypeIndex("ElementType", AT->ElementType); - printTypeIndex("IndexType", AT->IndexType); - uint64_t SizeOf; - error(decodeUIntLeaf(LeafData, SizeOf)); - W.printNumber("SizeOf", SizeOf); - Name = LeafData.split('\0').first; - W.printString("Name", Name); - break; - } - - case LF_VFTABLE: { - const VFTableType *VFT; - error(consumeObject(LeafData, VFT)); - printTypeIndex("CompleteClass", VFT->CompleteClass); - printTypeIndex("OverriddenVFTable", VFT->OverriddenVFTable); - W.printHex("VFPtrOffset", VFT->VFPtrOffset); - StringRef NamesData = LeafData.substr(0, VFT->NamesLen); - std::tie(Name, NamesData) = NamesData.split('\0'); - W.printString("VFTableName", Name); - while (!NamesData.empty()) { - StringRef MethodName; - std::tie(MethodName, NamesData) = NamesData.split('\0'); - W.printString("MethodName", MethodName); - } - break; - } - - case LF_MFUNC_ID: { - const MemberFuncId *Id; - error(consumeObject(LeafData, Id)); - printTypeIndex("ClassType", Id->ClassType); - printTypeIndex("FunctionType", Id->FunctionType); - Name = LeafData.split('\0').first; - W.printString("Name", Name); - break; - } - - case LF_PROCEDURE: { - const ProcedureType *Proc; - error(consumeObject(LeafData, Proc)); - printTypeIndex("ReturnType", Proc->ReturnType); - W.printEnum("CallingConvention", uint8_t(Proc->CallConv), - makeArrayRef(CallingConventions)); - W.printFlags("FunctionOptions", uint8_t(Proc->Options), - makeArrayRef(FunctionOptionEnum)); - W.printNumber("NumParameters", Proc->NumParameters); - printTypeIndex("ArgListType", Proc->ArgListType); - - StringRef ReturnTypeName = getTypeName(Proc->ReturnType); - StringRef ArgListTypeName = getTypeName(Proc->ArgListType); - SmallString<256> TypeName(ReturnTypeName); - TypeName.push_back(' '); - TypeName.append(ArgListTypeName); - Name = TypeNames.insert(TypeName).first->getKey(); - break; - } - - case LF_MFUNCTION: { - const MemberFunctionType *MemberFunc; - error(consumeObject(LeafData, MemberFunc)); - printTypeIndex("ReturnType", MemberFunc->ReturnType); - printTypeIndex("ClassType", MemberFunc->ClassType); - printTypeIndex("ThisType", MemberFunc->ThisType); - W.printEnum("CallingConvention", uint8_t(MemberFunc->CallConv), - makeArrayRef(CallingConventions)); - W.printFlags("FunctionOptions", uint8_t(MemberFunc->Options), - makeArrayRef(FunctionOptionEnum)); - W.printNumber("NumParameters", MemberFunc->NumParameters); - printTypeIndex("ArgListType", MemberFunc->ArgListType); - W.printNumber("ThisAdjustment", MemberFunc->ThisAdjustment); - - StringRef ReturnTypeName = getTypeName(MemberFunc->ReturnType); - StringRef ClassTypeName = getTypeName(MemberFunc->ClassType); - StringRef ArgListTypeName = getTypeName(MemberFunc->ArgListType); - SmallString<256> TypeName(ReturnTypeName); - TypeName.push_back(' '); - TypeName.append(ClassTypeName); - TypeName.append("::"); - TypeName.append(ArgListTypeName); - Name = TypeNames.insert(TypeName).first->getKey(); - break; - } - - case LF_METHODLIST: { - while (!LeafData.empty()) { - const MethodListEntry *Method; - error(consumeObject(LeafData, Method)); - ListScope S(W, "Method"); - printMemberAttributes(Method->Attrs); - printTypeIndex("Type", Method->Type); - if (Method->isIntroducedVirtual()) { - const little32_t *VFTOffsetPtr; - error(consumeObject(LeafData, VFTOffsetPtr)); - W.printHex("VFTableOffset", *VFTOffsetPtr); - } - } - break; - } - - case LF_FUNC_ID: { - const FuncId *Func; - error(consumeObject(LeafData, Func)); - printTypeIndex("ParentScope", Func->ParentScope); - printTypeIndex("FunctionType", Func->FunctionType); - StringRef Null; - std::tie(Name, Null) = LeafData.split('\0'); - W.printString("Name", Name); - break; - } - - case LF_TYPESERVER2: { - const TypeServer2 *TypeServer; - error(consumeObject(LeafData, TypeServer)); - W.printBinary("Signature", StringRef(TypeServer->Signature, 16)); - W.printNumber("Age", TypeServer->Age); - Name = LeafData.split('\0').first; - W.printString("Name", Name); - break; - } - - case LF_POINTER: { - const PointerType *Ptr; - error(consumeObject(LeafData, Ptr)); - printTypeIndex("PointeeType", Ptr->PointeeType); - W.printHex("PointerAttributes", Ptr->Attrs); - W.printEnum("PtrType", unsigned(Ptr->getPtrKind()), - makeArrayRef(PtrKindNames)); - W.printEnum("PtrMode", unsigned(Ptr->getPtrMode()), - makeArrayRef(PtrModeNames)); - W.printNumber("IsFlat", Ptr->isFlat()); - W.printNumber("IsConst", Ptr->isConst()); - W.printNumber("IsVolatile", Ptr->isVolatile()); - W.printNumber("IsUnaligned", Ptr->isUnaligned()); - - if (Ptr->isPointerToMember()) { - const PointerToMemberTail *PMT; - error(consumeObject(LeafData, PMT)); - printTypeIndex("ClassType", PMT->ClassType); - W.printEnum("Representation", PMT->Representation, - makeArrayRef(PtrMemberRepNames)); - - StringRef PointeeName = getTypeName(Ptr->PointeeType); - StringRef ClassName = getTypeName(PMT->ClassType); - SmallString<256> TypeName(PointeeName); - TypeName.push_back(' '); - TypeName.append(ClassName); - TypeName.append("::*"); - Name = TypeNames.insert(TypeName).first->getKey(); - } else { - W.printBinaryBlock("TailData", LeafData); - - SmallString<256> TypeName; - if (Ptr->isConst()) - TypeName.append("const "); - if (Ptr->isVolatile()) - TypeName.append("volatile "); - if (Ptr->isUnaligned()) - TypeName.append("__unaligned "); - - TypeName.append(getTypeName(Ptr->PointeeType)); - - if (Ptr->getPtrMode() == PointerMode::LValueReference) - TypeName.append("&"); - else if (Ptr->getPtrMode() == PointerMode::RValueReference) - TypeName.append("&&"); - else if (Ptr->getPtrMode() == PointerMode::Pointer) - TypeName.append("*"); - - Name = TypeNames.insert(TypeName).first->getKey(); - } - break; - } - - case LF_MODIFIER: { - const TypeModifier *Mod; - error(consumeObject(LeafData, Mod)); - printTypeIndex("ModifiedType", Mod->ModifiedType); - W.printFlags("Modifiers", Mod->Modifiers, - makeArrayRef(TypeModifierNames)); - - StringRef ModifiedName = getTypeName(Mod->ModifiedType); - SmallString<256> TypeName; - if (Mod->Modifiers & uint16_t(ModifierOptions::Const)) - TypeName.append("const "); - if (Mod->Modifiers & uint16_t(ModifierOptions::Volatile)) - TypeName.append("volatile "); - if (Mod->Modifiers & uint16_t(ModifierOptions::Unaligned)) - TypeName.append("__unaligned "); - TypeName.append(ModifiedName); - Name = TypeNames.insert(TypeName).first->getKey(); - break; - } - - case LF_VTSHAPE: { - const VTableShape *Shape; - error(consumeObject(LeafData, Shape)); - unsigned VFEntryCount = Shape->VFEntryCount; - W.printNumber("VFEntryCount", VFEntryCount); - // We could print out whether the methods are near or far, but in practice - // today everything is CV_VTS_near32, so it's just noise. - break; - } - - case LF_UDT_SRC_LINE: { - const UDTSrcLine *Line; - error(consumeObject(LeafData, Line)); - printTypeIndex("UDT", Line->UDT); - printTypeIndex("SourceFile", Line->SourceFile); - W.printNumber("LineNumber", Line->LineNumber); - break; - } - - case LF_BUILDINFO: { - const BuildInfo *Args; - error(consumeObject(LeafData, Args)); - W.printNumber("NumArgs", Args->NumArgs); - - ListScope Arguments(W, "Arguments"); - for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) { - const TypeIndex *Type; - error(consumeObject(LeafData, Type)); - printTypeIndex("ArgType", *Type); - } - break; - } - } - - if (opts::CodeViewSubsectionBytes) - W.printBinaryBlock("LeafData", LeafData); - - CVUDTNames.push_back(Name); - - Data = RemainingData; - // FIXME: The stream contains LF_PAD bytes that we need to ignore, but those - // are typically included in LeafData. We may need to call skipPadding() if - // we ever find a record that doesn't count those bytes. - } -} - -static StringRef skipPadding(StringRef Data) { - if (Data.empty()) - return Data; - uint8_t Leaf = Data.front(); - if (Leaf < LF_PAD0) - return Data; - // Leaf is greater than 0xf0. We should advance by the number of bytes in the - // low 4 bits. - return Data.drop_front(Leaf & 0x0F); -} - -void COFFDumper::printMemberAttributes(MemberAttributes Attrs) { - W.printEnum("AccessSpecifier", uint8_t(Attrs.getAccess()), - makeArrayRef(MemberAccessNames)); - auto MK = Attrs.getMethodKind(); - // Data members will be vanilla. Don't try to print a method kind for them. - if (MK != MethodKind::Vanilla) - W.printEnum("MethodKind", unsigned(MK), makeArrayRef(MemberKindNames)); - if (Attrs.getFlags() != MethodOptions::None) { - W.printFlags("MethodOptions", unsigned(Attrs.getFlags()), - makeArrayRef(MethodOptionNames)); - } -} - -void COFFDumper::printCodeViewFieldList(StringRef FieldData) { - while (!FieldData.empty()) { - const ulittle16_t *LeafPtr; - error(consumeObject(FieldData, LeafPtr)); - uint16_t Leaf = *LeafPtr; - switch (Leaf) { - default: - W.printHex("UnknownMember", Leaf); - // We can't advance once we hit an unknown field. The size is not encoded. - return; - - case LF_NESTTYPE: { - const NestedType *Nested; - error(consumeObject(FieldData, Nested)); - DictScope S(W, "NestedType"); - printTypeIndex("Type", Nested->Type); - StringRef Name; - std::tie(Name, FieldData) = FieldData.split('\0'); - W.printString("Name", Name); - break; - } - - case LF_ONEMETHOD: { - const OneMethod *Method; - error(consumeObject(FieldData, Method)); - DictScope S(W, "OneMethod"); - printMemberAttributes(Method->Attrs); - printTypeIndex("Type", Method->Type); - // If virtual, then read the vftable offset. - if (Method->isIntroducedVirtual()) { - const little32_t *VFTOffsetPtr; - error(consumeObject(FieldData, VFTOffsetPtr)); - W.printHex("VFTableOffset", *VFTOffsetPtr); - } - StringRef Name; - std::tie(Name, FieldData) = FieldData.split('\0'); - W.printString("Name", Name); - break; - } - - case LF_METHOD: { - const OverloadedMethod *Method; - error(consumeObject(FieldData, Method)); - DictScope S(W, "OverloadedMethod"); - W.printHex("MethodCount", Method->MethodCount); - W.printHex("MethodListIndex", Method->MethList.getIndex()); - StringRef Name; - std::tie(Name, FieldData) = FieldData.split('\0'); - W.printString("Name", Name); - break; - } - - case LF_MEMBER: { - const DataMember *Field; - error(consumeObject(FieldData, Field)); - DictScope S(W, "DataMember"); - printMemberAttributes(Field->Attrs); - printTypeIndex("Type", Field->Type); - uint64_t FieldOffset; - error(decodeUIntLeaf(FieldData, FieldOffset)); - W.printHex("FieldOffset", FieldOffset); - StringRef Name; - std::tie(Name, FieldData) = FieldData.split('\0'); - W.printString("Name", Name); - break; - } - - case LF_STMEMBER: { - const StaticDataMember *Field; - error(consumeObject(FieldData, Field)); - DictScope S(W, "StaticDataMember"); - printMemberAttributes(Field->Attrs); - printTypeIndex("Type", Field->Type); - StringRef Name; - std::tie(Name, FieldData) = FieldData.split('\0'); - W.printString("Name", Name); - break; - } - - case LF_VFUNCTAB: { - const VirtualFunctionPointer *VFTable; - error(consumeObject(FieldData, VFTable)); - DictScope S(W, "VirtualFunctionPointer"); - printTypeIndex("Type", VFTable->Type); - break; - } - - case LF_ENUMERATE: { - const Enumerator *Enum; - error(consumeObject(FieldData, Enum)); - DictScope S(W, "Enumerator"); - printMemberAttributes(Enum->Attrs); - APSInt EnumValue; - error(decodeNumerictLeaf(FieldData, EnumValue)); - W.printNumber("EnumValue", EnumValue); - StringRef Name; - std::tie(Name, FieldData) = FieldData.split('\0'); - W.printString("Name", Name); - break; - } - - case LF_BCLASS: - case LF_BINTERFACE: { - const BaseClass *Base; - error(consumeObject(FieldData, Base)); - DictScope S(W, "BaseClass"); - printMemberAttributes(Base->Attrs); - printTypeIndex("BaseType", Base->BaseType); - uint64_t BaseOffset; - error(decodeUIntLeaf(FieldData, BaseOffset)); - W.printHex("BaseOffset", BaseOffset); - break; - } - - case LF_VBCLASS: - case LF_IVBCLASS: { - const VirtualBaseClass *Base; - error(consumeObject(FieldData, Base)); - DictScope S(W, "VirtualBaseClass"); - printMemberAttributes(Base->Attrs); - printTypeIndex("BaseType", Base->BaseType); - printTypeIndex("VBPtrType", Base->VBPtrType); - uint64_t VBPtrOffset, VBTableIndex; - error(decodeUIntLeaf(FieldData, VBPtrOffset)); - error(decodeUIntLeaf(FieldData, VBTableIndex)); - W.printHex("VBPtrOffset", VBPtrOffset); - W.printHex("VBTableIndex", VBTableIndex); - break; - } - } - - // Handle padding. - FieldData = skipPadding(FieldData); + if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()})) { + W.flush(); + error(llvm::errorToErrorCode(std::move(EC))); } } @@ -2603,8 +1185,8 @@ void COFFDumper::printRelocation(const SectionRef &Section, Reloc.getTypeName(RelocName); symbol_iterator Symbol = Reloc.getSymbol(); if (Symbol != Obj->symbol_end()) { - ErrorOr SymbolNameOrErr = Symbol->getName(); - error(SymbolNameOrErr.getError()); + Expected SymbolNameOrErr = Symbol->getName(); + error(errorToErrorCode(SymbolNameOrErr.takeError())); SymbolName = *SymbolNameOrErr; } @@ -2947,3 +1529,18 @@ void COFFDumper::printStackMap() const { prettyPrintStackMap(llvm::outs(), StackMapV1Parser(StackMapContentsArray)); } + +void llvm::dumpCodeViewMergedTypes( + ScopedPrinter &Writer, llvm::codeview::MemoryTypeTableBuilder &CVTypes) { + // Flatten it first, then run our dumper on it. + ListScope S(Writer, "MergedTypeStream"); + SmallString<0> Buf; + CVTypes.ForEachRecord([&](TypeIndex TI, StringRef Record) { + Buf.append(Record.begin(), Record.end()); + }); + CVTypeDumper CVTD(&Writer, opts::CodeViewSubsectionBytes); + if (auto EC = CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()})) { + Writer.flush(); + error(llvm::errorToErrorCode(std::move(EC))); + } +} diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index a360d868155b949040e74fc9b11566fae3cfbf84..84e368e7aa36368c9ca72a5b73e98039176b8b44 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -12,13 +12,12 @@ /// //===----------------------------------------------------------------------===// -#include "llvm-readobj.h" #include "ARMAttributeParser.h" #include "ARMEHABIPrinter.h" #include "Error.h" #include "ObjDumper.h" #include "StackMapPrinter.h" -#include "StreamWriter.h" +#include "llvm-readobj.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -26,10 +25,11 @@ #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MipsABIFlags.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/FormattedStream.h" using namespace llvm; using namespace llvm::object; @@ -61,6 +61,8 @@ using namespace ELF; typedef typename ELFO::Elf_Half Elf_Half; \ typedef typename ELFO::Elf_Ehdr Elf_Ehdr; \ typedef typename ELFO::Elf_Word Elf_Word; \ + typedef typename ELFO::Elf_Hash Elf_Hash; \ + typedef typename ELFO::Elf_GnuHash Elf_GnuHash; \ typedef typename ELFO::uintX_t uintX_t; namespace { @@ -82,7 +84,7 @@ struct DynRegionInfo { /// \brief Size of each entity in the region. uint64_t EntSize; - template iterator_range getAsRange() const { + template ArrayRef getAsArrayRef() const { const Type *Start = reinterpret_cast(Addr); if (!Start) return {Start, Start}; @@ -95,7 +97,7 @@ struct DynRegionInfo { template class ELFDumper : public ObjDumper { public: - ELFDumper(const ELFFile *Obj, StreamWriter &Writer); + ELFDumper(const ELFFile *Obj, ScopedPrinter &Writer); void printFileHeaders() override; void printSections() override; @@ -118,9 +120,12 @@ public: void printMipsPLTGOT() override; void printMipsABIFlags() override; void printMipsReginfo() override; + void printMipsOptions() override; void printStackMap() const override; + void printHashHistogram() override; + private: std::unique_ptr> ELFDumperStyle; typedef ELFFile ELFO; @@ -215,11 +220,11 @@ private: public: Elf_Dyn_Range dynamic_table() const { - return DynamicTable.getAsRange(); + return DynamicTable.getAsArrayRef(); } Elf_Sym_Range dynamic_symbols() const { - return DynSymRegion.getAsRange(); + return DynSymRegion.getAsArrayRef(); } Elf_Rel_Range dyn_rels() const; @@ -234,6 +239,8 @@ public: const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; } const DynRegionInfo &getDynRelaRegion() const { return DynRelaRegion; } const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; } + const Elf_Hash *getHashTable() const { return HashTable; } + const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; } }; template @@ -284,6 +291,7 @@ public: const Elf_Sym *FirstSym, StringRef StrTable, bool IsDynamic) = 0; virtual void printProgramHeaders(const ELFFile *Obj) = 0; + virtual void printHashHistogram(const ELFFile *Obj) = 0; const ELFDumper *dumper() const { return Dumper; } private: const ELFDumper *Dumper; @@ -293,7 +301,7 @@ template class GNUStyle : public DumpStyle { formatted_raw_ostream OS; public: TYPEDEF_ELF_TYPES(ELFT) - GNUStyle(StreamWriter &W, ELFDumper *Dumper) + GNUStyle(ScopedPrinter &W, ELFDumper *Dumper) : DumpStyle(Dumper), OS(W.getOStream()) {} void printFileHeaders(const ELFO *Obj) override; void printGroupSections(const ELFFile *Obj) override; @@ -305,6 +313,7 @@ public: virtual void printSymtabMessage(const ELFO *Obj, StringRef Name, size_t Offset) override; void printProgramHeaders(const ELFO *Obj) override; + void printHashHistogram(const ELFFile *Obj) override; private: struct Field { @@ -335,6 +344,7 @@ private: StringRef StrTable, bool IsDynamic) override; std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *FirstSym); + void printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela); bool checkTLSSections(const Elf_Phdr &Phdr, const Elf_Shdr &Sec); bool checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec); bool checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec); @@ -344,7 +354,7 @@ private: template class LLVMStyle : public DumpStyle { public: TYPEDEF_ELF_TYPES(ELFT) - LLVMStyle(StreamWriter &W, ELFDumper *Dumper) + LLVMStyle(ScopedPrinter &W, ELFDumper *Dumper) : DumpStyle(Dumper), W(W) {} void printFileHeaders(const ELFO *Obj) override; @@ -356,13 +366,14 @@ public: void printDynamicSymbols(const ELFO *Obj) override; void printDynamicRelocations(const ELFO *Obj) override; void printProgramHeaders(const ELFO *Obj) override; + void printHashHistogram(const ELFFile *Obj) override; private: void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab); void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel); void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, StringRef StrTable, bool IsDynamic) override; - StreamWriter &W; + ScopedPrinter &W; }; } // namespace @@ -371,14 +382,14 @@ namespace llvm { template static std::error_code createELFDumper(const ELFFile *Obj, - StreamWriter &Writer, + ScopedPrinter &Writer, std::unique_ptr &Result) { Result.reset(new ELFDumper(Obj, Writer)); return readobj_error::success; } std::error_code createELFDumper(const object::ObjectFile *Obj, - StreamWriter &Writer, + ScopedPrinter &Writer, std::unique_ptr &Result) { // Little-endian 32-bit if (const ELF32LEObjectFile *ELFObj = dyn_cast(Obj)) @@ -481,12 +492,10 @@ template void ELFDumper::LoadVersionMap() const { LoadVersionNeeds(dot_gnu_version_r_sec); } - template -static void printVersionSymbolSection(ELFDumper *Dumper, - const ELFO *Obj, +static void printVersionSymbolSection(ELFDumper *Dumper, const ELFO *Obj, const typename ELFO::Elf_Shdr *Sec, - StreamWriter &W) { + ScopedPrinter &W) { DictScope SS(W, "Version symbols"); if (!Sec) return; @@ -511,26 +520,29 @@ static void printVersionSymbolSection(ELFDumper *Dumper, } } +static const EnumEntry SymVersionFlags[] = { + {"Base", "BASE", VER_FLG_BASE}, + {"Weak", "WEAK", VER_FLG_WEAK}, + {"Info", "INFO", VER_FLG_INFO}}; + template static void printVersionDefinitionSection(ELFDumper *Dumper, const ELFO *Obj, const typename ELFO::Elf_Shdr *Sec, - StreamWriter &W) { - DictScope SD(W, "Version definition"); + ScopedPrinter &W) { + typedef typename ELFO::Elf_Verdef VerDef; + typedef typename ELFO::Elf_Verdaux VerdAux; + + DictScope SD(W, "SHT_GNU_verdef"); if (!Sec) return; - StringRef Name = unwrapOrError(Obj->getSectionName(Sec)); - W.printNumber("Section Name", Name, Sec->sh_name); - W.printHex("Address", Sec->sh_addr); - W.printHex("Offset", Sec->sh_offset); - W.printNumber("Link", Sec->sh_link); - unsigned verdef_entries = 0; // The number of entries in the section SHT_GNU_verdef // is determined by DT_VERDEFNUM tag. + unsigned VerDefsNum = 0; for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) { if (Dyn.d_tag == DT_VERDEFNUM) - verdef_entries = Dyn.d_un.d_val; + VerDefsNum = Dyn.d_un.d_val; } const uint8_t *SecStartAddress = (const uint8_t *)Obj->base() + Sec->sh_offset; @@ -539,31 +551,92 @@ static void printVersionDefinitionSection(ELFDumper *Dumper, const typename ELFO::Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link)); - ListScope Entries(W, "Entries"); - for (unsigned i = 0; i < verdef_entries; ++i) { - if (P + sizeof(typename ELFO::Elf_Verdef) > SecEndAddress) + while (VerDefsNum--) { + if (P + sizeof(VerDef) > SecEndAddress) report_fatal_error("invalid offset in the section"); - auto *VD = reinterpret_cast(P); - DictScope Entry(W, "Entry"); - W.printHex("Offset", (uintptr_t)P - (uintptr_t)SecStartAddress); - W.printNumber("Rev", VD->vd_version); - // FIXME: print something more readable. - W.printNumber("Flags", VD->vd_flags); + + auto *VD = reinterpret_cast(P); + DictScope Def(W, "Definition"); + W.printNumber("Version", VD->vd_version); + W.printEnum("Flags", VD->vd_flags, makeArrayRef(SymVersionFlags)); W.printNumber("Index", VD->vd_ndx); - W.printNumber("Cnt", VD->vd_cnt); + W.printNumber("Hash", VD->vd_hash); W.printString("Name", StringRef((const char *)(Obj->base() + StrTab->sh_offset + VD->getAux()->vda_name))); + if (!VD->vd_cnt) + report_fatal_error("at least one definition string must exist"); + if (VD->vd_cnt > 2) + report_fatal_error("more than one predecessor is not expected"); + + if (VD->vd_cnt == 2) { + const uint8_t *PAux = P + VD->vd_aux + VD->getAux()->vda_next; + const VerdAux *Aux = reinterpret_cast(PAux); + W.printString("Predecessor", + StringRef((const char *)(Obj->base() + StrTab->sh_offset + + Aux->vda_name))); + } + P += VD->vd_next; } } +template +static void printVersionDependencySection(ELFDumper *Dumper, + const ELFO *Obj, + const typename ELFO::Elf_Shdr *Sec, + ScopedPrinter &W) { + typedef typename ELFO::Elf_Verneed VerNeed; + typedef typename ELFO::Elf_Vernaux VernAux; + + DictScope SD(W, "SHT_GNU_verneed"); + if (!Sec) + return; + + unsigned VerNeedNum = 0; + for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) + if (Dyn.d_tag == DT_VERNEEDNUM) + VerNeedNum = Dyn.d_un.d_val; + + const uint8_t *SecData = (const uint8_t *)Obj->base() + Sec->sh_offset; + const typename ELFO::Elf_Shdr *StrTab = + unwrapOrError(Obj->getSection(Sec->sh_link)); + + const uint8_t *P = SecData; + for (unsigned I = 0; I < VerNeedNum; ++I) { + const VerNeed *Need = reinterpret_cast(P); + DictScope Entry(W, "Dependency"); + W.printNumber("Version", Need->vn_version); + W.printNumber("Count", Need->vn_cnt); + W.printString("FileName", + StringRef((const char *)(Obj->base() + StrTab->sh_offset + + Need->vn_file))); + + const uint8_t *PAux = P + Need->vn_aux; + for (unsigned J = 0; J < Need->vn_cnt; ++J) { + const VernAux *Aux = reinterpret_cast(PAux); + DictScope Entry(W, "Entry"); + W.printNumber("Hash", Aux->vna_hash); + W.printEnum("Flags", Aux->vna_flags, makeArrayRef(SymVersionFlags)); + W.printNumber("Index", Aux->vna_other); + W.printString("Name", + StringRef((const char *)(Obj->base() + StrTab->sh_offset + + Aux->vna_name))); + PAux += Aux->vna_next; + } + P += Need->vn_next; + } +} + template void ELFDumper::printVersionInfo() { // Dump version symbol section. printVersionSymbolSection(this, Obj, dot_gnu_version_sec, W); // Dump version definition section. printVersionDefinitionSection(this, Obj, dot_gnu_version_d_sec, W); + + // Dump version dependency section. + printVersionDependencySection(this, Obj, dot_gnu_version_r_sec, W); } template @@ -982,8 +1055,14 @@ static const EnumEntry ElfSectionFlags[] = { ENUM_ENT(SHF_OS_NONCONFORMING, "o"), ENUM_ENT(SHF_GROUP, "G"), ENUM_ENT(SHF_TLS, "T"), - ENUM_ENT_1(XCORE_SHF_CP_SECTION), - ENUM_ENT_1(XCORE_SHF_DP_SECTION), + ENUM_ENT(SHF_MASKOS, "o"), + ENUM_ENT(SHF_MASKPROC, "p"), + ENUM_ENT_1(SHF_COMPRESSED), +}; + +static const EnumEntry ElfXCoreSectionFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION), + LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION) }; static const EnumEntry ElfAMDGPUSectionFlags[] = { @@ -1032,9 +1111,9 @@ static std::string getGNUFlags(uint64_t Flags) { Str += Entry.AltName; break; default: - if (Flags & ELF::SHF_MASKOS) + if (Flag & ELF::SHF_MASKOS) Str += "o"; - else if (Flags & ELF::SHF_MASKPROC) + else if (Flag & ELF::SHF_MASKPROC) Str += "p"; else if (Flag) Str += "x"; @@ -1205,8 +1284,27 @@ static const EnumEntry ElfMips16SymOtherFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_MIPS16) }; +static const char *getElfMipsOptionsOdkType(unsigned Odk) { + switch (Odk) { + LLVM_READOBJ_ENUM_CASE(ELF, ODK_NULL); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_REGINFO); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_EXCEPTIONS); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_PAD); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_HWPATCH); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_FILL); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_TAGS); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_HWAND); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_HWOR); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_GP_GROUP); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_IDENT); + LLVM_READOBJ_ENUM_CASE(ELF, ODK_PAGESIZE); + default: + return "Unknown"; + } +} + template -ELFDumper::ELFDumper(const ELFFile *Obj, StreamWriter &Writer) +ELFDumper::ELFDumper(const ELFFile *Obj, ScopedPrinter &Writer) : ObjDumper(Writer), Obj(Obj) { SmallVector LoadSegments; @@ -1348,12 +1446,12 @@ void ELFDumper::parseDynamicTable( template typename ELFDumper::Elf_Rel_Range ELFDumper::dyn_rels() const { - return DynRelRegion.getAsRange(); + return DynRelRegion.getAsArrayRef(); } template typename ELFDumper::Elf_Rela_Range ELFDumper::dyn_relas() const { - return DynRelaRegion.getAsRange(); + return DynRelaRegion.getAsArrayRef(); } template @@ -1389,6 +1487,9 @@ void ELFDumper::printDynamicSymbols() { ELFDumperStyle->printDynamicSymbols(Obj); } +template void ELFDumper::printHashHistogram() { + ELFDumperStyle->printHashHistogram(Obj); +} #define LLVM_READOBJ_TYPE_CASE(name) \ case DT_##name: return #name @@ -1544,6 +1645,7 @@ StringRef ELFDumper::getDynamicString(uint64_t Value) const { template void ELFDumper::printValue(uint64_t Type, uint64_t Value) { raw_ostream &OS = W.getOStream(); + const char* ConvChar = (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64; switch (Type) { case DT_PLTREL: if (Value == DT_REL) { @@ -1578,7 +1680,7 @@ void ELFDumper::printValue(uint64_t Type, uint64_t Value) { case DT_MIPS_RLD_MAP_REL: case DT_MIPS_PLTGOT: case DT_MIPS_OPTIONS: - OS << format("0x%" PRIX64, Value); + OS << format(ConvChar, Value); break; case DT_RELACOUNT: case DT_RELCOUNT: @@ -1622,7 +1724,7 @@ void ELFDumper::printValue(uint64_t Type, uint64_t Value) { printFlags(Value, makeArrayRef(ElfDynamicDTFlags1), OS); break; default: - OS << format("0x%" PRIX64, Value); + OS << format(ConvChar, Value); break; } } @@ -1675,7 +1777,7 @@ void ELFDumper::printDynamicTable() { const Elf_Dyn &Entry = *I; uintX_t Tag = Entry.getTag(); ++I; - W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " " + W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, opts::Output != opts::GNU) << " " << format("%-21s", getTypeString(Tag)); printValue(Tag, Entry.getVal()); OS << "\n"; @@ -1781,7 +1883,7 @@ public: typedef typename ELFO::Elf_Rela Elf_Rela; MipsGOTParser(ELFDumper *Dumper, const ELFO *Obj, - Elf_Dyn_Range DynTable, StreamWriter &W); + Elf_Dyn_Range DynTable, ScopedPrinter &W); void parseGOT(); void parsePLT(); @@ -1789,7 +1891,7 @@ public: private: ELFDumper *Dumper; const ELFO *Obj; - StreamWriter &W; + ScopedPrinter &W; llvm::Optional DtPltGot; llvm::Optional DtLocalGotNum; llvm::Optional DtGotSym; @@ -1814,7 +1916,7 @@ private: template MipsGOTParser::MipsGOTParser(ELFDumper *Dumper, const ELFO *Obj, - Elf_Dyn_Range DynTable, StreamWriter &W) + Elf_Dyn_Range DynTable, ScopedPrinter &W) : Dumper(Dumper), Obj(Obj), W(W) { for (const auto &Entry : DynTable) { switch (Entry.getTag()) { @@ -2175,6 +2277,17 @@ template void ELFDumper::printMipsABIFlags() { W.printHex("Flags 2", Flags->flags2); } +template +static void printMipsReginfoData(ScopedPrinter &W, + const Elf_Mips_RegInfo &Reginfo) { + W.printHex("GP", Reginfo.ri_gp_value); + W.printHex("General Mask", Reginfo.ri_gprmask); + W.printHex("Co-Proc Mask0", Reginfo.ri_cprmask[0]); + W.printHex("Co-Proc Mask1", Reginfo.ri_cprmask[1]); + W.printHex("Co-Proc Mask2", Reginfo.ri_cprmask[2]); + W.printHex("Co-Proc Mask3", Reginfo.ri_cprmask[3]); +} + template void ELFDumper::printMipsReginfo() { const Elf_Shdr *Shdr = findSectionByName(*Obj, ".reginfo"); if (!Shdr) { @@ -2187,15 +2300,38 @@ template void ELFDumper::printMipsReginfo() { return; } + DictScope GS(W, "MIPS RegInfo"); auto *Reginfo = reinterpret_cast *>(Sec.data()); + printMipsReginfoData(W, *Reginfo); +} - DictScope GS(W, "MIPS RegInfo"); - W.printHex("GP", Reginfo->ri_gp_value); - W.printHex("General Mask", Reginfo->ri_gprmask); - W.printHex("Co-Proc Mask0", Reginfo->ri_cprmask[0]); - W.printHex("Co-Proc Mask1", Reginfo->ri_cprmask[1]); - W.printHex("Co-Proc Mask2", Reginfo->ri_cprmask[2]); - W.printHex("Co-Proc Mask3", Reginfo->ri_cprmask[3]); +template void ELFDumper::printMipsOptions() { + const Elf_Shdr *Shdr = findSectionByName(*Obj, ".MIPS.options"); + if (!Shdr) { + W.startLine() << "There is no .MIPS.options section in the file.\n"; + return; + } + + DictScope GS(W, "MIPS Options"); + + ArrayRef Sec = unwrapOrError(Obj->getSectionContents(Shdr)); + while (!Sec.empty()) { + if (Sec.size() < sizeof(Elf_Mips_Options)) { + W.startLine() << "The .MIPS.options section has a wrong size.\n"; + return; + } + auto *O = reinterpret_cast *>(Sec.data()); + DictScope GS(W, getElfMipsOptionsOdkType(O->kind)); + switch (O->kind) { + case ODK_REGINFO: + printMipsReginfoData(W, O->getRegInfo()); + break; + default: + W.startLine() << "Unsupported MIPS options tag.\n"; + break; + } + Sec = Sec.slice(O->size); + } } template void ELFDumper::printStackMap() const { @@ -2323,16 +2459,8 @@ void GNUStyle::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); StringRef TargetName; const Elf_Sym *Sym = nullptr; - unsigned Bias; - unsigned Width; - - if (ELFT::Is64Bits) { - Bias = 8; - Width = 16; - } else { - Bias = 0; - Width = 8; - } + unsigned Width = ELFT::Is64Bits ? 16 : 8; + unsigned Bias = ELFT::Is64Bits ? 8 : 0; // First two fields are bit width dependent. The rest of them are after are // fixed width. @@ -2371,8 +2499,19 @@ void GNUStyle::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, Fields[4].Str = TargetName; for (auto &field : Fields) printField(field); + OS << Addend; + OS << "\n"; +} + +static inline void printRelocHeader(raw_ostream &OS, bool Is64, bool IsRela) { + if (Is64) + OS << " Offset Info Type" + << " Symbol's Value Symbol's Name"; + else + OS << " Offset Info Type Sym. Value " + << "Symbol's Name"; if (IsRela) - OS << Addend; + OS << (IsRela ? " + Addend" : ""); OS << "\n"; } @@ -2388,14 +2527,7 @@ template void GNUStyle::printRelocations(const ELFO *Obj) { OS << "\nRelocation section '" << Name << "' at offset 0x" << to_hexString(Offset, false) << " contains " << Entries << " entries:\n"; - if (ELFT::Is64Bits) - OS << " Offset Info Type" - << " Symbol's Value Symbol's Name"; - else - OS << " Offset Info Type Sym. Value " - << "Symbol's Name"; - OS << ((Sec.sh_type == ELF::SHT_RELA) ? " + Addend" : "") << "\n"; - + printRelocHeader(OS, ELFT::Is64Bits, (Sec.sh_type == ELF::SHT_RELA)); const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec.sh_link)); if (Sec.sh_type == ELF::SHT_REL) { for (const auto &R : Obj->rels(&Sec)) { @@ -2759,9 +2891,9 @@ bool GNUStyle::checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) { template void GNUStyle::printProgramHeaders(const ELFO *Obj) { - unsigned Bias = (ELFT::Is64Bits) ? 8 : 0; - unsigned Width = (ELFT::Is64Bits) ? 18 : 10; - unsigned SizeWidth = (ELFT::Is64Bits) ? 8 : 7; + unsigned Bias = ELFT::Is64Bits ? 8 : 0; + unsigned Width = ELFT::Is64Bits ? 18 : 10; + unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7; std::string Type, Offset, VMA, LMA, FileSz, MemSz, Flag, Align; const Elf_Ehdr *Header = Obj->getHeader(); @@ -2769,7 +2901,7 @@ void GNUStyle::printProgramHeaders(const ELFO *Obj) { 48 + Bias, 56 + Bias, 64 + Bias, 68 + Bias}; OS << "\nElf file type is " << printEnum(Header->e_type, makeArrayRef(ElfObjectFileType)) << "\n" - << "Entry point " << format_hex(Header->e_entry, 1) << "\n" + << "Entry point " << format_hex(Header->e_entry, 3) << "\n" << "There are " << Header->e_phnum << " program headers," << " starting at offset " << Header->e_phoff << "\n\n" << "Program Headers:\n"; @@ -2827,9 +2959,205 @@ void GNUStyle::printProgramHeaders(const ELFO *Obj) { } } +template +void GNUStyle::printDynamicRelocation(const ELFO *Obj, Elf_Rela R, + bool IsRela) { + SmallString<32> RelocName; + StringRef SymbolName; + unsigned Width = ELFT::Is64Bits ? 16 : 8; + unsigned Bias = ELFT::Is64Bits ? 8 : 0; + // First two fields are bit width dependent. The rest of them are after are + // fixed width. + Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias}; + + uint32_t SymIndex = R.getSymbol(Obj->isMips64EL()); + const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex; + Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName); + SymbolName = + unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable())); + std::string Addend = "", Info, Offset, Value; + Offset = to_string(format_hex_no_prefix(R.r_offset, Width)); + Info = to_string(format_hex_no_prefix(R.r_info, Width)); + Value = to_string(format_hex_no_prefix(Sym->getValue(), Width)); + int64_t RelAddend = R.r_addend; + if (SymbolName.size() && IsRela) { + if (R.r_addend < 0) + Addend = " - "; + else + Addend = " + "; + } + + if (!SymbolName.size() && Sym->getValue() == 0) + Value = ""; + + if (IsRela) + Addend += to_string(format_hex_no_prefix(std::abs(RelAddend), 1)); + + + Fields[0].Str = Offset; + Fields[1].Str = Info; + Fields[2].Str = RelocName.c_str(); + Fields[3].Str = Value; + Fields[4].Str = SymbolName; + for (auto &Field : Fields) + printField(Field); + OS << Addend; + OS << "\n"; +} + template void GNUStyle::printDynamicRelocations(const ELFO *Obj) { - OS << "GNU style dynamic relocations not implemented!\n"; + const DynRegionInfo &DynRelRegion = this->dumper()->getDynRelRegion(); + const DynRegionInfo &DynRelaRegion = this->dumper()->getDynRelaRegion(); + const DynRegionInfo &DynPLTRelRegion = this->dumper()->getDynPLTRelRegion(); + if (DynRelaRegion.Size > 0) { + OS << "\n'RELA' relocation section at offset " + << format_hex(reinterpret_cast(DynRelaRegion.Addr) - + Obj->base(), + 1) << " contains " << DynRelaRegion.Size << " bytes:\n"; + printRelocHeader(OS, ELFT::Is64Bits, true); + for (const Elf_Rela &Rela : this->dumper()->dyn_relas()) + printDynamicRelocation(Obj, Rela, true); + } + if (DynRelRegion.Size > 0) { + OS << "\n'REL' relocation section at offset " + << format_hex(reinterpret_cast(DynRelRegion.Addr) - + Obj->base(), + 1) << " contains " << DynRelRegion.Size << " bytes:\n"; + printRelocHeader(OS, ELFT::Is64Bits, false); + for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) { + Elf_Rela Rela; + Rela.r_offset = Rel.r_offset; + Rela.r_info = Rel.r_info; + Rela.r_addend = 0; + printDynamicRelocation(Obj, Rela, false); + } + } + if (DynPLTRelRegion.Size) { + OS << "\n'PLT' relocation section at offset " + << format_hex(reinterpret_cast(DynPLTRelRegion.Addr) - + Obj->base(), + 1) << " contains " << DynPLTRelRegion.Size << " bytes:\n"; + } + if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) { + printRelocHeader(OS, ELFT::Is64Bits, true); + for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef()) + printDynamicRelocation(Obj, Rela, true); + } else { + printRelocHeader(OS, ELFT::Is64Bits, false); + for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef()) { + Elf_Rela Rela; + Rela.r_offset = Rel.r_offset; + Rela.r_info = Rel.r_info; + Rela.r_addend = 0; + printDynamicRelocation(Obj, Rela, false); + } + } +} + +// Hash histogram shows statistics of how efficient the hash was for the +// dynamic symbol table. The table shows number of hash buckets for different +// lengths of chains as absolute number and percentage of the total buckets. +// Additionally cumulative coverage of symbols for each set of buckets. +template +void GNUStyle::printHashHistogram(const ELFFile *Obj) { + + const Elf_Hash *HashTable = this->dumper()->getHashTable(); + const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable(); + + // Print histogram for .hash section + if (HashTable) { + size_t NBucket = HashTable->nbucket; + size_t NChain = HashTable->nchain; + ArrayRef Buckets = HashTable->buckets(); + ArrayRef Chains = HashTable->chains(); + size_t TotalSyms = 0; + // If hash table is correct, we have at least chains with 0 length + size_t MaxChain = 1; + size_t CumulativeNonZero = 0; + + if (NChain == 0 || NBucket == 0) + return; + + std::vector ChainLen(NBucket, 0); + // Go over all buckets and and note chain lengths of each bucket (total + // unique chain lengths). + for (size_t B = 0; B < NBucket; B++) { + for (size_t C = Buckets[B]; C > 0 && C < NChain; C = Chains[C]) + if (MaxChain <= ++ChainLen[B]) + MaxChain++; + TotalSyms += ChainLen[B]; + } + + if (!TotalSyms) + return; + + std::vector Count(MaxChain, 0) ; + // Count how long is the chain for each bucket + for (size_t B = 0; B < NBucket; B++) + ++Count[ChainLen[B]]; + // Print Number of buckets with each chain lengths and their cumulative + // coverage of the symbols + OS << "Histogram for bucket list length (total of " << NBucket + << " buckets)\n" + << " Length Number % of total Coverage\n"; + for (size_t I = 0; I < MaxChain; I++) { + CumulativeNonZero += Count[I] * I; + OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I], + (Count[I] * 100.0) / NBucket, + (CumulativeNonZero * 100.0) / TotalSyms); + } + } + + // Print histogram for .gnu.hash section + if (GnuHashTable) { + size_t NBucket = GnuHashTable->nbuckets; + ArrayRef Buckets = GnuHashTable->buckets(); + unsigned NumSyms = this->dumper()->dynamic_symbols().size(); + if (!NumSyms) + return; + ArrayRef Chains = GnuHashTable->values(NumSyms); + size_t Symndx = GnuHashTable->symndx; + size_t TotalSyms = 0; + size_t MaxChain = 1; + size_t CumulativeNonZero = 0; + + if (Chains.size() == 0 || NBucket == 0) + return; + + std::vector ChainLen(NBucket, 0); + + for (size_t B = 0; B < NBucket; B++) { + if (!Buckets[B]) + continue; + size_t Len = 1; + for (size_t C = Buckets[B] - Symndx; + C < Chains.size() && (Chains[C] & 1) == 0; C++) + if (MaxChain < ++Len) + MaxChain++; + ChainLen[B] = Len; + TotalSyms += Len; + } + MaxChain++; + + if (!TotalSyms) + return; + + std::vector Count(MaxChain, 0) ; + for (size_t B = 0; B < NBucket; B++) + ++Count[ChainLen[B]]; + // Print Number of buckets with each chain lengths and their cumulative + // coverage of the symbols + OS << "Histogram for `.gnu.hash' bucket list length (total of " << NBucket + << " buckets)\n" + << " Length Number % of total Coverage\n"; + for (size_t I = 0; I void LLVMStyle::printFileHeaders(const ELFO *Obj) { @@ -3020,6 +3348,10 @@ template void LLVMStyle::printSections(const ELFO *Obj) { SectionFlags.insert(SectionFlags.end(), std::begin(ElfX86_64SectionFlags), std::end(ElfX86_64SectionFlags)); break; + case EM_XCORE: + SectionFlags.insert(SectionFlags.end(), std::begin(ElfXCoreSectionFlags), + std::end(ElfXCoreSectionFlags)); + break; default: // Nothing to do. break; @@ -3138,10 +3470,10 @@ void LLVMStyle::printDynamicRelocations(const ELFO *Obj) { printDynamicRelocation(Obj, Rela); } if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) - for (const Elf_Rela &Rela : DynPLTRelRegion.getAsRange()) + for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef()) printDynamicRelocation(Obj, Rela); else - for (const Elf_Rel &Rel : DynPLTRelRegion.getAsRange()) { + for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef()) { Elf_Rela Rela; Rela.r_offset = Rel.r_offset; Rela.r_info = Rel.r_info; @@ -3193,3 +3525,7 @@ void LLVMStyle::printProgramHeaders(const ELFO *Obj) { W.printNumber("Alignment", Phdr.p_align); } } +template +void LLVMStyle::printHashHistogram(const ELFFile *Obj) { + W.startLine() << "Hash Histogram not implemented!\n"; +} diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp index 7e6f780c5d1a29ef245fdd60903b369d8df3708b..492eb3309497688ed674e2c7b3a7f3c13b51ada9 100644 --- a/tools/llvm-readobj/Error.cpp +++ b/tools/llvm-readobj/Error.cpp @@ -17,6 +17,9 @@ using namespace llvm; namespace { +// FIXME: This class is only here to support the transition to llvm::Error. It +// will be removed once this transition is complete. Clients should prefer to +// deal with the Error value directly, rather than converting to error_code. class _readobj_error_category : public std::error_category { public: const char* name() const LLVM_NOEXCEPT override; diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp index 8bd09b62a1ff8b9c2b47e9e4610191ee85e180c2..3773df250578e95567df9b98d722f02ee2197cf5 100644 --- a/tools/llvm-readobj/MachODumper.cpp +++ b/tools/llvm-readobj/MachODumper.cpp @@ -11,15 +11,15 @@ // //===----------------------------------------------------------------------===// -#include "llvm-readobj.h" #include "Error.h" #include "ObjDumper.h" #include "StackMapPrinter.h" -#include "StreamWriter.h" +#include "llvm-readobj.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/ScopedPrinter.h" using namespace llvm; using namespace object; @@ -28,9 +28,8 @@ namespace { class MachODumper : public ObjDumper { public: - MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer) - : ObjDumper(Writer) - , Obj(Obj) { } + MachODumper(const MachOObjectFile *Obj, ScopedPrinter &Writer) + : ObjDumper(Writer), Obj(Obj) {} void printFileHeaders() override; void printSections() override; @@ -69,7 +68,7 @@ private: namespace llvm { std::error_code createMachODumper(const object::ObjectFile *Obj, - StreamWriter &Writer, + ScopedPrinter &Writer, std::unique_ptr &Result) { const MachOObjectFile *MachOObj = dyn_cast(Obj); if (!MachOObj) @@ -541,8 +540,9 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, if (IsExtern) { symbol_iterator Symbol = Reloc.getSymbol(); if (Symbol != Obj->symbol_end()) { - ErrorOr TargetNameOrErr = Symbol->getName(); - error(TargetNameOrErr.getError()); + Expected TargetNameOrErr = Symbol->getName(); + if (!TargetNameOrErr) + error(errorToErrorCode(TargetNameOrErr.takeError())); TargetName = *TargetNameOrErr; } } else if (!IsScattered) { @@ -605,15 +605,19 @@ void MachODumper::printDynamicSymbols() { void MachODumper::printSymbol(const SymbolRef &Symbol) { StringRef SymbolName; - if (ErrorOr SymbolNameOrErr = Symbol.getName()) + Expected SymbolNameOrErr = Symbol.getName(); + if (!SymbolNameOrErr) { + // TODO: Actually report errors helpfully. + consumeError(SymbolNameOrErr.takeError()); + } else SymbolName = *SymbolNameOrErr; MachOSymbol MOSymbol; getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol); StringRef SectionName = ""; - ErrorOr SecIOrErr = Symbol.getSection(); - error(SecIOrErr.getError()); + Expected SecIOrErr = Symbol.getSection(); + error(errorToErrorCode(SecIOrErr.takeError())); section_iterator SecI = *SecIOrErr; if (SecI != Obj->section_end()) error(SecI->getName(SectionName)); diff --git a/tools/llvm-readobj/ObjDumper.cpp b/tools/llvm-readobj/ObjDumper.cpp index f500a05815532ae41cae99c61ee986fe35f0010d..2a0a90e5cfd5dbd7866aab77deb25d0010a19cb4 100644 --- a/tools/llvm-readobj/ObjDumper.cpp +++ b/tools/llvm-readobj/ObjDumper.cpp @@ -14,16 +14,13 @@ #include "ObjDumper.h" #include "Error.h" -#include "StreamWriter.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" namespace llvm { -ObjDumper::ObjDumper(StreamWriter& Writer) - : W(Writer) { -} +ObjDumper::ObjDumper(ScopedPrinter &Writer) : W(Writer) {} ObjDumper::~ObjDumper() { } diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index b83b8d49f222488e227133a637c5c0aa0e59f428..a39fc260b54932e1d31cb0dac581bdeafb012230 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -18,12 +18,15 @@ namespace object { class COFFImportFile; class ObjectFile; } +namespace codeview { +class MemoryTypeTableBuilder; +} -class StreamWriter; +class ScopedPrinter; class ObjDumper { public: - ObjDumper(StreamWriter& Writer); + ObjDumper(ScopedPrinter &Writer); virtual ~ObjDumper(); virtual void printFileHeaders() = 0; @@ -43,6 +46,7 @@ public: virtual void printLoadName() {} virtual void printVersionInfo() {} virtual void printGroupSections() {} + virtual void printHashHistogram() {} // Only implemented for ARM ELF at this time. virtual void printAttributes() { } @@ -51,13 +55,17 @@ public: virtual void printMipsPLTGOT() { } virtual void printMipsABIFlags() { } virtual void printMipsReginfo() { } + virtual void printMipsOptions() { } // Only implemented for PE/COFF. virtual void printCOFFImports() { } virtual void printCOFFExports() { } virtual void printCOFFDirectives() { } virtual void printCOFFBaseReloc() { } + virtual void printCOFFDebugDirectory() { } virtual void printCodeViewDebugInfo() { } + virtual void + mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) {} // Only implemented for MachO. virtual void printMachODataInCode() { } @@ -70,23 +78,26 @@ public: virtual void printStackMap() const = 0; protected: - StreamWriter& W; + ScopedPrinter &W; }; std::error_code createCOFFDumper(const object::ObjectFile *Obj, - StreamWriter &Writer, + ScopedPrinter &Writer, std::unique_ptr &Result); std::error_code createELFDumper(const object::ObjectFile *Obj, - StreamWriter &Writer, + ScopedPrinter &Writer, std::unique_ptr &Result); std::error_code createMachODumper(const object::ObjectFile *Obj, - StreamWriter &Writer, + ScopedPrinter &Writer, std::unique_ptr &Result); void dumpCOFFImportFile(const object::COFFImportFile *File); +void dumpCodeViewMergedTypes(ScopedPrinter &Writer, + llvm::codeview::MemoryTypeTableBuilder &CVTypes); + } // namespace llvm #endif diff --git a/tools/llvm-readobj/Win64EHDumper.cpp b/tools/llvm-readobj/Win64EHDumper.cpp index 2da5ae3200fde841b46be0cdcdaf6c2d18e016d4..f7e56b3615425c8abe6b685fe7bf388f79ff9e9b 100644 --- a/tools/llvm-readobj/Win64EHDumper.cpp +++ b/tools/llvm-readobj/Win64EHDumper.cpp @@ -120,13 +120,17 @@ static std::string formatSymbol(const Dumper::Context &Ctx, SymbolRef Symbol; if (!Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) { - if (ErrorOr Name = Symbol.getName()) { + Expected Name = Symbol.getName(); + if (Name) { OS << *Name; if (Displacement > 0) OS << format(" +0x%X (0x%" PRIX64 ")", Displacement, Offset); else OS << format(" (0x%" PRIX64 ")", Offset); return OS.str(); + } else { + // TODO: Actually report errors helpfully. + consumeError(Name.takeError()); } } @@ -144,12 +148,14 @@ static std::error_code resolveRelocation(const Dumper::Context &Ctx, Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) return EC; - ErrorOr ResolvedAddressOrErr = Symbol.getAddress(); - if (std::error_code EC = ResolvedAddressOrErr.getError()) - return EC; + Expected ResolvedAddressOrErr = Symbol.getAddress(); + if (!ResolvedAddressOrErr) + return errorToErrorCode(ResolvedAddressOrErr.takeError()); ResolvedAddress = *ResolvedAddressOrErr; - ErrorOr SI = Symbol.getSection(); + Expected SI = Symbol.getSection(); + if (!SI) + return errorToErrorCode(SI.takeError()); ResolvedSection = Ctx.COFF.getCOFFSection(**SI); return std::error_code(); } diff --git a/tools/llvm-readobj/Win64EHDumper.h b/tools/llvm-readobj/Win64EHDumper.h index a80df9c4f94dde43807429801ad539a22334d415..772f68bf283f722bfb191ada9e1d8f4505d05c47 100644 --- a/tools/llvm-readobj/Win64EHDumper.h +++ b/tools/llvm-readobj/Win64EHDumper.h @@ -10,7 +10,7 @@ #ifndef LLVM_TOOLS_LLVM_READOBJ_WIN64EHDUMPER_H #define LLVM_TOOLS_LLVM_READOBJ_WIN64EHDUMPER_H -#include "StreamWriter.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/Win64EH.h" namespace llvm { @@ -22,7 +22,7 @@ struct coff_section; namespace Win64EH { class Dumper { - StreamWriter &SW; + ScopedPrinter &SW; raw_ostream &OS; public: @@ -53,7 +53,7 @@ private: uint64_t SectionOffset, const RuntimeFunction &RF); public: - Dumper(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {} + Dumper(ScopedPrinter &SW) : SW(SW), OS(SW.getOStream()) {} void printData(const Context &Ctx); }; diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 120d6c2e172a19ea279994a5fe067802e9836695..c293919fd95279bdc5c892588f177d43536d5b88 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -22,7 +22,7 @@ #include "llvm-readobj.h" #include "Error.h" #include "ObjDumper.h" -#include "StreamWriter.h" +#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/ELFObjectFile.h" @@ -35,6 +35,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" @@ -144,6 +145,11 @@ namespace opts { cl::opt CodeView("codeview", cl::desc("Display CodeView debug information")); + // -codeview-merged-types + cl::opt + CodeViewMergedTypes("codeview-merged-types", + cl::desc("Display the merged CodeView type stream")); + // -codeview-subsection-bytes cl::opt CodeViewSubsectionBytes( "codeview-subsection-bytes", @@ -168,6 +174,10 @@ namespace opts { cl::opt MipsReginfo("mips-reginfo", cl::desc("Display the MIPS .reginfo section")); + // -mips-options + cl::opt MipsOptions("mips-options", + cl::desc("Display the MIPS .MIPS.options section")); + // -coff-imports cl::opt COFFImports("coff-imports", cl::desc("Display the PE/COFF import table")); @@ -186,6 +196,11 @@ namespace opts { COFFBaseRelocs("coff-basereloc", cl::desc("Display the PE/COFF .reloc section")); + // -coff-debug-directory + cl::opt + COFFDebugDirectory("coff-debug-directory", + cl::desc("Display the PE/COFF debug directory")); + // -macho-data-in-code cl::opt MachODataInCode("macho-data-in-code", @@ -232,6 +247,11 @@ namespace opts { cl::desc("Display ELF section group contents")); cl::alias SectionGroupsShort("g", cl::desc("Alias for -elf-sections-groups"), cl::aliasopt(SectionGroups)); + cl::opt HashHistogram( + "elf-hash-histogram", + cl::desc("Display bucket list histogram for hash sections")); + cl::alias HashHistogramShort("I", cl::desc("Alias for -elf-hash-histogram"), + cl::aliasopt(HashHistogram)); cl::opt Output("elf-output-style", cl::desc("Specify ELF dump style"), @@ -275,6 +295,17 @@ static void reportError(StringRef Input, StringRef Message) { reportError(Twine(Input) + ": " + Message); } +static void reportError(StringRef Input, Error Err) { + if (Input == "-") + Input = ""; + std::string ErrMsg; + { + raw_string_ostream ErrStream(ErrMsg); + logAllUnhandledErrors(std::move(Err), ErrStream, Input + ": "); + } + reportError(ErrMsg); +} + static bool isMipsArch(unsigned Arch) { switch (Arch) { case llvm::Triple::mips: @@ -287,8 +318,11 @@ static bool isMipsArch(unsigned Arch) { } } +static llvm::codeview::MemoryTypeTableBuilder CVTypes; + /// @brief Creates an format-specific object file dumper. -static std::error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, +static std::error_code createDumper(const ObjectFile *Obj, + ScopedPrinter &Writer, std::unique_ptr &Result) { if (!Obj) return readobj_error::unsupported_file_format; @@ -305,7 +339,7 @@ static std::error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, /// @brief Dumps the specified object file. static void dumpObject(const ObjectFile *Obj) { - StreamWriter Writer(outs()); + ScopedPrinter Writer(outs()); std::unique_ptr Dumper; if (std::error_code EC = createDumper(Obj, Writer, Dumper)) reportError(Obj->getFileName(), EC); @@ -357,9 +391,13 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printMipsABIFlags(); if (opts::MipsReginfo) Dumper->printMipsReginfo(); + if (opts::MipsOptions) + Dumper->printMipsOptions(); } if (opts::SectionGroups) Dumper->printGroupSections(); + if (opts::HashHistogram) + Dumper->printHashHistogram(); } if (Obj->isCOFF()) { if (opts::COFFImports) @@ -370,8 +408,12 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printCOFFDirectives(); if (opts::COFFBaseRelocs) Dumper->printCOFFBaseReloc(); + if (opts::COFFDebugDirectory) + Dumper->printCOFFDebugDirectory(); if (opts::CodeView) Dumper->printCodeViewDebugInfo(); + if (opts::CodeViewMergedTypes) + Dumper->mergeCodeViewTypes(CVTypes); } if (Obj->isMachO()) { if (opts::MachODataInCode) @@ -393,35 +435,43 @@ static void dumpObject(const ObjectFile *Obj) { /// @brief Dumps each object file in \a Arc; static void dumpArchive(const Archive *Arc) { - for (auto &ErrorOrChild : Arc->children()) { - if (std::error_code EC = ErrorOrChild.getError()) - reportError(Arc->getFileName(), EC.message()); - const auto &Child = *ErrorOrChild; - ErrorOr> ChildOrErr = Child.getAsBinary(); - if (std::error_code EC = ChildOrErr.getError()) { - // Ignore non-object files. - if (EC != object_error::invalid_file_type) - reportError(Arc->getFileName(), EC.message()); + Error Err; + for (auto &Child : Arc->children(Err)) { + Expected> ChildOrErr = Child.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(ChildOrErr.takeError(), OS, ""); + OS.flush(); + reportError(Arc->getFileName(), Buf); + } continue; } - if (ObjectFile *Obj = dyn_cast(&*ChildOrErr.get())) dumpObject(Obj); else reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); } + if (Err) + reportError(Arc->getFileName(), std::move(Err)); } /// @brief Dumps each object file in \a MachO Universal Binary; static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) { for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) { - ErrorOr> ObjOrErr = Obj.getAsObjectFile(); + Expected> ObjOrErr = Obj.getAsObjectFile(); if (ObjOrErr) dumpObject(&*ObjOrErr.get()); - else if (ErrorOr> AOrErr = Obj.getAsArchive()) + else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(ObjOrErr.takeError(), OS, ""); + OS.flush(); + reportError(UBinary->getFileName(), Buf); + } + else if (Expected> AOrErr = Obj.getAsArchive()) dumpArchive(&*AOrErr.get()); - else - reportError(UBinary->getFileName(), ObjOrErr.getError().message()); } } @@ -429,9 +479,9 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) { static void dumpInput(StringRef File) { // Attempt to open the binary. - ErrorOr> BinaryOrErr = createBinary(File); - if (std::error_code EC = BinaryOrErr.getError()) - reportError(File, EC); + Expected> BinaryOrErr = createBinary(File); + if (!BinaryOrErr) + reportError(File, errorToErrorCode(BinaryOrErr.takeError())); Binary &Binary = *BinaryOrErr.get().getBinary(); if (Archive *Arc = dyn_cast(&Binary)) @@ -448,7 +498,7 @@ static void dumpInput(StringRef File) { } int main(int argc, const char *argv[]) { - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; @@ -464,5 +514,10 @@ int main(int argc, const char *argv[]) { std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), dumpInput); + if (opts::CodeViewMergedTypes) { + ScopedPrinter W(outs()); + dumpCodeViewMergedTypes(W, CVTypes); + } + return 0; } diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h index 7155d7e729826df409dce48b9799220d94f0d576..b169c00291838ef034bc0b1b7947d5a2bc8de060 100644 --- a/tools/llvm-readobj/llvm-readobj.h +++ b/tools/llvm-readobj/llvm-readobj.h @@ -13,6 +13,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/Error.h" #include namespace llvm { @@ -28,6 +29,15 @@ namespace llvm { return *EO; reportError(EO.getError().message()); } + template T unwrapOrError(Expected EO) { + if (EO) + return *EO; + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(EO.takeError(), OS, ""); + OS.flush(); + reportError(Buf); + } bool relocAddressLess(object::RelocationRef A, object::RelocationRef B); } // namespace llvm diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index d35d0c60a6f37e729f17b38ff69fb5f2d96192f8..b1460e35de80fbdb7735121f85e88242306f67a2 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -254,7 +254,7 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, static const char *ProgramName; -static int ErrorAndExit(const Twine &Msg) { +static void ErrorAndExit(const Twine &Msg) { errs() << ProgramName << ": error: " << Msg << "\n"; exit(1); } @@ -292,11 +292,16 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { if (std::error_code EC = InputBuffer.getError()) ErrorAndExit("unable to read input: '" + EC.message() + "'"); - ErrorOr> MaybeObj( + Expected> MaybeObj( ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); - if (std::error_code EC = MaybeObj.getError()) - ErrorAndExit("unable to create object file: '" + EC.message() + "'"); + if (!MaybeObj) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(MaybeObj.takeError(), OS, ""); + OS.flush(); + ErrorAndExit("unable to create object file: '" + Buf + "'"); + } ObjectFile &Obj = **MaybeObj; @@ -330,17 +335,26 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { // Use symbol info to iterate functions in the object. for (const auto &P : SymAddr) { object::SymbolRef Sym = P.first; - ErrorOr TypeOrErr = Sym.getType(); - if (!TypeOrErr) + Expected TypeOrErr = Sym.getType(); + if (!TypeOrErr) { + // TODO: Actually report errors helpfully. + consumeError(TypeOrErr.takeError()); continue; + } SymbolRef::Type Type = *TypeOrErr; if (Type == object::SymbolRef::ST_Function) { - ErrorOr Name = Sym.getName(); - if (!Name) + Expected Name = Sym.getName(); + if (!Name) { + // TODO: Actually report errors helpfully. + consumeError(Name.takeError()); continue; - ErrorOr AddrOrErr = Sym.getAddress(); - if (!AddrOrErr) + } + Expected AddrOrErr = Sym.getAddress(); + if (!AddrOrErr) { + // TODO: Actually report errors helpfully. + consumeError(AddrOrErr.takeError()); continue; + } uint64_t Addr = *AddrOrErr; uint64_t Size = P.second; @@ -348,7 +362,13 @@ static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { // symbol in memory (rather than that in the unrelocated object file) // and use that to query the DWARFContext. if (!UseDebugObj && LoadObjects) { - object::section_iterator Sec = *Sym.getSection(); + auto SecOrErr = Sym.getSection(); + if (!SecOrErr) { + // TODO: Actually report errors helpfully. + consumeError(SecOrErr.takeError()); + continue; + } + object::section_iterator Sec = *SecOrErr; StringRef SecName; Sec->getName(SecName); uint64_t SectionLoadAddress = @@ -401,11 +421,16 @@ static int executeInput() { MemoryBuffer::getFileOrSTDIN(File); if (std::error_code EC = InputBuffer.getError()) ErrorAndExit("unable to read input: '" + EC.message() + "'"); - ErrorOr> MaybeObj( + Expected> MaybeObj( ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); - if (std::error_code EC = MaybeObj.getError()) - ErrorAndExit("unable to create object file: '" + EC.message() + "'"); + if (!MaybeObj) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(MaybeObj.takeError(), OS, ""); + OS.flush(); + ErrorAndExit("unable to create object file: '" + Buf + "'"); + } ObjectFile &Obj = **MaybeObj; @@ -665,11 +690,16 @@ static int linkAndVerify() { if (std::error_code EC = InputBuffer.getError()) ErrorAndExit("unable to read input: '" + EC.message() + "'"); - ErrorOr> MaybeObj( + Expected> MaybeObj( ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); - if (std::error_code EC = MaybeObj.getError()) - ErrorAndExit("unable to create object file: '" + EC.message() + "'"); + if (!MaybeObj) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(MaybeObj.takeError(), OS, ""); + OS.flush(); + ErrorAndExit("unable to create object file: '" + Buf + "'"); + } ObjectFile &Obj = **MaybeObj; @@ -699,7 +729,7 @@ static int linkAndVerify() { } int main(int argc, char **argv) { - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); ProgramName = argv[0]; diff --git a/tools/llvm-shlib/CMakeLists.txt b/tools/llvm-shlib/CMakeLists.txt index 2356103a9cd510476bdbb79c9b4ce8b852ee740f..3fe672d679a3da8dcc7579206d1c7260349e6c38 100644 --- a/tools/llvm-shlib/CMakeLists.txt +++ b/tools/llvm-shlib/CMakeLists.txt @@ -2,8 +2,6 @@ # library is enabled by setting LLVM_BUILD_LLVM_DYLIB=yes on the CMake # commandline. By default the shared library only exports the LLVM C API. -add_definitions( -DLLVM_VERSION_INFO=\"${PACKAGE_VERSION}\" ) - set(SOURCES libllvm.cpp ) diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp index f386a244885baa96eacce7be660fc108c2fd5248..c5966ead4b6c5c38e7aa9e60dcb5881f9301e01a 100644 --- a/tools/llvm-size/llvm-size.cpp +++ b/tools/llvm-size/llvm-size.cpp @@ -84,6 +84,8 @@ RadixShort(cl::desc("Print size in radix:"), static cl::list InputFilenames(cl::Positional, cl::desc(""), cl::ZeroOrMore); +bool HadError = false; + static std::string ToolName; /// If ec is not success, print the error and return true. @@ -91,11 +93,64 @@ static bool error(std::error_code ec) { if (!ec) return false; + HadError = true; errs() << ToolName << ": error reading file: " << ec.message() << ".\n"; errs().flush(); return true; } +static bool error(Twine Message) { + HadError = true; + errs() << ToolName << ": " << Message << ".\n"; + errs().flush(); + return true; +} + +// This version of error() prints the archive name and member name, for example: +// "libx.a(foo.o)" after the ToolName before the error message. It sets +// HadError but returns allowing the code to move on to other archive members. +static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, + StringRef ArchitectureName = StringRef()) { + HadError = true; + errs() << ToolName << ": " << FileName; + + ErrorOr NameOrErr = C.getName(); + // TODO: if we have a error getting the name then it would be nice to print + // the index of which archive member this is and or its offset in the + // archive instead of "???" as the name. + if (NameOrErr.getError()) + errs() << "(" << "???" << ")"; + else + errs() << "(" << NameOrErr.get() << ")"; + + if (!ArchitectureName.empty()) + errs() << " (for architecture " << ArchitectureName << ") "; + + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS, ""); + OS.flush(); + errs() << " " << Buf << "\n"; +} + +// This version of error() prints the file name and which architecture slice it // is from, for example: "foo.o (for architecture i386)" after the ToolName +// before the error message. It sets HadError but returns allowing the code to +// move on to other architecture slices. +static void error(llvm::Error E, StringRef FileName, + StringRef ArchitectureName = StringRef()) { + HadError = true; + errs() << ToolName << ": " << FileName; + + if (!ArchitectureName.empty()) + errs() << " (for architecture " << ArchitectureName << ") "; + + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS, ""); + OS.flush(); + errs() << " " << Buf << "\n"; +} + /// 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) { @@ -438,10 +493,10 @@ static bool checkMachOAndArchFlags(ObjectFile *o, StringRef file) { Triple T; if (MachO->is64Bit()) { H_64 = MachO->MachOObjectFile::getHeader64(); - T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype); + T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); } else { H = MachO->MachOObjectFile::getHeader(); - T = MachOObjectFile::getArch(H.cputype, H.cpusubtype); + T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); } unsigned i; for (i = 0; i < ArchFlags.size(); ++i) { @@ -463,21 +518,23 @@ static bool checkMachOAndArchFlags(ObjectFile *o, StringRef file) { static void printFileSectionSizes(StringRef file) { // Attempt to open the binary. - ErrorOr> BinaryOrErr = createBinary(file); - if (error(BinaryOrErr.getError())) + Expected> BinaryOrErr = createBinary(file); + if (!BinaryOrErr) { + error(errorToErrorCode(BinaryOrErr.takeError())); return; + } Binary &Bin = *BinaryOrErr.get().getBinary(); if (Archive *a = dyn_cast(&Bin)) { // This is an archive. Iterate over each member and display its sizes. - for (object::Archive::child_iterator i = a->child_begin(), - e = a->child_end(); - i != e; ++i) { - if (error(i->getError())) - exit(1); - ErrorOr> ChildOrErr = i->get().getAsBinary(); - if (error(ChildOrErr.getError())) + Error Err; + for (auto &C : a->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + error(std::move(E), a->getFileName(), C); continue; + } if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { MachOObjectFile *MachO = dyn_cast(o); if (!checkMachOAndArchFlags(o, file)) @@ -495,6 +552,8 @@ static void printFileSectionSizes(StringRef file) { } } } + if (Err) + error(std::move(Err), a->getFileName()); } else if (MachOUniversalBinary *UB = dyn_cast(&Bin)) { // If we have a list of architecture flags specified dump only those. @@ -508,7 +567,7 @@ static void printFileSectionSizes(StringRef file) { I != E; ++I) { if (ArchFlags[i] == I->getArchTypeName()) { ArchFound = true; - ErrorOr> UO = I->getAsObjectFile(); + Expected> UO = I->getAsObjectFile(); if (UO) { if (ObjectFile *o = dyn_cast(&*UO.get())) { MachOObjectFile *MachO = dyn_cast(o); @@ -527,19 +586,27 @@ static void printFileSectionSizes(StringRef file) { outs() << "\n"; } } - } else if (ErrorOr> AOrErr = + } else if (auto E = isNotObjectErrorInvalidFileType( + UO.takeError())) { + error(std::move(E), file, ArchFlags.size() > 1 ? + StringRef(I->getArchTypeName()) : StringRef()); + return; + } else if (Expected> AOrErr = I->getAsArchive()) { std::unique_ptr &UA = *AOrErr; // This is an archive. Iterate over each member and display its // sizes. - for (object::Archive::child_iterator i = UA->child_begin(), - e = UA->child_end(); - i != e; ++i) { - if (error(i->getError())) - exit(1); - ErrorOr> ChildOrErr = i->get().getAsBinary(); - if (error(ChildOrErr.getError())) + Error Err; + for (auto &C : UA->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), UA->getFileName(), C, + ArchFlags.size() > 1 ? + StringRef(I->getArchTypeName()) : StringRef()); continue; + } if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { MachOObjectFile *MachO = dyn_cast(o); if (OutputFormat == sysv) @@ -565,6 +632,13 @@ static void printFileSectionSizes(StringRef file) { } } } + if (Err) + error(std::move(Err), UA->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error("Mach-O universal file: " + file + " for architecture " + + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file"); } } } @@ -584,7 +658,7 @@ static void printFileSectionSizes(StringRef file) { E = UB->end_objects(); I != E; ++I) { if (HostArchName == I->getArchTypeName()) { - ErrorOr> UO = I->getAsObjectFile(); + Expected> UO = I->getAsObjectFile(); if (UO) { if (ObjectFile *o = dyn_cast(&*UO.get())) { MachOObjectFile *MachO = dyn_cast(o); @@ -603,19 +677,23 @@ static void printFileSectionSizes(StringRef file) { outs() << "\n"; } } - } else if (ErrorOr> AOrErr = + } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { + error(std::move(E), file); + return; + } else if (Expected> AOrErr = I->getAsArchive()) { std::unique_ptr &UA = *AOrErr; // This is an archive. Iterate over each member and display its // sizes. - for (object::Archive::child_iterator i = UA->child_begin(), - e = UA->child_end(); - i != e; ++i) { - if (error(i->getError())) - exit(1); - ErrorOr> ChildOrErr = i->get().getAsBinary(); - if (error(ChildOrErr.getError())) + Error Err; + for (auto &C : UA->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), UA->getFileName(), C); continue; + } if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { MachOObjectFile *MachO = dyn_cast(o); if (OutputFormat == sysv) @@ -636,6 +714,13 @@ static void printFileSectionSizes(StringRef file) { } } } + if (Err) + error(std::move(Err), UA->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error("Mach-O universal file: " + file + " for architecture " + + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file"); } return; } @@ -647,7 +732,7 @@ static void printFileSectionSizes(StringRef file) { for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), E = UB->end_objects(); I != E; ++I) { - ErrorOr> UO = I->getAsObjectFile(); + Expected> UO = I->getAsObjectFile(); if (UO) { if (ObjectFile *o = dyn_cast(&*UO.get())) { MachOObjectFile *MachO = dyn_cast(o); @@ -667,18 +752,24 @@ static void printFileSectionSizes(StringRef file) { outs() << "\n"; } } - } else if (ErrorOr> AOrErr = + } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { + error(std::move(E), file, MoreThanOneArch ? + StringRef(I->getArchTypeName()) : StringRef()); + return; + } else if (Expected> AOrErr = I->getAsArchive()) { std::unique_ptr &UA = *AOrErr; // This is an archive. Iterate over each member and display its sizes. - for (object::Archive::child_iterator i = UA->child_begin(), - e = UA->child_end(); - i != e; ++i) { - if (error(i->getError())) - exit(1); - ErrorOr> ChildOrErr = i->get().getAsBinary(); - if (error(ChildOrErr.getError())) + Error Err; + for (auto &C : UA->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), UA->getFileName(), C, MoreThanOneArch ? + StringRef(I->getArchTypeName()) : StringRef()); continue; + } if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { MachOObjectFile *MachO = dyn_cast(o); if (OutputFormat == sysv) @@ -699,6 +790,13 @@ static void printFileSectionSizes(StringRef file) { } } } + if (Err) + error(std::move(Err), UA->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error("Mach-O universal file: " + file + " for architecture " + + StringRef(I->getArchTypeName()) + + " is not a Mach-O file or an archive file"); } } } else if (ObjectFile *o = dyn_cast(&Bin)) { @@ -724,7 +822,7 @@ static void printFileSectionSizes(StringRef file) { int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. @@ -755,5 +853,6 @@ int main(int argc, char **argv) { std::for_each(InputFilenames.begin(), InputFilenames.end(), printFileSectionSizes); - return 0; + if (HadError) + return 1; } diff --git a/tools/llvm-split/llvm-split.cpp b/tools/llvm-split/llvm-split.cpp index 010b1eb73209eb31e59bdb38576ce2087be7c3f1..024363547f937565164557dfce2db3e65c59c0f7 100644 --- a/tools/llvm-split/llvm-split.cpp +++ b/tools/llvm-split/llvm-split.cpp @@ -41,7 +41,7 @@ static cl::opt cl::desc("Split without externalizing locals")); int main(int argc, char **argv) { - LLVMContext &Context = getGlobalContext(); + LLVMContext Context; SMDiagnostic Err; cl::ParseCommandLineOptions(argc, argv, "LLVM module splitter\n"); diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp index 99d2afdcd3012515a37e6b34c49a70bee7b1f728..0b887ea9b4cd4d130e4336f994ef3e3909f330b3 100644 --- a/tools/llvm-stress/llvm-stress.cpp +++ b/tools/llvm-stress/llvm-stress.cpp @@ -17,10 +17,10 @@ #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" -#include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" @@ -28,8 +28,6 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/ToolOutputFile.h" #include -#include -#include #include namespace llvm { @@ -43,6 +41,8 @@ static cl::opt OutputFilename("o", cl::desc("Override output filename"), cl::value_desc("filename")); +static LLVMContext Context; + namespace cl { template <> class parser final : public basic_parser { public: @@ -50,7 +50,6 @@ public: // Parse options as IR types. Return true on error. bool parse(Option &O, StringRef, StringRef Arg, Type *&Value) { - auto &Context = getGlobalContext(); if (Arg == "half") Value = Type::getHalfTy(Context); else if (Arg == "fp128") Value = Type::getFP128Ty(Context); else if (Arg == "x86_fp80") Value = Type::getX86_FP80Ty(Context); @@ -687,7 +686,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm codegen stress-tester\n"); llvm_shutdown_obj Y; - auto M = make_unique("/tmp/autogen.bc", getGlobalContext()); + auto M = make_unique("/tmp/autogen.bc", Context); Function *F = GenEmptyFunction(M.get()); // Pick an initial seed value diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp index 950349377bf79c21ca85579188212b8442cc670c..7ee4ba19603b7c6360fb90ba9ee7d7e4bba7f4b2 100644 --- a/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -86,10 +86,12 @@ static cl::opt ClPrintSourceContextLines( "print-source-context-lines", cl::init(0), cl::desc("Print N number of source file context")); -static bool error(std::error_code ec) { - if (!ec) +template +static bool error(Expected &ResOrErr) { + if (ResOrErr) return false; - errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n"; + logAllUnhandledErrors(ResOrErr.takeError(), errs(), + "LLVMSymbolizer: error reading file: "); return true; } @@ -138,7 +140,7 @@ static bool parseCommand(StringRef InputString, bool &IsData, int main(int argc, char **argv) { // Print stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. @@ -185,14 +187,14 @@ int main(int argc, char **argv) { } if (IsData) { auto ResOrErr = Symbolizer.symbolizeData(ModuleName, ModuleOffset); - Printer << (error(ResOrErr.getError()) ? DIGlobal() : ResOrErr.get()); + Printer << (error(ResOrErr) ? DIGlobal() : ResOrErr.get()); } else if (ClPrintInlining) { auto ResOrErr = Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset); - Printer << (error(ResOrErr.getError()) ? DIInliningInfo() + Printer << (error(ResOrErr) ? DIInliningInfo() : ResOrErr.get()); } else { auto ResOrErr = Symbolizer.symbolizeCode(ModuleName, ModuleOffset); - Printer << (error(ResOrErr.getError()) ? DILineInfo() : ResOrErr.get()); + Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get()); } outs() << "\n"; outs().flush(); diff --git a/tools/lto/CMakeLists.txt b/tools/lto/CMakeLists.txt index 293a12608ae8d4a9726d04273be42b9b32e7ac76..8a1571ba03f126afc951e8959854ad9b285924a8 100644 --- a/tools/lto/CMakeLists.txt +++ b/tools/lto/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} + BitReader Core LTO MC diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index 165b23da0244a77edc9b1e87cf5cb5fd0e55e176..7109cf4d909705dc71d31bccc97ae854da3c7559 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -14,13 +14,14 @@ #include "llvm-c/lto.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/LTO/LTOCodeGenerator.h" -#include "llvm/LTO/LTOModule.h" -#include "llvm/LTO/ThinLTOCodeGenerator.h" +#include "llvm/LTO/legacy/LTOCodeGenerator.h" +#include "llvm/LTO/legacy/LTOModule.h" +#include "llvm/LTO/legacy/ThinLTOCodeGenerator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" @@ -101,7 +102,8 @@ static void lto_initialize() { InitializeAllAsmPrinters(); InitializeAllDisassemblers(); - LTOContext = &getGlobalContext(); + static LLVMContext Context; + LTOContext = &Context; LTOContext->setDiagnosticHandler(diagnosticHandler, nullptr, true); initialized = true; } @@ -118,16 +120,18 @@ static void handleLibLTODiagnostic(lto_codegen_diagnostic_severity_t Severity, // libLTO API semantics, which require that the code generator owns the object // file. struct LibLTOCodeGenerator : LTOCodeGenerator { - LibLTOCodeGenerator() : LTOCodeGenerator(*LTOContext) { - setDiagnosticHandler(handleLibLTODiagnostic, nullptr); } + LibLTOCodeGenerator() : LTOCodeGenerator(*LTOContext) { init(); } LibLTOCodeGenerator(std::unique_ptr Context) : LTOCodeGenerator(*Context), OwnedContext(std::move(Context)) { - setDiagnosticHandler(handleLibLTODiagnostic, nullptr); } + init(); + } // Reset the module first in case MergedModule is created in OwnedContext. // Module must be destructed before its context gets destructed. ~LibLTOCodeGenerator() { resetMergedModule(); } + void init() { setDiagnosticHandler(handleLibLTODiagnostic, nullptr); } + std::unique_ptr NativeObjectFile; std::unique_ptr OwnedContext; }; @@ -177,6 +181,14 @@ bool lto_module_is_object_file_for_target(const char* path, return LTOModule::isBitcodeForTarget(Buffer->get(), target_triplet_prefix); } +bool lto_module_has_objc_category(const void *mem, size_t length) { + std::unique_ptr Buffer(LTOModule::makeBuffer(mem, length)); + if (!Buffer) + return false; + LLVMContext Ctx; + return llvm::isBitcodeContainingObjCCategory(*Buffer, Ctx); +} + bool lto_module_is_object_file_in_memory(const void* mem, size_t length) { return LTOModule::isBitcodeFile(mem, length); } @@ -354,7 +366,7 @@ bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model) { unwrap(cg)->setCodePICModel(Reloc::DynamicNoPIC); return false; case LTO_CODEGEN_PIC_MODEL_DEFAULT: - unwrap(cg)->setCodePICModel(Reloc::Default); + unwrap(cg)->setCodePICModel(None); return false; } sLastErrorString = "Unknown PIC model"; @@ -473,6 +485,16 @@ LTOObjectBuffer thinlto_module_get_object(thinlto_code_gen_t cg, MemBuffer->getBufferSize()}; } +void thinlto_codegen_disable_codegen(thinlto_code_gen_t cg, + lto_bool_t disable) { + unwrap(cg)->disableCodeGen(disable); +} + +void thinlto_codegen_set_codegen_only(thinlto_code_gen_t cg, + lto_bool_t CodeGenOnly) { + unwrap(cg)->setCodeGenOnly(CodeGenOnly); +} + void thinlto_debug_options(const char *const *options, int number) { // if options were requested, set them if (number && options) { @@ -483,7 +505,7 @@ void thinlto_debug_options(const char *const *options, int number) { } } -bool lto_module_is_thinlto(lto_module_t mod) { +lto_bool_t lto_module_is_thinlto(lto_module_t mod) { return unwrap(mod)->isThinLTO(); } @@ -539,7 +561,7 @@ lto_bool_t thinlto_codegen_set_pic_model(thinlto_code_gen_t cg, unwrap(cg)->setCodePICModel(Reloc::DynamicNoPIC); return false; case LTO_CODEGEN_PIC_MODEL_DEFAULT: - unwrap(cg)->setCodePICModel(Reloc::Default); + unwrap(cg)->setCodePICModel(None); return false; } sLastErrorString = "Unknown PIC model"; diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports index e0df0ca0e4f74bfe190300e0b1b4ed2c5257be6c..74091c2641b7716be4d72deebc475a0035b92e95 100644 --- a/tools/lto/lto.exports +++ b/tools/lto/lto.exports @@ -18,6 +18,7 @@ lto_module_is_object_file lto_module_is_object_file_for_target lto_module_is_object_file_in_memory lto_module_is_object_file_in_memory_for_target +lto_module_has_objc_category lto_module_dispose lto_api_version lto_codegen_set_diagnostic_handler @@ -61,4 +62,6 @@ thinlto_debug_options lto_module_is_thinlto thinlto_codegen_add_must_preserve_symbol thinlto_codegen_add_cross_referenced_symbol -thinlto_codegen_set_final_cache_size_relative_to_available_space \ No newline at end of file +thinlto_codegen_set_final_cache_size_relative_to_available_space +thinlto_codegen_set_codegen_only +thinlto_codegen_disable_codegen \ No newline at end of file diff --git a/tools/obj2yaml/CMakeLists.txt b/tools/obj2yaml/CMakeLists.txt index 9d8c32f9e420325588618c8dd04b334223de581c..9b89552506025e6bbbe3465e1e603197f7e71700 100644 --- a/tools/obj2yaml/CMakeLists.txt +++ b/tools/obj2yaml/CMakeLists.txt @@ -5,5 +5,9 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_tool(obj2yaml - obj2yaml.cpp coff2yaml.cpp elf2yaml.cpp Error.cpp + obj2yaml.cpp + coff2yaml.cpp + elf2yaml.cpp + macho2yaml.cpp + Error.cpp ) diff --git a/tools/obj2yaml/Error.cpp b/tools/obj2yaml/Error.cpp index abef8af58cbfecd4797ed0dd0b2c3840e9ee6ad3..9d1af680a7399f8d1310abf3e727d12d354295eb 100644 --- a/tools/obj2yaml/Error.cpp +++ b/tools/obj2yaml/Error.cpp @@ -13,6 +13,9 @@ using namespace llvm; namespace { +// FIXME: This class is only here to support the transition to llvm::Error. It +// will be removed once this transition is complete. Clients should prefer to +// deal with the Error value directly, rather than converting to error_code. class _obj2yaml_error_category : public std::error_category { public: const char *name() const LLVM_NOEXCEPT override; @@ -34,14 +37,26 @@ std::string _obj2yaml_error_category::message(int ev) const { return "Unrecognized file type."; case obj2yaml_error::unsupported_obj_file_format: return "Unsupported object file format."; + case obj2yaml_error::not_implemented: + return "Feature not yet implemented."; } llvm_unreachable("An enumerator of obj2yaml_error does not have a message " "defined."); } namespace llvm { - const std::error_category &obj2yaml_category() { + +const std::error_category &obj2yaml_category() { static _obj2yaml_error_category o; return o; } + +char Obj2YamlError::ID = 0; + +void Obj2YamlError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } + +std::error_code Obj2YamlError::convertToErrorCode() const { + return std::error_code(static_cast(Code), obj2yaml_category()); +} + } // namespace llvm diff --git a/tools/obj2yaml/Error.h b/tools/obj2yaml/Error.h index 982f59e236cc024b9cdbee177c421d0875b79e0b..f5111f257ce36f257af540f56b8e6a9b7a7df8af 100644 --- a/tools/obj2yaml/Error.h +++ b/tools/obj2yaml/Error.h @@ -10,6 +10,8 @@ #ifndef LLVM_TOOLS_OBJ2YAML_ERROR_H #define LLVM_TOOLS_OBJ2YAML_ERROR_H +#include "llvm/Support/Error.h" + #include namespace llvm { @@ -19,13 +21,30 @@ enum class obj2yaml_error { success = 0, file_not_found, unrecognized_file_format, - unsupported_obj_file_format + unsupported_obj_file_format, + not_implemented }; inline std::error_code make_error_code(obj2yaml_error e) { return std::error_code(static_cast(e), obj2yaml_category()); } +class Obj2YamlError : public ErrorInfo { +public: + static char ID; + Obj2YamlError(obj2yaml_error C) : Code(C) {} + Obj2YamlError(std::string ErrMsg) : ErrMsg(std::move(ErrMsg)) {} + Obj2YamlError(obj2yaml_error C, std::string ErrMsg) + : ErrMsg(std::move(ErrMsg)), Code(C) {} + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const { return ErrMsg; } + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + obj2yaml_error Code; +}; + } // namespace llvm namespace std { diff --git a/tools/obj2yaml/coff2yaml.cpp b/tools/obj2yaml/coff2yaml.cpp index aea6fe90d70400e271b758e67d28b43bf11ac7db..c734601ede76b62d8d457d972aa9c146f1cc874a 100644 --- a/tools/obj2yaml/coff2yaml.cpp +++ b/tools/obj2yaml/coff2yaml.cpp @@ -121,9 +121,14 @@ void COFFDumper::dumpSections(unsigned NumSections) { const object::coff_relocation *reloc = Obj.getCOFFRelocation(Reloc); COFFYAML::Relocation Rel; object::symbol_iterator Sym = Reloc.getSymbol(); - ErrorOr SymbolNameOrErr = Sym->getName(); - if (std::error_code EC = SymbolNameOrErr.getError()) - report_fatal_error(EC.message()); + Expected SymbolNameOrErr = Sym->getName(); + if (!SymbolNameOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymbolNameOrErr.takeError(), OS, ""); + OS.flush(); + report_fatal_error(Buf); + } Rel.SymbolName = *SymbolNameOrErr; Rel.VirtualAddress = reloc->VirtualAddress; Rel.Type = reloc->Type; diff --git a/tools/obj2yaml/elf2yaml.cpp b/tools/obj2yaml/elf2yaml.cpp index e05f428e16ac57bd5e0603cd175ef715f5c4a6f4..782832d54571f50498428d3e6784873e2dcc4105 100644 --- a/tools/obj2yaml/elf2yaml.cpp +++ b/tools/obj2yaml/elf2yaml.cpp @@ -179,10 +179,10 @@ ELFDumper::dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab, S.Size = Sym->st_size; S.Other = Sym->st_other; - ErrorOr NameOrErr = Sym->getName(StrTable); - if (std::error_code EC = NameOrErr.getError()) - return EC; - S.Name = NameOrErr.get(); + Expected SymbolNameOrErr = Sym->getName(StrTable); + if (!SymbolNameOrErr) + return errorToErrorCode(SymbolNameOrErr.takeError()); + S.Name = SymbolNameOrErr.get(); ErrorOr ShdrOrErr = Obj.getSection(Sym, SymTab, ShndxTable); if (std::error_code EC = ShdrOrErr.getError()) @@ -191,7 +191,7 @@ ELFDumper::dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab, if (!Shdr) return obj2yaml_error::success; - NameOrErr = Obj.getSectionName(Shdr); + ErrorOr NameOrErr = Obj.getSectionName(Shdr); if (std::error_code EC = NameOrErr.getError()) return EC; S.Section = NameOrErr.get(); @@ -217,9 +217,9 @@ std::error_code ELFDumper::dumpRelocation(const RelT *Rel, return EC; StringRef StrTab = *StrTabOrErr; - ErrorOr NameOrErr = Sym->getName(StrTab); - if (std::error_code EC = NameOrErr.getError()) - return EC; + Expected NameOrErr = Sym->getName(StrTab); + if (!NameOrErr) + return errorToErrorCode(NameOrErr.takeError()); R.Symbol = NameOrErr.get(); return obj2yaml_error::success; @@ -368,9 +368,9 @@ ErrorOr ELFDumper::dumpGroup(const Elf_Shdr *Shdr) { auto sectionContents = Obj.getSectionContents(Shdr); if (std::error_code ec = sectionContents.getError()) return ec; - ErrorOr symbolName = symbol->getName(StrTab); - if (std::error_code EC = symbolName.getError()) - return EC; + Expected symbolName = symbol->getName(StrTab); + if (!symbolName) + return errorToErrorCode(symbolName.takeError()); S->Info = *symbolName; const Elf_Word *groupMembers = reinterpret_cast(sectionContents->data()); diff --git a/tools/obj2yaml/macho2yaml.cpp b/tools/obj2yaml/macho2yaml.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9a1385f173007768812eb12bc8ed73ecdb4e6c7 --- /dev/null +++ b/tools/obj2yaml/macho2yaml.cpp @@ -0,0 +1,527 @@ +//===------ macho2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "obj2yaml.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LEB128.h" + +#include // for memcpy + +using namespace llvm; + +class MachODumper { + + template + const char *processLoadCommandData( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd); + + const object::MachOObjectFile &Obj; + void dumpHeader(std::unique_ptr &Y); + void dumpLoadCommands(std::unique_ptr &Y); + void dumpLinkEdit(std::unique_ptr &Y); + void dumpRebaseOpcodes(std::unique_ptr &Y); + void dumpBindOpcodes(std::vector &BindOpcodes, + ArrayRef OpcodeBuffer, bool Lazy = false); + void dumpExportTrie(std::unique_ptr &Y); + void dumpSymbols(std::unique_ptr &Y); + +public: + MachODumper(const object::MachOObjectFile &O) : Obj(O) {} + Expected> dump(); +}; + +#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ + case MachO::LCName: \ + memcpy((void *) & (LC.Data.LCStruct##_data), LoadCmd.Ptr, \ + sizeof(MachO::LCStruct)); \ + if (Obj.isLittleEndian() != sys::IsLittleEndianHost) \ + MachO::swapStruct(LC.Data.LCStruct##_data); \ + EndPtr = processLoadCommandData(LC, LoadCmd); \ + break; + +template +MachOYAML::Section constructSectionCommon(SectionType Sec) { + MachOYAML::Section TempSec; + memcpy(reinterpret_cast(&TempSec.sectname[0]), &Sec.sectname[0], 16); + memcpy(reinterpret_cast(&TempSec.segname[0]), &Sec.segname[0], 16); + TempSec.addr = Sec.addr; + TempSec.size = Sec.size; + TempSec.offset = Sec.offset; + TempSec.align = Sec.align; + TempSec.reloff = Sec.reloff; + TempSec.nreloc = Sec.nreloc; + TempSec.flags = Sec.flags; + TempSec.reserved1 = Sec.reserved1; + TempSec.reserved2 = Sec.reserved2; + TempSec.reserved3 = 0; + return TempSec; +} + +template +MachOYAML::Section constructSection(SectionType Sec); + +template <> MachOYAML::Section constructSection(MachO::section Sec) { + MachOYAML::Section TempSec = constructSectionCommon(Sec); + TempSec.reserved3 = 0; + return TempSec; +} + +template <> MachOYAML::Section constructSection(MachO::section_64 Sec) { + MachOYAML::Section TempSec = constructSectionCommon(Sec); + TempSec.reserved3 = Sec.reserved3; + return TempSec; +} + +template +const char * +extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd, + std::vector &Sections, + bool IsLittleEndian) { + auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize; + const SectionType *Curr = + reinterpret_cast(LoadCmd.Ptr + sizeof(SegmentType)); + for (; reinterpret_cast(Curr) < End; Curr++) { + if (IsLittleEndian != sys::IsLittleEndianHost) { + SectionType Sec; + memcpy((void *)&Sec, Curr, sizeof(SectionType)); + MachO::swapStruct(Sec); + Sections.push_back(constructSection(Sec)); + } else { + Sections.push_back(constructSection(*Curr)); + } + } + return reinterpret_cast(Curr); +} + +template +const char *MachODumper::processLoadCommandData( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return LoadCmd.Ptr + sizeof(StructType); +} + +template <> +const char *MachODumper::processLoadCommandData( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return extractSections( + LoadCmd, LC.Sections, Obj.isLittleEndian()); +} + +template <> +const char *MachODumper::processLoadCommandData( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return extractSections( + LoadCmd, LC.Sections, Obj.isLittleEndian()); +} + +template +const char * +readString(MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + auto Start = LoadCmd.Ptr + sizeof(StructType); + auto MaxSize = LoadCmd.C.cmdsize - sizeof(StructType); + auto Size = strnlen(Start, MaxSize); + LC.PayloadString = StringRef(Start, Size).str(); + return Start + Size; +} + +template <> +const char *MachODumper::processLoadCommandData( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return readString(LC, LoadCmd); +} + +template <> +const char *MachODumper::processLoadCommandData( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return readString(LC, LoadCmd); +} + +template <> +const char *MachODumper::processLoadCommandData( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return readString(LC, LoadCmd); +} + +Expected> MachODumper::dump() { + auto Y = make_unique(); + dumpHeader(Y); + dumpLoadCommands(Y); + dumpLinkEdit(Y); + return std::move(Y); +} + +void MachODumper::dumpHeader(std::unique_ptr &Y) { + Y->Header.magic = Obj.getHeader().magic; + Y->Header.cputype = Obj.getHeader().cputype; + Y->Header.cpusubtype = Obj.getHeader().cpusubtype; + Y->Header.filetype = Obj.getHeader().filetype; + Y->Header.ncmds = Obj.getHeader().ncmds; + Y->Header.sizeofcmds = Obj.getHeader().sizeofcmds; + Y->Header.flags = Obj.getHeader().flags; + Y->Header.reserved = 0; +} + +void MachODumper::dumpLoadCommands(std::unique_ptr &Y) { + for (auto LoadCmd : Obj.load_commands()) { + MachOYAML::LoadCommand LC; + const char *EndPtr = LoadCmd.Ptr; + switch (LoadCmd.C.cmd) { + default: + memcpy((void *)&(LC.Data.load_command_data), LoadCmd.Ptr, + sizeof(MachO::load_command)); + if (Obj.isLittleEndian() != sys::IsLittleEndianHost) + MachO::swapStruct(LC.Data.load_command_data); + EndPtr = processLoadCommandData(LC, LoadCmd); + break; +#include "llvm/Support/MachO.def" + } + auto RemainingBytes = LoadCmd.C.cmdsize - (EndPtr - LoadCmd.Ptr); + if (!std::all_of(EndPtr, &EndPtr[RemainingBytes], + [](const char C) { return C == 0; })) { + LC.PayloadBytes.insert(LC.PayloadBytes.end(), EndPtr, + &EndPtr[RemainingBytes]); + RemainingBytes = 0; + } + LC.ZeroPadBytes = RemainingBytes; + Y->LoadCommands.push_back(std::move(LC)); + } +} + +void MachODumper::dumpLinkEdit(std::unique_ptr &Y) { + dumpRebaseOpcodes(Y); + dumpBindOpcodes(Y->LinkEdit.BindOpcodes, Obj.getDyldInfoBindOpcodes()); + dumpBindOpcodes(Y->LinkEdit.WeakBindOpcodes, + Obj.getDyldInfoWeakBindOpcodes()); + dumpBindOpcodes(Y->LinkEdit.LazyBindOpcodes, Obj.getDyldInfoLazyBindOpcodes(), + true); + dumpExportTrie(Y); + dumpSymbols(Y); +} + +void MachODumper::dumpRebaseOpcodes(std::unique_ptr &Y) { + MachOYAML::LinkEditData &LEData = Y->LinkEdit; + + auto RebaseOpcodes = Obj.getDyldInfoRebaseOpcodes(); + for (auto OpCode = RebaseOpcodes.begin(); OpCode != RebaseOpcodes.end(); + ++OpCode) { + MachOYAML::RebaseOpcode RebaseOp; + RebaseOp.Opcode = + static_cast(*OpCode & MachO::REBASE_OPCODE_MASK); + RebaseOp.Imm = *OpCode & MachO::REBASE_IMMEDIATE_MASK; + + unsigned Count; + uint64_t ULEB = 0; + + switch (RebaseOp.Opcode) { + case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: + + ULEB = decodeULEB128(OpCode + 1, &Count); + RebaseOp.ExtraData.push_back(ULEB); + OpCode += Count; + // Intentionally no break here -- This opcode has two ULEB values + case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: + case MachO::REBASE_OPCODE_ADD_ADDR_ULEB: + case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES: + case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: + + ULEB = decodeULEB128(OpCode + 1, &Count); + RebaseOp.ExtraData.push_back(ULEB); + OpCode += Count; + break; + default: + break; + } + + LEData.RebaseOpcodes.push_back(RebaseOp); + + if (RebaseOp.Opcode == MachO::REBASE_OPCODE_DONE) + break; + } +} + +StringRef ReadStringRef(const uint8_t *Start) { + const uint8_t *Itr = Start; + for (; *Itr; ++Itr) + ; + return StringRef(reinterpret_cast(Start), Itr - Start); +} + +void MachODumper::dumpBindOpcodes( + std::vector &BindOpcodes, + ArrayRef OpcodeBuffer, bool Lazy) { + for (auto OpCode = OpcodeBuffer.begin(); OpCode != OpcodeBuffer.end(); + ++OpCode) { + MachOYAML::BindOpcode BindOp; + BindOp.Opcode = + static_cast(*OpCode & MachO::BIND_OPCODE_MASK); + BindOp.Imm = *OpCode & MachO::BIND_IMMEDIATE_MASK; + + unsigned Count; + uint64_t ULEB = 0; + int64_t SLEB = 0; + + switch (BindOp.Opcode) { + case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: + ULEB = decodeULEB128(OpCode + 1, &Count); + BindOp.ULEBExtraData.push_back(ULEB); + OpCode += Count; + // Intentionally no break here -- this opcode has two ULEB values + + case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: + case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: + case MachO::BIND_OPCODE_ADD_ADDR_ULEB: + case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: + ULEB = decodeULEB128(OpCode + 1, &Count); + BindOp.ULEBExtraData.push_back(ULEB); + OpCode += Count; + break; + + case MachO::BIND_OPCODE_SET_ADDEND_SLEB: + SLEB = decodeSLEB128(OpCode + 1, &Count); + BindOp.SLEBExtraData.push_back(SLEB); + OpCode += Count; + break; + + case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: + BindOp.Symbol = ReadStringRef(OpCode + 1); + OpCode += BindOp.Symbol.size() + 1; + break; + default: + break; + } + + BindOpcodes.push_back(BindOp); + + // Lazy bindings have DONE opcodes between operations, so we need to keep + // processing after a DONE. + if (!Lazy && BindOp.Opcode == MachO::BIND_OPCODE_DONE) + break; + } +} + +/*! + * /brief processes a node from the export trie, and its children. + * + * To my knowledge there is no documentation of the encoded format of this data + * other than in the heads of the Apple linker engineers. To that end hopefully + * this comment and the implementation below can serve to light the way for + * anyone crazy enough to come down this path in the future. + * + * This function reads and preserves the trie structure of the export trie. To + * my knowledge there is no code anywhere else that reads the data and preserves + * the Trie. LD64 (sources available at opensource.apple.com) has a similar + * implementation that parses the export trie into a vector. That code as well + * as LLVM's libObject MachO implementation were the basis for this. + * + * The export trie is an encoded trie. The node serialization is a bit awkward. + * The below pseudo-code is the best description I've come up with for it. + * + * struct SerializedNode { + * ULEB128 TerminalSize; + * struct TerminalData { <-- This is only present if TerminalSize > 0 + * ULEB128 Flags; + * ULEB128 Address; <-- Present if (! Flags & REEXPORT ) + * ULEB128 Other; <-- Present if ( Flags & REEXPORT || + * Flags & STUB_AND_RESOLVER ) + * char[] ImportName; <-- Present if ( Flags & REEXPORT ) + * } + * uint8_t ChildrenCount; + * Pair ChildNameOffsetPair[ChildrenCount]; + * SerializedNode Children[ChildrenCount] + * } + * + * Terminal nodes are nodes that represent actual exports. They can appear + * anywhere in the tree other than at the root; they do not need to be leaf + * nodes. When reading the data out of the trie this routine reads it in-order, + * but it puts the child names and offsets directly into the child nodes. This + * results in looping over the children twice during serialization and + * de-serialization, but it makes the YAML representation more human readable. + * + * Below is an example of the graph from a "Hello World" executable: + * + * ------- + * | '' | + * ------- + * | + * ------- + * | '_' | + * ------- + * | + * |----------------------------------------| + * | | + * ------------------------ --------------------- + * | '_mh_execute_header' | | 'main' | + * | Flags: 0x00000000 | | Flags: 0x00000000 | + * | Addr: 0x00000000 | | Addr: 0x00001160 | + * ------------------------ --------------------- + * + * This graph represents the trie for the exports "__mh_execute_header" and + * "_main". In the graph only the "_main" and "__mh_execute_header" nodes are + * terminal. +*/ + +const uint8_t *processExportNode(const uint8_t *CurrPtr, + const uint8_t *const End, + MachOYAML::ExportEntry &Entry) { + if (CurrPtr >= End) + return CurrPtr; + unsigned Count = 0; + Entry.TerminalSize = decodeULEB128(CurrPtr, &Count); + CurrPtr += Count; + if (Entry.TerminalSize != 0) { + Entry.Flags = decodeULEB128(CurrPtr, &Count); + CurrPtr += Count; + if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) { + Entry.Address = 0; + Entry.Other = decodeULEB128(CurrPtr, &Count); + CurrPtr += Count; + Entry.ImportName = std::string(reinterpret_cast(CurrPtr)); + } else { + Entry.Address = decodeULEB128(CurrPtr, &Count); + CurrPtr += Count; + if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) { + Entry.Other = decodeULEB128(CurrPtr, &Count); + CurrPtr += Count; + } else + Entry.Other = 0; + } + } + uint8_t childrenCount = *CurrPtr++; + if (childrenCount == 0) + return CurrPtr; + + Entry.Children.insert(Entry.Children.begin(), (size_t)childrenCount, + MachOYAML::ExportEntry()); + for (auto &Child : Entry.Children) { + Child.Name = std::string(reinterpret_cast(CurrPtr)); + CurrPtr += Child.Name.length() + 1; + Child.NodeOffset = decodeULEB128(CurrPtr, &Count); + CurrPtr += Count; + } + for (auto &Child : Entry.Children) { + CurrPtr = processExportNode(CurrPtr, End, Child); + } + return CurrPtr; +} + +void MachODumper::dumpExportTrie(std::unique_ptr &Y) { + MachOYAML::LinkEditData &LEData = Y->LinkEdit; + auto ExportsTrie = Obj.getDyldInfoExportsTrie(); + processExportNode(ExportsTrie.begin(), ExportsTrie.end(), LEData.ExportTrie); +} + +template +MachOYAML::NListEntry constructNameList(const nlist_t &nlist) { + MachOYAML::NListEntry NL; + NL.n_strx = nlist.n_strx; + NL.n_type = nlist.n_type; + NL.n_sect = nlist.n_sect; + NL.n_desc = nlist.n_desc; + NL.n_value = nlist.n_value; + return NL; +} + +void MachODumper::dumpSymbols(std::unique_ptr &Y) { + MachOYAML::LinkEditData &LEData = Y->LinkEdit; + + for (auto Symbol : Obj.symbols()) { + MachOYAML::NListEntry NLE = + Obj.is64Bit() ? constructNameList( + *reinterpret_cast( + Symbol.getRawDataRefImpl().p)) + : constructNameList( + *reinterpret_cast( + Symbol.getRawDataRefImpl().p)); + LEData.NameList.push_back(NLE); + } + + StringRef RemainingTable = Obj.getStringTableData(); + while (RemainingTable.size() > 0) { + auto SymbolPair = RemainingTable.split('\0'); + RemainingTable = SymbolPair.second; + if (SymbolPair.first.empty()) + break; + LEData.StringTable.push_back(SymbolPair.first); + } +} + +Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) { + MachODumper Dumper(Obj); + Expected> YAML = Dumper.dump(); + if (!YAML) + return YAML.takeError(); + + yaml::YamlObjectFile YAMLFile; + YAMLFile.MachO = std::move(YAML.get()); + + yaml::Output Yout(Out); + Yout << YAMLFile; + return Error::success(); +} + +Error macho2yaml(raw_ostream &Out, const object::MachOUniversalBinary &Obj) { + yaml::YamlObjectFile YAMLFile; + YAMLFile.FatMachO.reset(new MachOYAML::UniversalBinary()); + MachOYAML::UniversalBinary &YAML = *YAMLFile.FatMachO; + YAML.Header.magic = Obj.getMagic(); + YAML.Header.nfat_arch = Obj.getNumberOfObjects(); + + for (auto Slice : Obj.objects()) { + MachOYAML::FatArch arch; + arch.cputype = Slice.getCPUType(); + arch.cpusubtype = Slice.getCPUSubType(); + arch.offset = Slice.getOffset(); + arch.size = Slice.getSize(); + arch.align = Slice.getAlign(); + arch.reserved = Slice.getReserved(); + YAML.FatArchs.push_back(arch); + + auto SliceObj = Slice.getAsObjectFile(); + if (!SliceObj) + return SliceObj.takeError(); + + MachODumper Dumper(*SliceObj.get()); + Expected> YAMLObj = Dumper.dump(); + if (!YAMLObj) + return YAMLObj.takeError(); + YAML.Slices.push_back(*YAMLObj.get()); + } + + yaml::Output Yout(Out); + Yout << YAML; + return Error::success(); +} + +std::error_code macho2yaml(raw_ostream &Out, const object::Binary &Binary) { + if (const auto *MachOObj = dyn_cast(&Binary)) { + if (auto Err = macho2yaml(Out, *MachOObj)) { + return errorToErrorCode(std::move(Err)); + } + return obj2yaml_error::success; + } + + if (const auto *MachOObj = dyn_cast(&Binary)) { + if (auto Err = macho2yaml(Out, *MachOObj)) { + return errorToErrorCode(std::move(Err)); + } + return obj2yaml_error::success; + } + + return obj2yaml_error::unsupported_obj_file_format; +} diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp index ee6284da6e417229aabb99a849e8b820067319e6..3f9373ee17e38e9881b2f024b379cd041094eb7e 100644 --- a/tools/obj2yaml/obj2yaml.cpp +++ b/tools/obj2yaml/obj2yaml.cpp @@ -29,11 +29,15 @@ static std::error_code dumpObject(const ObjectFile &Obj) { } static std::error_code dumpInput(StringRef File) { - ErrorOr> BinaryOrErr = createBinary(File); - if (std::error_code EC = BinaryOrErr.getError()) - return EC; + Expected> BinaryOrErr = createBinary(File); + if (!BinaryOrErr) + return errorToErrorCode(BinaryOrErr.takeError()); Binary &Binary = *BinaryOrErr.get().getBinary(); + // Universal MachO is not a subclass of ObjectFile, so it needs to be handled + // here with the other binary types. + if (Binary.isMachO() || Binary.isMachOUniversalBinary()) + return macho2yaml(outs(), Binary); // TODO: If this is an archive, then burst it and dump each entry if (ObjectFile *Obj = dyn_cast(&Binary)) return dumpObject(*Obj); @@ -46,7 +50,7 @@ cl::opt InputFilename(cl::Positional, cl::desc(""), int main(int argc, char *argv[]) { cl::ParseCommandLineOptions(argc, argv); - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. diff --git a/tools/obj2yaml/obj2yaml.h b/tools/obj2yaml/obj2yaml.h index 643ab7bc434d318eb7c57fbf0e058eee3669b110..28c74751c0d95bad88d4d23203d49cc77f7d4ab3 100644 --- a/tools/obj2yaml/obj2yaml.h +++ b/tools/obj2yaml/obj2yaml.h @@ -21,5 +21,7 @@ std::error_code coff2yaml(llvm::raw_ostream &Out, const llvm::object::COFFObjectFile &Obj); std::error_code elf2yaml(llvm::raw_ostream &Out, const llvm::object::ObjectFile &Obj); +std::error_code macho2yaml(llvm::raw_ostream &Out, + const llvm::object::Binary &Obj); #endif diff --git a/tools/opt/BreakpointPrinter.cpp b/tools/opt/BreakpointPrinter.cpp index 363a7cd80074ee5a1bc61c9e0ee5f9511355bbb5..33b3edcd1237831b34275eb3022752ba86abebd4 100644 --- a/tools/opt/BreakpointPrinter.cpp +++ b/tools/opt/BreakpointPrinter.cpp @@ -25,7 +25,6 @@ namespace { struct BreakpointPrinter : public ModulePass { raw_ostream &Out; static char ID; - DITypeIdentifierMap TypeIdentifierMap; BreakpointPrinter(raw_ostream &out) : ModulePass(ID), Out(out) {} @@ -37,18 +36,13 @@ struct BreakpointPrinter : public ModulePass { } } else if (auto *TY = dyn_cast(Context)) { if (!TY->getName().empty()) { - getContextName(TY->getScope().resolve(TypeIdentifierMap), N); + getContextName(TY->getScope().resolve(), N); N = N + TY->getName().str() + "::"; } } } bool runOnModule(Module &M) override { - TypeIdentifierMap.clear(); - NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu"); - if (CU_Nodes) - TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes); - StringSet<> Processed; if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp")) for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { @@ -56,7 +50,7 @@ struct BreakpointPrinter : public ModulePass { auto *SP = cast_or_null(NMD->getOperand(i)); if (!SP) continue; - getContextName(SP->getScope().resolve(TypeIdentifierMap), Name); + getContextName(SP->getScope().resolve(), Name); Name = Name + SP->getDisplayName().str(); if (!Name.empty() && Processed.insert(Name).second) { Out << Name << "\n"; diff --git a/tools/opt/NewPMDriver.cpp b/tools/opt/NewPMDriver.cpp index 130474408bdac33b53d73896769812cc31f5f4f5..f7b2f18d09d9006f6418984e7124ede8bc35debf 100644 --- a/tools/opt/NewPMDriver.cpp +++ b/tools/opt/NewPMDriver.cpp @@ -76,16 +76,7 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, PB.registerCGSCCAnalyses(CGAM); PB.registerFunctionAnalyses(FAM); PB.registerLoopAnalyses(LAM); - - // Cross register the analysis managers through their proxies. - MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); }); - MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); }); - CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); }); - CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); }); - FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); }); - FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); }); - FAM.registerPass([&] { return LoopAnalysisManagerFunctionProxy(LAM); }); - LAM.registerPass([&] { return FunctionAnalysisManagerLoopProxy(FAM); }); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); ModulePassManager MPM(DebugPM); if (VK > VK_NoVerifier) diff --git a/tools/opt/NewPMDriver.h b/tools/opt/NewPMDriver.h index 349a7b1267f8e6007f0ada7d9554daf435832cb2..66a470d49ba8b5cba65738e4157a225fa72d78b5 100644 --- a/tools/opt/NewPMDriver.h +++ b/tools/opt/NewPMDriver.h @@ -21,9 +21,8 @@ #ifndef LLVM_TOOLS_OPT_NEWPMDRIVER_H #define LLVM_TOOLS_OPT_NEWPMDRIVER_H -#include "llvm/ADT/StringRef.h" - namespace llvm { +class StringRef; class LLVMContext; class Module; class TargetMachine; diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index e374e1f54464b917446f28754d4833829a0a98dd..8ad560323afb3119a1fdb46614f231f0f5fe25dc 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -101,6 +101,10 @@ NoVerify("disable-verify", cl::desc("Do not run the verifier"), cl::Hidden); static cl::opt VerifyEach("verify-each", cl::desc("Verify after each transform")); +static cl::opt + DisableDITypeMap("disable-debug-info-type-map", + cl::desc("Don't use a uniquing type map for debug info")); + static cl::opt StripDebug("strip-debug", cl::desc("Strip debugger symbol info from translation unit")); @@ -136,6 +140,10 @@ static cl::opt OptLevelO3("O3", cl::desc("Optimization level 3. Similar to clang -O3")); +static cl::opt +CodeGenOptLevel("codegen-opt-level", + cl::desc("Override optimization level for codegen hooks")); + static cl::opt TargetTriple("mtriple", cl::desc("Override target triple for module")); @@ -158,6 +166,12 @@ DisableSLPVectorization("disable-slp-vectorization", cl::desc("Disable the slp vectorization pass"), cl::init(false)); +static cl::opt EmitSummaryIndex("module-summary", + cl::desc("Emit module summary index"), + cl::init(false)); + +static cl::opt EmitModuleHash("module-hash", cl::desc("Emit module hash"), + cl::init(false)); static cl::opt DisableSimplifyLibCalls("disable-simplify-libcalls", @@ -216,7 +230,8 @@ static inline void addPass(legacy::PassManagerBase &PM, Pass *P) { /// OptLevel - Optimization Level static void AddOptimizationPasses(legacy::PassManagerBase &MPM, legacy::FunctionPassManager &FPM, - unsigned OptLevel, unsigned SizeLevel) { + TargetMachine *TM, unsigned OptLevel, + unsigned SizeLevel) { if (!NoVerify || VerifyEach) FPM.add(createVerifierPass()); // Verify that input is correct @@ -246,6 +261,14 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM, Builder.SLPVectorize = DisableSLPVectorization ? false : OptLevel > 1 && SizeLevel < 2; + // Add target-specific passes that need to run as early as possible. + if (TM) + Builder.addExtension( + PassManagerBuilder::EP_EarlyAsPossible, + [&](const PassManagerBuilder &, legacy::PassManagerBase &PM) { + TM->addEarlyAsPossiblePasses(PM); + }); + Builder.populateFunctionPassManager(FPM); Builder.populateModulePassManager(MPM); } @@ -266,6 +289,8 @@ static void AddStandardLinkPasses(legacy::PassManagerBase &PM) { // static CodeGenOpt::Level GetCodeGenOptLevel() { + if (CodeGenOptLevel.getNumOccurrences()) + return static_cast(unsigned(CodeGenOptLevel)); if (OptLevelO1) return CodeGenOpt::Less; if (OptLevelO2) @@ -287,10 +312,9 @@ static TargetMachine* GetTargetMachine(Triple TheTriple, StringRef CPUStr, return nullptr; } - return TheTarget->createTargetMachine(TheTriple.getTriple(), - CPUStr, FeaturesStr, Options, - RelocModel, CMModel, - GetCodeGenOptLevel()); + return TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr, + FeaturesStr, Options, getRelocModel(), + CMModel, GetCodeGenOptLevel()); } #ifdef LINK_POLLY_INTO_TOOLS @@ -303,14 +327,14 @@ void initializePollyPasses(llvm::PassRegistry &Registry); // main for opt // int main(int argc, char **argv) { - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); llvm::PrettyStackTraceProgram X(argc, argv); // Enable debug stream buffering. EnableDebugBuffering = true; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - LLVMContext &Context = getGlobalContext(); + LLVMContext Context; InitializeAllTargets(); InitializeAllTargetMCs(); @@ -337,6 +361,10 @@ int main(int argc, char **argv) { initializeDwarfEHPreparePass(Registry); initializeSafeStackPass(Registry); initializeSjLjEHPreparePass(Registry); + initializePreISelIntrinsicLoweringLegacyPassPass(Registry); + initializeGlobalMergePass(Registry); + initializeInterleavedAccessPass(Registry); + initializeUnreachableBlockElimLegacyPassPass(Registry); #ifdef LINK_POLLY_INTO_TOOLS polly::initializePollyPasses(Registry); @@ -353,6 +381,8 @@ int main(int argc, char **argv) { SMDiagnostic Err; Context.setDiscardValueNames(DiscardValueNames); + if (!DisableDITypeMap) + Context.enableDebugTypeODRUniquing(); // Load the input module... std::unique_ptr M = parseIRFile(InputFilename, Err, Context); @@ -500,27 +530,27 @@ int main(int argc, char **argv) { } if (OptLevelO1 && OptLevelO1.getPosition() < PassList.getPosition(i)) { - AddOptimizationPasses(Passes, *FPasses, 1, 0); + AddOptimizationPasses(Passes, *FPasses, TM.get(), 1, 0); OptLevelO1 = false; } if (OptLevelO2 && OptLevelO2.getPosition() < PassList.getPosition(i)) { - AddOptimizationPasses(Passes, *FPasses, 2, 0); + AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 0); OptLevelO2 = false; } if (OptLevelOs && OptLevelOs.getPosition() < PassList.getPosition(i)) { - AddOptimizationPasses(Passes, *FPasses, 2, 1); + AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 1); OptLevelOs = false; } if (OptLevelOz && OptLevelOz.getPosition() < PassList.getPosition(i)) { - AddOptimizationPasses(Passes, *FPasses, 2, 2); + AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 2); OptLevelOz = false; } if (OptLevelO3 && OptLevelO3.getPosition() < PassList.getPosition(i)) { - AddOptimizationPasses(Passes, *FPasses, 3, 0); + AddOptimizationPasses(Passes, *FPasses, TM.get(), 3, 0); OptLevelO3 = false; } @@ -572,21 +602,21 @@ int main(int argc, char **argv) { } if (OptLevelO1) - AddOptimizationPasses(Passes, *FPasses, 1, 0); + AddOptimizationPasses(Passes, *FPasses, TM.get(), 1, 0); if (OptLevelO2) - AddOptimizationPasses(Passes, *FPasses, 2, 0); + AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 0); if (OptLevelOs) - AddOptimizationPasses(Passes, *FPasses, 2, 1); + AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 1); if (OptLevelOz) - AddOptimizationPasses(Passes, *FPasses, 2, 2); + AddOptimizationPasses(Passes, *FPasses, TM.get(), 2, 2); if (OptLevelO3) - AddOptimizationPasses(Passes, *FPasses, 3, 0); + AddOptimizationPasses(Passes, *FPasses, TM.get(), 3, 0); - if (OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || OptLevelO3) { + if (FPasses) { FPasses->doInitialization(); for (Function &F : *M) FPasses->run(F); @@ -614,10 +644,15 @@ int main(int argc, char **argv) { BOS = make_unique(Buffer); OS = BOS.get(); } - if (OutputAssembly) + if (OutputAssembly) { + if (EmitSummaryIndex) + report_fatal_error("Text output is incompatible with -module-summary"); + if (EmitModuleHash) + report_fatal_error("Text output is incompatible with -module-hash"); Passes.add(createPrintModulePass(*OS, "", PreserveAssemblyUseListOrder)); - else - Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder)); + } else + Passes.add(createBitcodeWriterPass(*OS, PreserveBitcodeUseListOrder, + EmitSummaryIndex, EmitModuleHash)); } // Before executing passes, print the final values of the LLVM options. diff --git a/tools/sancov/sancov.cc b/tools/sancov/sancov.cc index 0baaae16cfe3d8254676c2e6d86ad97d5e9baa5c..55b03709dde340eeeba948a2770354f420873ba3 100644 --- a/tools/sancov/sancov.cc +++ b/tools/sancov/sancov.cc @@ -135,6 +135,17 @@ template static void FailIfError(const ErrorOr &E) { FailIfError(E.getError()); } +static void FailIfError(Error Err) { + if (Err) { + logAllUnhandledErrors(std::move(Err), errs(), "Error: "); + exit(1); + } +} + +template static void FailIfError(Expected &E) { + FailIfError(E.takeError()); +} + static void FailIfNotEmpty(const llvm::Twine &E) { if (E.str().empty()) return; @@ -228,7 +239,7 @@ struct AddrInfo : public DILineInfo { } private: - static std::string normalizeFilename(std::string FileName) { + static std::string normalizeFilename(const std::string &FileName) { SmallString<256> S(FileName); sys::path::remove_dots(S, /* remove_dot_dot */ true); return S.str().str(); @@ -241,14 +252,16 @@ public: : DefaultBlacklist(createDefaultBlacklist()), UserBlacklist(createUserBlacklist()) {} - bool isBlacklisted(const DILineInfo &DI) { - if (DefaultBlacklist && DefaultBlacklist->inSection("fun", DI.FunctionName)) + // AddrInfo contains normalized filename. It is important to check it rather + // than DILineInfo. + bool isBlacklisted(const AddrInfo &AI) { + if (DefaultBlacklist && DefaultBlacklist->inSection("fun", AI.FunctionName)) return true; - if (DefaultBlacklist && DefaultBlacklist->inSection("src", DI.FileName)) + if (DefaultBlacklist && DefaultBlacklist->inSection("src", AI.FileName)) return true; - if (UserBlacklist && UserBlacklist->inSection("fun", DI.FunctionName)) + if (UserBlacklist && UserBlacklist->inSection("fun", AI.FunctionName)) return true; - if (UserBlacklist && UserBlacklist->inSection("src", DI.FileName)) + if (UserBlacklist && UserBlacklist->inSection("src", AI.FileName)) return true; return false; } @@ -276,7 +289,7 @@ private: }; // Collect all debug info for given addresses. -static std::vector getAddrInfo(std::string ObjectFile, +static std::vector getAddrInfo(const std::string &ObjectFile, const std::set &Addrs, bool InlinedCode) { std::vector Result; @@ -286,17 +299,19 @@ static std::vector getAddrInfo(std::string ObjectFile, for (auto Addr : Addrs) { auto LineInfo = Symbolizer->symbolizeCode(ObjectFile, Addr); FailIfError(LineInfo); - if (B.isBlacklisted(*LineInfo)) + auto LineAddrInfo = AddrInfo(*LineInfo, Addr); + if (B.isBlacklisted(LineAddrInfo)) continue; - Result.push_back(AddrInfo(*LineInfo, Addr)); + Result.push_back(LineAddrInfo); if (InlinedCode) { auto InliningInfo = Symbolizer->symbolizeInlinedCode(ObjectFile, Addr); FailIfError(InliningInfo); for (uint32_t I = 0; I < InliningInfo->getNumberOfFrames(); ++I) { auto FrameInfo = InliningInfo->getFrame(I); - if (B.isBlacklisted(FrameInfo)) + auto FrameAddrInfo = AddrInfo(FrameInfo, Addr); + if (B.isBlacklisted(FrameAddrInfo)) continue; - Result.push_back(AddrInfo(FrameInfo, Addr)); + Result.push_back(FrameAddrInfo); } } } @@ -311,11 +326,11 @@ findSanitizerCovFunctions(const object::ObjectFile &O) { std::set Result; for (const object::SymbolRef &Symbol : O.symbols()) { - ErrorOr AddressOrErr = Symbol.getAddress(); - FailIfError(AddressOrErr); + Expected AddressOrErr = Symbol.getAddress(); + FailIfError(errorToErrorCode(AddressOrErr.takeError())); - ErrorOr NameOrErr = Symbol.getName(); - FailIfError(NameOrErr); + Expected NameOrErr = Symbol.getName(); + FailIfError(errorToErrorCode(NameOrErr.takeError())); StringRef Name = NameOrErr.get(); if (Name == "__sanitizer_cov" || Name == "__sanitizer_cov_with_check" || @@ -406,25 +421,26 @@ static void getObjectCoveragePoints(const object::ObjectFile &O, static void visitObjectFiles(const object::Archive &A, - std::function Fn) { - for (auto &ErrorOrChild : A.children()) { - FailIfError(ErrorOrChild); - const object::Archive::Child &C = *ErrorOrChild; - ErrorOr> ChildOrErr = C.getAsBinary(); - FailIfError(ChildOrErr); + function_ref Fn) { + Error Err; + for (auto &C : A.children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + FailIfError(errorToErrorCode(ChildOrErr.takeError())); if (auto *O = dyn_cast(&*ChildOrErr.get())) Fn(*O); else FailIfError(object::object_error::invalid_file_type); } + FailIfError(std::move(Err)); } static void -visitObjectFiles(std::string FileName, - std::function Fn) { - ErrorOr> BinaryOrErr = +visitObjectFiles(const std::string &FileName, + function_ref Fn) { + Expected> BinaryOrErr = object::createBinary(FileName); - FailIfError(BinaryOrErr); + if (!BinaryOrErr) + FailIfError(errorToErrorCode(BinaryOrErr.takeError())); object::Binary &Binary = *BinaryOrErr.get().getBinary(); if (object::Archive *A = dyn_cast(&Binary)) @@ -435,7 +451,7 @@ visitObjectFiles(std::string FileName, FailIfError(object::object_error::invalid_file_type); } -std::set findSanitizerCovFunctions(std::string FileName) { +std::set findSanitizerCovFunctions(const std::string &FileName) { std::set Result; visitObjectFiles(FileName, [&](const object::ObjectFile &O) { auto Addrs = findSanitizerCovFunctions(O); @@ -447,7 +463,7 @@ std::set findSanitizerCovFunctions(std::string FileName) { // Locate addresses of all coverage points in a file. Coverage point // is defined as the 'address of instruction following __sanitizer_cov // call - 1'. -std::set getCoveragePoints(std::string FileName) { +std::set getCoveragePoints(const std::string &FileName) { std::set Result; visitObjectFiles(FileName, [&](const object::ObjectFile &O) { getObjectCoveragePoints(O, &Result); @@ -455,7 +471,7 @@ std::set getCoveragePoints(std::string FileName) { return Result; } -static void printCovPoints(std::string ObjFile, raw_ostream &OS) { +static void printCovPoints(const std::string &ObjFile, raw_ostream &OS) { for (uint64_t Addr : getCoveragePoints(ObjFile)) { OS << "0x"; OS.write_hex(Addr); @@ -504,7 +520,7 @@ static std::string formatHtmlPct(size_t Pct) { return Zeroes + Num; } -static std::string anchorName(std::string Anchor) { +static std::string anchorName(const std::string &Anchor) { llvm::MD5 Hasher; llvm::MD5::MD5Result Hash; Hasher.update(Anchor); @@ -515,7 +531,7 @@ static std::string anchorName(std::string Anchor) { return HexString.str().str(); } -static ErrorOr isCoverageFile(std::string FileName) { +static ErrorOr isCoverageFile(const std::string &FileName) { ErrorOr> BufOrErr = MemoryBuffer::getFile(FileName); if (!BufOrErr) { @@ -553,7 +569,8 @@ static raw_ostream &operator<<(raw_ostream &OS, const CoverageStats &Stats) { class CoverageData { public: // Read single file coverage data. - static ErrorOr> read(std::string FileName) { + static ErrorOr> + read(const std::string &FileName) { ErrorOr> BufOrErr = MemoryBuffer::getFile(FileName); if (!BufOrErr) @@ -836,7 +853,7 @@ static void printFunctionLocs(const SourceCoverageData::FunctionLocs &FnLocs, class CoverageDataWithObjectFile : public CoverageData { public: static ErrorOr> - readAndMerge(std::string ObjectFile, + readAndMerge(const std::string &ObjectFile, const std::vector &FileNames) { auto MergedDataOrError = CoverageData::readAndMerge(FileNames); if (!MergedDataOrError) @@ -889,7 +906,7 @@ public: OS << "
1
[[@LINE-53]]
int func(T x) {
+// HTML-SHARED: 
1
[[@LINE-53]]
  if(x)
+// HTML-SHARED: 
1
[[@LINE-53]]
    ret
+// HTML-SHARED: 
1
[[@LINE-53]]
  else
+// HTML-SHARED: 
0
[[@LINE-53]]
+// HTML-SHARED: 
0
[[@LINE-53]]
+// HTML-SHARED: 
1
[[@LINE-53]]
}
+
+// HTML-ALL: 
_Z4funcIiEiT_
+// HTML-FILTER-NOT:
_Z4funcIiEiT_
+// HTML-ALL: "; + +const char *BeginPre = "
";
+
+const char *EndPre = "
"; + +const char *BeginExpansionDiv = "
"; + +const char *EndExpansionDiv = "
"; + +const char *BeginTable = "
1
[[@LINE-63]]
int func(T x) {
+// HTML-ALL: 
1
[[@LINE-63]]
  if(x)
+// HTML-ALL: 
0
[[@LINE-63]]
+// HTML-ALL: 
1
[[@LINE-63]]
  else
+// HTML-ALL: 
1
[[@LINE-63]]
    ret
+// HTML-ALL: 
0
[[@LINE-63]]
+// HTML-ALL: 
1
[[@LINE-63]]
}
+
+// HTML-ALL: td class='covered-line'>
1
[[@LINE-44]]
int main() {
+// HTML-ALL: 
1
[[@LINE-44]]
  func<int>(0);
+// HTML-ALL: 
1
[[@LINE-44]]
  func<bool>(true);
+// HTML-ALL: 
1
[[@LINE-44]]
  return 0;
+// HTML-ALL: 
1
[[@LINE-44]]
}
+
+// HTML-ALL: 
[[@LINE-45]]
// after
+// HTML-FILTER-NOT: 
[[@LINE-46]]
// after
diff --git a/test/tools/llvm-cov/warnings.h b/test/tools/llvm-cov/warnings.h
new file mode 100644
index 0000000000000000000000000000000000000000..0517b6a7c875f02a647025b0c2a70c3dcadb6cba
--- /dev/null
+++ b/test/tools/llvm-cov/warnings.h
@@ -0,0 +1,11 @@
+// RUN: llvm-cov show %S/Inputs/prevent_false_instantiations.covmapping -instr-profile %S/Inputs/elf_binary_comdat.profdata -filename-equivalence /dev/null | FileCheck %s -allow-empty -check-prefix=FAKE-FILE-STDOUT
+// RUN: llvm-cov show %S/Inputs/prevent_false_instantiations.covmapping -instr-profile %S/Inputs/elf_binary_comdat.profdata -filename-equivalence /dev/null 2>&1 | FileCheck %s -check-prefix=FAKE-FILE-STDERR
+
+// FAKE-FILE-STDOUT-NOT: warning: The file '{{.*}}' isn't covered.
+// FAKE-FILE-STDERR: warning: The file '{{.*}}' isn't covered.
+
+// RUN: llvm-cov show %S/Inputs/prevent_false_instantiations.covmapping -instr-profile %S/Inputs/elf_binary_comdat.profdata -filename-equivalence -name ".*" /dev/null | FileCheck %s -allow-empty -check-prefix=FAKE-FUNC-STDOUT
+// RUN: llvm-cov show %S/Inputs/prevent_false_instantiations.covmapping -instr-profile %S/Inputs/elf_binary_comdat.profdata -filename-equivalence -name-regex ".*" /dev/null 2>&1 | FileCheck %s -check-prefix=FAKE-FUNC-STDERR
+
+// FAKE-FUNC-STDOUT-NOT: warning: Could not read coverage for '{{.*}}'.
+// FAKE-FUNC-STDERR: Could not read coverage for '{{.*}}'.
diff --git a/test/tools/llvm-dwp/Inputs/compressfail/a.dwo b/test/tools/llvm-dwp/Inputs/compressfail/a.dwo
new file mode 100644
index 0000000000000000000000000000000000000000..0201f07d8dafda4bd4309a2f2f4940da84f35336
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/compressfail/a.dwo differ
diff --git a/test/tools/llvm-dwp/Inputs/compressfail/compress.dwo b/test/tools/llvm-dwp/Inputs/compressfail/compress.dwo
new file mode 100644
index 0000000000000000000000000000000000000000..63459442e08df708bdc0ca84c7cfd86fea7674bc
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/compressfail/compress.dwo differ
diff --git a/test/tools/llvm-dwp/Inputs/compressfail/compress.o b/test/tools/llvm-dwp/Inputs/compressfail/compress.o
new file mode 100644
index 0000000000000000000000000000000000000000..f12bb0985792ec291a9f695356a221c1ed1c23eb
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/compressfail/compress.o differ
diff --git a/test/tools/llvm-dwp/Inputs/empty_compressed_section.dwo b/test/tools/llvm-dwp/Inputs/empty_compressed_section.dwo
new file mode 100644
index 0000000000000000000000000000000000000000..bc9b4ff983bc70122b1d7cf56cb3515ae0ab6874
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/empty_compressed_section.dwo differ
diff --git a/test/tools/llvm-dwp/Inputs/gcc_type/a.dwo b/test/tools/llvm-dwp/Inputs/gcc_type/a.dwo
new file mode 100644
index 0000000000000000000000000000000000000000..26c16f322fe8313a87bffdd41041e256bb8cbd11
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/gcc_type/a.dwo differ
diff --git a/test/tools/llvm-dwp/Inputs/invalid_compressed.dwo b/test/tools/llvm-dwp/Inputs/invalid_compressed.dwo
new file mode 100644
index 0000000000000000000000000000000000000000..0cbfd14ffe7b4b464f51ef2d8a92dacce477f671
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/invalid_compressed.dwo differ
diff --git a/test/tools/llvm-dwp/Inputs/invalid_cu_index/x.dwp b/test/tools/llvm-dwp/Inputs/invalid_cu_index/x.dwp
new file mode 100644
index 0000000000000000000000000000000000000000..1a1e94936bc83d35f184807415144fc7a0795cba
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/invalid_cu_index/x.dwp differ
diff --git a/test/tools/llvm-dwp/Inputs/invalid_string_form.dwo b/test/tools/llvm-dwp/Inputs/invalid_string_form.dwo
new file mode 100644
index 0000000000000000000000000000000000000000..663c70fd7f7f7dfb73aee65c1a8a07bca4d24fe3
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/invalid_string_form.dwo differ
diff --git a/test/tools/llvm-dwp/Inputs/missing_tu_index/x.dwp b/test/tools/llvm-dwp/Inputs/missing_tu_index/x.dwp
new file mode 100644
index 0000000000000000000000000000000000000000..f5d09f0f5e77ae5307e492350b0f56fa5d37c0a1
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/missing_tu_index/x.dwp differ
diff --git a/test/tools/llvm-dwp/Inputs/multiple_type_sections.dwp b/test/tools/llvm-dwp/Inputs/multiple_type_sections.dwp
new file mode 100644
index 0000000000000000000000000000000000000000..d313213c2b1e99ce96216e3c03f1166cadb3458b
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/multiple_type_sections.dwp differ
diff --git a/test/tools/llvm-dwp/Inputs/non_cu_top_level.dwo b/test/tools/llvm-dwp/Inputs/non_cu_top_level.dwo
new file mode 100644
index 0000000000000000000000000000000000000000..26f276ad05329c1c69b940d72df13e5de72bf572
Binary files /dev/null and b/test/tools/llvm-dwp/Inputs/non_cu_top_level.dwo differ
diff --git a/test/tools/llvm-dwp/X86/compressfail.test b/test/tools/llvm-dwp/X86/compressfail.test
new file mode 100644
index 0000000000000000000000000000000000000000..78b6255724fc4a0f32eed3d020e60980969fcc4f
--- /dev/null
+++ b/test/tools/llvm-dwp/X86/compressfail.test
@@ -0,0 +1,7 @@
+RUN: not llvm-dwp %p/../Inputs/compressfail/a.dwo -o %t 2>&1 | FileCheck %s
+RUN: not llvm-dwp %p/../Inputs/empty_compressed_section.dwo -o %t 2>&1 | FileCheck %s
+RUN: not llvm-dwp %p/../Inputs/invalid_compressed.dwo -o %t 2>&1 | FileCheck %s
+
+REQUIRES: zlib
+
+CHECK: error: failure while decompressing compressed section: 'zdebug_{{.*}}.dwo'
diff --git a/test/tools/llvm-dwp/X86/duplicate.test b/test/tools/llvm-dwp/X86/duplicate.test
index 67b6829478990222f619de0067a33e7d2933d2c1..43266a24b6014ca3e1f37d0f33f32d2bf3fcf2e0 100644
--- a/test/tools/llvm-dwp/X86/duplicate.test
+++ b/test/tools/llvm-dwp/X86/duplicate.test
@@ -18,10 +18,10 @@ RUN:   | FileCheck --check-prefix=DWO1DWP %s
 
 Build from a, b, and c.c all containing a single void() func by the name of the file.
 
-DWOS: Duplicate DWO ID ({{.*}}) in 'c.c' and 'c.c'{{$}}
-1DWP: Duplicate DWO ID ({{.*}}) in 'c.c' (from '{{.*}}ac.dwp') and 'c.c'{{$}}
-2DWP: Duplicate DWO ID ({{.*}}) in 'c.c' and 'c.c' (from '{{.*}}bc.dwp'){{$}}
+DWOS: error: Duplicate DWO ID ({{.*}}) in 'c.c' and 'c.c'{{$}}
+1DWP: error: Duplicate DWO ID ({{.*}}) in 'c.c' (from '{{.*}}ac.dwp') and 'c.c'{{$}}
+2DWP: error: Duplicate DWO ID ({{.*}}) in 'c.c' and 'c.c' (from '{{.*}}bc.dwp'){{$}}
 
-DWODWOS: Duplicate DWO ID ({{.*}}) in 'c.c' and 'c.c'{{$}}
-DWO1DWP: Duplicate DWO ID ({{.*}}) in 'c.c' (from 'c.dwo' in '{{.*}}ac.dwp') and 'c.c'{{$}}
-DWO2DWP: Duplicate DWO ID ({{.*}}) in 'c.c' and 'c.c' (from 'c.dwo' in '{{.*}}bc.dwp'){{$}}
+DWODWOS: error: Duplicate DWO ID ({{.*}}) in 'c.c' and 'c.c'{{$}}
+DWO1DWP: error: Duplicate DWO ID ({{.*}}) in 'c.c' (from 'c.dwo' in '{{.*}}ac.dwp') and 'c.c'{{$}}
+DWO2DWP: error: Duplicate DWO ID ({{.*}}) in 'c.c' and 'c.c' (from 'c.dwo' in '{{.*}}bc.dwp'){{$}}
diff --git a/test/tools/llvm-dwp/X86/gcc_type.test b/test/tools/llvm-dwp/X86/gcc_type.test
new file mode 100644
index 0000000000000000000000000000000000000000..b05fb01bdf7dfd744adf5297e6cbfb8a07efe4c1
--- /dev/null
+++ b/test/tools/llvm-dwp/X86/gcc_type.test
@@ -0,0 +1,9 @@
+RUN: llvm-dwp %p/../Inputs/gcc_type/a.dwo -o %t
+RUN: llvm-dwarfdump %t | FileCheck %s
+RUN: not llvm-dwp %p/../Inputs/gcc_type/a.dwo %p/../Inputs/gcc_type/a.dwo -o %t 2>&1 | FileCheck --check-prefix=DUP %s
+
+CHECK: Type Unit
+CHECK: Type Unit
+
+// Check that llvm-dwp can parse DW_FORM_string for CU name
+DUP: Duplicate DWO ID ({{.*}}) in 'a.cpp' and 'a.cpp'
diff --git a/test/tools/llvm-dwp/X86/invalid_cu_index.test b/test/tools/llvm-dwp/X86/invalid_cu_index.test
new file mode 100644
index 0000000000000000000000000000000000000000..6fc96b2a1a3012737db76a944fa1a553739a1d42
--- /dev/null
+++ b/test/tools/llvm-dwp/X86/invalid_cu_index.test
@@ -0,0 +1,3 @@
+RUN: not llvm-dwp %p/../Inputs/invalid_cu_index/x.dwp -o %t 2>&1 | FileCheck %s
+
+CHECK: error: Failed to parse cu_index
diff --git a/test/tools/llvm-dwp/X86/invalid_string_form.test b/test/tools/llvm-dwp/X86/invalid_string_form.test
new file mode 100644
index 0000000000000000000000000000000000000000..e78a145dcb59e38f578089401d94439260a9656e
--- /dev/null
+++ b/test/tools/llvm-dwp/X86/invalid_string_form.test
@@ -0,0 +1,3 @@
+RUN: not llvm-dwp %p/../Inputs/invalid_string_form.dwo -o %t 2>&1 | FileCheck %s
+
+CHECK: error: string field encoded without DW_FORM_string or DW_FORM_GNU_str_index
diff --git a/test/tools/llvm-dwp/X86/missing_tu_index.test b/test/tools/llvm-dwp/X86/missing_tu_index.test
new file mode 100644
index 0000000000000000000000000000000000000000..99f5253e8b32385ff42f5691546f381534ac5f1a
--- /dev/null
+++ b/test/tools/llvm-dwp/X86/missing_tu_index.test
@@ -0,0 +1,3 @@
+RUN: not llvm-dwp %p/../Inputs/missing_tu_index/x.dwp -o %t 2>&1 | FileCheck %s
+
+CHECK: error: Failed to parse tu_index
diff --git a/test/tools/llvm-dwp/X86/multiple_type_sections.test b/test/tools/llvm-dwp/X86/multiple_type_sections.test
new file mode 100644
index 0000000000000000000000000000000000000000..7953b88ad3dee46892a5bd5f82707a0c99005d57
--- /dev/null
+++ b/test/tools/llvm-dwp/X86/multiple_type_sections.test
@@ -0,0 +1,3 @@
+RUN: not llvm-dwp %p/../Inputs/multiple_type_sections.dwp -o %t 2>&1 | FileCheck %s
+
+CHECK: error: multiple type unit sections in .dwp file
diff --git a/test/tools/llvm-dwp/X86/nocompress.test b/test/tools/llvm-dwp/X86/nocompress.test
new file mode 100644
index 0000000000000000000000000000000000000000..1de9444dd3eb637a553e38a5a04e2fc2df438c54
--- /dev/null
+++ b/test/tools/llvm-dwp/X86/nocompress.test
@@ -0,0 +1,5 @@
+RUN: not llvm-dwp %p/../Inputs/compress/a.dwo -o %t 2>&1 | FileCheck %s
+
+REQUIRES: nozlib
+
+CHECK: error: zlib not available
diff --git a/test/tools/llvm-dwp/X86/non_cu_top_level.test b/test/tools/llvm-dwp/X86/non_cu_top_level.test
new file mode 100644
index 0000000000000000000000000000000000000000..60b8742cdc25eb4f3250f31399314cccb10036a3
--- /dev/null
+++ b/test/tools/llvm-dwp/X86/non_cu_top_level.test
@@ -0,0 +1,3 @@
+RUN: not llvm-dwp %p/../Inputs/non_cu_top_level.dwo -o %t 2>&1 | FileCheck %s
+
+CHECK: error: top level DIE is not a compile unit
diff --git a/test/tools/llvm-lto/thinlto.ll b/test/tools/llvm-lto/thinlto.ll
index 652437c2f725279e13d8667b21a292918f7268a0..38c4196bb256ec3f24b090ff1dbddca2a8d9e7bd 100644
--- a/test/tools/llvm-lto/thinlto.ll
+++ b/test/tools/llvm-lto/thinlto.ll
@@ -1,6 +1,6 @@
 ; Test combined function index generation for ThinLTO via llvm-lto.
-; RUN: llvm-as -module-summary %s -o %t.o
-; RUN: llvm-as -module-summary %p/Inputs/thinlto.ll -o %t2.o
+; RUN: opt -module-summary %s -o %t.o
+; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
 ; RUN: llvm-lto -thinlto -o %t3 %t.o %t2.o
 ; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED
 ; RUN: not test -e %t3
@@ -10,14 +10,15 @@
 ; COMBINED-NEXT: &1 | FileCheck -check-prefix BAD-SYMAME-1 %s
+BAD-SYMAME-1: -dis-symname: _environ not in the section
+
+# not RUN: llvm-objdump -m -d %p/Inputs/exeThread.macho-x86_64 -dis-symname __mh_execute_header 2>&1 | FileCheck -check-prefix BAD-SYMAME-2 %s
+BAD-SYMAME-2: -dis-symname: __mh_execute_header not in any section
diff --git a/test/tools/llvm-objdump/X86/macho-disassembly-stripped.test b/test/tools/llvm-objdump/X86/macho-disassembly-stripped.test
new file mode 100644
index 0000000000000000000000000000000000000000..fab86f8b9794a0b342dfacd6b16cdba22d00abf7
--- /dev/null
+++ b/test/tools/llvm-objdump/X86/macho-disassembly-stripped.test
@@ -0,0 +1,6 @@
+// RUN: llvm-objdump -d -m -no-show-raw-insn -full-leading-addr -print-imm-hex %p/Inputs/hello.exe.stripped.macho-x86_64 | FileCheck %s
+
+CHECK: (__TEXT,__text) section
+CHECK: 0000000100000f30	pushq	%rbp
+CHECK: 0000000100000f31	movq	%rsp, %rbp
+CHECK: 0000000100000f34	subq	$0x20, %rsp
diff --git a/test/tools/llvm-objdump/X86/macho-private-headers.test b/test/tools/llvm-objdump/X86/macho-private-headers.test
index ff45b1823fff28600900fb6e7aa11cfbb064c7c3..e0c68d7cd97a828c52974f8b63890c5b086ef166 100644
--- a/test/tools/llvm-objdump/X86/macho-private-headers.test
+++ b/test/tools/llvm-objdump/X86/macho-private-headers.test
@@ -21,6 +21,8 @@
 // RUN:     | FileCheck %s -check-prefix=FATi386
 // RUN: llvm-objdump -p -non-verbose %p/Inputs/hello.obj.macho-x86_64 \
 // RUN:     | FileCheck %s -check-prefix=NON_VERBOSE
+// RUN: llvm-objdump -p %p/Inputs/codesig.macho-x86_64 \
+// RUN:     | FileCheck %s -check-prefix=CODESIG
 
 CHECK: Mach header
 CHECK:       magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
@@ -537,3 +539,8 @@ NON_VERBOSE:       extreloff 0
 NON_VERBOSE:         nextrel 0
 NON_VERBOSE:       locreloff 0
 NON_VERBOSE:         nlocrel 0
+
+CODESIG:      cmd LC_CODE_SIGNATURE
+CODESIG:  cmdsize 16
+CODESIG:  dataoff 8496
+CODESIG: datasize 64
diff --git a/test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test b/test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test
index 260e9aa341e8c4b9955efa1aad1344048923d527..9089716f7a5edde48b45268a9062300719a3ce8f 100644
--- a/test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test
+++ b/test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test
@@ -6,6 +6,8 @@ RUN: llvm-objdump %p/Inputs/macho-universal.x86_64.i386 -universal-headers -m \
 RUN: | FileCheck %s -check-prefix FAT
 RUN: llvm-objdump %p/Inputs/macho-universal.x86_64.i386 -universal-headers -m \
 RUN: -non-verbose | FileCheck %s -check-prefix NON-VERBOSE
+RUN: llvm-objdump %p/Inputs/macho-universal64.x86_64.i386 -universal-headers \
+RUN: -m | FileCheck %s -check-prefix FAT-64
 
 UEXE-all: macho-universal.x86_64.i386 (architecture x86_64):
 UEXE-all: (__TEXT,__text) section
@@ -62,3 +64,7 @@ NON-VERBOSE:     capabilities 0x0
 NON-VERBOSE:     offset 12288
 NON-VERBOSE:     size 4336
 NON-VERBOSE:     align 2^12 (4096)
+
+FAT-64: Fat headers
+FAT-64: fat_magic FAT_MAGIC_64
+FAT-64: nfat_arch 2
diff --git a/test/tools/llvm-objdump/macho-LLVM-bundle.test b/test/tools/llvm-objdump/macho-LLVM-bundle.test
new file mode 100644
index 0000000000000000000000000000000000000000..b7134307257e506bfbab9dafed4dea5e7e6c53c4
--- /dev/null
+++ b/test/tools/llvm-objdump/macho-LLVM-bundle.test
@@ -0,0 +1,60 @@
+# REQUIRES: xar
+# RUN: llvm-objdump -macho -archive-headers -section __LLVM,__bundle %p/Inputs/LLVM-bundle.macho-x86_64 | FileCheck %s
+
+# CHECK: For (__LLVM,__bundle) section: xar header
+# CHECK:                   magic XAR_HEADER_MAGIC
+# CHECK:                    size 28
+# CHECK:                 version 1
+# CHECK:   toc_length_compressed 542
+# CHECK: toc_length_uncompressed 1250
+# CHECK:               cksum_alg XAR_CKSUM_SHA1
+# CHECK: For (__LLVM,__bundle) section: xar archive files:
+# CHECK:    1664 1
+# CHECK: For (__LLVM,__bundle) section: xar table of contents:
+# CHECK: 
+# CHECK: 
+# CHECK:  
+# CHECK:   1.0
+# CHECK:   x86_64
+# CHECK:   MacOSX
+# CHECK:   10.11.0
+# CHECK:   
+# CHECK:    libSystem.dylib
+# CHECK:   
+# CHECK:   
+# CHECK:    
+# CHECK:    
+# CHECK:    
+# CHECK:    
+# CHECK:    
+# CHECK:    
+# CHECK:    
+# CHECK:   
+# CHECK:  
+# CHECK:  
+# CHECK:   
+# CHECK:    20
+# CHECK:    0
+# CHECK:   
+# CHECK:   2016-05-23T20:49:10
+# CHECK:   
+# CHECK:    1
+# CHECK:    file
+# CHECK:    
+# CHECK:     a319940ff5f5248ca8b44cf7b4b65e7dd49a47ab
+# CHECK:     a319940ff5f5248ca8b44cf7b4b65e7dd49a47ab
+# CHECK:     1664
+# CHECK:     20
+# CHECK:     
+# CHECK:     1664
+# CHECK:    
+# CHECK:    Bitcode
+# CHECK:    
+# CHECK:     -triple
+# CHECK:     x86_64-apple-macosx10.11.0
+# CHECK:     -emit-obj
+# CHECK:     -disable-llvm-optzns
+# CHECK:    
+# CHECK:   
+# CHECK:  
+# CHECK: 
diff --git a/test/tools/llvm-objdump/macho-objc-meta-data.test b/test/tools/llvm-objdump/macho-objc-meta-data.test
new file mode 100644
index 0000000000000000000000000000000000000000..e659e7e577115e08202441077148f51f95f2f1f5
--- /dev/null
+++ b/test/tools/llvm-objdump/macho-objc-meta-data.test
@@ -0,0 +1,3 @@
+# RUN: llvm-objdump -macho -objc-meta-data %p/Inputs/empty.macho-armv7 | FileCheck %s
+
+# CHECK: empty.macho-armv7:
diff --git a/test/tools/llvm-objdump/macho-sections.test b/test/tools/llvm-objdump/macho-sections.test
index 07c2b52ebfc85a029bfe28de894fd19e1e5145ce..7b0d89ce505300807b3f6d35b2eb4a1476200494 100644
--- a/test/tools/llvm-objdump/macho-sections.test
+++ b/test/tools/llvm-objdump/macho-sections.test
@@ -1,3 +1,11 @@
 # RUN: llvm-objdump -macho -section=__data %p/Inputs/bind2.macho-x86_64 | FileCheck %s
 
 # CHECK: bind2.macho-x86_64:
+
+# RUN: llvm-objdump -macho -section=__data %p/Inputs/section.macho-armv7 | FileCheck -check-prefix CHECK-ADDR %s
+
+#  CHECK-ADDR: 00000004	00000001 00000002
+
+# RUN: llvm-objdump -macho -section=__const %p/Inputs/section.macho-armv7 | FileCheck -check-prefix CHECK-BYTES %s
+
+#  CHECK-BYTES: 0000000c	00000003 04 05 06
diff --git a/test/tools/llvm-objdump/malformed-macho.test b/test/tools/llvm-objdump/malformed-macho.test
index e96945d91125b12d36bcf0ae33c488f2c1f9b68d..0bc2ce8e898ffcebfa50e30bd603e4bedf236665 100644
--- a/test/tools/llvm-objdump/malformed-macho.test
+++ b/test/tools/llvm-objdump/malformed-macho.test
@@ -1,2 +1,2 @@
 RUN: not llvm-objdump -macho -s %p/Inputs/malformed-macho.bin 2>&1 | FileCheck %s -check-prefix=MALFORMED
-MALFORMED: '{{.*}}': The file was not recognized as a valid object file
+MALFORMED: The file was not recognized as a valid object file
diff --git a/test/tools/llvm-pdbdump/class-layout.test b/test/tools/llvm-pdbdump/class-layout.test
index a92145e59e7dd47ea23628ce52209bcecce2f394..d2e98de2a201308d7af8ac4427359a84f8359840 100644
--- a/test/tools/llvm-pdbdump/class-layout.test
+++ b/test/tools/llvm-pdbdump/class-layout.test
@@ -1,4 +1,4 @@
-; RUN: llvm-pdbdump -all %p/Inputs/ClassLayoutTest.pdb > %t
+; RUN: llvm-pdbdump pretty -all %p/Inputs/ClassLayoutTest.pdb > %t
 ; RUN: FileCheck -input-file=%t %s -check-prefix=GLOBALS_TEST
 ; RUN: FileCheck -input-file=%t %s -check-prefix=MEMBERS_TEST
 ; RUN: FileCheck -input-file=%t %s -check-prefix=BASE_CLASS_A
diff --git a/test/tools/llvm-pdbdump/enum-layout.test b/test/tools/llvm-pdbdump/enum-layout.test
index f6ebb20b8c561324e630d5be702a9b5ca16df80b..21e1867175f6b628bc66c1c7f5ae201d02ebfa5b 100644
--- a/test/tools/llvm-pdbdump/enum-layout.test
+++ b/test/tools/llvm-pdbdump/enum-layout.test
@@ -1,4 +1,4 @@
-; RUN: llvm-pdbdump -types %p/Inputs/ClassLayoutTest.pdb > %t
+; RUN: llvm-pdbdump pretty -types %p/Inputs/ClassLayoutTest.pdb > %t
 ; RUN: FileCheck -input-file=%t %s -check-prefix=GLOBAL_ENUM
 ; RUN: FileCheck -input-file=%t %s -check-prefix=MEMBER_ENUM
 
diff --git a/test/tools/llvm-pdbdump/load-address.test b/test/tools/llvm-pdbdump/load-address.test
index c559b5c7dcd65ded54da12a30cc7579e5ae04165..5791637d3a742282947de65c9841597223327c8b 100644
--- a/test/tools/llvm-pdbdump/load-address.test
+++ b/test/tools/llvm-pdbdump/load-address.test
@@ -1,6 +1,6 @@
-; RUN: llvm-pdbdump -externals %p/Inputs/LoadAddressTest.pdb \
+; RUN: llvm-pdbdump pretty -externals %p/Inputs/LoadAddressTest.pdb \
 ; RUN:    | FileCheck --check-prefix=RVA %s
-; RUN: llvm-pdbdump -externals -load-address=0x40000000 \
+; RUN: llvm-pdbdump pretty -externals -load-address=0x40000000 \
 ; RUN: %p/Inputs/LoadAddressTest.pdb | FileCheck --check-prefix=VA %s
 
 ; RVA: ---EXTERNALS---
diff --git a/test/tools/llvm-pdbdump/regex-filter.test b/test/tools/llvm-pdbdump/regex-filter.test
index cfc910e07171add67e4ab3f5213b0eb37c4a886f..b845f5a28cffd8cd18cf16777b5d5e10f885185e 100644
--- a/test/tools/llvm-pdbdump/regex-filter.test
+++ b/test/tools/llvm-pdbdump/regex-filter.test
@@ -1,18 +1,18 @@
-; RUN: llvm-pdbdump -symbols -globals -types %p/Inputs/FilterTest.pdb \
+; RUN: llvm-pdbdump pretty -symbols -globals -types %p/Inputs/FilterTest.pdb \
 ; RUN:    | FileCheck --check-prefix=NO_FILTER %s
-; RUN: llvm-pdbdump -types -exclude-types="GlobalTypedef|NestedTypedef" \
+; RUN: llvm-pdbdump pretty -types -exclude-types="GlobalTypedef|NestedTypedef" \
 ; RUN:    %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_TYPEDEFS %s
-; RUN: llvm-pdbdump -types -exclude-types="GlobalEnum|NestedEnum" \
+; RUN: llvm-pdbdump pretty -types -exclude-types="GlobalEnum|NestedEnum" \
 ; RUN:    %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_ENUMS %s
-; RUN: llvm-pdbdump -types -symbols -globals -exclude-symbols="MemberVar|GlobalVar" \
+; RUN: llvm-pdbdump pretty -types -symbols -globals -exclude-symbols="MemberVar|GlobalVar" \
 ; RUN:    %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_VARS %s
-; RUN: llvm-pdbdump -types -exclude-types="FilterTestClass" \
+; RUN: llvm-pdbdump pretty -types -exclude-types="FilterTestClass" \
 ; RUN:    %p/Inputs/FilterTest.pdb | FileCheck  --check-prefix=EXCLUDE_WHOLE_CLASS %s
-; RUN: llvm-pdbdump -symbols -globals -exclude-compilands="FilterTest.obj"  \
+; RUN: llvm-pdbdump pretty -symbols -globals -exclude-compilands="FilterTest.obj"  \
 ; RUN:    %p/Inputs/FilterTest.pdb | FileCheck  --check-prefix=EXCLUDE_COMPILAND %s
-; RUN: llvm-pdbdump -types -include-types="FilterTestClass" \
+; RUN: llvm-pdbdump pretty -types -include-types="FilterTestClass" \
 ; RUN:    %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=INCLUDE_ONLY_TYPES %s
-; RUN: llvm-pdbdump -types -symbols -globals -include-symbols="[[:<:]](IntGlobalVar|DoubleGlobalVar)[[:>:]]" \
+; RUN: llvm-pdbdump pretty -types -symbols -globals -include-symbols="[[:<:]](IntGlobalVar|DoubleGlobalVar)[[:>:]]" \
 ; RUN:    %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=INCLUDE_ONLY_VARS %s
 
 ; NO_FILTER: ---TYPES---
diff --git a/test/tools/llvm-profdata/Inputs/c-general.profraw b/test/tools/llvm-profdata/Inputs/c-general.profraw
index 26c7ec1c6f3b3096a81a966b2aea26ff88df086c..332d11b140f520ba1c97942d466866e3b230f731 100644
Binary files a/test/tools/llvm-profdata/Inputs/c-general.profraw and b/test/tools/llvm-profdata/Inputs/c-general.profraw differ
diff --git a/test/tools/llvm-profdata/c-general.test b/test/tools/llvm-profdata/c-general.test
index efa9bfa18d73c42e0d25ebfef41b3fe8f549608b..0ec7c113eb4c6155b7e452c67e24eea0868fb6e0 100644
--- a/test/tools/llvm-profdata/c-general.test
+++ b/test/tools/llvm-profdata/c-general.test
@@ -9,7 +9,7 @@ REGENERATE: $ CFE_TESTDIR=$CFE/test/Profile
 REGENERATE: $ clang -o a.out -fprofile-instr-generate $CFE_TESTDIR/c-general.c
 REGENERATE: $ LLVM_PROFILE_FILE=$TESTDIR/Inputs/c-general.profraw ./a.out
 
-RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - | FileCheck %s -check-prefix=CHECK
+RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - | FileCheck %s
 RUN: llvm-profdata show %p/Inputs/c-general.profraw -o - --function=switches | FileCheck %s -check-prefix=SWITCHES -check-prefix=CHECK
 
 SWITCHES-LABEL: Counters:
diff --git a/test/tools/llvm-profdata/input-filenames.test b/test/tools/llvm-profdata/input-filenames.test
new file mode 100644
index 0000000000000000000000000000000000000000..da0c47bf82acddd09a4bf25de1bfc7ebb44a5c87
--- /dev/null
+++ b/test/tools/llvm-profdata/input-filenames.test
@@ -0,0 +1,17 @@
+# Create an input file.
+RUN: echo '# comment 1' > %t.input
+RUN: echo ' # comment 2' >> %t.input
+RUN: echo 'bar' >> %t.input
+RUN: echo ' baz' >> %t.input
+RUN: echo "2,%t.weighted" >> %t.input
+
+# Create the weighted file, since these actually need to exist.
+RUN: echo ' ' > %t.weighted
+
+RUN: llvm-profdata merge -f %t.input -dump-input-file-list -o /dev/null foo | FileCheck %s
+RUN: llvm-profdata merge -input-files %t.input -dump-input-file-list -o /dev/null foo | FileCheck %s
+
+CHECK: 1,foo
+CHECK-NEXT: 1,bar
+CHECK-NEXT: 1,baz
+CHECK-NEXT: 2,{{.*}}.weighted
diff --git a/test/tools/llvm-profdata/raw-32-bits-be.test b/test/tools/llvm-profdata/raw-32-bits-be.test
index bc6ec0225875f506596a6ca98da54a7303dcaf21..d6e1daa1655cccb75d733f8e77f79b2e1723fe78 100644
--- a/test/tools/llvm-profdata/raw-32-bits-be.test
+++ b/test/tools/llvm-profdata/raw-32-bits-be.test
@@ -1,13 +1,11 @@
 RUN: printf '\377lprofR\201' > %t
-RUN: printf '\0\0\0\0\0\0\0\3' >> %t
+RUN: printf '\0\0\0\0\0\0\0\4' >> %t
 RUN: printf '\0\0\0\0\0\0\0\2' >> %t
 RUN: printf '\0\0\0\0\0\0\0\3' >> %t
 RUN: printf '\0\0\0\0\0\0\0\20' >> %t
 RUN: printf '\0\0\0\0\1\0\0\0' >> %t
 RUN: printf '\0\0\0\0\2\0\0\0' >> %t
 RUN: printf '\0\0\0\0\0\0\0\0' >> %t
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t
 
 RUN: printf '\134\370\302\114\333\030\275\254' >> %t
 RUN: printf '\0\0\0\0\0\0\0\1' >> %t
diff --git a/test/tools/llvm-profdata/raw-32-bits-le.test b/test/tools/llvm-profdata/raw-32-bits-le.test
index 5ee8b33df674d1242d15927d4077982f984b19c6..cd36aafc9ad9ea92b22b76e7f176a83a6d9076b2 100644
--- a/test/tools/llvm-profdata/raw-32-bits-le.test
+++ b/test/tools/llvm-profdata/raw-32-bits-le.test
@@ -1,13 +1,11 @@
 RUN: printf '\201Rforpl\377' > %t
-RUN: printf '\3\0\0\0\0\0\0\0' >> %t
+RUN: printf '\4\0\0\0\0\0\0\0' >> %t
 RUN: printf '\2\0\0\0\0\0\0\0' >> %t
 RUN: printf '\3\0\0\0\0\0\0\0' >> %t
 RUN: printf '\20\0\0\0\0\0\0\0' >> %t
 RUN: printf '\0\0\0\1\0\0\0\0' >> %t
 RUN: printf '\0\0\0\2\0\0\0\0' >> %t
 RUN: printf '\0\0\0\0\0\0\0\0' >> %t
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t
 
 RUN: printf '\254\275\030\333\114\302\370\134' >> %t
 RUN: printf '\1\0\0\0\0\0\0\0' >> %t
diff --git a/test/tools/llvm-profdata/raw-64-bits-be.test b/test/tools/llvm-profdata/raw-64-bits-be.test
index 9778f0627792ea807b908e896e043324d76ddaa6..75cc84d68862d0f7f3d0136b9893956e62abc7bd 100644
--- a/test/tools/llvm-profdata/raw-64-bits-be.test
+++ b/test/tools/llvm-profdata/raw-64-bits-be.test
@@ -1,13 +1,11 @@
 RUN: printf '\377lprofr\201' > %t
-RUN: printf '\0\0\0\0\0\0\0\3' >> %t
+RUN: printf '\0\0\0\0\0\0\0\4' >> %t
 RUN: printf '\0\0\0\0\0\0\0\2' >> %t
 RUN: printf '\0\0\0\0\0\0\0\3' >> %t
 RUN: printf '\0\0\0\0\0\0\0\20' >> %t
 RUN: printf '\0\0\0\1\0\4\0\0' >> %t
 RUN: printf '\0\0\0\2\0\4\0\0' >> %t
 RUN: printf '\0\0\0\0\0\0\0\0' >> %t
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t
 
 RUN: printf '\134\370\302\114\333\030\275\254' >> %t
 RUN: printf '\0\0\0\0\0\0\0\1' >> %t
diff --git a/test/tools/llvm-profdata/raw-64-bits-le.test b/test/tools/llvm-profdata/raw-64-bits-le.test
index 670bdb3ba854d6659a7e34ab14d09505dd3fcc70..d8a9c9a7586c779a041f85f58aff9b53b117be46 100644
--- a/test/tools/llvm-profdata/raw-64-bits-le.test
+++ b/test/tools/llvm-profdata/raw-64-bits-le.test
@@ -1,13 +1,11 @@
 RUN: printf '\201rforpl\377' > %t
-RUN: printf '\3\0\0\0\0\0\0\0' >> %t
+RUN: printf '\4\0\0\0\0\0\0\0' >> %t
 RUN: printf '\2\0\0\0\0\0\0\0' >> %t
 RUN: printf '\3\0\0\0\0\0\0\0' >> %t
 RUN: printf '\20\0\0\0\0\0\0\0' >> %t
 RUN: printf '\0\0\4\0\1\0\0\0' >> %t
 RUN: printf '\0\0\4\0\2\0\0\0' >> %t
 RUN: printf '\0\0\0\0\0\0\0\0' >> %t
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t
 
 RUN: printf '\254\275\030\333\114\302\370\134' >> %t
 RUN: printf '\1\0\0\0\0\0\0\0' >> %t
diff --git a/test/tools/llvm-profdata/raw-two-profiles.test b/test/tools/llvm-profdata/raw-two-profiles.test
index ed08333426a27e3261bb61de0fb3e7611b2a6320..a377375c1768c10ba6cedd1ac9a3cc251eeab94a 100644
--- a/test/tools/llvm-profdata/raw-two-profiles.test
+++ b/test/tools/llvm-profdata/raw-two-profiles.test
@@ -1,13 +1,11 @@
 RUN: printf '\201rforpl\377' > %t-foo.profraw
-RUN: printf '\3\0\0\0\0\0\0\0' >> %t-foo.profraw
+RUN: printf '\4\0\0\0\0\0\0\0' >> %t-foo.profraw
 RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
 RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
 RUN: printf '\10\0\0\0\0\0\0\0' >> %t-foo.profraw
 RUN: printf '\0\0\4\0\1\0\0\0' >> %t-foo.profraw
 RUN: printf '\0\0\4\0\2\0\0\0' >> %t-foo.profraw
 RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t-foo.profraw
 
 RUN: printf '\254\275\030\333\114\302\370\134' >> %t-foo.profraw
 RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
@@ -20,15 +18,13 @@ RUN: printf '\023\0\0\0\0\0\0\0' >> %t-foo.profraw
 RUN: printf '\3\0foo\0\0\0' >> %t-foo.profraw
 
 RUN: printf '\201rforpl\377' > %t-bar.profraw
-RUN: printf '\3\0\0\0\0\0\0\0' >> %t-bar.profraw
+RUN: printf '\4\0\0\0\0\0\0\0' >> %t-bar.profraw
 RUN: printf '\1\0\0\0\0\0\0\0' >> %t-bar.profraw
 RUN: printf '\2\0\0\0\0\0\0\0' >> %t-bar.profraw
 RUN: printf '\10\0\0\0\0\0\0\0' >> %t-bar.profraw
 RUN: printf '\0\0\6\0\1\0\0\0' >> %t-bar.profraw
 RUN: printf '\0\0\6\0\2\0\0\0' >> %t-bar.profraw
 RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
-RUN: printf '\0\0\0\0\0\0\0\0' >> %t-bar.profraw
 
 RUN: printf '\067\265\035\031\112\165\023\344' >> %t-bar.profraw
 RUN: printf '\02\0\0\0\0\0\0\0' >> %t-bar.profraw
diff --git a/test/tools/llvm-profdata/value-prof.proftext b/test/tools/llvm-profdata/value-prof.proftext
index a8f6e8641c679b4e69f7b4a47a4c3e305b7a5f45..75a745664499cc746359eabde9f44a1d8bc9c0e0 100644
--- a/test/tools/llvm-profdata/value-prof.proftext
+++ b/test/tools/llvm-profdata/value-prof.proftext
@@ -1,7 +1,7 @@
-# RUN: llvm-profdata show -ic-targets  -all-functions %s | FileCheck %s --check-prefix=ICTXT
+# RUN: llvm-profdata show -ic-targets  -all-functions %s | FileCheck %s --check-prefix=ICTXT --check-prefix=ICSUM
 # RUN: llvm-profdata show -ic-targets -counts -text -all-functions %s | FileCheck %s --check-prefix=ICTEXT
 # RUN: llvm-profdata merge -o %t.profdata  %s
-# RUN: llvm-profdata show -ic-targets  -all-functions %t.profdata | FileCheck %s --check-prefix=IC
+# RUN: llvm-profdata show -ic-targets  -all-functions %t.profdata | FileCheck %s --check-prefix=IC --check-prefix=ICSUM
 
 foo
 # Func Hash:
@@ -61,3 +61,9 @@ foo2:20000
 #ICTEXT-NEXT: foo2:1000
 #ICTEXT-NEXT: 1
 #ICTEXT-NEXT: foo2:20000
+#
+
+#ICSUM: Total Number of Indirect Call Sites : 3
+#ICSUM: Total Number of Sites With Values : 2
+#ICSUM: Total Number of Profiled Values : 3
+
diff --git a/test/tools/llvm-readobj/Inputs/codeview-merging-1.obj b/test/tools/llvm-readobj/Inputs/codeview-merging-1.obj
new file mode 100644
index 0000000000000000000000000000000000000000..e51643a136dc1fa21616af75f04e60ae46682a5f
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/codeview-merging-1.obj differ
diff --git a/test/tools/llvm-readobj/Inputs/codeview-merging-2.obj b/test/tools/llvm-readobj/Inputs/codeview-merging-2.obj
new file mode 100644
index 0000000000000000000000000000000000000000..4cf24257deed1443714b47d747c99ee49cbcd4c8
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/codeview-merging-2.obj differ
diff --git a/test/tools/llvm-readobj/Inputs/codeview-types.obj b/test/tools/llvm-readobj/Inputs/codeview-types.obj
new file mode 100644
index 0000000000000000000000000000000000000000..b00a7c6a3e10d6f273c11dcad1ed36244af9d499
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/codeview-types.obj differ
diff --git a/test/tools/llvm-readobj/Inputs/codeview-vftable.obj.coff b/test/tools/llvm-readobj/Inputs/codeview-vftable.obj.coff
new file mode 100644
index 0000000000000000000000000000000000000000..388a7212eb259af7f80f0905d4208b8be02eb63f
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/codeview-vftable.obj.coff differ
diff --git a/test/tools/llvm-readobj/Inputs/compression.zlib.style.elf-x86-64 b/test/tools/llvm-readobj/Inputs/compression.zlib.style.elf-x86-64
new file mode 100644
index 0000000000000000000000000000000000000000..34cdb8a89edf4b4b42fad3c2deacaaaf1acad20b
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/compression.zlib.style.elf-x86-64 differ
diff --git a/test/tools/llvm-readobj/Inputs/file-aux-record.yaml b/test/tools/llvm-readobj/Inputs/file-aux-record.yaml
index 89d6761a26dbd97931a7b7e3100e3d1b8475b9b1..2f74a9a6ef4a1ce9e4c16e49ad5d0b4f97a379a9 100644
--- a/test/tools/llvm-readobj/Inputs/file-aux-record.yaml
+++ b/test/tools/llvm-readobj/Inputs/file-aux-record.yaml
@@ -1,3 +1,4 @@
+!COFF
 header: !Header
   Machine: IMAGE_FILE_MACHINE_I386 # (0x14c)
   Characteristics: [ IMAGE_FILE_DEBUG_STRIPPED ]
diff --git a/test/tools/llvm-readobj/Inputs/file-multiple-aux-records.yaml b/test/tools/llvm-readobj/Inputs/file-multiple-aux-records.yaml
index d5b1eec878b0bcb8f7b708b1f11ab2887e5e12f6..42946b4fafb444518ddc9bf3516bef1c40380599 100644
--- a/test/tools/llvm-readobj/Inputs/file-multiple-aux-records.yaml
+++ b/test/tools/llvm-readobj/Inputs/file-multiple-aux-records.yaml
@@ -1,3 +1,4 @@
+!COFF
 header: !Header
   Machine: IMAGE_FILE_MACHINE_I386 # (0x14c)
   Characteristics: [ IMAGE_FILE_DEBUG_STRIPPED ]
diff --git a/test/tools/llvm-readobj/Inputs/has_pdb.exe b/test/tools/llvm-readobj/Inputs/has_pdb.exe
new file mode 100644
index 0000000000000000000000000000000000000000..60cc9f59fc1646bfd2bad9a84516ff0e96239504
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/has_pdb.exe differ
diff --git a/test/tools/llvm-readobj/Inputs/options.obj.elf-mipsel b/test/tools/llvm-readobj/Inputs/options.obj.elf-mipsel
new file mode 100644
index 0000000000000000000000000000000000000000..6309d87c592bd1db51a22b1ba5d863cd7ece3bbf
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/options.obj.elf-mipsel differ
diff --git a/test/tools/llvm-readobj/Inputs/relocs.obj.elf-lanai b/test/tools/llvm-readobj/Inputs/relocs.obj.elf-lanai
index c0bb9a046942cb78a784d3172034be3b20d069a8..70e25d1fca319223b9c6d923fd39633d909f8dcc 100644
Binary files a/test/tools/llvm-readobj/Inputs/relocs.obj.elf-lanai and b/test/tools/llvm-readobj/Inputs/relocs.obj.elf-lanai differ
diff --git a/test/tools/llvm-readobj/Inputs/trivial.obj.elf-lanai b/test/tools/llvm-readobj/Inputs/trivial.obj.elf-lanai
index 13bb30ca6fd9abb1c2cb970e5728a7251495722c..fe05a31e358b5fcc8f807680d120282fb13341f1 100644
Binary files a/test/tools/llvm-readobj/Inputs/trivial.obj.elf-lanai and b/test/tools/llvm-readobj/Inputs/trivial.obj.elf-lanai differ
diff --git a/test/tools/llvm-readobj/Inputs/verneed.elf-x86-64 b/test/tools/llvm-readobj/Inputs/verneed.elf-x86-64
new file mode 100644
index 0000000000000000000000000000000000000000..3a9c8d8df8da38631340f7dd361a3dd9c0efb7c8
Binary files /dev/null and b/test/tools/llvm-readobj/Inputs/verneed.elf-x86-64 differ
diff --git a/test/tools/llvm-readobj/codeview-merging.test b/test/tools/llvm-readobj/codeview-merging.test
new file mode 100644
index 0000000000000000000000000000000000000000..60894eff33eb1a817766511be5b9d9a583d490f9
--- /dev/null
+++ b/test/tools/llvm-readobj/codeview-merging.test
@@ -0,0 +1,65 @@
+# To regenerate t1.obj and t2.obj, run the following:
+# $ cat t.cpp
+# #ifdef CONFIG1
+# struct A;
+# struct B {
+#   A *a;
+# };
+# int f(A *a);
+# int g(B *b) { return f(b->a); }
+# #else
+# struct B;
+# struct A {
+#   B *b;
+# };
+# int g(B *b);
+# int f(A *a) { return g(a->b); }
+# #endif
+# $ cl -c -DCONFIG1 -Z7 t.cpp -Fot1.obj && cl -c -Z7 t.cpp -Fot2.obj
+
+RUN: llvm-readobj -codeview %S/Inputs/codeview-merging-1.obj | FileCheck %s --check-prefix=OBJ1
+RUN: llvm-readobj -codeview %S/Inputs/codeview-merging-2.obj | FileCheck %s --check-prefix=OBJ2
+RUN: llvm-readobj -codeview-merged-types %S/Inputs/codeview-merging-1.obj %S/Inputs/codeview-merging-2.obj | FileCheck %s
+
+OBJ1:       FuncId (0x100D) {
+OBJ1-NEXT:    TypeLeafKind: LF_FUNC_ID (0x1601)
+OBJ1-NEXT:    ParentScope: 0x0
+OBJ1-NEXT:    FunctionType: int (B*) (0x100C)
+OBJ1-NEXT:    Name: g
+OBJ1-NEXT:  }
+OBJ1-NEXT:  FuncId (0x100E) {
+OBJ1-NEXT:    TypeLeafKind: LF_FUNC_ID (0x1601)
+OBJ1-NEXT:    ParentScope: 0x0
+OBJ1-NEXT:    FunctionType: int (A*) (0x1003)
+OBJ1-NEXT:    Name: f
+OBJ1-NEXT:  }
+OBJ1-NOT: FuncId
+
+OBJ2:       FuncId (0x100D) {
+OBJ2-NEXT:    TypeLeafKind: LF_FUNC_ID (0x1601)
+OBJ2-NEXT:    ParentScope: 0x0
+OBJ2-NEXT:    FunctionType: int (A*) (0x100C)
+OBJ2-NEXT:    Name: f
+OBJ2-NEXT:  }
+
+OBJ2:       FuncId (0x1069) {
+OBJ2-NEXT:    TypeLeafKind: LF_FUNC_ID (0x1601)
+OBJ2-NEXT:    ParentScope: 0x0
+OBJ2-NEXT:    FunctionType: int (B*) (0x1003)
+OBJ2-NEXT:    Name: g
+OBJ2-NEXT:  }
+OBJ2-NOT: FuncId
+
+CHECK:       FuncId (0x100D) {
+CHECK-NEXT:    TypeLeafKind: LF_FUNC_ID (0x1601)
+CHECK-NEXT:    ParentScope: 0x0
+CHECK-NEXT:    FunctionType: int (B*) (0x100C)
+CHECK-NEXT:    Name: g
+CHECK-NEXT:  }
+CHECK-NEXT:  FuncId (0x100E) {
+CHECK-NEXT:    TypeLeafKind: LF_FUNC_ID (0x1601)
+CHECK-NEXT:    ParentScope: 0x0
+CHECK-NEXT:    FunctionType: int (A*) (0x1003)
+CHECK-NEXT:    Name: f
+CHECK-NEXT:  }
+CHECK-NOT: FuncId
diff --git a/test/tools/llvm-readobj/codeview-types.test b/test/tools/llvm-readobj/codeview-types.test
new file mode 100644
index 0000000000000000000000000000000000000000..4545b8e01dd27915afa171a682b76a8fb88fc2de
--- /dev/null
+++ b/test/tools/llvm-readobj/codeview-types.test
@@ -0,0 +1,95 @@
+// This tests that we can deserialize and reserialize every known type record.
+// If you need to update the object file, enable the RUNX line below using MSVC
+// from VS 2012. Newer versions of MSVC emit tons of internal types for
+// attributes that pollute the test output. When Clang fully supports all these
+// type records, we can regenerate the test using it instead.
+
+// RUNX: cl -GR- -Z7 -c -TP %s -Fo%S/Inputs/codeview-types.obj
+// RUN: llvm-readobj -codeview %S/Inputs/codeview-types.obj | FileCheck %s
+// RUN: llvm-readobj -codeview-merged-types %S/Inputs/codeview-types.obj | FileCheck %s
+
+// TYPE_RECORD
+// CHECK-DAG: {{^ *Pointer (.*) {$}}
+// CHECK-DAG: {{^ *Modifier (.*) {$}}
+// CHECK-DAG: {{^ *Procedure (.*) {$}}
+// CHECK-DAG: {{^ *MemberFunction (.*) {$}}
+// CHECK-DAG: {{^ *ArgList (.*) {$}}
+// CHECK-DAG: {{^ *Array (.*) {$}}
+// CHECK-DAG: {{^ *Class (.*) {$}}
+// CHECK-DAG: {{^ *Union (.*) {$}}
+// CHECK-DAG: {{^ *Enum (.*) {$}}
+// CHECK-DAG: {{^ *VFTable (.*) {$}}
+// CHECK-DAG: {{^ *VFTableShape (.*) {$}}
+// CHECK-DAG: {{^ *FuncId (.*) {$}}
+// CHECK-DAG: {{^ *MemberFuncId (.*) {$}}
+// CHECK-DAG: {{^ *BuildInfo (.*) {$}}
+// CHECK-DAG: {{^ *StringId (.*) {$}}
+// CHECK-DAG: {{^ *UdtSourceLine (.*) {$}}
+// CHECK-DAG: {{^ *MethodOverloadList (.*) {$}}
+// No TypeServer2, since that is used with /Zi
+
+// MEMBER_RECORD
+// CHECK-DAG: {{^ *BaseClass {$}}
+// CHECK-DAG: {{^ *VirtualBaseClass {$}}
+// CHECK-DAG: {{^ *VFPtr {$}}
+// CHECK-DAG: {{^ *StaticDataMember {$}}
+// CHECK-DAG: {{^ *OverloadedMethod {$}}
+// CHECK-DAG: {{^ *DataMember {$}}
+// CHECK-DAG: {{^ *NestedType {$}}
+// CHECK-DAG: {{^ *OneMethod {$}}
+// CHECK-DAG: {{^ *Enumerator {$}}
+
+#if !defined(__clang__) && _MSC_VER >= 1800
+#error "use clang or MSVC 2012 to regenerate the test"
+#endif
+
+struct VBaseA;
+void FriendFunc();
+
+class Class {
+public:
+  const Class *DataMember;
+private:
+  static int StaticDataMember;
+protected:
+  virtual void MemberFunction();
+public:
+  struct Nested;
+  friend ::VBaseA;
+  friend void FriendFunc() { }
+  void OverloadedMethod();
+  void OverloadedMethod(int);
+};
+
+enum Enum {
+  E1 = 0,
+  E2 = 1
+};
+
+int array[4] = {1, 2, 3, 4};
+
+struct Class::Nested {};
+
+struct ClassWithBase : Class {
+  virtual void MemberFunction();
+  virtual void NewVirtual();
+};
+struct VBaseA { int x; };
+struct VBaseB : virtual VBaseA { int x; };
+struct VBaseC : virtual VBaseA { int x; };
+struct VBaseD : VBaseB, VBaseC { int x; };
+
+union Union {
+  float f;
+  int i;
+};
+
+void UseAllTypes() {
+  Class a;
+  Class::Nested b;
+  ClassWithBase c;
+  VBaseD d;
+  Union e;
+  Enum f;
+  FriendFunc();
+}
diff --git a/test/tools/llvm-readobj/codeview-vftable.test b/test/tools/llvm-readobj/codeview-vftable.test
new file mode 100644
index 0000000000000000000000000000000000000000..772f0c764983a0d92483f6f69d767df97462691e
--- /dev/null
+++ b/test/tools/llvm-readobj/codeview-vftable.test
@@ -0,0 +1,48 @@
+; The following two object files were generated using the following command:
+;   $ cl /Z7 /c t.cpp
+; The contents of t.cpp follow:
+;   struct A {
+;     virtual void f();
+;   };
+;   struct B {
+;     virtual void f();
+;     virtual void g();
+;   };
+;   struct C {
+;     virtual void f();
+;     virtual void g();
+;     virtual void h();
+;   };
+;   A a;
+;   B b;
+;   C c;
+
+RUN: llvm-readobj -codeview %p/Inputs/codeview-vftable.obj.coff | FileCheck %s
+
+CHECK:       VFTable (0x10F0) {
+CHECK-NEXT:    TypeLeafKind: LF_VFTABLE (0x151D)
+CHECK-NEXT:    CompleteClass: A
+CHECK-NEXT:    OverriddenVFTable: 0x0
+CHECK-NEXT:    VFPtrOffset: 0x0
+CHECK-NEXT:    VFTableName: ??_7A@@6B@
+CHECK-NEXT:    MethodName: ?f@A@@UEAAXXZ
+CHECK-NEXT:  }
+CHECK-NEXT:  VFTable (0x10F1) {
+CHECK-NEXT:    TypeLeafKind: LF_VFTABLE (0x151D)
+CHECK-NEXT:    CompleteClass: B
+CHECK-NEXT:    OverriddenVFTable: ??_7A@@6B@ (0x10F0)
+CHECK-NEXT:    VFPtrOffset: 0x0
+CHECK-NEXT:    VFTableName: ??_7B@@6B@
+CHECK-NEXT:    MethodName: ?f@B@@UEAAXXZ
+CHECK-NEXT:    MethodName: ?g@B@@UEAAXXZ
+CHECK-NEXT:  }
+CHECK-NEXT:  VFTable (0x10F2) {
+CHECK-NEXT:    TypeLeafKind: LF_VFTABLE (0x151D)
+CHECK-NEXT:    CompleteClass: C
+CHECK-NEXT:    OverriddenVFTable: ??_7B@@6B@ (0x10F1)
+CHECK-NEXT:    VFPtrOffset: 0x0
+CHECK-NEXT:    VFTableName: ??_7C@@6B@
+CHECK-NEXT:    MethodName: ?f@C@@UEAAXXZ
+CHECK-NEXT:    MethodName: ?g@C@@UEAAXXZ
+CHECK-NEXT:    MethodName: ?h@C@@UEAAXXZ
+CHECK-NEXT:  }
diff --git a/test/tools/llvm-readobj/coff-debug-directory.test b/test/tools/llvm-readobj/coff-debug-directory.test
new file mode 100644
index 0000000000000000000000000000000000000000..f5c31c77abfe753512af68ba5cb5712f9a5c982d
--- /dev/null
+++ b/test/tools/llvm-readobj/coff-debug-directory.test
@@ -0,0 +1,34 @@
+RUN: llvm-readobj -coff-debug-directory %p/Inputs/has_pdb.exe | FileCheck %s
+
+CHECK: DebugDirectory [
+CHECK:   DebugEntry {
+CHECK:     Characteristics: 0x0
+CHECK:     TimeDateStamp: 2016-06-01 22:53:16 (0x574F675C)
+CHECK:     MajorVersion: 0x0
+CHECK:     MinorVersion: 0x0
+CHECK:     Type: CodeView (0x2)
+CHECK:     SizeOfData: 0x36
+CHECK:     AddressOfRawData: 0x5B068
+CHECK:     PointerToRawData: 0x5A268
+CHECK:     PDBInfo {
+CHECK:       PDBSignature: 0x53445352
+CHECK:       PDBGUID: (96 83 40 42 81 07 9D 40 90 1B 4A 3C 0D 4F 56 32)
+CHECK:       PDBAge: 3
+CHECK:       PDBFileName: D:\src\llvm\build\has_pdb.pdb
+CHECK:     }
+CHECK:   }
+CHECK:   DebugEntry {
+CHECK:     Characteristics: 0x0
+CHECK:     TimeDateStamp: 2016-06-01 22:53:16 (0x574F675C)
+CHECK:     MajorVersion: 0x0
+CHECK:     MinorVersion: 0x0
+CHECK:     Type: VCFeature (0xC)
+CHECK:     SizeOfData: 0x14
+CHECK:     AddressOfRawData: 0x5B0A0
+CHECK:     PointerToRawData: 0x5A2A0
+CHECK:     RawData (
+CHECK:       0000: 00000000 C1000000 C1000000 00000000  |................|
+CHECK:       0010: C0000000                             |....|
+CHECK:     )
+CHECK:   }
+CHECK: ]
diff --git a/test/tools/llvm-readobj/elf-hash-histogram.test b/test/tools/llvm-readobj/elf-hash-histogram.test
new file mode 100644
index 0000000000000000000000000000000000000000..b7ddfabacaadb8def629bec01ce35ec709401b9e
--- /dev/null
+++ b/test/tools/llvm-readobj/elf-hash-histogram.test
@@ -0,0 +1,27 @@
+RUN: llvm-readobj -elf-hash-histogram %p/Inputs/gnuhash.so.elf-ppc64 \
+RUN:  --elf-output-style=GNU | FileCheck %s -check-prefix PPC64GNU
+RUN: llvm-readobj -elf-hash-histogram %p/Inputs/gnuhash.so.elf-x86_64 --elf-output-style=GNU \
+RUN:   | FileCheck %s -check-prefix X86GNU
+RUN: llvm-readobj -elf-hash-histogram %p/Inputs/got-plt.exe.elf-mipsel --elf-output-style=GNU \
+RUN:   | FileCheck %s -check-prefix SYSV
+
+PPC64GNU: Histogram for `.gnu.hash' bucket list length (total of 3 buckets)
+PPC64GNU-NEXT:  Length  Number     % of total  Coverage
+PPC64GNU-NEXT:       0  1          ( 33.3%)       0.0%
+PPC64GNU-NEXT:       1  1          ( 33.3%)      25.0%
+PPC64GNU-NEXT:       2  0          (  0.0%)      25.0%
+PPC64GNU-NEXT:       3  1          ( 33.3%)     100.0%
+
+X86GNU: Histogram for `.gnu.hash' bucket list length (total of 3 buckets)
+X86GNU-NEXT:  Length  Number     % of total  Coverage
+X86GNU-NEXT:       0  1          ( 33.3%)       0.0%
+X86GNU-NEXT:       1  1          ( 33.3%)      25.0%
+X86GNU-NEXT:       2  0          (  0.0%)      25.0%
+X86GNU-NEXT:       3  1          ( 33.3%)     100.0%
+
+SYSV: Histogram for bucket list length (total of 3 buckets)
+SYSV-NEXT:  Length  Number     % of total  Coverage
+SYSV-NEXT:       0  0          (  0.0%)       0.0%
+SYSV-NEXT:       1  0          (  0.0%)       0.0%
+SYSV-NEXT:       2  2          ( 66.7%)      57.1%
+SYSV-NEXT:       3  1          ( 33.3%)     100.0%
diff --git a/test/tools/llvm-readobj/elf-sec-compressed.test b/test/tools/llvm-readobj/elf-sec-compressed.test
new file mode 100644
index 0000000000000000000000000000000000000000..baf0c687a9134304b7ef316f9e352737976293eb
--- /dev/null
+++ b/test/tools/llvm-readobj/elf-sec-compressed.test
@@ -0,0 +1,9 @@
+RUN: llvm-readobj -sections \
+RUN:   %p/Inputs/compression.zlib.style.elf-x86-64 | FileCheck %s
+
+CHECK:      Section {
+CHECK:       Name: .debug_info
+CHECK-NEXT:  Type: SHT_PROGBITS
+CHECK-NEXT:  Flags [ 
+CHECK-NEXT:   SHF_COMPRESSED (0x800)
+CHECK-NEXT:  ]
diff --git a/test/tools/llvm-readobj/elf-sec-flags.test b/test/tools/llvm-readobj/elf-sec-flags.test
index 95a417a054f98956bdcda390afd619ff61d996a3..842ded3e9e59ef1b6ba6739bb3b6bbc3b12b16cf 100644
--- a/test/tools/llvm-readobj/elf-sec-flags.test
+++ b/test/tools/llvm-readobj/elf-sec-flags.test
@@ -1,6 +1,6 @@
 # Check that llvm-readobj shows arch specific ELF section flags.
 
-# RUN: yaml2obj -format=elf -docnum 1 %s > %t-amdgpu.o
+# RUN: yaml2obj -docnum 1 %s > %t-amdgpu.o
 # RUN: llvm-readobj -s %t-amdgpu.o | FileCheck -check-prefix=AMD %s
 
 # AMD:      Flags [ (0x300000)
@@ -9,7 +9,7 @@
 # AMD-NEXT: ]
 
 # amdgpu.o
----
+--- !ELF
 FileHeader:
   Class:    ELFCLASS64
   Data:     ELFDATA2LSB
@@ -23,7 +23,7 @@ Sections:
     Flags:  [SHF_AMDGPU_HSA_GLOBAL, SHF_AMDGPU_HSA_READONLY]
     Size:   4
 
-# RUN: yaml2obj -format=elf -docnum 2 %s > %t-hex.o
+# RUN: yaml2obj -docnum 2 %s > %t-hex.o
 # RUN: llvm-readobj -s %t-hex.o | FileCheck -check-prefix=HEX %s
 
 # HEX:      Flags [ (0x10000000)
@@ -31,7 +31,7 @@ Sections:
 # HEX-NEXT: ]
 
 # hex.o
----
+--- !ELF
 FileHeader:
   Class:    ELFCLASS32
   Data:     ELFDATA2LSB
@@ -44,7 +44,7 @@ Sections:
     Flags:  [SHF_HEX_GPREL]
     Size:   4
 
-# RUN: yaml2obj -format=elf -docnum 3 %s > %t-mips.o
+# RUN: yaml2obj -docnum 3 %s > %t-mips.o
 # RUN: llvm-readobj -s %t-mips.o | FileCheck -check-prefix=MIPS %s
 
 # MIPS:      Flags [ (0x38000000)
@@ -54,7 +54,7 @@ Sections:
 # MIPS-NEXT: ]
 
 # mips.o
----
+--- !ELF
 FileHeader:
   Class:    ELFCLASS32
   Data:     ELFDATA2LSB
@@ -67,7 +67,7 @@ Sections:
     Flags:  [SHF_MIPS_GPREL, SHF_MIPS_MERGE, SHF_MIPS_NOSTRIP]
     Size:   4
 
-# RUN: yaml2obj -format=elf -docnum 4 %s > %t-x86_64.o
+# RUN: yaml2obj -docnum 4 %s > %t-x86_64.o
 # RUN: llvm-readobj -s %t-x86_64.o | FileCheck -check-prefix=X86_64 %s
 
 # X86_64:      Flags [ (0x10000000)
@@ -75,7 +75,7 @@ Sections:
 # X86_64-NEXT: ]
 
 # x86_64.o
----
+--- !ELF
 FileHeader:
   Class:    ELFCLASS64
   Data:     ELFDATA2LSB
diff --git a/test/tools/llvm-readobj/elf-versioninfo.test b/test/tools/llvm-readobj/elf-versioninfo.test
index e8113e4b2fed3b8b6c7952dca5f5a1bd92bbea65..919120e2caa936c7fef8c21e71ffc19411d4e4cc 100644
--- a/test/tools/llvm-readobj/elf-versioninfo.test
+++ b/test/tools/llvm-readobj/elf-versioninfo.test
@@ -47,35 +47,60 @@ CHECK-NEXT:     }
 CHECK-NEXT:   ]
 CHECK-NEXT: }
 
-CHECK: Version definition {
-CHECK-NEXT:   Section Name: .gnu.version_d (70)
-CHECK-NEXT:   Address: 0x25C
-CHECK-NEXT:   Offset: 0x25C
-CHECK-NEXT:   Link: 2
-CHECK-NEXT:   Entries [
-CHECK-NEXT:     Entry {
-CHECK-NEXT:       Offset: 0x0
-CHECK-NEXT:       Rev: 1
-CHECK-NEXT:       Flags: 1
-CHECK-NEXT:       Index: 1
-CHECK-NEXT:       Cnt: 1
-CHECK-NEXT:       Name: blah
-CHECK-NEXT:     }
-CHECK-NEXT:     Entry {
-CHECK-NEXT:       Offset: 0x1C
-CHECK-NEXT:       Rev: 1
-CHECK-NEXT:       Flags: 0
-CHECK-NEXT:       Index: 2
-CHECK-NEXT:       Cnt: 1
-CHECK-NEXT:       Name: VERSION1
-CHECK-NEXT:     }
-CHECK-NEXT:     Entry {
-CHECK-NEXT:       Offset: 0x38
-CHECK-NEXT:       Rev: 1
-CHECK-NEXT:       Flags: 0
-CHECK-NEXT:       Index: 3
-CHECK-NEXT:       Cnt: 2
-CHECK-NEXT:       Name: VERSION2
-CHECK-NEXT:     }
-CHECK-NEXT:   ]
+CHECK:      SHT_GNU_verdef {
+CHECK-NEXT:   Definition {
+CHECK-NEXT:     Version: 1
+CHECK-NEXT:     Flags: Base (0x1)
+CHECK-NEXT:     Index: 1
+CHECK-NEXT:     Hash: 430712
+CHECK-NEXT:     Name: blah
+CHECK-NEXT:   }
+CHECK-NEXT:   Definition {
+CHECK-NEXT:     Version: 1
+CHECK-NEXT:     Flags: 0x0
+CHECK-NEXT:     Index: 2
+CHECK-NEXT:     Hash: 175630257
+CHECK-NEXT:     Name: VERSION1
+CHECK-NEXT:   }
+CHECK-NEXT:   Definition {
+CHECK-NEXT:     Version: 1
+CHECK-NEXT:     Flags: 0x0
+CHECK-NEXT:     Index: 3
+CHECK-NEXT:     Hash: 175630258
+CHECK-NEXT:     Name: VERSION2
+CHECK-NEXT:     Predecessor: VERSION1
+CHECK-NEXT:   }
 CHECK-NEXT: }
+
+RUN: llvm-readobj -V %p/Inputs/verneed.elf-x86-64 | FileCheck %s --check-prefix=VERNEED
+
+VERNEED:       SHT_GNU_verneed {
+VERNEED-NEXT:   Dependency {
+VERNEED-NEXT:     Version: 1
+VERNEED-NEXT:     Count: 2
+VERNEED-NEXT:     FileName: verneed1.so.0
+VERNEED-NEXT:     Entry {
+VERNEED-NEXT:       Hash: 1938
+VERNEED-NEXT:       Flags: 0x0
+VERNEED-NEXT:       Index: 3
+VERNEED-NEXT:       Name: v2
+VERNEED-NEXT:     }
+VERNEED-NEXT:     Entry {
+VERNEED-NEXT:       Hash: 1939
+VERNEED-NEXT:       Flags: 0x0
+VERNEED-NEXT:       Index: 2
+VERNEED-NEXT:       Name: v3
+VERNEED-NEXT:     }
+VERNEED-NEXT:   }
+VERNEED-NEXT:   Dependency {
+VERNEED-NEXT:     Version: 1
+VERNEED-NEXT:     Count: 1
+VERNEED-NEXT:     FileName: verneed2.so.0
+VERNEED-NEXT:     Entry {
+VERNEED-NEXT:       Hash: 1937
+VERNEED-NEXT:       Flags: 0x0
+VERNEED-NEXT:       Index: 4
+VERNEED-NEXT:       Name: v1
+VERNEED-NEXT:     }
+VERNEED-NEXT:   }
+VERNEED-NEXT: }
diff --git a/test/tools/llvm-readobj/file-headers.test b/test/tools/llvm-readobj/file-headers.test
index 4fe8210c4dd7101c057ec4afa3758cc7cc22f258..662c9b6bd4d7b69c9cc8a4c9eba7fda3575cc7b2 100644
--- a/test/tools/llvm-readobj/file-headers.test
+++ b/test/tools/llvm-readobj/file-headers.test
@@ -353,7 +353,7 @@ ELF-LANAI-NEXT:     ABIVersion: 0
 ELF-LANAI-NEXT:     Unused: (00 00 00 00 00 00 00)
 ELF-LANAI-NEXT:   }
 ELF-LANAI-NEXT:   Type: Relocatable (0x1)
-ELF-LANAI-NEXT:   Machine: EM_LANAI (0x8123)
+ELF-LANAI-NEXT:   Machine: EM_LANAI (0xF4)
 ELF-LANAI-NEXT:   Version: 1
 ELF-LANAI-NEXT:   Entry: 0x0
 ELF-LANAI-NEXT:   ProgramHeaderOffset: 0x0
diff --git a/test/tools/llvm-readobj/mips-options-sec.test b/test/tools/llvm-readobj/mips-options-sec.test
new file mode 100644
index 0000000000000000000000000000000000000000..0fe8aad3dfa14f771b7855ebc512b072e2603973
--- /dev/null
+++ b/test/tools/llvm-readobj/mips-options-sec.test
@@ -0,0 +1,12 @@
+RUN: llvm-readobj -mips-options %p/Inputs/options.obj.elf-mipsel | FileCheck %s
+
+CHECK:      MIPS Options {
+CHECK-NEXT:   ODK_REGINFO {
+CHECK-NEXT:     GP: 0x0
+CHECK-NEXT:     General Mask: 0xF2000017
+CHECK-NEXT:     Co-Proc Mask0: 0x0
+CHECK-NEXT:     Co-Proc Mask1: 0x0
+CHECK-NEXT:     Co-Proc Mask2: 0x0
+CHECK-NEXT:     Co-Proc Mask3: 0x0
+CHECK-NEXT:   }
+CHECK-NEXT: }
diff --git a/test/tools/llvm-size/basic.test b/test/tools/llvm-size/basic.test
index 614c6394027878f3cc6226d18f8bc04428fe460b..88b8dcbcbffad196da786eb609ea705d26210522 100644
--- a/test/tools/llvm-size/basic.test
+++ b/test/tools/llvm-size/basic.test
@@ -1,2 +1,2 @@
-RUN: llvm-size %t.blah 2>&1 | FileCheck --check-prefix=ENOENT %s
+RUN: not llvm-size %t.blah 2>&1 | FileCheck --check-prefix=ENOENT %s
 ENOENT: {{.*}}llvm-size{{(\.EXE|\.exe)?}}: error reading file: {{[Nn]}}o such file or directory
diff --git a/test/tools/llvm-split/blockaddress.ll b/test/tools/llvm-split/blockaddress.ll
new file mode 100644
index 0000000000000000000000000000000000000000..2672f8f98490b0b8f58b8130b05edf6a16d5d69b
--- /dev/null
+++ b/test/tools/llvm-split/blockaddress.ll
@@ -0,0 +1,37 @@
+; Test that blockaddress target is in the same partition.
+; RUN: llvm-split -j5 -o %t %s
+; RUN: llvm-dis -o - %t0 | FileCheck --check-prefix=CHECK0 %s
+; RUN: llvm-dis -o - %t1 | FileCheck --check-prefix=CHECK1234 %s
+; RUN: llvm-dis -o - %t2 | FileCheck --check-prefix=CHECK1234 %s
+; RUN: llvm-dis -o - %t3 | FileCheck --check-prefix=CHECK1234 %s
+; RUN: llvm-dis -o - %t4 | FileCheck --check-prefix=CHECK1234 %s
+
+; CHECK0:    @xxx = global [2 x i8*] [i8* blockaddress(@f, %exit), i8* blockaddress(@g, %exit)]
+; CHECK1234: @xxx = external global [2 x i8*]
+; CHECK1234-NOT: blockaddress
+@xxx = global [2 x i8*] [i8* blockaddress(@f, %exit), i8* blockaddress(@g, %exit)]
+
+; CHECK0:    define i32 @f()
+; CHECK1234: declare i32 @f()
+define i32 @f(){
+entry:
+  br label %exit
+exit:
+  ret i32 0
+}
+
+; CHECK0:    define i32 @g()
+; CHECK1234: declare i32 @g()
+define i32 @g(){
+entry:
+  br label %exit
+exit:
+  ret i32 0
+}
+
+; CHECK0:    define i8* @h()
+; CHECK1234: declare i8* @h()
+define i8* @h(){
+entry:
+  ret i8* blockaddress(@f, %exit)
+}
diff --git a/test/tools/llvm-split/extern_linkage.ll b/test/tools/llvm-split/extern_linkage.ll
new file mode 100644
index 0000000000000000000000000000000000000000..d8dde7963e72d8608d8ee90ba2d87a497f9f64e0
--- /dev/null
+++ b/test/tools/llvm-split/extern_linkage.ll
@@ -0,0 +1,12 @@
+; Test that extern_weak linkage is preserved.
+; RUN: llvm-split -o %t %s
+; RUN: llvm-dis -o - %t0 | FileCheck %s
+; RUN: llvm-dis -o - %t1 | FileCheck %s
+
+; Both declarations are extern_weak in all partitions.
+
+; CHECK: @x = extern_weak global i32, align 4
+@x = extern_weak global i32, align 4
+
+; CHECK: declare extern_weak void @f(...)
+declare extern_weak void @f(...)
diff --git a/test/tools/llvm-symbolizer/fat.test b/test/tools/llvm-symbolizer/fat.test
index 1ecd1abb356f48ba75b6fddcdd29c4376715a370..f943150441fea656c29d62c15351d010b93cd4bb 100644
--- a/test/tools/llvm-symbolizer/fat.test
+++ b/test/tools/llvm-symbolizer/fat.test
@@ -1,8 +1,8 @@
 RUN: echo 0 | llvm-symbolizer -obj=%p/Inputs/fat.o -default-arch=x86_64 | FileCheck --check-prefix=X86_64 %s
 RUN: echo 0 | llvm-symbolizer -obj=%p/Inputs/fat.o -default-arch=x86_64h | FileCheck --check-prefix=X86_64H %s
 RUN: echo 0 | llvm-symbolizer -obj=%p/Inputs/fat.o -default-arch=armv7 | FileCheck --check-prefix=ARMV7 %s
-RUN: echo 0 | llvm-symbolizer -obj=%p/Inputs/fat.o -default-arch=armv7em | FileCheck --check-prefix=ARMV7EM %s
-RUN: echo 0 | llvm-symbolizer -obj=%p/Inputs/fat.o -default-arch=armv7m | FileCheck --check-prefix=ARMV7M %s
+RUN: echo 0 | llvm-symbolizer -obj=%p/Inputs/fat.o -default-arch=thumbv7em | FileCheck --check-prefix=ARMV7EM %s
+RUN: echo 0 | llvm-symbolizer -obj=%p/Inputs/fat.o -default-arch=thumbv7m | FileCheck --check-prefix=ARMV7M %s
 
 X86_64: x86_64_function
 X86_64H: x86_64h_function
diff --git a/test/tools/llvm-symbolizer/pdb/Inputs/missing_pdb.exe b/test/tools/llvm-symbolizer/pdb/Inputs/missing_pdb.exe
new file mode 100644
index 0000000000000000000000000000000000000000..320e1f30e582c6f2ea99773990e51dbbff74e6a0
Binary files /dev/null and b/test/tools/llvm-symbolizer/pdb/Inputs/missing_pdb.exe differ
diff --git a/test/tools/llvm-symbolizer/pdb/Inputs/test.cpp b/test/tools/llvm-symbolizer/pdb/Inputs/test.cpp
index e317ed33589e868532f0070bad35bda5265771a3..bf97594fa4c802e6eacaf440b17b24ff8a26aed0 100644
--- a/test/tools/llvm-symbolizer/pdb/Inputs/test.cpp
+++ b/test/tools/llvm-symbolizer/pdb/Inputs/test.cpp
@@ -10,11 +10,15 @@ struct Foo {
 void foo() {
 }
 
+static void private_symbol() {
+}
+
 int main() {
   foo();
   
   NS::Foo f;
   f.bar();
+  private_symbol();
 }
 
 extern "C" {
diff --git a/test/tools/llvm-symbolizer/pdb/Inputs/test.exe b/test/tools/llvm-symbolizer/pdb/Inputs/test.exe
index a4f148e67c2fc4d7019438a9a80a4b5294ca998f..935f92cdb84f873f00851588ec3c1c05ece2247e 100644
Binary files a/test/tools/llvm-symbolizer/pdb/Inputs/test.exe and b/test/tools/llvm-symbolizer/pdb/Inputs/test.exe differ
diff --git a/test/tools/llvm-symbolizer/pdb/Inputs/test.pdb b/test/tools/llvm-symbolizer/pdb/Inputs/test.pdb
index d26d33a862d8f79c2143dff97d7178ef4ca57b6d..9d9086874e5f94e9b0202df916e044a1665c0a0a 100644
Binary files a/test/tools/llvm-symbolizer/pdb/Inputs/test.pdb and b/test/tools/llvm-symbolizer/pdb/Inputs/test.pdb differ
diff --git a/test/tools/llvm-symbolizer/pdb/missing_pdb.test b/test/tools/llvm-symbolizer/pdb/missing_pdb.test
new file mode 100644
index 0000000000000000000000000000000000000000..0478dfbc05ebc4cc90fe05916d1ab2f67a7ed8e2
--- /dev/null
+++ b/test/tools/llvm-symbolizer/pdb/missing_pdb.test
@@ -0,0 +1,17 @@
+RUN: grep '^ADDR:' %s | sed -s 's/ADDR: //' \
+RUN:    | llvm-symbolizer -obj="%p/Inputs/missing_pdb.exe" 2>%t.err \
+RUN:    | FileCheck %s
+RUN: FileCheck --check-prefix=ERROR %s < %t.err
+
+ADDR: 0x401000
+ADDR: 0x401001
+
+llvm-symbolizer should print one error and two unknown line info records.
+
+ERROR: LLVMSymbolizer: error reading file: PDB Error: Unable to load PDB.  Make sure the file exists and is readable.
+ERROR-NOT: error reading file
+
+CHECK: ??
+CHECK: ??:0:0
+CHECK: ??
+CHECK: ??:0:0
diff --git a/test/tools/llvm-symbolizer/pdb/pdb.test b/test/tools/llvm-symbolizer/pdb/pdb.test
index c84ad872bbe2c02a690bab2620c2c9004e76db75..a97b35eab9c405b8556663c2f2bd82c3ec416d28 100644
--- a/test/tools/llvm-symbolizer/pdb/pdb.test
+++ b/test/tools/llvm-symbolizer/pdb/pdb.test
@@ -1,6 +1,6 @@
 RUN: grep '^ADDR:' %s | sed -s 's/ADDR: //' \
 RUN: 	| llvm-symbolizer -obj="%p/Inputs/test.exe" \
-RUN:    | FileCheck %s --check-prefix=CHECK
+RUN:    | FileCheck %s
 RUN: grep '^ADDR:' %s | sed -s 's/ADDR: //' \
 RUN: 	| llvm-symbolizer -obj="%p/Inputs/test.exe" -demangle=false \
 RUN: 	| FileCheck %s --check-prefix=CHECK-NO-DEMANGLE
@@ -13,33 +13,37 @@ RUN: 	| %python -c 'import sys;print("\n".join([hex(int(x, 16) - 0x400000) for x
 RUN:	| llvm-symbolizer -obj="%p/Inputs/test.exe" -demangle=false --relative-address \
 RUN:    | FileCheck %s --check-prefix=CHECK-NO-DEMANGLE
 
-ADDR: 0x401000
-ADDR: 0x401010
-ADDR: 0x401070
-ADDR: 0x401030
-ADDR: 0x401040
-ADDR: 0x401050
-ADDR: 0x401060
-ADDR: 0x500000
+ADDR: 0x401380
+ADDR: 0x401390
+ADDR: 0x4013A0
+ADDR: 0x4013C0
+ADDR: 0x4013D0
+ADDR: 0x4013E0
+ADDR: 0x4013F0
+ADDR: 0x401420
 
 CHECK: foo(void)
 CHECK-NEXT: test.cpp:10
-CHECK: main
+CHECK: {{^private_symbol$}}
 CHECK-NEXT: test.cpp:13:0
-CHECK: NS::Foo::bar(void)
-CHECK-NEXT: test.cpp:6:0
+CHECK: {{^main}}
+CHECK-NEXT: test.cpp:16:0
 CHECK: {{^foo_cdecl$}}
 CHECK: {{^foo_stdcall$}}
 CHECK: {{^foo_fastcall$}}
 CHECK: {{^foo_vectorcall$}}
+CHECK: NS::Foo::bar(void)
+CHECK-NEXT: test.cpp:6:0
 
 CHECK-NO-DEMANGLE: ?foo@@YAXXZ
 CHECK-NO-DEMANGLE-NEXT: test.cpp:10
-CHECK-NO-DEMANGLE: _main
+CHECK-NO-DEMANGLE: private_symbol
 CHECK-NO-DEMANGLE-NEXT: test.cpp:13
-CHECK-NO-DEMANGLE: ?bar@Foo@NS@@QAEXXZ
-CHECK-NO-DEMANGLE-NEXT: test.cpp:6
+CHECK-NO-DEMANGLE: _main
+CHECK-NO-DEMANGLE-NEXT: test.cpp:16
 CHECK-NO-DEMANGLE: _foo_cdecl
 CHECK-NO-DEMANGLE: _foo_stdcall@0
 CHECK-NO-DEMANGLE: @foo_fastcall@0
 CHECK-NO-DEMANGLE: foo_vectorcall@@0
+CHECK-NO-DEMANGLE: ?bar@Foo@NS@@QAEXXZ
+CHECK-NO-DEMANGLE-NEXT: test.cpp:6
diff --git a/test/tools/llvm-symbolizer/print_context.c b/test/tools/llvm-symbolizer/print_context.c
index f1860e919881aa5e3b3ec8417924a9f7855547b6..3fd881c7359f4046070e6038484c011257341f04 100644
--- a/test/tools/llvm-symbolizer/print_context.c
+++ b/test/tools/llvm-symbolizer/print_context.c
@@ -1,6 +1,6 @@
 // REQUIRES: x86_64-linux
 // RUN: %host_cc -O0 -g %s -o %t 2>&1
-// RUN: %t 2>&1 | llvm-symbolizer -print-source-context-lines=5 -obj=%t | FileCheck %s --check-prefix=CHECK
+// RUN: %t 2>&1 | llvm-symbolizer -print-source-context-lines=5 -obj=%t | FileCheck %s
 
 #include 
 
diff --git a/test/tools/lto/hide-linkonce-odr.ll b/test/tools/lto/hide-linkonce-odr.ll
index a1de96e8b3330e366a172072f417c6b6804db96c..6fbd75764ce808ea94eeb2b461e86fe1cdcd9b2b 100644
--- a/test/tools/lto/hide-linkonce-odr.ll
+++ b/test/tools/lto/hide-linkonce-odr.ll
@@ -1,21 +1,28 @@
 ; RUN: llvm-as %s -o %t.o
-; RUN: %ld64 -lto_library %llvmshlibdir/libLTO.dylib -dylib -arch x86_64 -macosx_version_min 10.10.0 -lSystem -o %t.dylib %t.o -save-temps  -undefined dynamic_lookup
+; RUN: %ld64 -lto_library %llvmshlibdir/libLTO.dylib -dylib -arch x86_64 -macosx_version_min 10.10.0 -lSystem -o %t.dylib %t.o -save-temps  -undefined dynamic_lookup -exported_symbol _c -exported_symbol _b  -exported_symbol _GlobLinkonce
 
 ; RUN: llvm-dis %t.dylib.lto.opt.bc -o - | FileCheck --check-prefix=IR %s
-; check that @a is still a linkonce_odr definition
-; IR: define linkonce_odr void @a()
+; check that @a is no longer a linkonce_odr definition
+; IR-NOT: define linkonce_odr void @a()
+; check that @b is appended in llvm.used
+; IR: @llvm.compiler.used = appending global [2 x i8*] [i8* bitcast ([1 x i8*]* @GlobLinkonce to i8*), i8* bitcast (void ()* @b to i8*)], section "llvm.metadata"
 
 ; RUN: llvm-nm %t.dylib | FileCheck --check-prefix=NM %s
-; check that the linker can hide @a but not @b
+; check that the linker can hide @a but not @b, nor @GlobLinkonce
+; NM: 0000000000000f48 S _GlobLinkonce
 ; NM: 0000000000000f10 t _a
 ; NM: 0000000000000f20 T _b
 ; NM: 0000000000000f00 T _c
 
+
 target triple = "x86_64-apple-macosx10.10.0"
 
 declare void @external()
 
+@GlobLinkonce = linkonce_odr unnamed_addr constant [1 x i8*] [i8* null], align 8
+
 define linkonce_odr void @a() noinline {
+  %use_of_GlobLinkonce = load [1 x i8*], [1 x i8*] *@GlobLinkonce
   call void @external()
   ret void
 }
diff --git a/test/tools/sancov/Inputs/blacklist.txt b/test/tools/sancov/Inputs/fun_blacklist.txt
similarity index 100%
rename from test/tools/sancov/Inputs/blacklist.txt
rename to test/tools/sancov/Inputs/fun_blacklist.txt
diff --git a/test/tools/sancov/Inputs/src_blacklist.txt b/test/tools/sancov/Inputs/src_blacklist.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8f5cbc838f4aeec1149b3738ea3d6c1034f8c5f7
--- /dev/null
+++ b/test/tools/sancov/Inputs/src_blacklist.txt
@@ -0,0 +1,3 @@
+# this path looks like sancov/Inputs/../Inputs/ in the binary. 
+# Make sure it is filtered out correctly.
+src:*/sancov/Inputs/foo.cpp
diff --git a/test/tools/sancov/Inputs/test-linux_x86_64 b/test/tools/sancov/Inputs/test-linux_x86_64
index 2d141b693b2e8534288aa0e657df34ef409cabde..9ffac6f81b9d935988b2462b1edc86a94b5cbfc0 100755
Binary files a/test/tools/sancov/Inputs/test-linux_x86_64 and b/test/tools/sancov/Inputs/test-linux_x86_64 differ
diff --git a/test/tools/sancov/Inputs/test-linux_x86_64.0.sancov b/test/tools/sancov/Inputs/test-linux_x86_64.0.sancov
index e5ed81ed906e07fa1c4019b3ccfdac80155a9ced..4603e965b0b39c8156ae91b3b19b8b0cd47bc6e1 100644
Binary files a/test/tools/sancov/Inputs/test-linux_x86_64.0.sancov and b/test/tools/sancov/Inputs/test-linux_x86_64.0.sancov differ
diff --git a/test/tools/sancov/Inputs/test-linux_x86_64.1.sancov b/test/tools/sancov/Inputs/test-linux_x86_64.1.sancov
index a1c7f7b6cc38561aa1ca2c72908bcd4dd70ef101..2de5f51135fb2f2ea73d980db6f09ef7b6dbe3e3 100644
Binary files a/test/tools/sancov/Inputs/test-linux_x86_64.1.sancov and b/test/tools/sancov/Inputs/test-linux_x86_64.1.sancov differ
diff --git a/test/tools/sancov/Inputs/test.cpp b/test/tools/sancov/Inputs/test.cpp
index 5690409a27815e4cab942b4b966c2c13c7afca37..a14b4cb93b00999063506cc67c262b1ebbadf63c 100644
--- a/test/tools/sancov/Inputs/test.cpp
+++ b/test/tools/sancov/Inputs/test.cpp
@@ -1,7 +1,7 @@
 // compile & generate coverage data using:
-// clang++ -g -o test-linux_x86_64 -fsanitize=address -fsanitize-coverage=bb test.cpp foo.cpp
-// ASAN_OPTIONS="coverage=1" ./test-linux_x86_64 && mv test-linux_x86_64.*.sancov test-linux_x86_64.sancov
-// ASAN_OPTIONS="coverage=1" ./test-linux_x86_64 1 && mv test-linux_x86_64.*.sancov test-linux_x86_64-1.sancov
+// clang++ -g -o test-linux_x86_64 -fsanitize=address -fsanitize-coverage=bb test.cpp ../Inputs/foo.cpp
+// ASAN_OPTIONS="coverage=1" ./test-linux_x86_64 && mv test-linux_x86_64.??*.sancov test-linux_x86_64.0.sancov
+// ASAN_OPTIONS="coverage=1" ./test-linux_x86_64 1 && mv test-linux_x86_64.??*.sancov test-linux_x86_64.1.sancov
 
 #include 
 #include 
diff --git a/test/tools/sancov/blacklist.test b/test/tools/sancov/blacklist.test
index 2deb383a69a7d0bdbfb5e9c48f0cafe42dba14da..6af1799a481d9b76f2118e2fc402e9954778aa9a 100644
--- a/test/tools/sancov/blacklist.test
+++ b/test/tools/sancov/blacklist.test
@@ -1,5 +1,10 @@
 REQUIRES: x86_64-linux
-RUN: sancov -covered-functions -blacklist %p/Inputs/blacklist.txt %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s
+RUN: sancov -covered-functions -blacklist %p/Inputs/fun_blacklist.txt %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s
+RUN: sancov -covered-functions -blacklist %p/Inputs/src_blacklist.txt %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.1.sancov | FileCheck --check-prefix=CHECK1 %s
 
 CHECK-NOT: Inputs{{[/\\]}}test.cpp:12 bar(std::string)
 CHECK: Inputs{{[/\\]}}test.cpp:14 main
+
+CHECK1-NOT: foo
+CHECK1: Inputs{{[/\\]}}test.cpp:12 bar(std::string)
+CHECK1: Inputs{{[/\\]}}test.cpp:14 main
diff --git a/test/tools/sancov/lit.local.cfg b/test/tools/sancov/lit.local.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..456c28b3cef67ce52017349b9088d4482b5381b8
--- /dev/null
+++ b/test/tools/sancov/lit.local.cfg
@@ -0,0 +1,4 @@
+# These tests require a registered x86 backend.
+
+if not 'X86' in config.root.targets:
+    config.unsupported = True
diff --git a/test/tools/sancov/print.test b/test/tools/sancov/print.test
index f43733f155d96b865760056b447339641a967cc7..fe94216b051a2eb4dbd668ef23c8468e0505e6fe 100644
--- a/test/tools/sancov/print.test
+++ b/test/tools/sancov/print.test
@@ -1,11 +1,9 @@
 REQUIRES: x86_64-linux
 RUN: sancov -print %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s
 
-CHECK: 0x4dbe2b
-CHECK: 0x4dbf72
-CHECK: 0x4dbfec
-CHECK: 0x4dc033
-CHECK: 0x4dc06a
-CHECK: 0x4dc09d
-CHECK: 0x4dc0d0
+CHECK: 0x4e132b
+CHECK: 0x4e1472
+CHECK: 0x4e1520
+CHECK: 0x4e1553
+CHECK: 0x4e1586
 
diff --git a/test/tools/sancov/print_coverage_pcs.test b/test/tools/sancov/print_coverage_pcs.test
index 572bce807ba1f04140be21099ddb67eebc5548b6..2756eb03ba0d1bba01933c58e315ff65716fc93a 100644
--- a/test/tools/sancov/print_coverage_pcs.test
+++ b/test/tools/sancov/print_coverage_pcs.test
@@ -1,20 +1,13 @@
 REQUIRES: x86_64-linux
 RUN: sancov -print-coverage-pcs %p/Inputs/test-linux_x86_64 | FileCheck %s
 
-CHECK: 0x4cced1
-CHECK: 0x4ccf01
-CHECK: 0x4dbe2b
-CHECK: 0x4dbf72
-CHECK: 0x4dbfc2
-CHECK: 0x4dbfec
-CHECK: 0x4dc033
-CHECK: 0x4dc06a
-CHECK: 0x4dc09d
-CHECK: 0x4dc0d0
-CHECK: 0x4dc17f
-CHECK: 0x4dc1c6
-CHECK: 0x4dc20d
-CHECK: 0x4dc237
-CHECK: 0x4dc265
-CHECK: 0x4dc34c
+CHECK: 0x4e132b
+CHECK: 0x4e1472
+CHECK: 0x4e14c2
+CHECK: 0x4e1520
+CHECK: 0x4e1553
+CHECK: 0x4e1586
+CHECK: 0x4e1635
+CHECK: 0x4e1690
+CHECK: 0x4e178c
 
diff --git a/test/tools/sancov/stats.test b/test/tools/sancov/stats.test
index 2e1324dedcd0665acd09448125cd885f98c042b8..05e712b0bde92fbb4babc03b00a186b647a2c05e 100644
--- a/test/tools/sancov/stats.test
+++ b/test/tools/sancov/stats.test
@@ -1,8 +1,8 @@
 REQUIRES: x86_64-linux
 RUN: sancov -print-coverage-stats %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s
 
-CHECK: all-edges: 16
-CHECK: cov-edges: 7
+CHECK: all-edges: 9
+CHECK: cov-edges: 5
 CHECK: all-functions: 3
 CHECK: cov-functions: 2
 
diff --git a/test/tools/sanstats/elf.test b/test/tools/sanstats/elf.test
index 0b6292f82f8a46a0a684f5ccf21aa8b7c7f64f49..91651bc3f9d1bfe804f0bff2ec615f470d6bb1bc 100644
--- a/test/tools/sanstats/elf.test
+++ b/test/tools/sanstats/elf.test
@@ -1,5 +1,5 @@
-# RUN: yaml2obj -format=elf %s > %t1.o
-# RUN: yaml2obj -format=elf %s > %t2.o
+# RUN: yaml2obj %s > %t1.o
+# RUN: yaml2obj %s > %t2.o
 
 # RUN: echo -ne "\x04" > %t.stats
 
@@ -39,7 +39,7 @@
 # CHECK: /tmp{{[/\\]}}f.c:2 f2 cfi-icall 12
 # CHECK: /tmp{{[/\\]}}f.c:1 f1  14
 
----
+--- !ELF
 FileHeader:      
   Class:           ELFCLASS64
   Data:            ELFDATA2LSB
diff --git a/test/tools/yaml2obj/missing_document_tag.yaml b/test/tools/yaml2obj/missing_document_tag.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3cec172d580136eea3043bc2ab0372e8020e9c71
--- /dev/null
+++ b/test/tools/yaml2obj/missing_document_tag.yaml
@@ -0,0 +1,6 @@
+# RUN: not yaml2obj %s 2>&1 | FileCheck %s
+
+---
+DummyData:
+  foo:           0
+...
diff --git a/test/tools/yaml2obj/unsupported_document_tag.yaml b/test/tools/yaml2obj/unsupported_document_tag.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e73d450a9bb817a6deafbe65afef0360d1fdf3ab
--- /dev/null
+++ b/test/tools/yaml2obj/unsupported_document_tag.yaml
@@ -0,0 +1,8 @@
+# RUN: not yaml2obj %s 2>&1 | FileCheck %s
+
+--- !unsupported-tag
+DummyData:
+  foo:           0
+...
+
+#check error: YAML Object File unsupported document type tag '!unsupported-tag'!
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 8ca7bae8971f355fea767dfead19e48799ee5eaa..b654b8c5cb8e0d1f24d4acc8b8faa9d48422733c 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -37,6 +37,7 @@ add_llvm_tool_subdirectory(lto)
 add_llvm_tool_subdirectory(gold)
 add_llvm_tool_subdirectory(llvm-ar)
 add_llvm_tool_subdirectory(llvm-config)
+add_llvm_tool_subdirectory(llvm-lto)
 add_llvm_tool_subdirectory(llvm-profdata)
 
 # Projects supported via LLVM_EXTERNAL_*_SOURCE_DIR need to be explicitly
@@ -50,4 +51,9 @@ add_llvm_external_project(lldb)
 # file as external projects.
 add_llvm_implicit_projects()
 
+# Add subprojects specified using LLVM_EXTERNAL_PROJECTS
+foreach(p ${LLVM_EXTERNAL_PROJECTS})
+  add_llvm_external_project(${p})
+endforeach(p)
+
 set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE)
diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h
index 20efff3fda5f7e7e9599ca25af901010b8938232..52ec2c00564969811f0f3e7fa0b3e607a5c7d8e1 100644
--- a/tools/bugpoint/BugDriver.h
+++ b/tools/bugpoint/BugDriver.h
@@ -76,7 +76,7 @@ public:
   // command line arguments into instance variables of BugDriver.
   //
   bool addSources(const std::vector &FileNames);
-  void addPass(std::string p) { PassesToRun.push_back(p); }
+  void addPass(std::string p) { PassesToRun.push_back(std::move(p)); }
   void setPassesToRun(const std::vector &PTR) {
     PassesToRun = PTR;
   }
@@ -130,12 +130,6 @@ public:
   ///
   bool isExecutingJIT();
 
-  /// runPasses - Run all of the passes in the "PassesToRun" list, discard the
-  /// output, and return true if any of the passes crashed.
-  bool runPasses(Module *M) const {
-    return runPasses(M, PassesToRun);
-  }
-
   Module *getProgram() const { return Program; }
 
   /// swapProgramIn - Set the current module to the specified module, returning
@@ -183,7 +177,7 @@ public:
   /// Error.
   ///
   std::string executeProgramSafely(const Module *Program,
-                                   std::string OutputFile,
+                                   const std::string &OutputFile,
                                    std::string *Error) const;
 
   /// createReferenceFile - calls compileProgram and then records the output
@@ -243,12 +237,8 @@ public:
 
   /// Carefully run the specified set of pass on the specified/ module,
   /// returning the transformed module on success, or a null pointer on failure.
-  /// If AutoDebugCrashes is set to true, then bugpoint will automatically
-  /// attempt to track down a crashing pass if one exists, and this method will
-  /// never return null.
   std::unique_ptr runPassesOn(Module *M,
                                       const std::vector &Passes,
-                                      bool AutoDebugCrashes = false,
                                       unsigned NumExtraArgs = 0,
                                       const char *const *ExtraArgs = nullptr);
 
@@ -266,6 +256,16 @@ public:
                  std::string &OutputFilename, bool DeleteOutput = false,
                  bool Quiet = false, unsigned NumExtraArgs = 0,
                  const char * const *ExtraArgs = nullptr) const;
+
+  /// runPasses - Just like the method above, but this just returns true or
+  /// false indicating whether or not the optimizer crashed on the specified
+  /// input (true = crashed).  Does not produce any output.
+  ///
+  bool runPasses(Module *M,
+                 const std::vector &PassesToRun) const {
+    std::string Filename;
+    return runPasses(M, PassesToRun, Filename, true);
+  }
                  
   /// runManyPasses - Take the specified pass list and create different 
   /// combinations of passes to compile the program with. Compile the program with
@@ -285,17 +285,6 @@ public:
                           const Module *M) const;
 
 private:
-  /// runPasses - Just like the method above, but this just returns true or
-  /// false indicating whether or not the optimizer crashed on the specified
-  /// input (true = crashed).
-  ///
-  bool runPasses(Module *M,
-                 const std::vector &PassesToRun,
-                 bool DeleteOutput = true) const {
-    std::string Filename;
-    return runPasses(M, PassesToRun, Filename, DeleteOutput);
-  }
-
   /// initializeExecutionEnvironment - This method is used to set up the
   /// environment for executing LLVM programs.
   ///
diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp
index 493bda64f193254da7b58a09ba3331dc4f35d536..07fe0d7acbdeb3a740661842cc3465a0ed27abfe 100644
--- a/tools/bugpoint/CrashDebugger.cpp
+++ b/tools/bugpoint/CrashDebugger.cpp
@@ -164,6 +164,7 @@ ReduceCrashingGlobalVariables::TestGlobalVariables(
     if (I.hasInitializer() && !GVSet.count(&I)) {
       DeleteGlobalInitializer(&I);
       I.setLinkage(GlobalValue::ExternalLinkage);
+      I.setComdat(nullptr);
     }
 
   // Try running the hacked up program...
@@ -264,8 +265,8 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector &Funcs) {
     std::vector ToRemove;
     // First, remove aliases to functions we're about to purge.
     for (GlobalAlias &Alias : M->aliases()) {
-      Constant *Root = Alias.getAliasee()->stripPointerCasts();
-      Function *F = dyn_cast(Root);
+      GlobalObject *Root = Alias.getBaseObject();
+      Function *F = dyn_cast_or_null(Root);
       if (F) {
         if (Functions.count(F))
           // We're keeping this function.
@@ -373,9 +374,9 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector &BBs) {
           (*SI)->removePredecessor(&*BB);
 
         TerminatorInst *BBTerm = BB->getTerminator();
-        if (BBTerm->isEHPad())
+        if (BBTerm->isEHPad() || BBTerm->getType()->isTokenTy())
           continue;
-        if (!BBTerm->getType()->isVoidTy() && !BBTerm->getType()->isTokenTy())
+        if (!BBTerm->getType()->isVoidTy())
           BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType()));
 
         // Replace the old terminator instruction.
@@ -476,8 +477,8 @@ bool ReduceCrashingInstructions::TestInsts(std::vector
       for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) {
         Instruction *Inst = &*I++;
         if (!Instructions.count(Inst) && !isa(Inst) &&
-            !Inst->isEHPad()) {
-          if (!Inst->getType()->isVoidTy() && !Inst->getType()->isTokenTy())
+            !Inst->isEHPad() && !Inst->getType()->isTokenTy()) {
+          if (!Inst->getType()->isVoidTy())
             Inst->replaceAllUsesWith(UndefValue::get(Inst->getType()));
           Inst->eraseFromParent();
         }
@@ -639,7 +640,7 @@ bool ReduceCrashingNamedMDOps::TestNamedMDOps(
     // module, and that they don't include any deleted blocks.
     NamedMDOps.clear();
     for (const MDNode *Node : OldMDNodeOps)
-      NamedMDOps.push_back(cast(VMap.MD()[Node].get()));
+      NamedMDOps.push_back(cast(*VMap.getMappedMD(Node)));
 
     BD.setNewProgram(M); // It crashed, keep the trimmed version...
     return true;
@@ -648,16 +649,10 @@ bool ReduceCrashingNamedMDOps::TestNamedMDOps(
   return false;
 }
 
-/// DebugACrash - Given a predicate that determines whether a component crashes
-/// on a program, try to destructively reduce the program while still keeping
-/// the predicate true.
-static bool DebugACrash(BugDriver &BD,
-                        bool (*TestFn)(const BugDriver &, Module *),
-                        std::string &Error) {
-  // See if we can get away with nuking some of the global variable initializers
-  // in the program...
-  if (!NoGlobalRM &&
-      BD.getProgram()->global_begin() != BD.getProgram()->global_end()) {
+static void ReduceGlobalInitializers(BugDriver &BD,
+                                     bool (*TestFn)(const BugDriver &, Module *),
+                                     std::string &Error) {
+  if (BD.getProgram()->global_begin() != BD.getProgram()->global_end()) {
     // Now try to reduce the number of global variable initializers in the
     // module to something small.
     Module *M = CloneModule(BD.getProgram()).release();
@@ -668,6 +663,7 @@ static bool DebugACrash(BugDriver &BD,
       if (I->hasInitializer()) {
         DeleteGlobalInitializer(&*I);
         I->setLinkage(GlobalValue::ExternalLinkage);
+        I->setComdat(nullptr);
         DeletedInit = true;
       }
 
@@ -697,8 +693,7 @@ static bool DebugACrash(BugDriver &BD,
 
           unsigned OldSize = GVs.size();
           ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs, Error);
-          if (!Error.empty())
-            return true;
+          assert(!Error.empty());
 
           if (GVs.size() < OldSize)
             BD.EmitProgressBitcode(BD.getProgram(), "reduced-global-variables");
@@ -706,40 +701,11 @@ static bool DebugACrash(BugDriver &BD,
       }
     }
   }
+}
 
-  // Now try to reduce the number of functions in the module to something small.
-  std::vector Functions;
-  for (Function &F : *BD.getProgram())
-    if (!F.isDeclaration())
-      Functions.push_back(&F);
-
-  if (Functions.size() > 1 && !BugpointIsInterrupted) {
-    outs() << "\n*** Attempting to reduce the number of functions "
-      "in the testcase\n";
-
-    unsigned OldSize = Functions.size();
-    ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error);
-
-    if (Functions.size() < OldSize)
-      BD.EmitProgressBitcode(BD.getProgram(), "reduced-function");
-  }
-
-  // Attempt to delete entire basic blocks at a time to speed up
-  // convergence... this actually works by setting the terminator of the blocks
-  // to a return instruction then running simplifycfg, which can potentially
-  // shrinks the code dramatically quickly
-  //
-  if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
-    std::vector Blocks;
-    for (Function &F : *BD.getProgram())
-      for (BasicBlock &BB : F)
-        Blocks.push_back(&BB);
-    unsigned OldSize = Blocks.size();
-    ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error);
-    if (Blocks.size() < OldSize)
-      BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks");
-  }
-
+static void ReduceInsts(BugDriver &BD,
+                        bool (*TestFn)(const BugDriver &, Module *),
+                        std::string &Error) {
   // Attempt to delete instructions using bisection. This should help out nasty
   // cases with large basic blocks where the problem is at one end.
   if (!BugpointIsInterrupted) {
@@ -753,11 +719,10 @@ static bool DebugACrash(BugDriver &BD,
     ReduceCrashingInstructions(BD, TestFn).reduceList(Insts, Error);
   }
 
-  // FIXME: This should use the list reducer to converge faster by deleting
-  // larger chunks of instructions at a time!
   unsigned Simplification = 2;
   do {
-    if (BugpointIsInterrupted) break;
+    if (BugpointIsInterrupted)
+      return;
     --Simplification;
     outs() << "\n*** Attempting to reduce testcase by deleting instruc"
            << "tions: Simplification Level #" << Simplification << '\n';
@@ -786,7 +751,8 @@ static bool DebugACrash(BugDriver &BD,
             if (InstructionsToSkipBeforeDeleting) {
               --InstructionsToSkipBeforeDeleting;
             } else {
-              if (BugpointIsInterrupted) goto ExitLoops;
+              if (BugpointIsInterrupted)
+                return;
 
               if (I->isEHPad() || I->getType()->isTokenTy())
                 continue;
@@ -812,10 +778,60 @@ static bool DebugACrash(BugDriver &BD,
     }
 
   } while (Simplification);
+  BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions");
+}
 
-  if (!NoNamedMDRM) {
-    BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions");
 
+/// DebugACrash - Given a predicate that determines whether a component crashes
+/// on a program, try to destructively reduce the program while still keeping
+/// the predicate true.
+static bool DebugACrash(BugDriver &BD,
+                        bool (*TestFn)(const BugDriver &, Module *),
+                        std::string &Error) {
+  // See if we can get away with nuking some of the global variable initializers
+  // in the program...
+  if (!NoGlobalRM)
+    ReduceGlobalInitializers(BD, TestFn, Error);
+
+  // Now try to reduce the number of functions in the module to something small.
+  std::vector Functions;
+  for (Function &F : *BD.getProgram())
+    if (!F.isDeclaration())
+      Functions.push_back(&F);
+
+  if (Functions.size() > 1 && !BugpointIsInterrupted) {
+    outs() << "\n*** Attempting to reduce the number of functions "
+      "in the testcase\n";
+
+    unsigned OldSize = Functions.size();
+    ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error);
+
+    if (Functions.size() < OldSize)
+      BD.EmitProgressBitcode(BD.getProgram(), "reduced-function");
+  }
+
+  // Attempt to delete entire basic blocks at a time to speed up
+  // convergence... this actually works by setting the terminator of the blocks
+  // to a return instruction then running simplifycfg, which can potentially
+  // shrinks the code dramatically quickly
+  //
+  if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
+    std::vector Blocks;
+    for (Function &F : *BD.getProgram())
+      for (BasicBlock &BB : F)
+        Blocks.push_back(&BB);
+    unsigned OldSize = Blocks.size();
+    ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error);
+    if (Blocks.size() < OldSize)
+      BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks");
+  }
+
+  // Attempt to delete instructions using bisection. This should help out nasty
+  // cases with large basic blocks where the problem is at one end.
+  if (!BugpointIsInterrupted)
+    ReduceInsts(BD, TestFn, Error);
+
+  if (!NoNamedMDRM) {
     if (!BugpointIsInterrupted) {
       // Try to reduce the amount of global metadata (particularly debug info),
       // by dropping global named metadata that anchors them
@@ -835,10 +851,9 @@ static bool DebugACrash(BugDriver &BD,
           NamedMDOps.push_back(op);
       ReduceCrashingNamedMDOps(BD, TestFn).reduceList(NamedMDOps, Error);
     }
+    BD.EmitProgressBitcode(BD.getProgram(), "reduced-named-md");
   }
 
-ExitLoops:
-
   // Try to clean up the testcase by running funcresolve and globaldce...
   if (!BugpointIsInterrupted) {
     outs() << "\n*** Attempting to perform final cleanups: ";
@@ -859,7 +874,7 @@ ExitLoops:
 }
 
 static bool TestForOptimizerCrash(const BugDriver &BD, Module *M) {
-  return BD.runPasses(M);
+  return BD.runPasses(M, BD.getPassesToRun());
 }
 
 /// debugOptimizerCrash - This method is called when some pass crashes on input.
diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp
index 41b8ccc18e87136dfc1b2000990de0e385fd1148..ab9c05fa924af3d6ac5ad7f449f565c6d2116a7e 100644
--- a/tools/bugpoint/ExecutionDriver.cpp
+++ b/tools/bugpoint/ExecutionDriver.cpp
@@ -384,7 +384,7 @@ std::string BugDriver::executeProgram(const Module *Program,
 /// backend, if reference output is not provided.
 ///
 std::string BugDriver::executeProgramSafely(const Module *Program,
-                                            std::string OutputFile,
+                                            const std::string &OutputFile,
                                             std::string *Error) const {
   return executeProgram(Program, OutputFile, "", "", SafeInterpreter, Error);
 }
diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp
index fe0ab69dc162d8f1ebfb287eb1ca1f3dadc6fc52..de596a57d83cd13f615a96ab6bd1e98d29ff010c 100644
--- a/tools/bugpoint/ExtractFunction.cpp
+++ b/tools/bugpoint/ExtractFunction.cpp
@@ -215,6 +215,8 @@ void llvm::DeleteGlobalInitializer(GlobalVariable *GV) {
 //
 void llvm::DeleteFunctionBody(Function *F) {
   eliminateAliases(F);
+  // Function declarations can't have comdats.
+  F->setComdat(nullptr);
 
   // delete the body of the function...
   F->deleteBody();
@@ -409,7 +411,7 @@ BugDriver::extractMappedBlocksFromModule(const std::vector &BBs,
 
   std::vector PI;
   PI.push_back("extract-blocks");
-  std::unique_ptr Ret = runPassesOn(M, PI, false, 1, &ExtraArg);
+  std::unique_ptr Ret = runPassesOn(M, PI, 1, &ExtraArg);
 
   sys::fs::remove(Filename.c_str());
 
diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp
index 863aaa24780afef1904ceb24235f57746ccc849b..40955ed3caa9335c84a75bb42f8d274b8e440d73 100644
--- a/tools/bugpoint/Miscompilation.cpp
+++ b/tools/bugpoint/Miscompilation.cpp
@@ -697,8 +697,14 @@ static bool TestOptimizer(BugDriver &BD, std::unique_ptr Test,
   // of the functions being tested.
   outs() << "  Optimizing functions being tested: ";
   std::unique_ptr Optimized =
-      BD.runPassesOn(Test.get(), BD.getPassesToRun(),
-                     /*AutoDebugCrashes*/ true);
+      BD.runPassesOn(Test.get(), BD.getPassesToRun());
+  if (!Optimized) {
+    errs() << " Error running this sequence of passes"
+           << " on the input program!\n";
+    delete BD.swapProgramIn(Test.get());
+    BD.EmitProgressBitcode(Test.get(), "pass-error",  false);
+    return BD.debugOptimizerCrash();
+  }
   outs() << "done.\n";
 
   outs() << "  Checking to see if the merged program executes correctly: ";
diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp
index 344e7b588fb864a9df18211128aaddcf24828a1d..2cc2f4471a581b35f3b3c561223a1b3f4be8b4f8 100644
--- a/tools/bugpoint/OptimizerDriver.cpp
+++ b/tools/bugpoint/OptimizerDriver.cpp
@@ -267,18 +267,11 @@ bool BugDriver::runPasses(Module *Program,
 
 std::unique_ptr
 BugDriver::runPassesOn(Module *M, const std::vector &Passes,
-                       bool AutoDebugCrashes, unsigned NumExtraArgs,
+                       unsigned NumExtraArgs,
                        const char *const *ExtraArgs) {
   std::string BitcodeResult;
   if (runPasses(M, Passes, BitcodeResult, false/*delete*/, true/*quiet*/,
                 NumExtraArgs, ExtraArgs)) {
-    if (AutoDebugCrashes) {
-      errs() << " Error running this sequence of passes"
-             << " on the input program!\n";
-      delete swapProgramIn(M);
-      EmitProgressBitcode(M, "pass-error",  false);
-      exit(debugOptimizerCrash());
-    }
     return nullptr;
   }
 
diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp
index 2ccd649051289b65075f11fa1af97a6bbc9fe171..4af4b10c4d78a22c90085ccfaf3e5c57329ecb29 100644
--- a/tools/bugpoint/ToolRunner.cpp
+++ b/tools/bugpoint/ToolRunner.cpp
@@ -21,6 +21,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include 
 #include 
+#include 
 using namespace llvm;
 
 #define DEBUG_TYPE "toolrunner"
@@ -272,9 +273,9 @@ namespace {
     std::string CompilerCommand;
     std::vector CompilerArgs;
   public:
-    CustomCompiler(
-      const std::string &CompilerCmd, std::vector CompArgs) :
-      CompilerCommand(CompilerCmd), CompilerArgs(CompArgs) {}
+    CustomCompiler(const std::string &CompilerCmd,
+                   std::vector CompArgs)
+        : CompilerCommand(CompilerCmd), CompilerArgs(std::move(CompArgs)) {}
 
     void compileProgram(const std::string &Bitcode,
                         std::string *Error,
@@ -333,9 +334,9 @@ namespace {
     std::string ExecutionCommand;
     std::vector ExecutorArgs;
   public:
-    CustomExecutor(
-      const std::string &ExecutionCmd, std::vector ExecArgs) :
-      ExecutionCommand(ExecutionCmd), ExecutorArgs(ExecArgs) {}
+    CustomExecutor(const std::string &ExecutionCmd,
+                   std::vector ExecArgs)
+        : ExecutionCommand(ExecutionCmd), ExecutorArgs(std::move(ExecArgs)) {}
 
     int ExecuteProgram(const std::string &Bitcode,
                        const std::vector &Args,
diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp
index 48f30e6709f8089002fddcea620b8c7d34a1041d..28565f1daac335ce7a303db6a3f4a9071345be21 100644
--- a/tools/bugpoint/bugpoint.cpp
+++ b/tools/bugpoint/bugpoint.cpp
@@ -113,7 +113,7 @@ void initializePollyPasses(llvm::PassRegistry &Registry);
 
 int main(int argc, char **argv) {
 #ifndef DEBUG_BUGPOINT
-  llvm::sys::PrintStackTraceOnErrorSignal();
+  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
   llvm::PrettyStackTraceProgram X(argc, argv);
   llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
 #endif
@@ -143,7 +143,7 @@ int main(int argc, char **argv) {
   sys::SetInterruptFunction(BugpointInterruptFunction);
 #endif
 
-  LLVMContext& Context = getGlobalContext();
+  LLVMContext Context;
   // If we have an override, set it and then track the triple we want Modules
   // to use.
   if (!OverrideTriple.empty()) {
diff --git a/tools/dsymutil/BinaryHolder.cpp b/tools/dsymutil/BinaryHolder.cpp
index 4c2c1d195c3ca5a55a33648b4c21dbdba28a30fd..e45f7fefe0844006a8036522a8941db8356fafba 100644
--- a/tools/dsymutil/BinaryHolder.cpp
+++ b/tools/dsymutil/BinaryHolder.cpp
@@ -19,15 +19,6 @@
 namespace llvm {
 namespace dsymutil {
 
-Triple BinaryHolder::getTriple(const object::MachOObjectFile &Obj) {
-  // If a ThumbTriple is returned, use it instead of the standard
-  // one. This is because the thumb triple always allows to create a
-  // target, whereas the non-thumb one might not.
-  Triple ThumbTriple;
-  Triple T = Obj.getArch(nullptr, &ThumbTriple);
-  return ThumbTriple.getArch() ? ThumbTriple : T;
-}
-
 static std::vector
 getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
                          object::MachOUniversalBinary &Fat) {
@@ -82,13 +73,15 @@ BinaryHolder::GetMemoryBuffersForFile(StringRef Filename,
 
   auto ErrOrFat = object::MachOUniversalBinary::create(
       CurrentMemoryBuffer->getMemBufferRef());
-  if (ErrOrFat.getError()) {
+  if (!ErrOrFat) {
+    consumeError(ErrOrFat.takeError());
     // Not a fat binary must be a standard one. Return a one element vector.
     return std::vector{CurrentMemoryBuffer->getMemBufferRef()};
   }
 
   CurrentFatBinary = std::move(*ErrOrFat);
-  return getMachOFatMemoryBuffers(Filename, *CurrentMemoryBuffer,
+  CurrentFatBinaryName = Filename;
+  return getMachOFatMemoryBuffers(CurrentFatBinaryName, *CurrentMemoryBuffer,
                                   *CurrentFatBinary);
 }
 
@@ -109,10 +102,8 @@ BinaryHolder::GetArchiveMemberBuffers(StringRef Filename,
   Buffers.reserve(CurrentArchives.size());
 
   for (const auto &CurrentArchive : CurrentArchives) {
-    for (auto ChildOrErr : CurrentArchive->children()) {
-      if (std::error_code Err = ChildOrErr.getError())
-        return Err;
-      const auto &Child = *ChildOrErr;
+    Error Err;
+    for (auto Child : CurrentArchive->children(Err)) {
       if (auto NameOrErr = Child.getName()) {
         if (*NameOrErr == Filename) {
           if (Timestamp != sys::TimeValue::PosixZeroTime() &&
@@ -130,6 +121,8 @@ BinaryHolder::GetArchiveMemberBuffers(StringRef Filename,
         }
       }
     }
+    if (Err)
+      return errorToErrorCode(std::move(Err));
   }
 
   if (Buffers.empty())
@@ -153,19 +146,21 @@ BinaryHolder::MapArchiveAndGetMemberBuffers(StringRef Filename,
   std::vector ArchiveBuffers;
   auto ErrOrFat = object::MachOUniversalBinary::create(
       CurrentMemoryBuffer->getMemBufferRef());
-  if (ErrOrFat.getError()) {
+  if (!ErrOrFat) {
+    consumeError(ErrOrFat.takeError());
     // Not a fat binary must be a standard one.
     ArchiveBuffers.push_back(CurrentMemoryBuffer->getMemBufferRef());
   } else {
     CurrentFatBinary = std::move(*ErrOrFat);
+    CurrentFatBinaryName = ArchiveFilename;
     ArchiveBuffers = getMachOFatMemoryBuffers(
-        ArchiveFilename, *CurrentMemoryBuffer, *CurrentFatBinary);
+        CurrentFatBinaryName, *CurrentMemoryBuffer, *CurrentFatBinary);
   }
 
   for (auto MemRef : ArchiveBuffers) {
     auto ErrOrArchive = object::Archive::create(MemRef);
-    if (auto Err = ErrOrArchive.getError())
-      return Err;
+    if (!ErrOrArchive)
+      return errorToErrorCode(ErrOrArchive.takeError());
     CurrentArchives.push_back(std::move(*ErrOrArchive));
   }
   return GetArchiveMemberBuffers(Filename, Timestamp);
@@ -175,7 +170,7 @@ ErrorOr
 BinaryHolder::getObjfileForArch(const Triple &T) {
   for (const auto &Obj : CurrentObjectFiles) {
     if (const auto *MachO = dyn_cast(Obj.get())) {
-      if (getTriple(*MachO).str() == T.str())
+      if (MachO->getArchTriple().str() == T.str())
         return *MachO;
     } else if (Obj->getArch() == T.getArch())
       return *Obj;
@@ -196,8 +191,8 @@ BinaryHolder::GetObjectFiles(StringRef Filename, sys::TimeValue Timestamp) {
   CurrentObjectFiles.clear();
   for (auto MemBuf : *ErrOrMemBufferRefs) {
     auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemBuf);
-    if (auto Err = ErrOrObjectFile.getError())
-      return Err;
+    if (!ErrOrObjectFile)
+      return errorToErrorCode(ErrOrObjectFile.takeError());
 
     Objects.push_back(ErrOrObjectFile->get());
     CurrentObjectFiles.push_back(std::move(*ErrOrObjectFile));
diff --git a/tools/dsymutil/BinaryHolder.h b/tools/dsymutil/BinaryHolder.h
index 9d7b4bd8787f3cb126852e836c5ef94027d51003..97508b9fb09da831531bf102be66e604e0446207 100644
--- a/tools/dsymutil/BinaryHolder.h
+++ b/tools/dsymutil/BinaryHolder.h
@@ -42,6 +42,7 @@ class BinaryHolder {
   std::unique_ptr CurrentMemoryBuffer;
   std::vector> CurrentObjectFiles;
   std::unique_ptr CurrentFatBinary;
+  std::string CurrentFatBinaryName;
   bool Verbose;
 
   /// Get the MemoryBufferRefs for the file specification in \p
@@ -128,8 +129,6 @@ public:
       return Err;
     return cast(*ErrOrObj);
   }
-
-  static Triple getTriple(const object::MachOObjectFile &Obj);
 };
 }
 }
diff --git a/tools/dsymutil/DebugMap.cpp b/tools/dsymutil/DebugMap.cpp
index 114e22c07453ce254edb3062815ae8444fb86819..5130cd62ed2fcf79af4300235f2e04f62b4b85d4 100644
--- a/tools/dsymutil/DebugMap.cpp
+++ b/tools/dsymutil/DebugMap.cpp
@@ -228,10 +228,14 @@ MappingTraits::YamlDMO::denormalize(IO &IO) {
     // look them up here and rewrite them.
     for (const auto &Sym : ErrOrObjectFile->symbols()) {
       uint64_t Address = Sym.getValue();
-      ErrorOr Name = Sym.getName();
+      Expected Name = Sym.getName();
       if (!Name ||
-          (Sym.getFlags() & (SymbolRef::SF_Absolute | SymbolRef::SF_Common)))
+          (Sym.getFlags() & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) {
+        // TODO: Actually report errors helpfully.
+        if (!Name)
+          consumeError(Name.takeError());
         continue;
+      }
       SymbolAddresses[*Name] = Address;
     }
   }
diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp
index d08f30dadab9e6c604d137a4cb9ea3bd541d7888..bea30ded591fc55e304824d8d7a87be043c60eaa 100644
--- a/tools/dsymutil/DwarfLinker.cpp
+++ b/tools/dsymutil/DwarfLinker.cpp
@@ -531,7 +531,7 @@ public:
   /// original \p Entries.
   void emitRangesEntries(
       int64_t UnitPcOffset, uint64_t OrigLowPc,
-      FunctionIntervals::const_iterator FuncRange,
+      const FunctionIntervals::const_iterator &FuncRange,
       const std::vector &Entries,
       unsigned AddressSize);
 
@@ -595,8 +595,7 @@ bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) {
 
   MOFI.reset(new MCObjectFileInfo);
   MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get()));
-  MOFI->InitMCObjectFileInfo(TheTriple, Reloc::Default, CodeModel::Default,
-                             *MC);
+  MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, CodeModel::Default, *MC);
 
   MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, "");
   if (!MAB)
@@ -630,7 +629,8 @@ bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) {
     return error("no object streamer for target " + TripleName, Context);
 
   // Finally create the AsmPrinter we'll use to emit the DIEs.
-  TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions()));
+  TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
+                                          None));
   if (!TM)
     return error("no target machine for target " + TripleName, Context);
 
@@ -715,7 +715,7 @@ void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
 /// sized addresses describing the ranges.
 void DwarfStreamer::emitRangesEntries(
     int64_t UnitPcOffset, uint64_t OrigLowPc,
-    FunctionIntervals::const_iterator FuncRange,
+    const FunctionIntervals::const_iterator &FuncRange,
     const std::vector &Entries,
     unsigned AddressSize) {
   MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
@@ -792,7 +792,7 @@ void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit,
     Asm->EmitInt8(AddressSize);                // Address size
     Asm->EmitInt8(0);                          // Segment size
 
-    Asm->OutStreamer->EmitFill(Padding, 0x0);
+    Asm->OutStreamer->emitFill(Padding, 0x0);
 
     for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End;
          ++Range) {
@@ -1416,7 +1416,7 @@ private:
   /// \defgroup Helpers Various helper methods.
   ///
   /// @{
-  bool createStreamer(Triple TheTriple, StringRef OutputFilename);
+  bool createStreamer(const Triple &TheTriple, StringRef OutputFilename);
 
   /// \brief Attempt to load a debug object from disk.
   ErrorOr loadObject(BinaryHolder &BinaryHolder,
@@ -1744,7 +1744,8 @@ void DwarfLinker::reportWarning(const Twine &Warning, const DWARFUnit *Unit,
             6 /* Indent */);
 }
 
-bool DwarfLinker::createStreamer(Triple TheTriple, StringRef OutputFilename) {
+bool DwarfLinker::createStreamer(const Triple &TheTriple,
+                                 StringRef OutputFilename) {
   if (Options.NoOutput)
     return true;
 
@@ -1951,8 +1952,9 @@ findValidRelocsMachO(const object::SectionRef &Section,
 
     auto Sym = Reloc.getSymbol();
     if (Sym != Obj.symbol_end()) {
-      ErrorOr SymbolName = Sym->getName();
+      Expected SymbolName = Sym->getName();
       if (!SymbolName) {
+        consumeError(SymbolName.takeError());
         Linker.reportWarning("error getting relocation symbol name.");
         continue;
       }
@@ -3248,7 +3250,10 @@ bool DwarfLinker::registerModuleReference(
 
   auto Cached = ClangModules.find(PCMfile);
   if (Cached != ClangModules.end()) {
-    if (Cached->second != DwoId)
+    // FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is
+    // fixed in clang, only warn about DWO_id mismatches in verbose mode.
+    // ASTFileSignatures will change randomly when a module is rebuilt.
+    if (Options.Verbose && (Cached->second != DwoId))
       reportWarning(Twine("hash mismatch: this object file was built against a "
                           "different version of the module ") + PCMfile);
     if (Options.Verbose)
@@ -3298,7 +3303,6 @@ void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
     bool isClangModule = sys::path::extension(Filename).equals(".pcm");
     bool isArchive = ObjFile.endswith(")");
     if (isClangModule) {
-      sys::path::remove_filename(Path);
       StringRef ModuleCacheDir = sys::path::parent_path(Path);
       if (sys::fs::exists(ModuleCacheDir)) {
         // If the module's parent directory exists, we assume that the module
@@ -3316,8 +3320,11 @@ void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
         // was built on a different machine. We don't want to discourage module
         // debugging for convenience libraries within a project though.
         if (!ArchiveHintDisplayed) {
-          errs() << "note: Module debugging should be disabled when shipping "
-                    "static libraries.\n";
+          errs() << "note: Linking a static library that was built with "
+                    "-gmodules, but the module cache was not found.  "
+                    "Redistributable static libraries should never be built "
+                    "with module debugging enabled.  The debug experience will "
+                    "be degraded due to incomplete debug information.\n";
           ArchiveHintDisplayed = true;
         }
       }
@@ -3339,10 +3346,18 @@ void DwarfLinker::loadClangModule(StringRef Filename, StringRef ModulePath,
                << " 1 compile unit.\n";
         exitDsymutil(1);
       }
-      if (getDwoId(*CUDie, *CU) != DwoId)
-        reportWarning(
-            Twine("hash mismatch: this object file was built against a "
-                  "different version of the module ") + Filename);
+      // FIXME: Until PR27449 (https://llvm.org/bugs/show_bug.cgi?id=27449) is
+      // fixed in clang, only warn about DWO_id mismatches in verbose mode.
+      // ASTFileSignatures will change randomly when a module is rebuilt.
+      uint64_t PCMDwoId = getDwoId(*CUDie, *CU);
+      if (PCMDwoId != DwoId) {
+        if (Options.Verbose)
+          reportWarning(
+              Twine("hash mismatch: this object file was built against a "
+                    "different version of the module ") + Filename);
+        // Update the cache entry with the DwoId of the module loaded from disk.
+        ClangModules[Filename] = PCMDwoId;
+      }
 
       // Add this module.
       Unit = llvm::make_unique(*CU, UnitID++, !Options.NoODR,
diff --git a/tools/dsymutil/MachODebugMapParser.cpp b/tools/dsymutil/MachODebugMapParser.cpp
index 29529942cb8aea845fe3d49957cd5792f57554d7..22215200ed5f611adfd50c6f8a2322fa3dc4d1a6 100644
--- a/tools/dsymutil/MachODebugMapParser.cpp
+++ b/tools/dsymutil/MachODebugMapParser.cpp
@@ -137,8 +137,7 @@ void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename,
 }
 
 static std::string getArchName(const object::MachOObjectFile &Obj) {
-  Triple ThumbTriple;
-  Triple T = Obj.getArch(nullptr, &ThumbTriple);
+  Triple T = Obj.getArchTriple();
   return T.getArchName();
 }
 
@@ -146,8 +145,7 @@ std::unique_ptr
 MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
                                     StringRef BinaryPath) {
   loadMainBinarySymbols(MainBinary);
-  Result =
-      make_unique(BinaryHolder::getTriple(MainBinary), BinaryPath);
+  Result = make_unique(MainBinary.getArchTriple(), BinaryPath);
   MainBinaryStrings = MainBinary.getStringTableData();
   for (const SymbolRef &Symbol : MainBinary.symbols()) {
     const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
@@ -296,7 +294,11 @@ static bool shouldLinkArch(SmallVectorImpl &Archs, StringRef Arch) {
       std::find(Archs.begin(), Archs.end(), "arm") != Archs.end())
     return true;
 
-  return std::find(Archs.begin(), Archs.end(), Arch) != Archs.end();
+  SmallString<16> ArchName = Arch;
+  if (Arch.startswith("thumb"))
+    ArchName = ("arm" + Arch.substr(5)).str();
+
+  return std::find(Archs.begin(), Archs.end(), ArchName) != Archs.end();
 }
 
 bool MachODebugMapParser::dumpStab() {
@@ -308,9 +310,8 @@ bool MachODebugMapParser::dumpStab() {
     return false;
   }
 
-  Triple T;
   for (const auto *Binary : *MainBinOrError)
-    if (shouldLinkArch(Archs, Binary->getArch(nullptr, &T).getArchName()))
+    if (shouldLinkArch(Archs, Binary->getArchTriple().getArchName()))
       dumpOneBinaryStab(*Binary, BinaryPath);
 
   return true;
@@ -326,9 +327,8 @@ ErrorOr>> MachODebugMapParser::parse() {
     return Error;
 
   std::vector> Results;
-  Triple T;
   for (const auto *Binary : *MainBinOrError)
-    if (shouldLinkArch(Archs, Binary->getArch(nullptr, &T).getArchName()))
+    if (shouldLinkArch(Archs, Binary->getArchTriple().getArchName()))
       Results.push_back(parseOneBinary(*Binary, BinaryPath));
 
   return std::move(Results);
@@ -402,9 +402,12 @@ void MachODebugMapParser::loadCurrentObjectFileSymbols(
 
   for (auto Sym : Obj.symbols()) {
     uint64_t Addr = Sym.getValue();
-    ErrorOr Name = Sym.getName();
-    if (!Name)
+    Expected Name = Sym.getName();
+    if (!Name) {
+      // TODO: Actually report errors helpfully.
+      consumeError(Name.takeError());
       continue;
+    }
     // The value of some categories of symbols isn't meaningful. For
     // example common symbols store their size in the value field, not
     // their address. Absolute symbols have a fixed address that can
@@ -437,9 +440,12 @@ void MachODebugMapParser::loadMainBinarySymbols(
   section_iterator Section = MainBinary.section_end();
   MainBinarySymbolAddresses.clear();
   for (const auto &Sym : MainBinary.symbols()) {
-    ErrorOr TypeOrErr = Sym.getType();
-    if (!TypeOrErr)
+    Expected TypeOrErr = Sym.getType();
+    if (!TypeOrErr) {
+      // TODO: Actually report errors helpfully.
+      consumeError(TypeOrErr.takeError());
       continue;
+    }
     SymbolRef::Type Type = *TypeOrErr;
     // Skip undefined and STAB entries.
     if ((Type & SymbolRef::ST_Debug) || (Type & SymbolRef::ST_Unknown))
@@ -450,16 +456,22 @@ void MachODebugMapParser::loadMainBinarySymbols(
     // addresses should be fetched for the debug map.
     if (!(Sym.getFlags() & SymbolRef::SF_Global))
       continue;
-    ErrorOr SectionOrErr = Sym.getSection();
-    if (!SectionOrErr)
+    Expected SectionOrErr = Sym.getSection();
+    if (!SectionOrErr) {
+      // TODO: Actually report errors helpfully.
+      consumeError(SectionOrErr.takeError());
       continue;
+    }
     Section = *SectionOrErr;
     if (Section == MainBinary.section_end() || Section->isText())
       continue;
     uint64_t Addr = Sym.getValue();
-    ErrorOr NameOrErr = Sym.getName();
-    if (!NameOrErr)
+    Expected NameOrErr = Sym.getName();
+    if (!NameOrErr) {
+      // TODO: Actually report errors helpfully.
+      consumeError(NameOrErr.takeError());
       continue;
+    }
     StringRef Name = *NameOrErr;
     if (Name.size() == 0 || Name[0] == '\0')
       continue;
diff --git a/tools/dsymutil/MachOUtils.cpp b/tools/dsymutil/MachOUtils.cpp
index 628c1b6380a28e034080d91b5aad15be7995e41d..8a730a1d0c8a2e36989071661a889690f2e981ba 100644
--- a/tools/dsymutil/MachOUtils.cpp
+++ b/tools/dsymutil/MachOUtils.cpp
@@ -16,6 +16,7 @@
 #include "llvm/MC/MCAsmLayout.h"
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCMachObjectWriter.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/Object/MachO.h"
 #include "llvm/Support/FileUtilities.h"
diff --git a/tools/dsymutil/dsymutil.cpp b/tools/dsymutil/dsymutil.cpp
index e9ee57f3dee674e6dad863b2ed055a17f0f0e5f7..1ce0aefeec2afb4802e6c2e0a55450d7cbcf2888 100644
--- a/tools/dsymutil/dsymutil.cpp
+++ b/tools/dsymutil/dsymutil.cpp
@@ -176,14 +176,17 @@ static std::error_code getUniqueFile(const llvm::Twine &Model, int &ResultFD,
 static std::string getOutputFileName(llvm::StringRef InputFile,
                                      bool TempFile = false) {
   if (TempFile) {
+    llvm::SmallString<128> TmpFile;
+    llvm::sys::path::system_temp_directory(true, TmpFile);
     llvm::StringRef Basename =
         OutputFileOpt.empty() ? InputFile : llvm::StringRef(OutputFileOpt);
-    llvm::Twine OutputFile = Basename + ".tmp%%%%%%.dwarf";
+    llvm::sys::path::append(TmpFile, llvm::sys::path::filename(Basename));
+
     int FD;
     llvm::SmallString<128> UniqueFile;
-    if (auto EC = getUniqueFile(OutputFile, FD, UniqueFile)) {
+    if (auto EC = getUniqueFile(TmpFile + ".tmp%%%%%.dwarf", FD, UniqueFile)) {
       llvm::errs() << "error: failed to create temporary outfile '"
-                   << OutputFile << "': " << EC.message() << '\n';
+                   << TmpFile << "': " << EC.message() << '\n';
       return "";
     }
     llvm::sys::RemoveFileOnSignal(UniqueFile);
@@ -234,7 +237,7 @@ void llvm::dsymutil::exitDsymutil(int ExitStatus) {
 }
 
 int main(int argc, char **argv) {
-  llvm::sys::PrintStackTraceOnErrorSignal();
+  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
   llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
   llvm::llvm_shutdown_obj Shutdown;
   LinkOptions Options;
diff --git a/tools/gold/CMakeLists.txt b/tools/gold/CMakeLists.txt
index 1a6169d65c2ca78a00d6382c1f270bb1a86d41d2..e9029e1e7c107f250cece06323f3c72d8392b409 100644
--- a/tools/gold/CMakeLists.txt
+++ b/tools/gold/CMakeLists.txt
@@ -10,6 +10,7 @@ if( LLVM_ENABLE_PIC AND LLVM_BINUTILS_INCDIR )
   set(LLVM_LINK_COMPONENTS
      ${LLVM_TARGETS_TO_BUILD}
      Linker
+     LTO
      BitWriter
      IPO
      )
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp
index b70c072f9bfb46cc44659392a11e110c231f4f9e..e3351c29fcdb7ad375f0bcd27fa7caaed345dbe4 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -12,8 +12,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H
-#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
@@ -21,6 +19,7 @@
 #include "llvm/CodeGen/Analysis.h"
 #include "llvm/CodeGen/CommandFlags.h"
 #include "llvm/CodeGen/ParallelCG.h"
+#include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H
 #include "llvm/IR/AutoUpgrade.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DiagnosticInfo.h"
@@ -29,27 +28,30 @@
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Verifier.h"
+#include "llvm/LTO/LTO.h"
 #include "llvm/Linker/IRMover.h"
 #include "llvm/MC/SubtargetFeature.h"
-#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
 #include "llvm/Object/IRObjectFile.h"
+#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
 #include "llvm/Support/Host.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/ThreadPool.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/thread.h"
 #include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/FunctionImport.h"
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
 #include "llvm/Transforms/Utils/FunctionImportUtils.h"
 #include "llvm/Transforms/Utils/GlobalStatus.h"
-#include "llvm/Transforms/Utils/ModuleUtils.h"
 #include "llvm/Transforms/Utils/ValueMapper.h"
 #include 
 #include 
 #include 
+#include 
 #include 
 
 // FIXME: remove this declaration when we stop maintaining Ubuntu Quantal and
@@ -73,7 +75,10 @@ static ld_plugin_message message = discard_message;
 namespace {
 struct claimed_file {
   void *handle;
+  void *leader_handle;
   std::vector syms;
+  off_t filesize;
+  std::string name;
 };
 
 /// RAII wrapper to manage opening and releasing of a ld_plugin_input_file.
@@ -104,7 +109,7 @@ struct ResolutionInfo {
   uint64_t CommonSize = 0;
   unsigned CommonAlign = 0;
   bool IsLinkonceOdr = true;
-  bool UnnamedAddr = true;
+  GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::Global;
   GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility;
   bool CommonInternal = false;
   bool UseCommon = false;
@@ -113,9 +118,6 @@ struct ResolutionInfo {
 /// Class to own information used by a task or during its cleanup for a
 /// ThinLTO backend instantiation.
 class ThinLTOTaskInfo {
-  /// The input file holding the module bitcode read by the ThinLTO task.
-  PluginInputFile InputFile;
-
   /// The output stream the task will codegen into.
   std::unique_ptr OS;
 
@@ -127,9 +129,9 @@ class ThinLTOTaskInfo {
   bool TempOutFile;
 
 public:
-  ThinLTOTaskInfo(PluginInputFile InputFile, std::unique_ptr OS,
-                  std::string Filename, bool TempOutFile)
-      : InputFile(std::move(InputFile)), OS(std::move(OS)), Filename(Filename),
+  ThinLTOTaskInfo(std::unique_ptr OS, std::string Filename,
+                  bool TempOutFile)
+      : OS(std::move(OS)), Filename(std::move(Filename)),
         TempOutFile(TempOutFile) {}
 
   /// Performs task related cleanup activities that must be done
@@ -143,9 +145,10 @@ static ld_plugin_get_symbols get_symbols = nullptr;
 static ld_plugin_add_input_file add_input_file = nullptr;
 static ld_plugin_set_extra_library_path set_extra_library_path = nullptr;
 static ld_plugin_get_view get_view = nullptr;
-static Reloc::Model RelocationModel = Reloc::Default;
+static Optional RelocationModel;
 static std::string output_name = "";
 static std::list Modules;
+static DenseMap FDToLeaderHandle;
 static StringMap ResInfo;
 static std::vector Cleanup;
 static llvm::TargetOptions TargetOpts;
@@ -181,9 +184,22 @@ namespace options {
   static bool thinlto = false;
   // If false, all ThinLTO backend compilations through code gen are performed
   // using multiple threads in the gold-plugin, before handing control back to
-  // gold. If true, exit after creating the combined index, the assuming is
+  // gold. If true, write individual backend index files which reflect
+  // the import decisions, and exit afterwards. The assumption is
   // that the build system will launch the backend processes.
   static bool thinlto_index_only = false;
+  // If true, when generating individual index files for distributed backends,
+  // also generate a "${bitcodefile}.imports" file at the same location for each
+  // bitcode file, listing the files it imports from in plain text. This is to
+  // support distributed build file staging.
+  static bool thinlto_emit_imports_files = false;
+  // Option to control where files for a distributed backend (the individual
+  // index files and optional imports files) are created.
+  // If specified, expects a string of the form "oldprefix:newprefix", and
+  // instead of generating these files in the same directory path as the
+  // corresponding bitcode file, will use a path formed by replacing the
+  // bitcode file's path prefix matching oldprefix with newprefix.
+  static std::string thinlto_prefix_replace;
   // Additional options to pass into the code generator.
   // Note: This array will contain all plugin options which are not claimed
   // as plugin exclusive to pass to the code generator.
@@ -217,6 +233,12 @@ namespace options {
       thinlto = true;
     } else if (opt == "thinlto-index-only") {
       thinlto_index_only = true;
+    } else if (opt == "thinlto-emit-imports-files") {
+      thinlto_emit_imports_files = true;
+    } else if (opt.startswith("thinlto-prefix-replace=")) {
+      thinlto_prefix_replace = opt.substr(strlen("thinlto-prefix-replace="));
+      if (thinlto_prefix_replace.find(";") == std::string::npos)
+        message(LDPL_FATAL, "thinlto-prefix-replace expects 'old;new' format");
     } else if (opt.size() == 2 && opt[0] == 'O') {
       if (opt[1] < '0' || opt[1] > '3')
         message(LDPL_FATAL, "Optimization level must be between 0 and 3");
@@ -362,7 +384,7 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
     return LDPS_ERR;
   }
   if (!release_input_file) {
-    message(LDPL_ERROR, "relesase_input_file not passed to LLVMgold.");
+    message(LDPL_ERROR, "release_input_file not passed to LLVMgold.");
     return LDPS_ERR;
   }
 
@@ -484,11 +506,23 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
   claimed_file &cf = Modules.back();
 
   cf.handle = file->handle;
-
-  // If we are doing ThinLTO compilation, don't need to process the symbols.
-  // Later we simply build a combined index file after all files are claimed.
-  if (options::thinlto && options::thinlto_index_only)
-    return LDPS_OK;
+  // Keep track of the first handle for each file descriptor, since there are
+  // multiple in the case of an archive. This is used later in the case of
+  // ThinLTO parallel backends to ensure that each file is only opened and
+  // released once.
+  auto LeaderHandle =
+      FDToLeaderHandle.insert(std::make_pair(file->fd, file->handle)).first;
+  cf.leader_handle = LeaderHandle->second;
+  // Save the filesize since for parallel ThinLTO backends we can only
+  // invoke get_input_file once per archive (only for the leader handle).
+  cf.filesize = file->filesize;
+  // In the case of an archive library, all but the first member must have a
+  // non-zero offset, which we can append to the file name to obtain a
+  // unique name.
+  cf.name = file->name;
+  if (file->offset)
+    cf.name += ".llvm." + std::to_string(file->offset) + "." +
+               sys::path::filename(Obj->getModule().getSourceFileName()).str();
 
   for (auto &Sym : Obj->symbols()) {
     uint32_t Symflags = Sym.getFlags();
@@ -512,12 +546,12 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
 
     sym.visibility = LDPV_DEFAULT;
     if (GV) {
-      Res.UnnamedAddr &= GV->hasUnnamedAddr();
+      Res.UnnamedAddr =
+          GlobalValue::getMinUnnamedAddr(Res.UnnamedAddr, GV->getUnnamedAddr());
       Res.IsLinkonceOdr &= GV->hasLinkOnceLinkage();
       Res.Visibility = getMinVisibility(Res.Visibility, GV->getVisibility());
       switch (GV->getVisibility()) {
       case GlobalValue::DefaultVisibility:
-        sym.visibility = LDPV_DEFAULT;
         break;
       case GlobalValue::HiddenVisibility:
         sym.visibility = LDPV_HIDDEN;
@@ -625,13 +659,12 @@ static const void *getSymbolsAndView(claimed_file &F) {
 }
 
 static std::unique_ptr
-getModuleSummaryIndexForFile(claimed_file &F, ld_plugin_input_file &Info) {
+getModuleSummaryIndexForFile(claimed_file &F) {
   const void *View = getSymbolsAndView(F);
   if (!View)
     return nullptr;
 
-  MemoryBufferRef BufferRef(StringRef((const char *)View, Info.filesize),
-                            Info.name);
+  MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize), F.name);
 
   // Don't bother trying to build an index if there is no summary information
   // in this bitcode file.
@@ -655,12 +688,10 @@ getModuleSummaryIndexForFile(claimed_file &F, ld_plugin_input_file &Info) {
 
 static std::unique_ptr
 getModuleForFile(LLVMContext &Context, claimed_file &F, const void *View,
-                 ld_plugin_input_file &Info, raw_fd_ostream *ApiFile,
-                 StringSet<> &Internalize, StringSet<> &Maybe,
-                 std::vector &Keep,
+                 StringRef Name, raw_fd_ostream *ApiFile,
+                 StringSet<> &Internalize, std::vector &Keep,
                  StringMap &Realign) {
-  MemoryBufferRef BufferRef(StringRef((const char *)View, Info.filesize),
-                            Info.name);
+  MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize), Name);
   ErrorOr> ObjOrErr =
       object::IRObjectFile::create(BufferRef, Context);
 
@@ -704,16 +735,6 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, const void *View,
     if (Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP && !Res.IsLinkonceOdr)
       Resolution = LDPR_PREVAILING_DEF;
 
-    // In ThinLTO mode change all prevailing resolutions to LDPR_PREVAILING_DEF.
-    // For ThinLTO the IR files are compiled through the backend independently,
-    // so we need to ensure that any prevailing linkonce copy will be emitted
-    // into the object file by making it weak. Additionally, we can skip the
-    // IRONLY handling for internalization, which isn't performed in ThinLTO
-    // mode currently anyway.
-    if (options::thinlto && (Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP ||
-                             Resolution == LDPR_PREVAILING_DEF_IRONLY))
-      Resolution = LDPR_PREVAILING_DEF;
-
     GV->setUnnamedAddr(Res.UnnamedAddr);
     GV->setVisibility(Res.Visibility);
 
@@ -793,12 +814,9 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, const void *View,
       break;
 
     case LDPR_PREVAILING_DEF_IRONLY_EXP: {
-      // We can only check for address uses after we merge the modules. The
-      // reason is that this GV might have a copy in another module
-      // and in that module the address might be significant, but that
-      // copy will be LDPR_PREEMPTED_IR.
-      Maybe.insert(GV->getName());
       Keep.push_back(GV);
+      if (canBeOmittedFromSymbolTable(GV))
+        Internalize.insert(GV->getName());
       break;
     }
     }
@@ -856,17 +874,32 @@ class CodeGen {
   /// a unique and identifiable save-temps output file for each ThinLTO backend.
   std::string SaveTempsFilename;
 
+  /// Map from a module name to the corresponding buffer holding a view of the
+  /// bitcode provided via the get_view gold callback.
+  StringMap *ModuleMap;
+
+  // Functions to import into this module.
+  FunctionImporter::ImportMapTy *ImportList;
+
+  // Map of globals defined in this module to their summary.
+  std::map *DefinedGlobals;
+
 public:
   /// Constructor used by full LTO.
   CodeGen(std::unique_ptr M)
-      : M(std::move(M)), OS(nullptr), TaskID(-1), CombinedIndex(nullptr) {
+      : M(std::move(M)), OS(nullptr), TaskID(-1), CombinedIndex(nullptr),
+        ModuleMap(nullptr) {
     initTargetMachine();
   }
   /// Constructor used by ThinLTO.
   CodeGen(std::unique_ptr M, raw_fd_ostream *OS, int TaskID,
-          const ModuleSummaryIndex *CombinedIndex, std::string Filename)
+          const ModuleSummaryIndex *CombinedIndex, std::string Filename,
+          StringMap *ModuleMap,
+          FunctionImporter::ImportMapTy *ImportList,
+          std::map *DefinedGlobals)
       : M(std::move(M)), OS(OS), TaskID(TaskID), CombinedIndex(CombinedIndex),
-        SaveTempsFilename(Filename) {
+        SaveTempsFilename(std::move(Filename)), ModuleMap(ModuleMap),
+        ImportList(ImportList), DefinedGlobals(DefinedGlobals) {
     assert(options::thinlto == !!CombinedIndex &&
            "Expected module summary index iff performing ThinLTO");
     initTargetMachine();
@@ -879,16 +912,25 @@ public:
   void runCodegenPasses();
 
 private:
+  const Target *TheTarget;
+  std::string TripleStr;
+  std::string FeaturesString;
+  TargetOptions Options;
+
   /// Create a target machine for the module. Must be unique for each
   /// module/task.
   void initTargetMachine();
 
+  std::unique_ptr createTargetMachine();
+
   /// Run all LTO passes on the module.
   void runLTOPasses();
 
   /// Sets up output files necessary to perform optional multi-threaded
   /// split code generation, and invokes the code generation implementation.
-  void runSplitCodeGen();
+  /// If BCFileName is not empty, saves bitcode for module partitions into
+  /// {BCFileName}0 .. {BCFileName}N.
+  void runSplitCodeGen(const SmallString<128> &BCFilename);
 };
 }
 
@@ -915,26 +957,57 @@ static CodeGenOpt::Level getCGOptLevel() {
 }
 
 void CodeGen::initTargetMachine() {
-  const std::string &TripleStr = M->getTargetTriple();
+  TripleStr = M->getTargetTriple();
   Triple TheTriple(TripleStr);
 
   std::string ErrMsg;
-  const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
+  TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
   if (!TheTarget)
     message(LDPL_FATAL, "Target not found: %s", ErrMsg.c_str());
 
   SubtargetFeatures Features = getFeatures(TheTriple);
-  TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+  FeaturesString = Features.getString();
+  Options = InitTargetOptionsFromCodeGenFlags();
+
+  // Disable the new X86 relax relocations since gold might not support them.
+  // FIXME: Check the gold version or add a new option to enable them.
+  Options.RelaxELFRelocations = false;
+
+  TM = createTargetMachine();
+}
+
+std::unique_ptr CodeGen::createTargetMachine() {
   CodeGenOpt::Level CGOptLevel = getCGOptLevel();
 
-  TM.reset(TheTarget->createTargetMachine(
-      TripleStr, options::mcpu, Features.getString(), Options, RelocationModel,
+  return std::unique_ptr(TheTarget->createTargetMachine(
+      TripleStr, options::mcpu, FeaturesString, Options, RelocationModel,
       CodeModel::Default, CGOptLevel));
 }
 
 void CodeGen::runLTOPasses() {
   M->setDataLayout(TM->createDataLayout());
 
+  if (CombinedIndex) {
+    // Apply summary-based LinkOnce/Weak resolution decisions.
+    thinLTOResolveWeakForLinkerModule(*M, *DefinedGlobals);
+
+    // Apply summary-based internalization decisions. Skip if there are no
+    // defined globals from the summary since not only is it unnecessary, but
+    // if this module did not have a summary section the internalizer will
+    // assert if it finds any definitions in this module that aren't in the
+    // DefinedGlobals set.
+    if (!DefinedGlobals->empty())
+      thinLTOInternalizeModule(*M, *DefinedGlobals);
+
+    // Create a loader that will parse the bitcode from the buffers
+    // in the ModuleMap.
+    ModuleLoader Loader(M->getContext(), *ModuleMap);
+
+    // Perform function importing.
+    FunctionImporter Importer(*CombinedIndex, Loader);
+    Importer.importFunctions(*M, *ImportList);
+  }
+
   legacy::PassManager passes;
   passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
 
@@ -948,8 +1021,10 @@ void CodeGen::runLTOPasses() {
   PMB.LoopVectorize = true;
   PMB.SLPVectorize = true;
   PMB.OptLevel = options::OptLevel;
-  PMB.ModuleSummary = CombinedIndex;
-  PMB.populateLTOPassManager(passes);
+  if (options::thinlto)
+    PMB.populateThinLTOPassManager(passes);
+  else
+    PMB.populateLTOPassManager(passes);
   passes.run(*M);
 }
 
@@ -987,15 +1062,7 @@ void CodeGen::runCodegenPasses() {
   CodeGenPasses.run(*M);
 }
 
-void CodeGen::runSplitCodeGen() {
-  const std::string &TripleStr = M->getTargetTriple();
-  Triple TheTriple(TripleStr);
-
-  SubtargetFeatures Features = getFeatures(TheTriple);
-
-  TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
-  CodeGenOpt::Level CGOptLevel = getCGOptLevel();
-
+void CodeGen::runSplitCodeGen(const SmallString<128> &BCFilename) {
   SmallString<128> Filename;
   // Note that openOutputFile will append a unique ID for each task
   if (!options::obj_path.empty())
@@ -1010,6 +1077,7 @@ void CodeGen::runSplitCodeGen() {
   unsigned int MaxThreads = options::Parallelism ? options::Parallelism : 1;
 
   std::vector> Filenames(MaxThreads);
+  std::vector> BCFilenames(MaxThreads);
   bool TempOutFile = Filename.empty();
   {
     // Open a file descriptor for each backend task. This is done in a block
@@ -1024,9 +1092,19 @@ void CodeGen::runSplitCodeGen() {
       OSPtrs[I] = &OSs.back();
     }
 
+    std::list BCOSs;
+    std::vector BCOSPtrs;
+    if (!BCFilename.empty() && MaxThreads > 1) {
+      for (unsigned I = 0; I != MaxThreads; ++I) {
+        int FD = openOutputFile(BCFilename, false, BCFilenames[I], I);
+        BCOSs.emplace_back(FD, true);
+        BCOSPtrs.push_back(&BCOSs.back());
+      }
+    }
+
     // Run backend tasks.
-    splitCodeGen(std::move(M), OSPtrs, options::mcpu, Features.getString(),
-                 Options, RelocationModel, CodeModel::Default, CGOptLevel);
+    splitCodeGen(std::move(M), OSPtrs, BCOSPtrs,
+                 [&]() { return createTargetMachine(); });
   }
 
   for (auto &Filename : Filenames)
@@ -1036,14 +1114,16 @@ void CodeGen::runSplitCodeGen() {
 void CodeGen::runAll() {
   runLTOPasses();
 
+  SmallString<128> OptFilename;
   if (options::TheOutputType == options::OT_SAVE_TEMPS) {
-    std::string OptFilename = output_name;
+    OptFilename = output_name;
     // If the CodeGen client provided a filename, use it. Always expect
     // a provided filename if we are in a task (i.e. ThinLTO backend).
     assert(!SaveTempsFilename.empty() || TaskID == -1);
     if (!SaveTempsFilename.empty())
       OptFilename = SaveTempsFilename;
-    saveBCFile(OptFilename + ".opt.bc", *M);
+    OptFilename += ".opt.bc";
+    saveBCFile(OptFilename, *M);
   }
 
   // If we are already in a thread (i.e. ThinLTO), just perform
@@ -1052,29 +1132,40 @@ void CodeGen::runAll() {
     runCodegenPasses();
   // Otherwise attempt split code gen.
   else
-    runSplitCodeGen();
+    runSplitCodeGen(OptFilename);
 }
 
 /// Links the module in \p View from file \p F into the combined module
-/// saved in the IRMover \p L. Returns true on error, false on success.
-static bool linkInModule(LLVMContext &Context, IRMover &L, claimed_file &F,
-                         const void *View, ld_plugin_input_file &File,
+/// saved in the IRMover \p L.
+static void linkInModule(LLVMContext &Context, IRMover &L, claimed_file &F,
+                         const void *View, StringRef Name,
                          raw_fd_ostream *ApiFile, StringSet<> &Internalize,
-                         StringSet<> &Maybe) {
+                         bool SetName = false) {
   std::vector Keep;
   StringMap Realign;
-  std::unique_ptr M = getModuleForFile(
-      Context, F, View, File, ApiFile, Internalize, Maybe, Keep, Realign);
+  std::unique_ptr M = getModuleForFile(Context, F, View, Name, ApiFile,
+                                               Internalize, Keep, Realign);
   if (!M.get())
-    return false;
+    return;
   if (!options::triple.empty())
     M->setTargetTriple(options::triple.c_str());
   else if (M->getTargetTriple().empty()) {
     M->setTargetTriple(DefaultTriple);
   }
 
-  if (!L.move(std::move(M), Keep, [](GlobalValue &, IRMover::ValueAdder) {}))
-    return false;
+  // For ThinLTO we want to propagate the source file name to ensure
+  // we can create the correct global identifiers matching those in the
+  // original module.
+  if (SetName)
+    L.getModule().setSourceFileName(M->getSourceFileName());
+
+  if (Error E = L.move(std::move(M), Keep,
+                       [](GlobalValue &, IRMover::ValueAdder) {})) {
+    handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) {
+      message(LDPL_FATAL, "Failed to link module %s: %s", Name.str().c_str(),
+              EIB.message().c_str());
+    });
+  }
 
   for (const auto &I : Realign) {
     GlobalValue *Dst = L.getModule().getNamedValue(I.first());
@@ -1082,37 +1173,45 @@ static bool linkInModule(LLVMContext &Context, IRMover &L, claimed_file &F,
       continue;
     cast(Dst)->setAlignment(I.second);
   }
-
-  return true;
 }
 
 /// Perform the ThinLTO backend on a single module, invoking the LTO and codegen
 /// pipelines.
 static void thinLTOBackendTask(claimed_file &F, const void *View,
-                               ld_plugin_input_file &File,
-                               raw_fd_ostream *ApiFile,
+                               StringRef Name, raw_fd_ostream *ApiFile,
                                const ModuleSummaryIndex &CombinedIndex,
-                               raw_fd_ostream *OS, unsigned TaskID) {
+                               raw_fd_ostream *OS, unsigned TaskID,
+                               StringMap &ModuleMap,
+                               FunctionImporter::ImportMapTy &ImportList,
+                               std::map &DefinedGlobals) {
   // Need to use a separate context for each task
   LLVMContext Context;
+  Context.setDiscardValueNames(options::TheOutputType !=
+                               options::OT_SAVE_TEMPS);
+  Context.enableDebugTypeODRUniquing(); // Merge debug info types.
   Context.setDiagnosticHandler(diagnosticHandlerForContext, nullptr, true);
 
-  std::unique_ptr NewModule(new llvm::Module(File.name, Context));
+  std::unique_ptr NewModule(new llvm::Module(Name, Context));
   IRMover L(*NewModule.get());
 
   StringSet<> Dummy;
-  if (linkInModule(Context, L, F, View, File, ApiFile, Dummy, Dummy))
-    message(LDPL_FATAL, "Failed to rename module for ThinLTO");
+  linkInModule(Context, L, F, View, Name, ApiFile, Dummy, true);
   if (renameModuleForThinLTO(*NewModule, CombinedIndex))
     message(LDPL_FATAL, "Failed to rename module for ThinLTO");
 
-  CodeGen codeGen(std::move(NewModule), OS, TaskID, &CombinedIndex, File.name);
+  CodeGen codeGen(std::move(NewModule), OS, TaskID, &CombinedIndex, Name,
+                  &ModuleMap, &ImportList, &DefinedGlobals);
   codeGen.runAll();
 }
 
 /// Launch each module's backend pipeline in a separate task in a thread pool.
-static void thinLTOBackends(raw_fd_ostream *ApiFile,
-                            const ModuleSummaryIndex &CombinedIndex) {
+static void
+thinLTOBackends(raw_fd_ostream *ApiFile,
+                const ModuleSummaryIndex &CombinedIndex,
+                StringMap &ModuleMap,
+                StringMap &ImportLists,
+  StringMap>
+      &ModuleToDefinedGVSummaries) {
   unsigned TaskCount = 0;
   std::vector Tasks;
   Tasks.reserve(Modules.size());
@@ -1127,7 +1226,6 @@ static void thinLTOBackends(raw_fd_ostream *ApiFile,
     for (claimed_file &F : Modules) {
       // Do all the gold callbacks in the main thread, since gold is not thread
       // safe by default.
-      PluginInputFile InputFile(F.handle);
       const void *View = getSymbolsAndView(F);
       if (!View)
         continue;
@@ -1139,7 +1237,7 @@ static void thinLTOBackends(raw_fd_ostream *ApiFile,
       else if (options::TheOutputType == options::OT_SAVE_TEMPS) {
         // Use the input file name so that we get a unique and identifiable
         // output file for each ThinLTO backend task.
-        Filename = InputFile.file().name;
+        Filename = F.name;
         Filename += ".thinlto.o";
       }
       bool TempOutFile = Filename.empty();
@@ -1154,15 +1252,16 @@ static void thinLTOBackends(raw_fd_ostream *ApiFile,
           llvm::make_unique(FD, true);
 
       // Enqueue the task
-      ThinLTOThreadPool.async(thinLTOBackendTask, std::ref(F), View,
-                              std::ref(InputFile.file()), ApiFile,
-                              std::ref(CombinedIndex), OS.get(), TaskCount);
+      ThinLTOThreadPool.async(thinLTOBackendTask, std::ref(F), View, F.name,
+                              ApiFile, std::ref(CombinedIndex), OS.get(),
+                              TaskCount, std::ref(ModuleMap),
+                              std::ref(ImportLists[F.name]),
+                              std::ref(ModuleToDefinedGVSummaries[F.name]));
 
       // Record the information needed by the task or during its cleanup
       // to a ThinLTOTaskInfo instance. For information needed by the task
       // the unique_ptr ownership is transferred to the ThinLTOTaskInfo.
-      Tasks.emplace_back(std::move(InputFile), std::move(OS),
-                         NewFilename.c_str(), TempOutFile);
+      Tasks.emplace_back(std::move(OS), NewFilename.c_str(), TempOutFile);
     }
   }
 
@@ -1170,33 +1269,181 @@ static void thinLTOBackends(raw_fd_ostream *ApiFile,
     Task.cleanup();
 }
 
-/// gold informs us that all symbols have been read. At this point, we use
-/// get_symbols to see if any of our definitions have been overridden by a
-/// native object file. Then, perform optimization and codegen.
-static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
-  if (Modules.empty())
-    return LDPS_OK;
+/// Parse the thinlto_prefix_replace option into the \p OldPrefix and
+/// \p NewPrefix strings, if it was specified.
+static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,
+                                      std::string &NewPrefix) {
+  StringRef PrefixReplace = options::thinlto_prefix_replace;
+  assert(PrefixReplace.empty() || PrefixReplace.find(";") != StringRef::npos);
+  std::pair Split = PrefixReplace.split(";");
+  OldPrefix = Split.first.str();
+  NewPrefix = Split.second.str();
+}
 
-  if (unsigned NumOpts = options::extra.size())
-    cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);
+/// Given the original \p Path to an output file, replace any path
+/// prefix matching \p OldPrefix with \p NewPrefix. Also, create the
+/// resulting directory if it does not yet exist.
+static std::string getThinLTOOutputFile(const std::string &Path,
+                                        const std::string &OldPrefix,
+                                        const std::string &NewPrefix) {
+  if (OldPrefix.empty() && NewPrefix.empty())
+    return Path;
+  SmallString<128> NewPath(Path);
+  llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix);
+  StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str());
+  if (!ParentPath.empty()) {
+    // Make sure the new directory exists, creating it if necessary.
+    if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))
+      llvm::errs() << "warning: could not create directory '" << ParentPath
+                   << "': " << EC.message() << '\n';
+  }
+  return NewPath.str();
+}
 
-  // If we are doing ThinLTO compilation, simply build the combined
-  // module index/summary and emit it. We don't need to parse the modules
-  // and link them in this case.
-  if (options::thinlto) {
-    ModuleSummaryIndex CombinedIndex;
-    uint64_t NextModuleId = 0;
-    for (claimed_file &F : Modules) {
-      PluginInputFile InputFile(F.handle);
+/// Perform ThinLTO link, which creates the combined index file.
+/// Also, either launch backend threads or (under thinlto-index-only)
+/// emit individual index files for distributed backends and exit.
+static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) {
+  // Map from a module name to the corresponding buffer holding a view of the
+  // bitcode provided via the get_view gold callback.
+  StringMap ModuleMap;
+  // Map to own RAII objects that manage the file opening and releasing
+  // interfaces with gold.
+  DenseMap> HandleToInputFile;
+
+  // Keep track of symbols that must not be internalized because they
+  // are referenced outside of a single IR module.
+  DenseSet Preserve;
+
+  // Keep track of the prevailing copy for each GUID, for use in resolving
+  // weak linkages.
+  DenseMap PrevailingCopy;
+
+  ModuleSummaryIndex CombinedIndex;
+  uint64_t NextModuleId = 0;
+  for (claimed_file &F : Modules) {
+    if (!HandleToInputFile.count(F.leader_handle))
+      HandleToInputFile.insert(std::make_pair(
+          F.leader_handle, llvm::make_unique(F.handle)));
+    // Pass this into getModuleSummaryIndexForFile
+    const void *View = getSymbolsAndView(F);
+    if (!View)
+      continue;
 
-      std::unique_ptr Index =
-          getModuleSummaryIndexForFile(F, InputFile.file());
+    MemoryBufferRef ModuleBuffer(StringRef((const char *)View, F.filesize),
+                                 F.name);
+    assert(ModuleMap.find(ModuleBuffer.getBufferIdentifier()) ==
+               ModuleMap.end() &&
+           "Expect unique Buffer Identifier");
+    ModuleMap[ModuleBuffer.getBufferIdentifier()] = ModuleBuffer;
+
+    std::unique_ptr Index = getModuleSummaryIndexForFile(F);
+
+    // Use gold's symbol resolution information to identify symbols referenced
+    // by more than a single IR module (i.e. referenced by multiple IR modules
+    // or by a non-IR module). Cross references introduced by importing are
+    // checked separately via the export lists. Also track the prevailing copy
+    // for later symbol resolution.
+    for (auto &Sym : F.syms) {
+      ld_plugin_symbol_resolution Resolution =
+          (ld_plugin_symbol_resolution)Sym.resolution;
+      GlobalValue::GUID SymGUID = GlobalValue::getGUID(Sym.name);
+      if (Resolution != LDPR_PREVAILING_DEF_IRONLY)
+        Preserve.insert(SymGUID);
+
+      if (Index && (Resolution == LDPR_PREVAILING_DEF ||
+                    Resolution == LDPR_PREVAILING_DEF_IRONLY ||
+                    Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP))
+        PrevailingCopy[SymGUID] = Index->getGlobalValueSummary(SymGUID);
+    }
+
+    // Skip files without a module summary.
+    if (Index)
+      CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
+  }
 
-      // Skip files without a module summary.
-      if (Index)
-        CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
+  // Collect for each module the list of function it defines (GUID ->
+  // Summary).
+  StringMap>
+      ModuleToDefinedGVSummaries(NextModuleId);
+  CombinedIndex.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
+
+  StringMap ImportLists(NextModuleId);
+  StringMap ExportLists(NextModuleId);
+  ComputeCrossModuleImport(CombinedIndex, ModuleToDefinedGVSummaries,
+                           ImportLists, ExportLists);
+
+  auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
+    const auto &Prevailing = PrevailingCopy.find(GUID);
+    assert(Prevailing != PrevailingCopy.end());
+    return Prevailing->second == S;
+  };
+
+  // Callback for internalization, to prevent internalization of symbols
+  // that were not candidates initially, and those that are being imported
+  // (which introduces new cross references).
+  auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
+    const auto &ExportList = ExportLists.find(ModuleIdentifier);
+    return (ExportList != ExportLists.end() &&
+            ExportList->second.count(GUID)) ||
+           Preserve.count(GUID);
+  };
+
+  thinLTOResolveWeakForLinkerInIndex(
+      CombinedIndex, isPrevailing,
+      [](StringRef ModuleIdentifier, GlobalValue::GUID GUID,
+         GlobalValue::LinkageTypes NewLinkage) {});
+
+  // Use global summary-based analysis to identify symbols that can be
+  // internalized (because they aren't exported or preserved as per callback).
+  // Changes are made in the index, consumed in the ThinLTO backends.
+  thinLTOInternalizeAndPromoteInIndex(CombinedIndex, isExported);
+
+  if (options::thinlto_emit_imports_files && !options::thinlto_index_only)
+    message(LDPL_WARNING,
+            "thinlto-emit-imports-files ignored unless thinlto-index-only");
+
+  if (options::thinlto_index_only) {
+    // If the thinlto-prefix-replace option was specified, parse it and
+    // extract the old and new prefixes.
+    std::string OldPrefix, NewPrefix;
+    getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
+
+    // For each input bitcode file, generate an individual index that
+    // contains summaries only for its own global values, and for any that
+    // should be imported.
+    for (claimed_file &F : Modules) {
+      std::error_code EC;
+
+      std::string NewModulePath =
+          getThinLTOOutputFile(F.name, OldPrefix, NewPrefix);
+      raw_fd_ostream OS((Twine(NewModulePath) + ".thinlto.bc").str(), EC,
+                        sys::fs::OpenFlags::F_None);
+      if (EC)
+        message(LDPL_FATAL, "Unable to open %s.thinlto.bc for writing: %s",
+                NewModulePath.c_str(), EC.message().c_str());
+      // Build a map of module to the GUIDs and summary objects that should
+      // be written to its index.
+      std::map ModuleToSummariesForIndex;
+      gatherImportedSummariesForModule(F.name, ModuleToDefinedGVSummaries,
+                                       ImportLists, ModuleToSummariesForIndex);
+      WriteIndexToFile(CombinedIndex, OS, &ModuleToSummariesForIndex);
+
+      if (options::thinlto_emit_imports_files) {
+        if ((EC = EmitImportsFiles(F.name,
+                                   (Twine(NewModulePath) + ".imports").str(),
+                                   ImportLists)))
+          message(LDPL_FATAL, "Unable to open %s.imports",
+                  NewModulePath.c_str(), EC.message().c_str());
+      }
     }
 
+    cleanup_hook();
+    exit(0);
+  }
+
+  // Create OS in nested scope so that it will be closed on destruction.
+  {
     std::error_code EC;
     raw_fd_ostream OS(output_name + ".thinlto.bc", EC,
                       sys::fs::OpenFlags::F_None);
@@ -1204,33 +1451,44 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
       message(LDPL_FATAL, "Unable to open %s.thinlto.bc for writing: %s",
               output_name.data(), EC.message().c_str());
     WriteIndexToFile(CombinedIndex, OS);
-    OS.close();
+  }
 
-    if (options::thinlto_index_only) {
-      cleanup_hook();
-      exit(0);
-    }
+  thinLTOBackends(ApiFile, CombinedIndex, ModuleMap, ImportLists,
+                  ModuleToDefinedGVSummaries);
+  return LDPS_OK;
+}
 
-    thinLTOBackends(ApiFile, CombinedIndex);
+/// gold informs us that all symbols have been read. At this point, we use
+/// get_symbols to see if any of our definitions have been overridden by a
+/// native object file. Then, perform optimization and codegen.
+static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
+  if (Modules.empty())
     return LDPS_OK;
-  }
+
+  if (unsigned NumOpts = options::extra.size())
+    cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);
+
+  if (options::thinlto)
+    return thinLTOLink(ApiFile);
 
   LLVMContext Context;
+  Context.setDiscardValueNames(options::TheOutputType !=
+                               options::OT_SAVE_TEMPS);
+  Context.enableDebugTypeODRUniquing(); // Merge debug info types.
   Context.setDiagnosticHandler(diagnosticHandlerForContext, nullptr, true);
 
   std::unique_ptr Combined(new Module("ld-temp.o", Context));
   IRMover L(*Combined);
 
   StringSet<> Internalize;
-  StringSet<> Maybe;
   for (claimed_file &F : Modules) {
+    // RAII object to manage the file opening and releasing interfaces with
+    // gold.
     PluginInputFile InputFile(F.handle);
     const void *View = getSymbolsAndView(F);
     if (!View)
       continue;
-    if (linkInModule(Context, L, F, View, InputFile.file(), ApiFile,
-                     Internalize, Maybe))
-      message(LDPL_FATAL, "Failed to link module");
+    linkInModule(Context, L, F, View, F.name, ApiFile, Internalize);
   }
 
   for (const auto &Name : Internalize) {
@@ -1239,15 +1497,6 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
       internalize(*GV);
   }
 
-  for (const auto &Name : Maybe) {
-    GlobalValue *GV = Combined->getNamedValue(Name.first());
-    if (!GV)
-      continue;
-    GV->setLinkage(GlobalValue::LinkOnceODRLinkage);
-    if (canBeOmittedFromSymbolTable(GV))
-      internalize(*GV);
-  }
-
   if (options::TheOutputType == options::OT_DISABLE)
     return LDPS_OK;
 
diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp
index 55f458e6be3251e2903dc9abe880ba644884e847..f30dbd2a1c4e329f334321511cc66572d0cf2021 100644
--- a/tools/llc/llc.cpp
+++ b/tools/llc/llc.cpp
@@ -21,7 +21,12 @@
 #include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
 #include "llvm/CodeGen/LinkAllCodegenComponents.h"
 #include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
 #include "llvm/IR/IRPrintingPasses.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/LegacyPassManager.h"
@@ -68,6 +73,11 @@ static cl::opt
 NoIntegratedAssembler("no-integrated-as", cl::Hidden,
                       cl::desc("Disable integrated assembler"));
 
+static cl::opt
+    PreserveComments("preserve-as-comments", cl::Hidden,
+                     cl::desc("Preserve Comments in outputted assembly"),
+                     cl::init(true));
+
 // Determine optimization level.
 static cl::opt
 OptLevel("O",
@@ -108,6 +118,28 @@ static cl::opt DiscardValueNames(
     cl::desc("Discard names from Value (other than GlobalValue)."),
     cl::init(false), cl::Hidden);
 
+namespace {
+static ManagedStatic> RunPassNames;
+
+struct RunPassOption {
+  void operator=(const std::string &Val) const {
+    if (Val.empty())
+      return;
+    SmallVector PassNames;
+    StringRef(Val).split(PassNames, ',', -1, false);
+    for (auto PassName : PassNames)
+      RunPassNames->push_back(PassName);
+  }
+};
+}
+
+static RunPassOption RunPassOpt;
+
+static cl::opt> RunPass(
+    "run-pass",
+    cl::desc("Run compiler only for specified passes (comma separated list)"),
+    cl::value_desc("pass-name"), cl::ZeroOrMore, cl::location(RunPassOpt));
+
 static int compileModule(char **, LLVMContext &);
 
 static std::unique_ptr
@@ -178,16 +210,27 @@ GetOutputStream(const char *TargetName, Triple::OSType OS,
   return FDOut;
 }
 
+static void DiagnosticHandler(const DiagnosticInfo &DI, void *Context) {
+  bool *HasError = static_cast(Context);
+  if (DI.getSeverity() == DS_Error)
+    *HasError = true;
+
+  DiagnosticPrinterRawOStream DP(errs());
+  errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
+  DI.print(DP);
+  errs() << "\n";
+}
+
 // main - Entry point for the llc compiler.
 //
 int main(int argc, char **argv) {
-  sys::PrintStackTraceOnErrorSignal();
+  sys::PrintStackTraceOnErrorSignal(argv[0]);
   PrettyStackTraceProgram X(argc, argv);
 
   // Enable debug stream buffering.
   EnableDebugBuffering = true;
 
-  LLVMContext &Context = getGlobalContext();
+  LLVMContext Context;
   llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
 
   // Initialize targets first, so that --version shows registered targets.
@@ -203,7 +246,7 @@ int main(int argc, char **argv) {
   initializeCodeGen(*Registry);
   initializeLoopStrengthReducePass(*Registry);
   initializeLowerIntrinsicsPass(*Registry);
-  initializeUnreachableBlockElimPass(*Registry);
+  initializeUnreachableBlockElimLegacyPassPass(*Registry);
 
   // Register the target printer for --version.
   cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
@@ -212,6 +255,10 @@ int main(int argc, char **argv) {
 
   Context.setDiscardValueNames(DiscardValueNames);
 
+  // Set a diagnostic handler that doesn't exit on the first error
+  bool HasError = false;
+  Context.setDiagnosticHandler(DiagnosticHandler, &HasError);
+
   // Compile the module TimeCompilations times to give better compile time
   // metrics.
   for (unsigned I = TimeCompilations; I; --I)
@@ -234,10 +281,8 @@ static int compileModule(char **argv, LLVMContext &Context) {
   if (!SkipModule) {
     if (StringRef(InputFilename).endswith_lower(".mir")) {
       MIR = createMIRParserFromFile(InputFilename, Err, Context);
-      if (MIR) {
+      if (MIR)
         M = MIR->parseLLVMModule();
-        assert(M && "parseLLVMModule should exit on failure");
-      }
     } else
       M = parseIRFile(InputFilename, Err, Context);
     if (!M) {
@@ -292,10 +337,11 @@ static int compileModule(char **argv, LLVMContext &Context) {
   Options.MCOptions.ShowMCEncoding = ShowMCEncoding;
   Options.MCOptions.MCUseDwarfDirectory = EnableDwarfDirectory;
   Options.MCOptions.AsmVerbose = AsmVerbose;
+  Options.MCOptions.PreserveAsmComments = PreserveComments;
 
   std::unique_ptr Target(
       TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr, FeaturesStr,
-                                     Options, RelocModel, CMModel, OLvl));
+                                     Options, getRelocModel(), CMModel, OLvl));
 
   assert(Target && "Could not allocate target machine!");
 
@@ -355,18 +401,46 @@ static int compileModule(char **argv, LLVMContext &Context) {
     AnalysisID StartAfterID = nullptr;
     AnalysisID StopAfterID = nullptr;
     const PassRegistry *PR = PassRegistry::getPassRegistry();
-    if (!RunPass.empty()) {
+    if (!RunPassNames->empty()) {
       if (!StartAfter.empty() || !StopAfter.empty()) {
         errs() << argv[0] << ": start-after and/or stop-after passes are "
                              "redundant when run-pass is specified.\n";
         return 1;
       }
-      const PassInfo *PI = PR->getPassInfo(RunPass);
-      if (!PI) {
-        errs() << argv[0] << ": run-pass pass is not registered.\n";
+      if (!MIR) {
+        errs() << argv[0] << ": run-pass needs a .mir input.\n";
         return 1;
       }
-      StopAfterID = StartBeforeID = PI->getTypeInfo();
+      LLVMTargetMachine &LLVMTM = static_cast(*Target);
+      TargetPassConfig *TPC = LLVMTM.createPassConfig(PM);
+      PM.add(TPC);
+      LLVMTM.addMachineModuleInfo(PM);
+      LLVMTM.addMachineFunctionAnalysis(PM, MIR.get());
+      TPC->printAndVerify("");
+
+      for (std::string &RunPassName : *RunPassNames) {
+        const PassInfo *PI = PR->getPassInfo(RunPassName);
+        if (!PI) {
+          errs() << argv[0] << ": run-pass " << RunPassName << " is not registered.\n";
+          return 1;
+        }
+
+        Pass *P;
+        if (PI->getTargetMachineCtor())
+          P = PI->getTargetMachineCtor()(Target.get());
+        else if (PI->getNormalCtor())
+          P = PI->getNormalCtor()();
+        else {
+          errs() << argv[0] << ": cannot create pass: "
+                 << PI->getPassName() << "\n";
+          return 1;
+        }
+        std::string Banner
+          = std::string("After ") + std::string(P->getPassName());
+        PM.add(P);
+        TPC->printAndVerify(Banner);
+      }
+      PM.add(createPrintMIRPass(*OS));
     } else {
       if (!StartAfter.empty()) {
         const PassInfo *PI = PR->getPassInfo(StartAfter);
@@ -384,14 +458,15 @@ static int compileModule(char **argv, LLVMContext &Context) {
         }
         StopAfterID = PI->getTypeInfo();
       }
-    }
 
-    // Ask the target to add backend passes as necessary.
-    if (Target->addPassesToEmitFile(PM, *OS, FileType, NoVerify, StartBeforeID,
-                                    StartAfterID, StopAfterID, MIR.get())) {
-      errs() << argv[0] << ": target does not support generation of this"
-             << " file type!\n";
-      return 1;
+      // Ask the target to add backend passes as necessary.
+      if (Target->addPassesToEmitFile(PM, *OS, FileType, NoVerify,
+                                      StartBeforeID, StartAfterID, StopAfterID,
+                                      MIR.get())) {
+        errs() << argv[0] << ": target does not support generation of this"
+               << " file type!\n";
+        return 1;
+      }
     }
 
     // Before executing passes, print the final values of the LLVM options.
@@ -411,6 +486,10 @@ static int compileModule(char **argv, LLVMContext &Context) {
 
     PM.run(*M);
 
+    auto HasError = *static_cast(Context.getDiagnosticContext());
+    if (HasError)
+      return 1;
+
     // Compare the two outputs and make sure they're the same
     if (CompileTwice) {
       if (Buffer.size() != CompileTwiceBuffer.size() ||
diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt
index e317db6b713c92d5bc71bfcc3373ff791aae8f40..2bdd066eb7a62621ea1dd29368ef6c5f041f6280 100644
--- a/tools/lli/CMakeLists.txt
+++ b/tools/lli/CMakeLists.txt
@@ -1,4 +1,6 @@
-add_subdirectory(ChildTarget)
+if ( LLVM_INCLUDE_UTILS )
+  add_subdirectory(ChildTarget)
+endif()
 
 set(LLVM_LINK_COMPONENTS
   CodeGen
diff --git a/tools/lli/ChildTarget/CMakeLists.txt b/tools/lli/ChildTarget/CMakeLists.txt
index 0f851d593444df3ced971ade90aef712c6ac67a9..e4fe0c7197f24d542a2bfa4f0fe5e3268198f89b 100644
--- a/tools/lli/ChildTarget/CMakeLists.txt
+++ b/tools/lli/ChildTarget/CMakeLists.txt
@@ -4,8 +4,7 @@ set(LLVM_LINK_COMPONENTS
   Support
   )
 
-add_llvm_executable(lli-child-target
+add_llvm_utility(lli-child-target
   ChildTarget.cpp
 )
 
-set_target_properties(lli-child-target PROPERTIES FOLDER "Misc")
diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp
index 93925d6aa873f2ed779e30141c83387377a2e3e6..f6d2413655eacf3d470c5e9532c0e235cb916541 100644
--- a/tools/lli/ChildTarget/ChildTarget.cpp
+++ b/tools/lli/ChildTarget/ChildTarget.cpp
@@ -1,4 +1,4 @@
-#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
+#include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/DynamicLibrary.h"
@@ -12,11 +12,13 @@ using namespace llvm::orc;
 using namespace llvm::sys;
 
 #ifdef __x86_64__
-typedef OrcX86_64 HostOrcArch;
+typedef OrcX86_64_SysV HostOrcArch;
 #else
-typedef OrcGenericArchitecture HostOrcArch;
+typedef OrcGenericABI HostOrcArch;
 #endif
 
+ExitOnError ExitOnErr;
+
 int main(int argc, char *argv[]) {
 
   if (argc != 3) {
@@ -24,6 +26,8 @@ int main(int argc, char *argv[]) {
     return 1;
   }
 
+  ExitOnErr.setBanner(std::string(argv[0]) + ":");
+
   int InFD;
   int OutFD;
   {
@@ -54,19 +58,16 @@ int main(int argc, char *argv[]) {
   JITServer Server(Channel, SymbolLookup, RegisterEHFrames, DeregisterEHFrames);
 
   while (1) {
-    JITServer::JITProcId Id = JITServer::InvalidId;
-    if (auto EC = Server.getNextProcId(Id)) {
-      errs() << "Error: " << EC.message() << "\n";
-      return 1;
-    }
+    uint32_t RawId;
+    ExitOnErr(Server.startReceivingFunction(Channel, RawId));
+    auto Id = static_cast(RawId);
     switch (Id) {
     case JITServer::TerminateSessionId:
+      ExitOnErr(Server.handleTerminateSession());
       return 0;
     default:
-      if (auto EC = Server.handleKnownProcedure(Id)) {
-        errs() << "Error: " << EC.message() << "\n";
-        return 1;
-      }
+      ExitOnErr(Server.handleKnownFunction(Id));
+      break;
     }
   }
 
diff --git a/tools/lli/OrcLazyJIT.cpp b/tools/lli/OrcLazyJIT.cpp
index fee3c72d643278cda6418c943a9157cfdc3e848b..b13e7696627f0b6e7168ab138a35815d6d7e47b0 100644
--- a/tools/lli/OrcLazyJIT.cpp
+++ b/tools/lli/OrcLazyJIT.cpp
@@ -8,7 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "OrcLazyJIT.h"
-#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
+#include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/DynamicLibrary.h"
 #include 
@@ -46,42 +46,6 @@ namespace {
                                cl::init(true), cl::Hidden);
 }
 
-std::unique_ptr
-OrcLazyJIT::createCompileCallbackMgr(Triple T) {
-  switch (T.getArch()) {
-    default: return nullptr;
-
-    case Triple::x86: {
-      typedef orc::LocalJITCompileCallbackManager CCMgrT;
-      return llvm::make_unique(0);
-    }
-
-    case Triple::x86_64: {
-      typedef orc::LocalJITCompileCallbackManager CCMgrT;
-      return llvm::make_unique(0);
-    }
-  }
-}
-
-OrcLazyJIT::IndirectStubsManagerBuilder
-OrcLazyJIT::createIndirectStubsMgrBuilder(Triple T) {
-  switch (T.getArch()) {
-    default: return nullptr;
-
-    case Triple::x86:
-      return [](){
-        return llvm::make_unique<
-                       orc::LocalIndirectStubsManager>();
-      };
-
-    case Triple::x86_64:
-      return [](){
-        return llvm::make_unique<
-                       orc::LocalIndirectStubsManager>();
-      };
-  }
-}
-
 OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() {
 
   switch (OrcDumpKind) {
@@ -153,8 +117,8 @@ int llvm::runOrcLazyJIT(std::unique_ptr M, int ArgC, char* ArgV[]) {
   EngineBuilder EB;
   EB.setOptLevel(getOptLevel());
   auto TM = std::unique_ptr(EB.selectTarget());
-  auto CompileCallbackMgr =
-    OrcLazyJIT::createCompileCallbackMgr(Triple(TM->getTargetTriple()));
+  Triple T(TM->getTargetTriple());
+  auto CompileCallbackMgr = orc::createLocalCompileCallbackManager(T, 0);
 
   // If we couldn't build the factory function then there must not be a callback
   // manager for this target. Bail out.
@@ -164,8 +128,7 @@ int llvm::runOrcLazyJIT(std::unique_ptr M, int ArgC, char* ArgV[]) {
     return 1;
   }
 
-  auto IndirectStubsMgrBuilder =
-    OrcLazyJIT::createIndirectStubsMgrBuilder(Triple(TM->getTargetTriple()));
+  auto IndirectStubsMgrBuilder = orc::createLocalIndirectStubsManagerBuilder(T);
 
   // If we couldn't build a stubs-manager-builder for this target then bail out.
   if (!IndirectStubsMgrBuilder) {
@@ -192,3 +155,4 @@ int llvm::runOrcLazyJIT(std::unique_ptr M, int ArgC, char* ArgV[]) {
   auto Main = fromTargetAddress(MainSym.getAddress());
   return Main(ArgC, ArgV);
 }
+
diff --git a/tools/lli/OrcLazyJIT.h b/tools/lli/OrcLazyJIT.h
index 2a5b31d1bfb8e9810d11a08391bad8deef9d0e6d..733bdd8c04d5f124ced5312a464b40523ec5a9a2 100644
--- a/tools/lli/OrcLazyJIT.h
+++ b/tools/lli/OrcLazyJIT.h
@@ -62,9 +62,6 @@ public:
       DtorRunner.runViaLayer(CODLayer);
   }
 
-  static std::unique_ptr createCompileCallbackMgr(Triple T);
-  static IndirectStubsManagerBuilder createIndirectStubsMgrBuilder(Triple T);
-
   ModuleHandleT addModule(std::unique_ptr M) {
     // Attach a data-layout if one isn't already present.
     if (M->getDataLayout().isDefault())
@@ -82,12 +79,11 @@ public:
     //   1) Search the JIT symbols.
     //   2) Check for C++ runtime overrides.
     //   3) Search the host process (LLI)'s symbol table.
-    std::shared_ptr Resolver =
+    auto Resolver =
       orc::createLambdaResolver(
         [this](const std::string &Name) {
           if (auto Sym = CODLayer.findSymbol(Name, true))
-            return RuntimeDyld::SymbolInfo(Sym.getAddress(),
-                                           Sym.getFlags());
+            return Sym.toRuntimeDyldSymbol();
           if (auto Sym = CXXRuntimeOverrides.searchOverrides(Name))
             return Sym;
 
diff --git a/tools/lli/RemoteJITUtils.h b/tools/lli/RemoteJITUtils.h
index d5488ad555cace1e7b273016165846d50ce4bb63..15068d2faf6fd6379d66c8190ef0ed5e7011d86d 100644
--- a/tools/lli/RemoteJITUtils.h
+++ b/tools/lli/RemoteJITUtils.h
@@ -16,6 +16,7 @@
 
 #include "llvm/ExecutionEngine/Orc/RPCChannel.h"
 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
+#include 
 
 #if !defined(_MSC_VER) && !defined(__MINGW32__)
 #include 
@@ -28,23 +29,43 @@ class FDRPCChannel final : public llvm::orc::remote::RPCChannel {
 public:
   FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
 
-  std::error_code readBytes(char *Dst, unsigned Size) override {
+  llvm::Error readBytes(char *Dst, unsigned Size) override {
     assert(Dst && "Attempt to read into null.");
-    ssize_t ReadResult = ::read(InFD, Dst, Size);
-    if (ReadResult != (ssize_t)Size)
-      return std::error_code(errno, std::generic_category());
-    return std::error_code();
+    ssize_t Completed = 0;
+    while (Completed < static_cast(Size)) {
+      ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
+      if (Read <= 0) {
+        auto ErrNo = errno;
+        if (ErrNo == EAGAIN || ErrNo == EINTR)
+          continue;
+        else
+          return llvm::errorCodeToError(
+                   std::error_code(errno, std::generic_category()));
+      }
+      Completed += Read;
+    }
+    return llvm::Error::success();
   }
 
-  std::error_code appendBytes(const char *Src, unsigned Size) override {
+  llvm::Error appendBytes(const char *Src, unsigned Size) override {
     assert(Src && "Attempt to append from null.");
-    ssize_t WriteResult = ::write(OutFD, Src, Size);
-    if (WriteResult != (ssize_t)Size)
-      std::error_code(errno, std::generic_category());
-    return std::error_code();
+    ssize_t Completed = 0;
+    while (Completed < static_cast(Size)) {
+      ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
+      if (Written < 0) {
+        auto ErrNo = errno;
+        if (ErrNo == EAGAIN || ErrNo == EINTR)
+          continue;
+        else
+          return llvm::errorCodeToError(
+                   std::error_code(errno, std::generic_category()));
+      }
+      Completed += Written;
+    }
+    return llvm::Error::success();
   }
 
-  std::error_code send() override { return std::error_code(); }
+  llvm::Error send() override { return llvm::Error::success(); }
 
 private:
   int InFD, OutFD;
diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp
index 78b4941ca00f5b2b804bc06bbd9166e22720faa4..92de5da4721665d59690f6d3a7aa9f7943d47a9b 100644
--- a/tools/lli/lli.cpp
+++ b/tools/lli/lli.cpp
@@ -187,20 +187,15 @@ namespace {
                   cl::desc("Disable JIT lazy compilation"),
                   cl::init(false));
 
-  cl::opt
-  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 RelocModel(
+      "relocation-model", cl::desc("Choose relocation model"),
+      cl::values(
+          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
   CMModel("code-model",
@@ -235,6 +230,8 @@ namespace {
                      clEnumValN(FloatABI::Hard, "hard",
                                 "Hard float ABI (uses FP registers)"),
                      clEnumValEnd));
+
+  ExitOnError ExitOnErr;
 }
 
 //===----------------------------------------------------------------------===//
@@ -257,7 +254,7 @@ public:
   ~LLIObjectCache() override {}
 
   void notifyObjectCompiled(const Module *M, MemoryBufferRef Obj) override {
-    const std::string ModuleID = M->getModuleIdentifier();
+    const std::string &ModuleID = M->getModuleIdentifier();
     std::string CacheName;
     if (!getCacheFilename(ModuleID, CacheName))
       return;
@@ -272,7 +269,7 @@ public:
   }
 
   std::unique_ptr getObject(const Module* M) override {
-    const std::string ModuleID = M->getModuleIdentifier();
+    const std::string &ModuleID = M->getModuleIdentifier();
     std::string CacheName;
     if (!getCacheFilename(ModuleID, CacheName))
       return nullptr;
@@ -312,26 +309,12 @@ private:
   }
 };
 
-static ExecutionEngine *EE = nullptr;
-static LLIObjectCache *CacheManager = nullptr;
-
-static void do_shutdown() {
-  // Cygwin-1.5 invokes DLL's dtors before atexit handler.
-#ifndef DO_NOTHING_ATEXIT
-  delete EE;
-  if (CacheManager)
-    delete CacheManager;
-  llvm_shutdown();
-#endif
-}
-
 // On Mingw and Cygwin, an external symbol named '__main' is called from the
 // generated 'main' function to allow static intialization.  To avoid linking
 // problems with remote targets (because lli's remote target support does not
 // currently handle external linking) we add a secondary module which defines
 // an empty '__main' function.
-static void addCygMingExtraModule(ExecutionEngine *EE,
-                                  LLVMContext &Context,
+static void addCygMingExtraModule(ExecutionEngine &EE, LLVMContext &Context,
                                   StringRef TargetTripleStr) {
   IRBuilder<> Builder(Context);
   Triple TargetTriple(TargetTripleStr);
@@ -361,7 +344,7 @@ static void addCygMingExtraModule(ExecutionEngine *EE,
   Builder.CreateRet(ReturnVal);
 
   // Add this new module to the ExecutionEngine.
-  EE->addModule(std::move(M));
+  EE.addModule(std::move(M));
 }
 
 CodeGenOpt::Level getOptLevel() {
@@ -382,11 +365,13 @@ CodeGenOpt::Level getOptLevel() {
 // main Driver function
 //
 int main(int argc, char **argv, char * const *envp) {
-  sys::PrintStackTraceOnErrorSignal();
+  sys::PrintStackTraceOnErrorSignal(argv[0]);
   PrettyStackTraceProgram X(argc, argv);
 
-  LLVMContext &Context = getGlobalContext();
-  atexit(do_shutdown);  // Call llvm_shutdown() on exit.
+  atexit(llvm_shutdown); // Call llvm_shutdown() on exit.
+
+  if (argc > 1)
+    ExitOnErr.setBanner(std::string(argv[0]) + ": ");
 
   // If we have a native target, initialize it to ensure it is linked in and
   // usable by the JIT.
@@ -401,6 +386,8 @@ int main(int argc, char **argv, char * const *envp) {
   if (DisableCoreFiles)
     sys::Process::PreventCoreFiles();
 
+  LLVMContext Context;
+
   // Load the bitcode...
   SMDiagnostic Err;
   std::unique_ptr Owner = parseIRFile(InputFile, Err, Context);
@@ -433,7 +420,8 @@ int main(int argc, char **argv, char * const *envp) {
   builder.setMArch(MArch);
   builder.setMCPU(MCPU);
   builder.setMAttrs(MAttrs);
-  builder.setRelocationModel(RelocModel);
+  if (RelocModel.getNumOccurrences())
+    builder.setRelocationModel(RelocModel);
   builder.setCodeModel(CMModel);
   builder.setErrorStr(&ErrorMsg);
   builder.setEngineKind(ForceInterpreter
@@ -471,7 +459,7 @@ int main(int argc, char **argv, char * const *envp) {
 
   builder.setTargetOptions(Options);
 
-  EE = builder.create();
+  std::unique_ptr EE(builder.create());
   if (!EE) {
     if (!ErrorMsg.empty())
       errs() << argv[0] << ": error creating EE: " << ErrorMsg << "\n";
@@ -480,9 +468,10 @@ int main(int argc, char **argv, char * const *envp) {
     exit(1);
   }
 
+  std::unique_ptr CacheManager;
   if (EnableCacheManager) {
-    CacheManager = new LLIObjectCache(ObjectCacheDir);
-    EE->setObjectCache(CacheManager);
+    CacheManager.reset(new LLIObjectCache(ObjectCacheDir));
+    EE->setObjectCache(CacheManager.get());
   }
 
   // Load any additional modules specified on the command line.
@@ -501,9 +490,11 @@ int main(int argc, char **argv, char * const *envp) {
   }
 
   for (unsigned i = 0, e = ExtraObjects.size(); i != e; ++i) {
-    ErrorOr> Obj =
+    Expected> Obj =
         object::ObjectFile::createObjectFile(ExtraObjects[i]);
     if (!Obj) {
+      // TODO: Actually report errors helpfully.
+      consumeError(Obj.takeError());
       Err.print(argv[0], errs());
       return 1;
     }
@@ -520,10 +511,14 @@ int main(int argc, char **argv, char * const *envp) {
     }
     std::unique_ptr &ArBuf = ArBufOrErr.get();
 
-    ErrorOr> ArOrErr =
+    Expected> ArOrErr =
         object::Archive::create(ArBuf->getMemBufferRef());
-    if (std::error_code EC = ArOrErr.getError()) {
-      errs() << EC.message();
+    if (!ArOrErr) {
+      std::string Buf;
+      raw_string_ostream OS(Buf);
+      logAllUnhandledErrors(ArOrErr.takeError(), OS, "");
+      OS.flush();
+      errs() << Buf;
       return 1;
     }
     std::unique_ptr &Ar = ArOrErr.get();
@@ -536,7 +531,7 @@ int main(int argc, char **argv, char * const *envp) {
   // If the target is Cygwin/MingW and we are generating remote code, we
   // need an extra module to help out with linking.
   if (RemoteMCJIT && Triple(Mod->getTargetTriple()).isOSCygMing()) {
-    addCygMingExtraModule(EE, Context, Mod->getTargetTriple());
+    addCygMingExtraModule(*EE, Context, Mod->getTargetTriple());
   }
 
   // The following functions have no effect if their respective profiling
@@ -580,7 +575,7 @@ int main(int argc, char **argv, char * const *envp) {
   // Reset errno to zero on entry to main.
   errno = 0;
 
-  int Result;
+  int Result = -1;
 
   // Sanity check use of remote-jit: LLI currently only supports use of the
   // remote JIT on Unix platforms.
@@ -658,18 +653,11 @@ int main(int argc, char **argv, char * const *envp) {
 
     // Create a remote target client running over the channel.
     typedef orc::remote::OrcRemoteTargetClient MyRemote;
-    ErrorOr R = MyRemote::Create(*C);
-    if (!R) {
-      errs() << "Could not create remote: " << R.getError().message() << "\n";
-      exit(1);
-    }
+    MyRemote R = ExitOnErr(MyRemote::Create(*C));
 
     // Create a remote memory manager.
     std::unique_ptr RemoteMM;
-    if (auto EC = R->createRemoteMemoryManager(RemoteMM)) {
-      errs() << "Could not create remote memory manager: " << EC.message() << "\n";
-      exit(1);
-    }
+    ExitOnErr(R.createRemoteMemoryManager(RemoteMM));
 
     // Forward MCJIT's memory manager calls to the remote memory manager.
     static_cast(RTDyldMM)->setMemMgr(
@@ -678,15 +666,12 @@ int main(int argc, char **argv, char * const *envp) {
     // Forward MCJIT's symbol resolution calls to the remote.
     static_cast(RTDyldMM)->setResolver(
       orc::createLambdaResolver(
+        [](const std::string &Name) { return nullptr; },
         [&](const std::string &Name) {
-          orc::TargetAddress Addr = 0;
-          if (auto EC = R->getSymbolAddress(Addr, Name)) {
-            errs() << "Failure during symbol lookup: " << EC.message() << "\n";
-            exit(1);
-          }
-          return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported);
-        },
-        [](const std::string &Name) { return nullptr; }
+          if (auto Addr = ExitOnErr(R.getSymbolAddress(Name)))
+	    return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported);
+          return RuntimeDyld::SymbolInfo(nullptr);
+        }
       ));
 
     // Grab the target address of the JIT'd main function on the remote and call
@@ -696,8 +681,7 @@ int main(int argc, char **argv, char * const *envp) {
     EE->finalizeObject();
     DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x"
                  << format("%llx", Entry) << "\n");
-    if (auto EC = R->callIntVoid(Result, Entry))
-      errs() << "ERROR: " << EC.message() << "\n";
+    Result = ExitOnErr(R.callIntVoid(Entry));
 
     // Like static constructors, the remote target MCJIT support doesn't handle
     // this yet. It could. FIXME.
@@ -705,11 +689,10 @@ int main(int argc, char **argv, char * const *envp) {
     // Delete the EE - we need to tear it down *before* we terminate the session
     // with the remote, otherwise it'll crash when it tries to release resources
     // on a remote that has already been disconnected.
-    delete EE;
-    EE = nullptr;
+    EE.reset();
 
     // Signal the remote target that we're done JITing.
-    R->terminateSession();
+    ExitOnErr(R.terminateSession());
   }
 
   return Result;
diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp
index ef5fab68b9479fdff29375db7bf25130b4d786de..865152b6af831797465af43d983cc42227a1463b 100644
--- a/tools/llvm-ar/llvm-ar.cpp
+++ b/tools/llvm-ar/llvm-ar.cpp
@@ -19,6 +19,7 @@
 #include "llvm/LibDriver/LibDriver.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/MachO.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Errc.h"
@@ -64,12 +65,25 @@ static void failIfError(std::error_code EC, Twine Context = "") {
   fail(Context + ": " + EC.message());
 }
 
+static void failIfError(Error E, Twine Context = "") {
+  if (!E)
+    return;
+
+  handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) {
+    std::string ContextStr = Context.str();
+    if (ContextStr == "")
+      fail(EIB.message());
+    fail(Context + ": " + EIB.message());
+  });
+}
+
 // llvm-ar/llvm-ranlib remaining positional arguments.
 static cl::list
     RestOfArgs(cl::Positional, cl::ZeroOrMore,
                cl::desc("[relpos] [count]  [members]..."));
 
 static cl::opt MRI("M", cl::desc(""));
+static cl::opt Plugin("plugin", cl::desc("plugin (ignored for compatibility"));
 
 namespace {
 enum Format { Default, GNU, BSD };
@@ -77,7 +91,7 @@ enum Format { Default, GNU, BSD };
 
 static cl::opt
     FormatOpt("format", cl::desc("Archive format to create"),
-              cl::values(clEnumValN(Default, "defalut", "default"),
+              cl::values(clEnumValN(Default, "default", "default"),
                          clEnumValN(GNU, "gnu", "gnu"),
                          clEnumValN(BSD, "bsd", "bsd"), clEnumValEnd));
 
@@ -343,12 +357,9 @@ static void doDisplayTable(StringRef Name, const object::Archive::Child &C) {
 static void doExtract(StringRef Name, const object::Archive::Child &C) {
   // Retain the original mode.
   sys::fs::perms Mode = C.getAccessMode();
-  SmallString<128> Storage = Name;
 
   int FD;
-  failIfError(
-      sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_None, Mode),
-      Storage.c_str());
+  failIfError(sys::fs::openFileForWrite(Name, FD, sys::fs::F_None, Mode), Name);
 
   {
     raw_fd_ostream file(FD, false);
@@ -394,35 +405,37 @@ static void performReadOperation(ArchiveOperation Operation,
     fail("extracting from a thin archive is not supported");
 
   bool Filter = !Members.empty();
-  for (auto &ChildOrErr : OldArchive->children()) {
-    failIfError(ChildOrErr.getError());
-    const object::Archive::Child &C = *ChildOrErr;
-
-    ErrorOr NameOrErr = C.getName();
-    failIfError(NameOrErr.getError());
-    StringRef Name = NameOrErr.get();
-
-    if (Filter) {
-      auto I = std::find(Members.begin(), Members.end(), Name);
-      if (I == Members.end())
-        continue;
-      Members.erase(I);
-    }
+  {
+    Error Err;
+    for (auto &C : OldArchive->children(Err)) {
+      ErrorOr NameOrErr = C.getName();
+      failIfError(NameOrErr.getError());
+      StringRef Name = NameOrErr.get();
 
-    switch (Operation) {
-    default:
-      llvm_unreachable("Not a read operation");
-    case Print:
-      doPrint(Name, C);
-      break;
-    case DisplayTable:
-      doDisplayTable(Name, C);
-      break;
-    case Extract:
-      doExtract(Name, C);
-      break;
+      if (Filter) {
+        auto I = std::find(Members.begin(), Members.end(), Name);
+        if (I == Members.end())
+          continue;
+        Members.erase(I);
+      }
+
+      switch (Operation) {
+      default:
+        llvm_unreachable("Not a read operation");
+      case Print:
+        doPrint(Name, C);
+        break;
+      case DisplayTable:
+        doDisplayTable(Name, C);
+        break;
+      case Extract:
+        doExtract(Name, C);
+        break;
+      }
     }
+    failIfError(std::move(Err));
   }
+
   if (Members.empty())
     return;
   for (StringRef Name : Members)
@@ -430,25 +443,28 @@ static void performReadOperation(ArchiveOperation Operation,
   std::exit(1);
 }
 
-static void addMember(std::vector &Members,
+static void addMember(std::vector &Members,
                       StringRef FileName, int Pos = -1) {
-  NewArchiveIterator NI(FileName);
+  Expected NMOrErr =
+      NewArchiveMember::getFile(FileName, Deterministic);
+  failIfError(NMOrErr.takeError(), FileName);
   if (Pos == -1)
-    Members.push_back(NI);
+    Members.push_back(std::move(*NMOrErr));
   else
-    Members[Pos] = NI;
+    Members[Pos] = std::move(*NMOrErr);
 }
 
-static void addMember(std::vector &Members,
-                      const object::Archive::Child &M, StringRef Name,
-                      int Pos = -1) {
+static void addMember(std::vector &Members,
+                      const object::Archive::Child &M, int Pos = -1) {
   if (Thin && !M.getParent()->isThin())
     fail("Cannot convert a regular archive to a thin one");
-  NewArchiveIterator NI(M, Name);
+  Expected NMOrErr =
+      NewArchiveMember::getOldMember(M, Deterministic);
+  failIfError(NMOrErr.takeError());
   if (Pos == -1)
-    Members.push_back(NI);
+    Members.push_back(std::move(*NMOrErr));
   else
-    Members[Pos] = NI;
+    Members[Pos] = std::move(*NMOrErr);
 }
 
 enum InsertAction {
@@ -509,17 +525,16 @@ static InsertAction computeInsertAction(ArchiveOperation Operation,
 
 // We have to walk this twice and computing it is not trivial, so creating an
 // explicit std::vector is actually fairly efficient.
-static std::vector
+static std::vector
 computeNewArchiveMembers(ArchiveOperation Operation,
                          object::Archive *OldArchive) {
-  std::vector Ret;
-  std::vector Moved;
+  std::vector Ret;
+  std::vector Moved;
   int InsertPos = -1;
   StringRef PosName = sys::path::filename(RelPos);
   if (OldArchive) {
-    for (auto &ChildOrErr : OldArchive->children()) {
-      failIfError(ChildOrErr.getError());
-      auto &Child = ChildOrErr.get();
+    Error Err;
+    for (auto &Child : OldArchive->children(Err)) {
       int Pos = Ret.size();
       ErrorOr NameOrErr = Child.getName();
       failIfError(NameOrErr.getError());
@@ -537,7 +552,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
           computeInsertAction(Operation, Child, Name, MemberI);
       switch (Action) {
       case IA_AddOldMember:
-        addMember(Ret, Child, Name);
+        addMember(Ret, Child);
         break;
       case IA_AddNewMeber:
         addMember(Ret, *MemberI);
@@ -545,7 +560,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
       case IA_Delete:
         break;
       case IA_MoveOldMember:
-        addMember(Moved, Child, Name);
+        addMember(Moved, Child);
         break;
       case IA_MoveNewMember:
         addMember(Moved, *MemberI);
@@ -554,6 +569,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
       if (MemberI != Members.end())
         Members.erase(MemberI);
     }
+    failIfError(std::move(Err));
   }
 
   if (Operation == Delete)
@@ -566,10 +582,15 @@ computeNewArchiveMembers(ArchiveOperation Operation,
     InsertPos = Ret.size();
 
   assert(unsigned(InsertPos) <= Ret.size());
-  Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end());
-
-  Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator(""));
   int Pos = InsertPos;
+  for (auto &M : Moved) {
+    Ret.insert(Ret.begin() + Pos, std::move(M));
+    ++Pos;
+  }
+
+  for (unsigned I = 0; I != Members.size(); ++I)
+    Ret.insert(Ret.begin() + InsertPos, NewArchiveMember());
+  Pos = InsertPos;
   for (auto &Member : Members) {
     addMember(Ret, Member, Pos);
     ++Pos;
@@ -578,36 +599,61 @@ computeNewArchiveMembers(ArchiveOperation Operation,
   return Ret;
 }
 
+static object::Archive::Kind getDefaultForHost() {
+  return Triple(sys::getProcessTriple()).isOSDarwin() ? object::Archive::K_BSD
+                                                      : object::Archive::K_GNU;
+}
+
+static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
+  Expected> OptionalObject =
+      object::ObjectFile::createObjectFile(Member.Buf->getMemBufferRef());
+
+  if (OptionalObject)
+    return isa(**OptionalObject)
+               ? object::Archive::K_BSD
+               : object::Archive::K_GNU;
+
+  // squelch the error in case we had a non-object file
+  consumeError(OptionalObject.takeError());
+  return getDefaultForHost();
+}
+
 static void
-performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive,
-                      std::vector *NewMembersP) {
+performWriteOperation(ArchiveOperation Operation,
+                      object::Archive *OldArchive,
+                      std::unique_ptr OldArchiveBuf,
+                      std::vector *NewMembersP) {
+  std::vector NewMembers;
+  if (!NewMembersP)
+    NewMembers = computeNewArchiveMembers(Operation, OldArchive);
+
   object::Archive::Kind Kind;
   switch (FormatOpt) {
-  case Default: {
-    Triple T(sys::getProcessTriple());
-    if (T.isOSDarwin())
-      Kind = object::Archive::K_BSD;
-    else
+  case Default:
+    if (Thin)
       Kind = object::Archive::K_GNU;
+    else if (OldArchive)
+      Kind = OldArchive->kind();
+    else if (NewMembersP)
+      Kind = NewMembersP->size() ? getKindFromMember(NewMembersP->front())
+                                 : getDefaultForHost();
+    else
+      Kind = NewMembers.size() ? getKindFromMember(NewMembers.front())
+                               : getDefaultForHost();
     break;
-  }
   case GNU:
     Kind = object::Archive::K_GNU;
     break;
   case BSD:
+    if (Thin)
+      fail("Only the gnu format has a thin mode");
     Kind = object::Archive::K_BSD;
     break;
   }
-  if (NewMembersP) {
-    std::pair Result = writeArchive(
-        ArchiveName, *NewMembersP, Symtab, Kind, Deterministic, Thin);
-    failIfError(Result.second, Result.first);
-    return;
-  }
-  std::vector NewMembers =
-      computeNewArchiveMembers(Operation, OldArchive);
-  auto Result =
-      writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic, Thin);
+
+  std::pair Result =
+      writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab,
+                   Kind, Deterministic, Thin, std::move(OldArchiveBuf));
   failIfError(Result.second, Result.first);
 }
 
@@ -621,12 +667,13 @@ static void createSymbolTable(object::Archive *OldArchive) {
   if (OldArchive->hasSymbolTable())
     return;
 
-  performWriteOperation(CreateSymTab, OldArchive, nullptr);
+  performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr);
 }
 
 static void performOperation(ArchiveOperation Operation,
                              object::Archive *OldArchive,
-                             std::vector *NewMembers) {
+                             std::unique_ptr OldArchiveBuf,
+                             std::vector *NewMembers) {
   switch (Operation) {
   case Print:
   case DisplayTable:
@@ -638,7 +685,8 @@ static void performOperation(ArchiveOperation Operation,
   case Move:
   case QuickAppend:
   case ReplaceOrInsert:
-    performWriteOperation(Operation, OldArchive, NewMembers);
+    performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf),
+                          NewMembers);
     return;
   case CreateSymTab:
     createSymbolTable(OldArchive);
@@ -648,7 +696,7 @@ static void performOperation(ArchiveOperation Operation,
 }
 
 static int performOperation(ArchiveOperation Operation,
-                            std::vector *NewMembers) {
+                            std::vector *NewMembers) {
   // Create or open the archive object.
   ErrorOr> Buf =
       MemoryBuffer::getFile(ArchiveName, -1, false);
@@ -657,10 +705,12 @@ static int performOperation(ArchiveOperation Operation,
     fail("error opening '" + ArchiveName + "': " + EC.message() + "!");
 
   if (!EC) {
-    object::Archive Archive(Buf.get()->getMemBufferRef(), EC);
+    Error Err;
+    object::Archive Archive(Buf.get()->getMemBufferRef(), Err);
+    EC = errorToErrorCode(std::move(Err));
     failIfError(EC,
                 "error loading '" + ArchiveName + "': " + EC.message() + "!");
-    performOperation(Operation, &Archive, NewMembers);
+    performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers);
     return 0;
   }
 
@@ -675,7 +725,7 @@ static int performOperation(ArchiveOperation Operation,
     }
   }
 
-  performOperation(Operation, nullptr, NewMembers);
+  performOperation(Operation, nullptr, nullptr, NewMembers);
   return 0;
 }
 
@@ -686,7 +736,7 @@ static void runMRIScript() {
   failIfError(Buf.getError());
   const MemoryBuffer &Ref = *Buf.get();
   bool Saved = false;
-  std::vector NewMembers;
+  std::vector NewMembers;
   std::vector> ArchiveBuffers;
   std::vector> Archives;
 
@@ -712,15 +762,15 @@ static void runMRIScript() {
       ArchiveBuffers.push_back(std::move(*BufOrErr));
       auto LibOrErr =
           object::Archive::create(ArchiveBuffers.back()->getMemBufferRef());
-      failIfError(LibOrErr.getError(), "Could not parse library");
+      failIfError(errorToErrorCode(LibOrErr.takeError()),
+                  "Could not parse library");
       Archives.push_back(std::move(*LibOrErr));
       object::Archive &Lib = *Archives.back();
-      for (auto &MemberOrErr : Lib.children()) {
-        failIfError(MemberOrErr.getError());
-        auto &Member = MemberOrErr.get();
-        ErrorOr NameOrErr = Member.getName();
-        failIfError(NameOrErr.getError());
-        addMember(NewMembers, Member, *NameOrErr);
+      {
+        Error Err;
+        for (auto &Member : Lib.children(Err))
+          addMember(NewMembers, Member);
+        failIfError(std::move(Err));
       }
       break;
     }
@@ -760,7 +810,7 @@ static int ar_main() {
 
 static int ranlib_main() {
   if (RestOfArgs.size() != 1)
-    fail(ToolName + "takes just one archive as argument");
+    fail(ToolName + " takes just one archive as an argument");
   ArchiveName = RestOfArgs[0];
   return performOperation(CreateSymTab, nullptr);
 }
@@ -768,7 +818,7 @@ static int ranlib_main() {
 int main(int argc, char **argv) {
   ToolName = argv[0];
   // Print a stack trace if we signal out.
-  sys::PrintStackTraceOnErrorSignal();
+  sys::PrintStackTraceOnErrorSignal(argv[0]);
   PrettyStackTraceProgram X(argc, argv);
   llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
 
diff --git a/tools/llvm-as-fuzzer/llvm-as-fuzzer.cpp b/tools/llvm-as-fuzzer/llvm-as-fuzzer.cpp
index b4024bcaa99ae68908a6b62ad6d4afc7698a15c9..52deca6e9cd779581213ea65fe08dce2a7ac5071 100644
--- a/tools/llvm-as-fuzzer/llvm-as-fuzzer.cpp
+++ b/tools/llvm-as-fuzzer/llvm-as-fuzzer.cpp
@@ -53,7 +53,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   // parsed is always null terminated.
   std::unique_ptr MemBuf = MemoryBuffer::getMemBufferCopy(Input);
   SMDiagnostic Err;
-  LLVMContext &Context = getGlobalContext();
+  LLVMContext Context;
   std::unique_ptr M;
 
   if (setjmp(JmpBuf))
diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp
index 7318bfe341dd0546ce81f3de15ffd677073ef2fa..89a6ee5edfd890a394086200e2a933aeb225c942 100644
--- a/tools/llvm-as/llvm-as.cpp
+++ b/tools/llvm-as/llvm-as.cpp
@@ -15,9 +15,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/IR/LLVMContext.h"
 #include "llvm/AsmParser/Parser.h"
 #include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Verifier.h"
 #include "llvm/Support/CommandLine.h"
@@ -31,29 +31,28 @@
 #include 
 using namespace llvm;
 
-static cl::opt
-InputFilename(cl::Positional, cl::desc(""), cl::init("-"));
+static cl::opt InputFilename(cl::Positional,
+                                          cl::desc(""),
+                                          cl::init("-"));
 
-static cl::opt
-OutputFilename("o", cl::desc("Override output filename"),
-               cl::value_desc("filename"));
+static cl::opt OutputFilename("o",
+                                           cl::desc("Override output filename"),
+                                           cl::value_desc("filename"));
 
-static cl::opt
-Force("f", cl::desc("Enable binary output on terminals"));
+static cl::opt Force("f", cl::desc("Enable binary output on terminals"));
 
-static cl::opt
-DisableOutput("disable-output", cl::desc("Disable output"), cl::init(false));
+static cl::opt DisableOutput("disable-output", cl::desc("Disable output"),
+                                   cl::init(false));
 
-static cl::opt EmitSummaryIndex("module-summary",
-                                      cl::desc("Emit module summary index"),
-                                      cl::init(false));
+static cl::opt EmitModuleHash("module-hash", cl::desc("Emit module hash"),
+                                    cl::init(false));
 
-static cl::opt
-DumpAsm("d", cl::desc("Print assembly as parsed"), cl::Hidden);
+static cl::opt DumpAsm("d", cl::desc("Print assembly as parsed"),
+                             cl::Hidden);
 
 static cl::opt
-DisableVerify("disable-verify", cl::Hidden,
-              cl::desc("Do not run verifier on input LLVM (dangerous!)"));
+    DisableVerify("disable-verify", cl::Hidden,
+                  cl::desc("Do not run verifier on input LLVM (dangerous!)"));
 
 static cl::opt PreserveBitcodeUseListOrder(
     "preserve-bc-uselistorder",
@@ -81,8 +80,8 @@ static void WriteOutputFile(const Module *M) {
   }
 
   if (Force || !CheckBitcodeOutputToConsole(Out->os(), true))
-    WriteBitcodeToFile(M, Out->os(), PreserveBitcodeUseListOrder,
-                       EmitSummaryIndex);
+    WriteBitcodeToFile(M, Out->os(), PreserveBitcodeUseListOrder, nullptr,
+                       EmitModuleHash);
 
   // Declare success.
   Out->keep();
@@ -90,10 +89,10 @@ static void WriteOutputFile(const Module *M) {
 
 int main(int argc, char **argv) {
   // Print a stack trace if we signal out.
-  sys::PrintStackTraceOnErrorSignal();
+  sys::PrintStackTraceOnErrorSignal(argv[0]);
   PrettyStackTraceProgram X(argc, argv);
-  LLVMContext &Context = getGlobalContext();
-  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
+  LLVMContext Context;
+  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
   cl::ParseCommandLineOptions(argc, argv, "llvm .ll -> .bc assembler\n");
 
   // Parse the file now...
@@ -115,7 +114,8 @@ int main(int argc, char **argv) {
     }
   }
 
-  if (DumpAsm) errs() << "Here's the assembly:\n" << *M.get();
+  if (DumpAsm)
+    errs() << "Here's the assembly:\n" << *M.get();
 
   if (!DisableOutput)
     WriteOutputFile(M.get());
diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index 6645045db8fa458847f311de8054bfd8d03b0dc1..319e34d882dcc689ed036f063691b36948451521 100644
--- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -27,8 +27,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Bitcode/BitstreamReader.h"
-#include "llvm/ADT/Optional.h"
 #include "llvm/Bitcode/LLVMBitCodes.h"
 #include "llvm/Bitcode/ReaderWriter.h"
 #include "llvm/IR/Verifier.h"
@@ -37,6 +37,7 @@
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/SHA1.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -103,23 +104,24 @@ static const char *GetBlockName(unsigned BlockID,
   if (CurStreamType != LLVMIRBitstream) return nullptr;
 
   switch (BlockID) {
-  default:                             return nullptr;
-  case bitc::MODULE_BLOCK_ID:          return "MODULE_BLOCK";
-  case bitc::PARAMATTR_BLOCK_ID:       return "PARAMATTR_BLOCK";
-  case bitc::PARAMATTR_GROUP_BLOCK_ID: return "PARAMATTR_GROUP_BLOCK_ID";
-  case bitc::TYPE_BLOCK_ID_NEW:        return "TYPE_BLOCK_ID";
-  case bitc::CONSTANTS_BLOCK_ID:       return "CONSTANTS_BLOCK";
-  case bitc::FUNCTION_BLOCK_ID:        return "FUNCTION_BLOCK";
+  default:                                 return nullptr;
+  case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID: return "OPERAND_BUNDLE_TAGS_BLOCK";
+  case bitc::MODULE_BLOCK_ID:              return "MODULE_BLOCK";
+  case bitc::PARAMATTR_BLOCK_ID:           return "PARAMATTR_BLOCK";
+  case bitc::PARAMATTR_GROUP_BLOCK_ID:     return "PARAMATTR_GROUP_BLOCK_ID";
+  case bitc::TYPE_BLOCK_ID_NEW:            return "TYPE_BLOCK_ID";
+  case bitc::CONSTANTS_BLOCK_ID:           return "CONSTANTS_BLOCK";
+  case bitc::FUNCTION_BLOCK_ID:            return "FUNCTION_BLOCK";
   case bitc::IDENTIFICATION_BLOCK_ID:
-    return "IDENTIFICATION_BLOCK_ID";
-  case bitc::VALUE_SYMTAB_BLOCK_ID:    return "VALUE_SYMTAB";
-  case bitc::METADATA_BLOCK_ID:        return "METADATA_BLOCK";
-  case bitc::METADATA_KIND_BLOCK_ID:   return "METADATA_KIND_BLOCK";
-  case bitc::METADATA_ATTACHMENT_ID:   return "METADATA_ATTACHMENT_BLOCK";
-  case bitc::USELIST_BLOCK_ID:         return "USELIST_BLOCK_ID";
+                                           return "IDENTIFICATION_BLOCK_ID";
+  case bitc::VALUE_SYMTAB_BLOCK_ID:        return "VALUE_SYMTAB";
+  case bitc::METADATA_BLOCK_ID:            return "METADATA_BLOCK";
+  case bitc::METADATA_KIND_BLOCK_ID:       return "METADATA_KIND_BLOCK";
+  case bitc::METADATA_ATTACHMENT_ID:       return "METADATA_ATTACHMENT_BLOCK";
+  case bitc::USELIST_BLOCK_ID:             return "USELIST_BLOCK_ID";
   case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
-    return "GLOBALVAL_SUMMARY_BLOCK";
-  case bitc::MODULE_STRTAB_BLOCK_ID:   return "MODULE_STRTAB_BLOCK";
+                                           return "GLOBALVAL_SUMMARY_BLOCK";
+  case bitc::MODULE_STRTAB_BLOCK_ID:       return "MODULE_STRTAB_BLOCK";
   }
 }
 
@@ -174,6 +176,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
       STRINGIFY_CODE(MODULE_CODE, VSTOFFSET)
       STRINGIFY_CODE(MODULE_CODE, METADATA_VALUES_UNUSED)
       STRINGIFY_CODE(MODULE_CODE, SOURCE_FILENAME)
+      STRINGIFY_CODE(MODULE_CODE, HASH)
     }
   case bitc::IDENTIFICATION_BLOCK_ID:
     switch (CodeID) {
@@ -277,6 +280,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
       STRINGIFY_CODE(FUNC_CODE, INST_CALL)
       STRINGIFY_CODE(FUNC_CODE, DEBUG_LOC)
       STRINGIFY_CODE(FUNC_CODE, INST_GEP)
+      STRINGIFY_CODE(FUNC_CODE, OPERAND_BUNDLE)
     }
   case bitc::VALUE_SYMTAB_BLOCK_ID:
     switch (CodeID) {
@@ -284,7 +288,6 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
     STRINGIFY_CODE(VST_CODE, ENTRY)
     STRINGIFY_CODE(VST_CODE, BBENTRY)
     STRINGIFY_CODE(VST_CODE, FNENTRY)
-    STRINGIFY_CODE(VST_CODE, COMBINED_GVDEFENTRY)
     STRINGIFY_CODE(VST_CODE, COMBINED_ENTRY)
     }
   case bitc::MODULE_STRTAB_BLOCK_ID:
@@ -292,6 +295,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
     default:
       return nullptr;
       STRINGIFY_CODE(MST_CODE, ENTRY)
+      STRINGIFY_CODE(MST_CODE, HASH)
     }
   case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
     switch (CodeID) {
@@ -303,6 +307,10 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
       STRINGIFY_CODE(FS, COMBINED)
       STRINGIFY_CODE(FS, COMBINED_PROFILE)
       STRINGIFY_CODE(FS, COMBINED_GLOBALVAR_INIT_REFS)
+      STRINGIFY_CODE(FS, ALIAS)
+      STRINGIFY_CODE(FS, COMBINED_ALIAS)
+      STRINGIFY_CODE(FS, COMBINED_ORIGINAL_NAME)
+      STRINGIFY_CODE(FS, VERSION)
     }
   case bitc::METADATA_ATTACHMENT_ID:
     switch(CodeID) {
@@ -357,6 +365,12 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
     case bitc::USELIST_CODE_DEFAULT: return "USELIST_CODE_DEFAULT";
     case bitc::USELIST_CODE_BB:      return "USELIST_CODE_BB";
     }
+
+  case bitc::OPERAND_BUNDLE_TAGS_BLOCK_ID:
+    switch(CodeID) {
+    default: return nullptr;
+    case bitc::OPERAND_BUNDLE_TAG: return "OPERAND_BUNDLE_TAG";
+    }
   }
 #undef STRINGIFY_CODE
 }
@@ -481,6 +495,9 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
   if (Stream.EnterSubBlock(BlockID, &NumWords))
     return Error("Malformed block record");
 
+  // Keep it for later, when we see a MODULE_HASH record
+  uint64_t BlockEntryPos = Stream.getCurrentByteNo();
+
   const char *BlockName = nullptr;
   if (DumpRecords) {
     outs() << Indent << "<";
@@ -552,6 +569,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
     ++BlockStats.NumRecords;
 
     StringRef Blob;
+    unsigned CurrentRecordPos = Stream.getCurrentByteNo();
     unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob);
 
     // Increment the # occurrences of this code.
@@ -586,6 +604,37 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
       for (unsigned i = 0, e = Record.size(); i != e; ++i)
         outs() << " op" << i << "=" << (int64_t)Record[i];
 
+      // If we found a module hash, let's verify that it matches!
+      if (BlockID == bitc::MODULE_BLOCK_ID && Code == bitc::MODULE_CODE_HASH) {
+        if (Record.size() != 5)
+          outs() << " (invalid)";
+        else {
+          // Recompute the hash and compare it to the one in the bitcode
+          SHA1 Hasher;
+          StringRef Hash;
+          {
+            int BlockSize = CurrentRecordPos - BlockEntryPos;
+            auto Ptr = Stream.getPointerToByte(BlockEntryPos, BlockSize);
+            Hasher.update(ArrayRef(Ptr, BlockSize));
+            Hash = Hasher.result();
+          }
+          SmallString<20> RecordedHash;
+          RecordedHash.resize(20);
+          int Pos = 0;
+          for (auto &Val : Record) {
+            assert(!(Val >> 32) && "Unexpected high bits set");
+            RecordedHash[Pos++] = (Val >> 24) & 0xFF;
+            RecordedHash[Pos++] = (Val >> 16) & 0xFF;
+            RecordedHash[Pos++] = (Val >> 8) & 0xFF;
+            RecordedHash[Pos++] = (Val >> 0) & 0xFF;
+          }
+          if (Hash == RecordedHash)
+            outs() << " (match)";
+          else
+            outs() << " (!mismatch!)";
+        }
+      }
+
       outs() << "/>";
 
       if (Abbv) {
@@ -664,7 +713,7 @@ static bool openBitcodeFile(StringRef Path,
   // If we have a wrapper header, parse it and ignore the non-bc file contents.
   // The magic number is 0x0B17C0DE stored in little endian.
   if (isBitcodeWrapper(BufPtr, EndBufPtr)) {
-    if (EndBufPtr - BufPtr < BWH_HeaderSize)
+    if (MemBuf->getBufferSize() < BWH_HeaderSize)
       return Error("Invalid bitcode wrapper header");
 
     if (Dump) {
@@ -866,7 +915,7 @@ static int AnalyzeBitcode() {
 
 int main(int argc, char **argv) {
   // Print a stack trace if we signal out.
-  sys::PrintStackTraceOnErrorSignal();
+  sys::PrintStackTraceOnErrorSignal(argv[0]);
   PrettyStackTraceProgram X(argc, argv);
   llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
   cl::ParseCommandLineOptions(argc, argv, "llvm-bcanalyzer file analyzer\n");
diff --git a/tools/llvm-c-test/CMakeLists.txt b/tools/llvm-c-test/CMakeLists.txt
index 991e853f0b04c223ac6d17578cdf04b48df28099..858f2b07214a1bb22518ded45d04cc5ae8952564 100644
--- a/tools/llvm-c-test/CMakeLists.txt
+++ b/tools/llvm-c-test/CMakeLists.txt
@@ -37,6 +37,7 @@ endif ()
 
 add_llvm_tool(llvm-c-test
   calc.c
+  diagnostic.c
   disassemble.c
   echo.cpp
   helpers.c
diff --git a/tools/llvm-c-test/diagnostic.c b/tools/llvm-c-test/diagnostic.c
new file mode 100644
index 0000000000000000000000000000000000000000..16d5174732360c12db34560de73efa13fa376788
--- /dev/null
+++ b/tools/llvm-c-test/diagnostic.c
@@ -0,0 +1,89 @@
+//===-- diagnostic.cpp - tool for testing libLLVM and llvm-c API ----------===//
+//
+//                     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 --test-diagnostic-handler command in llvm-c-test.
+//
+// This command uses the C API to read a module with a custom diagnostic
+// handler set to test the diagnostic handler functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c-test.h"
+#include "llvm-c/BitReader.h"
+#include "llvm-c/Core.h"
+
+#include 
+
+static void diagnosticHandler(LLVMDiagnosticInfoRef DI, void *C) {
+  fprintf(stderr, "Executing diagnostic handler\n");
+
+  fprintf(stderr, "Diagnostic severity is of type ");
+  switch (LLVMGetDiagInfoSeverity(DI)) {
+  case LLVMDSError:
+    fprintf(stderr, "error");
+    break;
+  case LLVMDSWarning:
+    fprintf(stderr, "warning");
+    break;
+  case LLVMDSRemark:
+    fprintf(stderr, "remark");
+    break;
+  case LLVMDSNote:
+    fprintf(stderr, "note");
+    break;
+  }
+  fprintf(stderr, "\n");
+
+  (*(int *)C) = 1;
+}
+
+static int handlerCalled = 0;
+
+int llvm_test_diagnostic_handler(void) {
+  LLVMContextRef C = LLVMGetGlobalContext();
+  LLVMContextSetDiagnosticHandler(C, diagnosticHandler, &handlerCalled);
+
+  if (LLVMContextGetDiagnosticHandler(C) != diagnosticHandler) {
+    fprintf(stderr, "LLVMContext{Set,Get}DiagnosticHandler failed\n");
+    return 1;
+  }
+
+  int *DC = (int *)LLVMContextGetDiagnosticContext(C);
+  if (DC != &handlerCalled || *DC) {
+    fprintf(stderr, "LLVMContextGetDiagnosticContext failed\n");
+    return 1;
+  }
+
+  LLVMMemoryBufferRef MB;
+  char *msg = NULL;
+  if (LLVMCreateMemoryBufferWithSTDIN(&MB, &msg)) {
+    fprintf(stderr, "Error reading file: %s\n", msg);
+    LLVMDisposeMessage(msg);
+    return 1;
+  }
+
+
+  LLVMModuleRef M;
+  int Ret = LLVMGetBitcodeModule2(MB, &M);
+  if (Ret) {
+    // We do not return if the bitcode was invalid, as we want to test whether
+    // the diagnostic handler was executed.
+    fprintf(stderr, "Error parsing bitcode: %s\n", msg);
+  }
+
+  LLVMDisposeMemoryBuffer(MB);
+
+  if (handlerCalled) {
+    fprintf(stderr, "Diagnostic handler was called while loading module\n");
+  } else {
+    fprintf(stderr, "Diagnostic handler was not called while loading module\n");
+  }
+
+  return 0;
+}
diff --git a/tools/llvm-c-test/echo.cpp b/tools/llvm-c-test/echo.cpp
index 5a2102a15794ccc03fd8ea2a3a1d7200eeb184f2..72ff138c74e325d16ce648909f519ea3a9ca19b0 100644
--- a/tools/llvm-c-test/echo.cpp
+++ b/tools/llvm-c-test/echo.cpp
@@ -7,7 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements the --echo commands in llvm-c-test.
+// This file implements the --echo command in llvm-c-test.
 //
 // This command uses the C API to read a module and output an exact copy of it
 // as output. It is used to check that the resulting module matches the input
@@ -212,7 +212,20 @@ static ValueMap clone_params(LLVMValueRef Src, LLVMValueRef Dst) {
   return VMap;
 }
 
-LLVMValueRef clone_constant(LLVMValueRef Cst, LLVMModuleRef M) {
+static void check_value_kind(LLVMValueRef V, LLVMValueKind K) {
+  if (LLVMGetValueKind(V) != K)
+    report_fatal_error("LLVMGetValueKind returned incorrect type");
+}
+
+static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M);
+
+static LLVMValueRef clone_constant(LLVMValueRef Cst, LLVMModuleRef M) {
+  LLVMValueRef Ret = clone_constant_impl(Cst, M);
+  check_value_kind(Ret, LLVMGetValueKind(Cst));
+  return Ret;
+}
+
+static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) {
   if (!LLVMIsAConstant(Cst))
     report_fatal_error("Expected a constant");
 
@@ -222,6 +235,7 @@ LLVMValueRef clone_constant(LLVMValueRef Cst, LLVMModuleRef M) {
 
     // Try function
     if (LLVMIsAFunction(Cst)) {
+      check_value_kind(Cst, LLVMFunctionValueKind);
       LLVMValueRef Dst = LLVMGetNamedFunction(M, Name);
       if (Dst)
         return Dst;
@@ -230,7 +244,8 @@ LLVMValueRef clone_constant(LLVMValueRef Cst, LLVMModuleRef M) {
 
     // Try global variable
     if (LLVMIsAGlobalVariable(Cst)) {
-      LLVMValueRef Dst = LLVMGetNamedGlobal(M, Name);
+      check_value_kind(Cst, LLVMGlobalVariableValueKind);
+      LLVMValueRef Dst  = LLVMGetNamedGlobal(M, Name);
       if (Dst)
         return Dst;
       report_fatal_error("Could not find function");
@@ -241,16 +256,21 @@ LLVMValueRef clone_constant(LLVMValueRef Cst, LLVMModuleRef M) {
   }
 
   // Try integer literal
-  if (LLVMIsAConstantInt(Cst))
+  if (LLVMIsAConstantInt(Cst)) {
+    check_value_kind(Cst, LLVMConstantIntValueKind);
     return LLVMConstInt(TypeCloner(M).Clone(Cst),
                         LLVMConstIntGetZExtValue(Cst), false);
+  }
 
   // Try zeroinitializer
-  if (LLVMIsAConstantAggregateZero(Cst))
+  if (LLVMIsAConstantAggregateZero(Cst)) {
+    check_value_kind(Cst, LLVMConstantAggregateZeroValueKind);
     return LLVMConstNull(TypeCloner(M).Clone(Cst));
+  }
 
   // Try constant array
   if (LLVMIsAConstantArray(Cst)) {
+    check_value_kind(Cst, LLVMConstantArrayValueKind);
     LLVMTypeRef Ty = TypeCloner(M).Clone(Cst);
     unsigned EltCount = LLVMGetArrayLength(Ty);
     SmallVector Elts;
@@ -261,6 +281,7 @@ LLVMValueRef clone_constant(LLVMValueRef Cst, LLVMModuleRef M) {
 
   // Try contant data array
   if (LLVMIsAConstantDataArray(Cst)) {
+    check_value_kind(Cst, LLVMConstantDataArrayValueKind);
     LLVMTypeRef Ty = TypeCloner(M).Clone(Cst);
     unsigned EltCount = LLVMGetArrayLength(Ty);
     SmallVector Elts;
@@ -271,6 +292,7 @@ LLVMValueRef clone_constant(LLVMValueRef Cst, LLVMModuleRef M) {
 
   // Try constant struct
   if (LLVMIsAConstantStruct(Cst)) {
+    check_value_kind(Cst, LLVMConstantStructValueKind);
     LLVMTypeRef Ty = TypeCloner(M).Clone(Cst);
     unsigned EltCount = LLVMCountStructElementTypes(Ty);
     SmallVector Elts;
@@ -283,18 +305,24 @@ LLVMValueRef clone_constant(LLVMValueRef Cst, LLVMModuleRef M) {
   }
 
   // Try undef
-  if (LLVMIsUndef(Cst))
+  if (LLVMIsUndef(Cst)) {
+    check_value_kind(Cst, LLVMUndefValueValueKind);
     return LLVMGetUndef(TypeCloner(M).Clone(Cst));
+  }
 
   // Try float literal
-  if (LLVMIsAConstantFP(Cst))
+  if (LLVMIsAConstantFP(Cst)) {
+    check_value_kind(Cst, LLVMConstantFPValueKind);
     report_fatal_error("ConstantFP is not supported");
+  }
 
   // This kind of constant is not supported
   if (!LLVMIsAConstantExpr(Cst))
     report_fatal_error("Expected a constant expression");
 
   // At this point, it must be a constant expression
+  check_value_kind(Cst, LLVMConstantExprValueKind);
+
   LLVMOpcode Op = LLVMGetConstOpcode(Cst);
   switch(Op) {
     case LLVMBitCast:
@@ -347,11 +375,27 @@ struct FunCloner {
     return Dst;
   }
 
+  void CloneAttrs(LLVMValueRef Src, LLVMValueRef Dst) {
+    auto Ctx = LLVMGetModuleContext(M);
+    int ArgCount = LLVMGetNumArgOperands(Src);
+    for (int i = LLVMAttributeReturnIndex; i <= ArgCount; i++) {
+      for (unsigned k = 0, e = LLVMGetLastEnumAttributeKind(); k < e; ++k) {
+        if (auto SrcA = LLVMGetCallSiteEnumAttribute(Src, i, k)) {
+          auto Val = LLVMGetEnumAttributeValue(SrcA);
+          auto A = LLVMCreateEnumAttribute(Ctx, k, Val);
+          LLVMAddCallSiteAttribute(Dst, i, A);
+        }
+      }
+    }
+  }
+
   LLVMValueRef CloneInstruction(LLVMValueRef Src, LLVMBuilderRef Builder) {
-    const char *Name = LLVMGetValueName(Src);
+    check_value_kind(Src, LLVMInstructionValueKind);
     if (!LLVMIsAInstruction(Src))
       report_fatal_error("Expected an instruction");
 
+    const char *Name = LLVMGetValueName(Src);
+
     // Check if this is something we already computed.
     {
       auto i = VMap.find(Src);
@@ -409,6 +453,7 @@ struct FunCloner {
         LLVMBasicBlockRef Unwind = DeclareBB(LLVMGetUnwindDest(Src));
         Dst = LLVMBuildInvoke(Builder, Fn, Args.data(), ArgCount,
                               Then, Unwind, Name);
+        CloneAttrs(Src, Dst);
         break;
       }
       case LLVMUnreachable:
@@ -569,6 +614,7 @@ struct FunCloner {
         LLVMValueRef Fn = CloneValue(LLVMGetCalledValue(Src));
         Dst = LLVMBuildCall(Builder, Fn, Args.data(), ArgCount, Name);
         LLVMSetTailCall(Dst, LLVMIsTailCall(Src));
+        CloneAttrs(Src, Dst);
         break;
       }
       case LLVMResume: {
@@ -610,6 +656,7 @@ struct FunCloner {
       exit(-1);
     }
 
+    check_value_kind(Dst, LLVMInstructionValueKind);
     return VMap[Src] = Dst;
   }
 
@@ -751,13 +798,28 @@ FunDecl:
     return;
   }
 
+  auto Ctx = LLVMGetModuleContext(M);
+
   Cur = Begin;
   Next = nullptr;
   while (true) {
     const char *Name = LLVMGetValueName(Cur);
     if (LLVMGetNamedFunction(M, Name))
       report_fatal_error("Function already cloned");
-    LLVMAddFunction(M, Name, LLVMGetElementType(TypeCloner(M).Clone(Cur)));
+    auto Ty = LLVMGetElementType(TypeCloner(M).Clone(Cur));
+    auto F = LLVMAddFunction(M, Name, Ty);
+
+    // Copy attributes
+    for (int i = LLVMAttributeFunctionIndex, c = LLVMCountParams(F);
+         i <= c; ++i) {
+      for (unsigned k = 0, e = LLVMGetLastEnumAttributeKind(); k < e; ++k) {
+        if (auto SrcA = LLVMGetEnumAttributeAtIndex(Cur, i, k)) {
+          auto Val = LLVMGetEnumAttributeValue(SrcA);
+          auto DstA = LLVMCreateEnumAttribute(Ctx, k, Val);
+          LLVMAddAttributeAtIndex(F, i, DstA);
+        }
+      }
+    }
 
     Next = LLVMGetNextFunction(Cur);
     if (Next == nullptr) {
@@ -865,9 +927,18 @@ int llvm_echo(void) {
   LLVMEnablePrettyStackTrace();
 
   LLVMModuleRef Src = llvm_load_module(false, true);
-
+  size_t Len;
+  const char *ModuleName = LLVMGetModuleIdentifier(Src, &Len);
   LLVMContextRef Ctx = LLVMContextCreate();
-  LLVMModuleRef M = LLVMModuleCreateWithNameInContext("", Ctx);
+  LLVMModuleRef M = LLVMModuleCreateWithNameInContext(ModuleName, Ctx);
+
+  // This whole switcharound is done because the C API has no way to
+  // set the source_filename
+  LLVMSetModuleIdentifier(M, "", 0);
+  LLVMGetModuleIdentifier(M, &Len);
+  if (Len != 0)
+      report_fatal_error("LLVM{Set,Get}ModuleIdentifier failed");
+  LLVMSetModuleIdentifier(M, ModuleName, strlen(ModuleName));
 
   LLVMSetTarget(M, LLVMGetTarget(Src));
   LLVMSetModuleDataLayout(M, LLVMGetModuleDataLayout(Src));
diff --git a/tools/llvm-c-test/llvm-c-test.h b/tools/llvm-c-test/llvm-c-test.h
index 60edc0df4d17d7804453e1726d48dfaac3a08264..0d1ade093bc7f190d872546ed0adc71f05330e95 100644
--- a/tools/llvm-c-test/llvm-c-test.h
+++ b/tools/llvm-c-test/llvm-c-test.h
@@ -49,6 +49,9 @@ int llvm_targets_list(void);
 // echo.c
 int llvm_echo(void);
 
+// diagnostic.c
+int llvm_test_diagnostic_handler(void);
+
 #ifdef __cplusplus
 }
 #endif /* !defined(__cplusplus) */
diff --git a/tools/llvm-c-test/main.c b/tools/llvm-c-test/main.c
index ec09467d85bc83605aba48da39dcb1f01bd5fdc6..90d3501778516b1f3182beb8b750ef912addb1d5 100644
--- a/tools/llvm-c-test/main.c
+++ b/tools/llvm-c-test/main.c
@@ -21,20 +21,20 @@ static void print_usage(void) {
   fprintf(stderr, "llvm-c-test command\n\n");
   fprintf(stderr, " Commands:\n");
   fprintf(stderr, "  * --module-dump\n");
-  fprintf(stderr, "    Read bytecode from stdin - print disassembly\n\n");
+  fprintf(stderr, "    Read bitcode from stdin - print disassembly\n\n");
   fprintf(stderr, "  * --lazy-module-dump\n");
   fprintf(stderr,
-          "    Lazily read bytecode from stdin - print disassembly\n\n");
+          "    Lazily read bitcode from stdin - print disassembly\n\n");
   fprintf(stderr, "  * --new-module-dump\n");
-  fprintf(stderr, "    Read bytecode from stdin - print disassembly\n\n");
+  fprintf(stderr, "    Read bitcode from stdin - print disassembly\n\n");
   fprintf(stderr, "  * --lazy-new-module-dump\n");
   fprintf(stderr,
-          "    Lazily read bytecode from stdin - print disassembly\n\n");
+          "    Lazily read bitcode from stdin - print disassembly\n\n");
   fprintf(stderr, "  * --module-list-functions\n");
   fprintf(stderr,
-          "    Read bytecode from stdin - list summary of functions\n\n");
+          "    Read bitcode from stdin - list summary of functions\n\n");
   fprintf(stderr, "  * --module-list-globals\n");
-  fprintf(stderr, "    Read bytecode from stdin - list summary of globals\n\n");
+  fprintf(stderr, "    Read bitcode from stdin - list summary of globals\n\n");
   fprintf(stderr, "  * --targets-list\n");
   fprintf(stderr, "    List available targets\n\n");
   fprintf(stderr, "  * --object-list-sections\n");
@@ -46,12 +46,15 @@ static void print_usage(void) {
   fprintf(stderr, "    Read lines of triple, hex ascii machine code from stdin "
                   "- print disassembly\n\n");
   fprintf(stderr, "  * --calc\n");
-  fprintf(stderr, "  * --echo\n");
-  fprintf(stderr,
-          "    Read object file form stdin - and print it back out\n\n");
   fprintf(
       stderr,
       "    Read lines of name, rpn from stdin - print generated module\n\n");
+  fprintf(stderr, "  * --echo\n");
+  fprintf(stderr,
+          "    Read bitcode file form stdin - print it back out\n\n");
+  fprintf(stderr, "  * --test-diagnostic-handler\n");
+  fprintf(stderr,
+          "    Read bitcode file form stdin with a diagnostic handler set\n\n");
 }
 
 int main(int argc, char **argv) {
@@ -87,6 +90,8 @@ int main(int argc, char **argv) {
     return llvm_set_metadata();
   } else if (argc == 2 && !strcmp(argv[1], "--echo")) {
     return llvm_echo();
+  } else if (argc == 2 && !strcmp(argv[1], "--test-diagnostic-handler")) {
+    return llvm_test_diagnostic_handler();
   } else {
     print_usage();
   }
diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt
index 32d0f4c6bd6a31d868c65b5a9b5396c21aedcee4..d45877135ba2ab8d0b886f000215575572881add 100644
--- a/tools/llvm-config/CMakeLists.txt
+++ b/tools/llvm-config/CMakeLists.txt
@@ -14,7 +14,13 @@ foreach(l ${LLVM_SYSTEM_LIBS_LIST})
   if(MSVC)
     set(SYSTEM_LIBS ${SYSTEM_LIBS} "${l}.lib")
   else()
-    set(SYSTEM_LIBS ${SYSTEM_LIBS} "-l${l}")
+    if (l MATCHES "^-")
+      # If it's an option, pass it without changes.
+      set(SYSTEM_LIBS ${SYSTEM_LIBS} "${l}")
+    else()
+      # Otherwise assume it's a library name we need to link with.
+      set(SYSTEM_LIBS ${SYSTEM_LIBS} "-l${l}")
+    endif()
   endif()
 endforeach()
 string(REPLACE ";" " " SYSTEM_LIBS "${SYSTEM_LIBS}")
diff --git a/tools/llvm-cov/CMakeLists.txt b/tools/llvm-cov/CMakeLists.txt
index 193218a6639f22d1b0ce1a0f13e7396577d3b573..e22828e11effe6bd9d6ab29499a9224844776347 100644
--- a/tools/llvm-cov/CMakeLists.txt
+++ b/tools/llvm-cov/CMakeLists.txt
@@ -1,4 +1,4 @@
-set(LLVM_LINK_COMPONENTS core support object profiledata)
+set(LLVM_LINK_COMPONENTS core support object coverage profiledata)
 
 add_llvm_tool(llvm-cov
   llvm-cov.cpp
@@ -8,5 +8,7 @@ add_llvm_tool(llvm-cov
   CoverageReport.cpp
   CoverageSummaryInfo.cpp
   SourceCoverageView.cpp
+  SourceCoverageViewHTML.cpp
+  SourceCoverageViewText.cpp
   TestingSupport.cpp
   )
diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp
index 8dc4d665f23ca62784c959895e7c3f93cbc63d94..693c80249204345da63ef738189cc886f7725057 100644
--- a/tools/llvm-cov/CodeCoverage.cpp
+++ b/tools/llvm-cov/CodeCoverage.cpp
@@ -13,24 +13,22 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "RenderingSupport.h"
 #include "CoverageFilters.h"
 #include "CoverageReport.h"
 #include "CoverageViewOptions.h"
+#include "RenderingSupport.h"
 #include "SourceCoverageView.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Triple.h"
-#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
-#include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
 #include "llvm/Support/Process.h"
-#include "llvm/Support/Signals.h"
+#include "llvm/Support/ThreadPool.h"
 #include 
 #include 
 
@@ -51,6 +49,18 @@ public:
   /// \brief Print the error message to the error output stream.
   void error(const Twine &Message, StringRef Whence = "");
 
+  /// \brief Record (but do not print) an error message in a thread-safe way.
+  void deferError(const Twine &Message, StringRef Whence = "");
+
+  /// \brief Record (but do not print) a warning message in a thread-safe way.
+  void deferWarning(const Twine &Message, StringRef Whence = "");
+
+  /// \brief Print (and then clear) all deferred error and warning messages.
+  void consumeDeferredMessages();
+
+  /// \brief Append a reference to a private copy of \p Path into SourceFiles.
+  void addCollectedPath(const std::string &Path);
+
   /// \brief Return a memory buffer for the given source file.
   ErrorOr getSourceFile(StringRef SourceFile);
 
@@ -72,7 +82,7 @@ public:
 
   int run(Command Cmd, int argc, const char **argv);
 
-  typedef std::function CommandLineParserType;
+  typedef llvm::function_ref CommandLineParserType;
 
   int show(int argc, const char **argv,
            CommandLineParserType commandLineParser);
@@ -84,20 +94,57 @@ public:
   CoverageViewOptions ViewOpts;
   std::string PGOFilename;
   CoverageFiltersMatchAll Filters;
-  std::vector SourceFiles;
-  std::vector>>
-      LoadedSourceFiles;
+  std::vector SourceFiles;
   bool CompareFilenamesOnly;
   StringMap RemappedFilenames;
   std::string CoverageArch;
+
+private:
+  std::vector CollectedPaths;
+
+  std::mutex DeferredMessagesLock;
+  std::vector DeferredMessages;
+
+  std::mutex LoadedSourceFilesLock;
+  std::vector>>
+      LoadedSourceFiles;
 };
 }
 
-void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
-  errs() << "error: ";
+static std::string getErrorString(const Twine &Message, StringRef Whence,
+                                  bool Warning) {
+  std::string Str = (Warning ? "warning" : "error");
+  Str += ": ";
   if (!Whence.empty())
-    errs() << Whence << ": ";
-  errs() << Message << "\n";
+    Str += Whence;
+  Str += Message.str() + "\n";
+  return Str;
+}
+
+void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
+  errs() << getErrorString(Message, Whence, false);
+}
+
+void CodeCoverageTool::deferError(const Twine &Message, StringRef Whence) {
+  std::unique_lock Guard{DeferredMessagesLock};
+  DeferredMessages.emplace_back(getErrorString(Message, Whence, false));
+}
+
+void CodeCoverageTool::deferWarning(const Twine &Message, StringRef Whence) {
+  std::unique_lock Guard{DeferredMessagesLock};
+  DeferredMessages.emplace_back(getErrorString(Message, Whence, true));
+}
+
+void CodeCoverageTool::consumeDeferredMessages() {
+  std::unique_lock Guard{DeferredMessagesLock};
+  for (const std::string &Message : DeferredMessages)
+    ViewOpts.colored_ostream(errs(), raw_ostream::RED) << Message;
+  DeferredMessages.clear();
+}
+
+void CodeCoverageTool::addCollectedPath(const std::string &Path) {
+  CollectedPaths.push_back(Path);
+  SourceFiles.emplace_back(CollectedPaths.back());
 }
 
 ErrorOr
@@ -113,9 +160,10 @@ CodeCoverageTool::getSourceFile(StringRef SourceFile) {
       return *Files.second;
   auto Buffer = MemoryBuffer::getFile(SourceFile);
   if (auto EC = Buffer.getError()) {
-    error(EC.message(), SourceFile);
+    deferError(EC.message(), SourceFile);
     return EC;
   }
+  std::unique_lock Guard{LoadedSourceFilesLock};
   LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get()));
   return *LoadedSourceFiles.back().second;
 }
@@ -135,8 +183,9 @@ CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View,
       continue;
 
     auto SubViewExpansions = ExpansionCoverage.getExpansions();
-    auto SubView = llvm::make_unique(
-        SourceBuffer.get(), ViewOpts, std::move(ExpansionCoverage));
+    auto SubView =
+        SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
+                                   ViewOpts, std::move(ExpansionCoverage));
     attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
     View.addExpansion(Expansion.Region, std::move(SubView));
   }
@@ -153,8 +202,8 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
     return nullptr;
 
   auto Expansions = FunctionCoverage.getExpansions();
-  auto View = llvm::make_unique(
-      SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage));
+  auto View = SourceCoverageView::create(Function.Name, SourceBuffer.get(),
+                                         ViewOpts, std::move(FunctionCoverage));
   attachExpansionSubViews(*View, Expansions, Coverage);
 
   return View;
@@ -171,15 +220,16 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
     return nullptr;
 
   auto Expansions = FileCoverage.getExpansions();
-  auto View = llvm::make_unique(
-      SourceBuffer.get(), ViewOpts, std::move(FileCoverage));
+  auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
+                                         ViewOpts, std::move(FileCoverage));
   attachExpansionSubViews(*View, Expansions, Coverage);
 
   for (auto Function : Coverage.getInstantiations(SourceFile)) {
     auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
     auto SubViewExpansions = SubViewCoverage.getExpansions();
-    auto SubView = llvm::make_unique(
-        SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
+    auto SubView =
+        SourceCoverageView::create(Function->Name, SourceBuffer.get(), ViewOpts,
+                                   std::move(SubViewCoverage));
     attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
 
     if (SubView) {
@@ -210,10 +260,9 @@ std::unique_ptr CodeCoverageTool::load() {
     errs() << "warning: profile data may be out of date - object is newer\n";
   auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename,
                                              CoverageArch);
-  if (std::error_code EC = CoverageOrErr.getError()) {
+  if (Error E = CoverageOrErr.takeError()) {
     colored_ostream(errs(), raw_ostream::RED)
-        << "error: Failed to load coverage: " << EC.message();
-    errs() << "\n";
+        << "error: Failed to load coverage: " << toString(std::move(E)) << "\n";
     return nullptr;
   }
   auto Coverage = std::move(CoverageOrErr.get());
@@ -241,11 +290,6 @@ std::unique_ptr CodeCoverageTool::load() {
 }
 
 int CodeCoverageTool::run(Command Cmd, int argc, const 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::opt ObjectFilename(
       cl::Positional, cl::Required, cl::location(this->ObjectFilename),
       cl::desc("Covered executable or object file."));
@@ -264,6 +308,15 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
   cl::opt DebugDump("dump", cl::Optional,
                           cl::desc("Show internal debug dump"));
 
+  cl::opt Format(
+      "format", cl::desc("Output format for line-based coverage reports"),
+      cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
+                            "Text output"),
+                 clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html",
+                            "HTML output"),
+                 clEnumValEnd),
+      cl::init(CoverageViewOptions::OutputFormat::Text));
+
   cl::opt FilenameEquivalence(
       "filename-equivalence", cl::Optional,
       cl::desc("Treat source files as equivalent to paths in the coverage data "
@@ -315,9 +368,19 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
     ViewOpts.Debug = DebugDump;
     CompareFilenamesOnly = FilenameEquivalence;
 
-    ViewOpts.Colors = UseColor == cl::BOU_UNSET
-                          ? sys::Process::StandardOutHasColors()
-                          : UseColor == cl::BOU_TRUE;
+    ViewOpts.Format = Format;
+    switch (ViewOpts.Format) {
+    case CoverageViewOptions::OutputFormat::Text:
+      ViewOpts.Colors = UseColor == cl::BOU_UNSET
+                            ? sys::Process::StandardOutHasColors()
+                            : UseColor == cl::BOU_TRUE;
+      break;
+    case CoverageViewOptions::OutputFormat::HTML:
+      if (UseColor == cl::BOU_FALSE)
+        error("Color output cannot be disabled when generating html.");
+      ViewOpts.Colors = true;
+      break;
+    }
 
     // Create the function filters
     if (!NameFilters.empty() || !NameRegexFilters.empty()) {
@@ -363,7 +426,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
           errs() << "error: " << File << ": " << EC.message();
           return 1;
         }
-      SourceFiles.push_back(Path.str());
+      addCollectedPath(Path.str());
     }
     return 0;
   };
@@ -406,6 +469,12 @@ int CodeCoverageTool::show(int argc, const char **argv,
                                    cl::desc("Show function instantiations"),
                                    cl::cat(ViewCategory));
 
+  cl::opt ShowOutputDirectory(
+      "output-dir", cl::init(""),
+      cl::desc("Directory in which coverage information is written out"));
+  cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
+                                 cl::aliasopt(ShowOutputDirectory));
+
   auto Err = commandLineParser(argc, argv);
   if (Err)
     return Err;
@@ -417,30 +486,46 @@ int CodeCoverageTool::show(int argc, const char **argv,
   ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
   ViewOpts.ShowExpandedRegions = ShowExpansions;
   ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
+  ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
+
+  if (ViewOpts.hasOutputDirectory()) {
+    if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
+      error("Could not create output directory!", E.message());
+      return 1;
+    }
+  }
 
   auto Coverage = load();
   if (!Coverage)
     return 1;
 
+  auto Printer = CoveragePrinter::create(ViewOpts);
+
   if (!Filters.empty()) {
-    // Show functions
+    auto OSOrErr = Printer->createViewFile("functions", /*InToplevel=*/true);
+    if (Error E = OSOrErr.takeError()) {
+      error(toString(std::move(E)));
+      return 1;
+    }
+    auto OS = std::move(OSOrErr.get());
+
+    // Show functions.
     for (const auto &Function : Coverage->getCoveredFunctions()) {
       if (!Filters.matches(Function))
         continue;
 
       auto mainView = createFunctionView(Function, *Coverage);
       if (!mainView) {
-        ViewOpts.colored_ostream(outs(), raw_ostream::RED)
-            << "warning: Could not read coverage for '" << Function.Name;
-        outs() << "\n";
+        ViewOpts.colored_ostream(errs(), raw_ostream::RED)
+            << "warning: Could not read coverage for '" << Function.Name << "'."
+            << "\n";
         continue;
       }
-      ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << Function.Name
-                                                          << ":";
-      outs() << "\n";
-      mainView->render(outs(), /*WholeFile=*/false);
-      outs() << "\n";
+
+      mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true);
     }
+
+    Printer->closeViewFile(std::move(OS));
     return 0;
   }
 
@@ -448,28 +533,49 @@ int CodeCoverageTool::show(int argc, const char **argv,
   bool ShowFilenames = SourceFiles.size() != 1;
 
   if (SourceFiles.empty())
-    // Get the source files from the function coverage mapping
+    // Get the source files from the function coverage mapping.
     for (StringRef Filename : Coverage->getUniqueSourceFiles())
       SourceFiles.push_back(Filename);
 
-  for (const auto &SourceFile : SourceFiles) {
-    auto mainView = createSourceFileView(SourceFile, *Coverage);
-    if (!mainView) {
-      ViewOpts.colored_ostream(outs(), raw_ostream::RED)
-          << "warning: The file '" << SourceFile << "' isn't covered.";
-      outs() << "\n";
-      continue;
+  // Create an index out of the source files.
+  if (ViewOpts.hasOutputDirectory()) {
+    if (Error E = Printer->createIndexFile(SourceFiles)) {
+      error(toString(std::move(E)));
+      return 1;
     }
+  }
 
-    if (ShowFilenames) {
-      ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":";
-      outs() << "\n";
-    }
-    mainView->render(outs(), /*Wholefile=*/true);
-    if (SourceFiles.size() > 1)
-      outs() << "\n";
+  // In -output-dir mode, it's safe to use multiple threads to print files.
+  unsigned ThreadCount = 1;
+  if (ViewOpts.hasOutputDirectory())
+    ThreadCount = std::thread::hardware_concurrency();
+  ThreadPool Pool(ThreadCount);
+
+  for (StringRef &SourceFile : SourceFiles) {
+    Pool.async([this, &SourceFile, &Coverage, &Printer, ShowFilenames] {
+      auto View = createSourceFileView(SourceFile, *Coverage);
+      if (!View) {
+        deferWarning("The file '" + SourceFile.str() + "' isn't covered.");
+        return;
+      }
+
+      auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
+      if (Error E = OSOrErr.takeError()) {
+        deferError(toString(std::move(E)));
+        return;
+      }
+      auto OS = std::move(OSOrErr.get());
+
+      View->print(*OS.get(), /*Wholefile=*/true,
+                  /*ShowSourceName=*/ShowFilenames);
+      Printer->closeViewFile(std::move(OS));
+    });
   }
 
+  Pool.wait();
+
+  consumeDeferredMessages();
+
   return 0;
 }
 
@@ -479,6 +585,9 @@ int CodeCoverageTool::report(int argc, const char **argv,
   if (Err)
     return Err;
 
+  if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML)
+    error("HTML output for summary reports is not yet supported.");
+
   auto Coverage = load();
   if (!Coverage)
     return 1;
diff --git a/tools/llvm-cov/CoverageFilters.h b/tools/llvm-cov/CoverageFilters.h
index dc5dc98807b1a10b96d1a3a71f953659c4b00f23..756c4b47872c1ac9b04c805fc0b1d05f3c7c9a94 100644
--- a/tools/llvm-cov/CoverageFilters.h
+++ b/tools/llvm-cov/CoverageFilters.h
@@ -14,7 +14,7 @@
 #ifndef LLVM_COV_COVERAGEFILTERS_H
 #define LLVM_COV_COVERAGEFILTERS_H
 
-#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include 
 #include 
 
diff --git a/tools/llvm-cov/CoverageReport.cpp b/tools/llvm-cov/CoverageReport.cpp
index ed01a2e154f1ba364f31b31a229b872b46323123..10e53b3f1f723d7a1c501e2fb23d26280edfadb4 100644
--- a/tools/llvm-cov/CoverageReport.cpp
+++ b/tools/llvm-cov/CoverageReport.cpp
@@ -171,7 +171,7 @@ void CoverageReport::render(const FunctionCoverageSummary &Function,
   OS << "\n";
 }
 
-void CoverageReport::renderFunctionReports(ArrayRef Files,
+void CoverageReport::renderFunctionReports(ArrayRef Files,
                                            raw_ostream &OS) {
   adjustColumnWidths(Coverage.get());
   bool isFirst = true;
diff --git a/tools/llvm-cov/CoverageReport.h b/tools/llvm-cov/CoverageReport.h
index 7ec3df90b8f92d32dc10cceef06bfbbec75896fd..bb3d734b52a5483e928a535f70c121aad8cc6c9f 100644
--- a/tools/llvm-cov/CoverageReport.h
+++ b/tools/llvm-cov/CoverageReport.h
@@ -32,7 +32,7 @@ public:
                  std::unique_ptr Coverage)
       : Options(Options), Coverage(std::move(Coverage)) {}
 
-  void renderFunctionReports(ArrayRef Files, raw_ostream &OS);
+  void renderFunctionReports(ArrayRef Files, raw_ostream &OS);
 
   void renderFileReports(raw_ostream &OS);
 };
diff --git a/tools/llvm-cov/CoverageSummaryInfo.h b/tools/llvm-cov/CoverageSummaryInfo.h
index c393b00d32a43ee157b5d6e2bb7f296931a6de2f..822742b635e967ad8c757955b9ef4882b0ff2812 100644
--- a/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/tools/llvm-cov/CoverageSummaryInfo.h
@@ -15,7 +15,7 @@
 #ifndef LLVM_COV_COVERAGESUMMARYINFO_H
 #define LLVM_COV_COVERAGESUMMARYINFO_H
 
-#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/Support/raw_ostream.h"
 
 namespace llvm {
@@ -47,6 +47,8 @@ struct RegionCoverageInfo {
   bool isFullyCovered() const { return Covered == NumRegions; }
 
   double getPercentCovered() const {
+    if (NumRegions == 0)
+      return 0.0;
     return double(Covered) / double(NumRegions) * 100.0;
   }
 };
@@ -83,6 +85,8 @@ struct LineCoverageInfo {
   bool isFullyCovered() const { return Covered == (NumLines - NonCodeLines); }
 
   double getPercentCovered() const {
+    if (NumLines - NonCodeLines == 0)
+      return 0.0;
     return double(Covered) / double(NumLines - NonCodeLines) * 100.0;
   }
 };
@@ -109,6 +113,8 @@ struct FunctionCoverageInfo {
   bool isFullyCovered() const { return Executed == NumFunctions; }
 
   double getPercentCovered() const {
+    if (NumFunctions == 0)
+      return 0.0;
     return double(Executed) / double(NumFunctions) * 100.0;
   }
 };
diff --git a/tools/llvm-cov/CoverageViewOptions.h b/tools/llvm-cov/CoverageViewOptions.h
index 1208fad791766109ab7047022a5a4a61596e9d94..873eae885a7bedeab105fe71cb65ceffb2c99fac 100644
--- a/tools/llvm-cov/CoverageViewOptions.h
+++ b/tools/llvm-cov/CoverageViewOptions.h
@@ -16,6 +16,11 @@ namespace llvm {
 
 /// \brief The options for displaying the code coverage information.
 struct CoverageViewOptions {
+  enum class OutputFormat {
+    Text,
+    HTML
+  };
+
   bool Debug;
   bool Colors;
   bool ShowLineNumbers;
@@ -25,12 +30,17 @@ struct CoverageViewOptions {
   bool ShowExpandedRegions;
   bool ShowFunctionInstantiations;
   bool ShowFullFilenames;
+  OutputFormat Format;
+  std::string ShowOutputDirectory;
 
   /// \brief Change the output's stream color if the colors are enabled.
   ColoredRawOstream colored_ostream(raw_ostream &OS,
                                     raw_ostream::Colors Color) const {
     return llvm::colored_ostream(OS, Color, Colors);
   }
+
+  /// \brief Check if an output directory has been specified.
+  bool hasOutputDirectory() const { return ShowOutputDirectory != ""; }
 };
 }
 
diff --git a/tools/llvm-cov/LLVMBuild.txt b/tools/llvm-cov/LLVMBuild.txt
index d6eb74de0d4bf9327e46f572229373dac508ab28..33f51fb2ed5a9ff0c92762720363517ee8c70441 100644
--- a/tools/llvm-cov/LLVMBuild.txt
+++ b/tools/llvm-cov/LLVMBuild.txt
@@ -19,4 +19,4 @@
 type = Tool
 name = llvm-cov
 parent = Tools
-required_libraries = ProfileData Support Instrumentation
+required_libraries = Coverage Support Instrumentation
diff --git a/tools/llvm-cov/RenderingSupport.h b/tools/llvm-cov/RenderingSupport.h
index 3ef155d3fd4bbd414090b97384b27c5068a1e672..aa70fbc23e3c0505cb5e9f0282291b5d626eeb00 100644
--- a/tools/llvm-cov/RenderingSupport.h
+++ b/tools/llvm-cov/RenderingSupport.h
@@ -55,6 +55,7 @@ inline ColoredRawOstream colored_ostream(raw_ostream &OS,
     OS.changeColor(Color, Bold, BG);
   return ColoredRawOstream(OS, IsColorUsed);
 }
-}
+
+} // namespace llvm
 
 #endif // LLVM_COV_RENDERINGSUPPORT_H
diff --git a/tools/llvm-cov/SourceCoverageView.cpp b/tools/llvm-cov/SourceCoverageView.cpp
index 58c8a679529464e90a56b8345451c8db879fb3aa..baf7c148bb800224b773a7d3ea63ad9644f8136b 100644
--- a/tools/llvm-cov/SourceCoverageView.cpp
+++ b/tools/llvm-cov/SourceCoverageView.cpp
@@ -6,80 +6,82 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-//
-// This class implements rendering for code coverage of source code.
-//
+///
+/// \file This class implements rendering for code coverage of source code.
+///
 //===----------------------------------------------------------------------===//
 
 #include "SourceCoverageView.h"
-#include "llvm/ADT/Optional.h"
+#include "SourceCoverageViewHTML.h"
+#include "SourceCoverageViewText.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/LineIterator.h"
+#include "llvm/Support/Path.h"
 
 using namespace llvm;
 
-void SourceCoverageView::renderLine(
-    raw_ostream &OS, StringRef Line, int64_t LineNumber,
-    const coverage::CoverageSegment *WrappedSegment,
-    ArrayRef Segments,
-    unsigned ExpansionCol) {
-  Optional Highlight;
-  SmallVector, 2> HighlightedRanges;
-
-  // The first segment overlaps from a previous line, so we treat it specially.
-  if (WrappedSegment && WrappedSegment->HasCount && WrappedSegment->Count == 0)
-    Highlight = raw_ostream::RED;
-
-  // Output each segment of the line, possibly highlighted.
-  unsigned Col = 1;
-  for (const auto *S : Segments) {
-    unsigned End = std::min(S->Col, static_cast(Line.size()) + 1);
-    colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
-                    Options.Colors && Highlight, /*Bold=*/false, /*BG=*/true)
-        << Line.substr(Col - 1, End - Col);
-    if (Options.Debug && Highlight)
-      HighlightedRanges.push_back(std::make_pair(Col, End));
-    Col = End;
-    if (Col == ExpansionCol)
-      Highlight = raw_ostream::CYAN;
-    else if (S->HasCount && S->Count == 0)
-      Highlight = raw_ostream::RED;
-    else
-      Highlight = None;
-  }
+void CoveragePrinter::StreamDestructor::operator()(raw_ostream *OS) const {
+  if (OS == &outs())
+    return;
+  delete OS;
+}
 
-  // Show the rest of the line
-  colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
-                  Options.Colors && Highlight, /*Bold=*/false, /*BG=*/true)
-      << Line.substr(Col - 1, Line.size() - Col + 1);
-  OS << "\n";
-
-  if (Options.Debug) {
-    for (const auto &Range : HighlightedRanges)
-      errs() << "Highlighted line " << LineNumber << ", " << Range.first
-             << " -> " << Range.second << "\n";
-    if (Highlight)
-      errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n";
-  }
+std::string CoveragePrinter::getOutputPath(StringRef Path, StringRef Extension,
+                                           bool InToplevel, bool Relative) {
+  assert(Extension.size() && "The file extension may not be empty");
+
+  SmallString<256> FullPath;
+
+  if (!Relative)
+    FullPath.append(Opts.ShowOutputDirectory);
+
+  if (!InToplevel)
+    sys::path::append(FullPath, getCoverageDir());
+
+  SmallString<256> ParentPath = sys::path::parent_path(Path);
+  sys::path::remove_dots(ParentPath, /*remove_dot_dots=*/true);
+  sys::path::append(FullPath, sys::path::relative_path(ParentPath));
+
+  auto PathFilename = (sys::path::filename(Path) + "." + Extension).str();
+  sys::path::append(FullPath, PathFilename);
+
+  return FullPath.str();
 }
 
-void SourceCoverageView::renderIndent(raw_ostream &OS, unsigned Level) {
-  for (unsigned I = 0; I < Level; ++I)
-    OS << "  |";
+Expected
+CoveragePrinter::createOutputStream(StringRef Path, StringRef Extension,
+                                    bool InToplevel) {
+  if (!Opts.hasOutputDirectory())
+    return OwnedStream(&outs());
+
+  std::string FullPath = getOutputPath(Path, Extension, InToplevel, false);
+
+  auto ParentDir = sys::path::parent_path(FullPath);
+  if (auto E = sys::fs::create_directories(ParentDir))
+    return errorCodeToError(E);
+
+  std::error_code E;
+  raw_ostream *RawStream = new raw_fd_ostream(FullPath, E, sys::fs::F_RW);
+  auto OS = CoveragePrinter::OwnedStream(RawStream);
+  if (E)
+    return errorCodeToError(E);
+  return std::move(OS);
 }
 
-void SourceCoverageView::renderViewDivider(unsigned Level, unsigned Length,
-                                           raw_ostream &OS) {
-  assert(Level != 0 && "Cannot render divider at top level");
-  renderIndent(OS, Level - 1);
-  OS.indent(2);
-  for (unsigned I = 0; I < Length; ++I)
-    OS << "-";
+std::unique_ptr
+CoveragePrinter::create(const CoverageViewOptions &Opts) {
+  switch (Opts.Format) {
+  case CoverageViewOptions::OutputFormat::Text:
+    return llvm::make_unique(Opts);
+  case CoverageViewOptions::OutputFormat::HTML:
+    return llvm::make_unique(Opts);
+  }
+  llvm_unreachable("Unknown coverage output format!");
 }
 
-/// Format a count using engineering notation with 3 significant digits.
-static std::string formatCount(uint64_t N) {
+std::string SourceCoverageView::formatCount(uint64_t N) {
   std::string Number = utostr(N);
   int Len = Number.size();
   if (Len <= 3)
@@ -94,63 +96,49 @@ static std::string formatCount(uint64_t N) {
   return Result;
 }
 
-void
-SourceCoverageView::renderLineCoverageColumn(raw_ostream &OS,
-                                             const LineCoverageInfo &Line) {
-  if (!Line.isMapped()) {
-    OS.indent(LineCoverageColumnWidth) << '|';
-    return;
-  }
-  std::string C = formatCount(Line.ExecutionCount);
-  OS.indent(LineCoverageColumnWidth - C.size());
-  colored_ostream(OS, raw_ostream::MAGENTA,
-                  Line.hasMultipleRegions() && Options.Colors)
-      << C;
-  OS << '|';
+bool SourceCoverageView::shouldRenderRegionMarkers(
+    bool LineHasMultipleRegions) const {
+  return getOptions().ShowRegionMarkers &&
+         (!getOptions().ShowLineStatsOrRegionMarkers || LineHasMultipleRegions);
 }
 
-void SourceCoverageView::renderLineNumberColumn(raw_ostream &OS,
-                                                unsigned LineNo) {
-  SmallString<32> Buffer;
-  raw_svector_ostream BufferOS(Buffer);
-  BufferOS << LineNo;
-  auto Str = BufferOS.str();
-  // Trim and align to the right
-  Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth));
-  OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
+bool SourceCoverageView::hasSubViews() const {
+  return !ExpansionSubViews.empty() || !InstantiationSubViews.empty();
 }
 
-void SourceCoverageView::renderRegionMarkers(
-    raw_ostream &OS, ArrayRef Segments) {
-  unsigned PrevColumn = 1;
-  for (const auto *S : Segments) {
-    if (!S->IsRegionEntry)
-      continue;
-    // Skip to the new region
-    if (S->Col > PrevColumn)
-      OS.indent(S->Col - PrevColumn);
-    PrevColumn = S->Col + 1;
-    std::string C = formatCount(S->Count);
-    PrevColumn += C.size();
-    OS << '^' << C;
+std::unique_ptr
+SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File,
+                           const CoverageViewOptions &Options,
+                           coverage::CoverageData &&CoverageInfo) {
+  switch (Options.Format) {
+  case CoverageViewOptions::OutputFormat::Text:
+    return llvm::make_unique(SourceName, File, Options,
+                                                     std::move(CoverageInfo));
+  case CoverageViewOptions::OutputFormat::HTML:
+    return llvm::make_unique(SourceName, File, Options,
+                                                     std::move(CoverageInfo));
   }
-  OS << "\n";
+  llvm_unreachable("Unknown coverage output format!");
+}
+
+void SourceCoverageView::addExpansion(
+    const coverage::CounterMappingRegion &Region,
+    std::unique_ptr View) {
+  ExpansionSubViews.emplace_back(Region, std::move(View));
+}
 
-  if (Options.Debug)
-    for (const auto *S : Segments)
-      errs() << "Marker at " << S->Line << ":" << S->Col << " = "
-             << formatCount(S->Count) << (S->IsRegionEntry ? "\n" : " (pop)\n");
+void SourceCoverageView::addInstantiation(
+    StringRef FunctionName, unsigned Line,
+    std::unique_ptr View) {
+  InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
 }
 
-void SourceCoverageView::render(raw_ostream &OS, bool WholeFile,
-                                unsigned IndentLevel) {
-  // The width of the leading columns
-  unsigned CombinedColumnWidth =
-      (Options.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
-      (Options.ShowLineNumbers ? LineNumberColumnWidth + 1 : 0);
-  // The width of the line that is used to divide between the view and the
-  // subviews.
-  unsigned DividerWidth = CombinedColumnWidth + 4;
+void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
+                               bool ShowSourceName, unsigned ViewDepth) {
+  if (ShowSourceName)
+    renderSourceName(OS);
+
+  renderViewHeader(OS);
 
   // We need the expansions and instantiations sorted so we can go through them
   // while we iterate lines.
@@ -186,79 +174,60 @@ void SourceCoverageView::render(raw_ostream &OS, bool WholeFile,
       LineSegments.push_back(&*NextSegment++);
 
     // Calculate a count to be for the line as a whole.
-    LineCoverageInfo LineCount;
+    LineCoverageStats LineCount;
     if (WrappedSegment && WrappedSegment->HasCount)
       LineCount.addRegionCount(WrappedSegment->Count);
     for (const auto *S : LineSegments)
       if (S->HasCount && S->IsRegionEntry)
-          LineCount.addRegionStartCount(S->Count);
+        LineCount.addRegionStartCount(S->Count);
 
-    // Render the line prefix.
-    renderIndent(OS, IndentLevel);
-    if (Options.ShowLineStats)
+    renderLinePrefix(OS, ViewDepth);
+    if (getOptions().ShowLineStats)
       renderLineCoverageColumn(OS, LineCount);
-    if (Options.ShowLineNumbers)
+    if (getOptions().ShowLineNumbers)
       renderLineNumberColumn(OS, LI.line_number());
 
     // If there are expansion subviews, we want to highlight the first one.
     unsigned ExpansionColumn = 0;
     if (NextESV != EndESV && NextESV->getLine() == LI.line_number() &&
-        Options.Colors)
+        getOptions().Colors)
       ExpansionColumn = NextESV->getStartCol();
 
     // Display the source code for the current line.
-    renderLine(OS, *LI, LI.line_number(), WrappedSegment, LineSegments,
-               ExpansionColumn);
+    renderLine(OS, {*LI, LI.line_number()}, WrappedSegment, LineSegments,
+               ExpansionColumn, ViewDepth);
 
     // Show the region markers.
-    if (Options.ShowRegionMarkers && (!Options.ShowLineStatsOrRegionMarkers ||
-                                      LineCount.hasMultipleRegions()) &&
-        !LineSegments.empty()) {
-      renderIndent(OS, IndentLevel);
-      OS.indent(CombinedColumnWidth);
-      renderRegionMarkers(OS, LineSegments);
-    }
+    if (shouldRenderRegionMarkers(LineCount.hasMultipleRegions()))
+      renderRegionMarkers(OS, LineSegments, ViewDepth);
 
     // Show the expansions and instantiations for this line.
-    unsigned NestedIndent = IndentLevel + 1;
     bool RenderedSubView = false;
     for (; NextESV != EndESV && NextESV->getLine() == LI.line_number();
          ++NextESV) {
-      renderViewDivider(NestedIndent, DividerWidth, OS);
-      OS << "\n";
+      renderViewDivider(OS, ViewDepth + 1);
+
+      // Re-render the current line and highlight the expansion range for
+      // this subview.
       if (RenderedSubView) {
-        // Re-render the current line and highlight the expansion range for
-        // this subview.
         ExpansionColumn = NextESV->getStartCol();
-        renderIndent(OS, IndentLevel);
-        OS.indent(CombinedColumnWidth + (IndentLevel == 0 ? 0 : 1));
-        renderLine(OS, *LI, LI.line_number(), WrappedSegment, LineSegments,
-                   ExpansionColumn);
-        renderViewDivider(NestedIndent, DividerWidth, OS);
-        OS << "\n";
+        renderExpansionSite(OS, {*LI, LI.line_number()}, WrappedSegment,
+                            LineSegments, ExpansionColumn, ViewDepth);
+        renderViewDivider(OS, ViewDepth + 1);
       }
-      // Render the child subview
-      if (Options.Debug)
-        errs() << "Expansion at line " << NextESV->getLine() << ", "
-               << NextESV->getStartCol() << " -> " << NextESV->getEndCol()
-               << "\n";
-      NextESV->View->render(OS, false, NestedIndent);
+
+      renderExpansionView(OS, *NextESV, ViewDepth + 1);
       RenderedSubView = true;
     }
     for (; NextISV != EndISV && NextISV->Line == LI.line_number(); ++NextISV) {
-      renderViewDivider(NestedIndent, DividerWidth, OS);
-      OS << "\n";
-      renderIndent(OS, NestedIndent);
-      OS << ' ';
-      Options.colored_ostream(OS, raw_ostream::CYAN) << NextISV->FunctionName
-                                                     << ":";
-      OS << "\n";
-      NextISV->View->render(OS, false, NestedIndent);
+      renderViewDivider(OS, ViewDepth + 1);
+      renderInstantiationView(OS, *NextISV, ViewDepth + 1);
       RenderedSubView = true;
     }
-    if (RenderedSubView) {
-      renderViewDivider(NestedIndent, DividerWidth, OS);
-      OS << "\n";
-    }
+    if (RenderedSubView)
+      renderViewDivider(OS, ViewDepth + 1);
+    renderLineSuffix(OS, ViewDepth);
   }
+
+  renderViewFooter(OS);
 }
diff --git a/tools/llvm-cov/SourceCoverageView.h b/tools/llvm-cov/SourceCoverageView.h
index 9e6fe5f3500125188288d7f7952922064f2e87a6..feef959f86bf12204858cd483ae5a9dad01c182c 100644
--- a/tools/llvm-cov/SourceCoverageView.h
+++ b/tools/llvm-cov/SourceCoverageView.h
@@ -6,16 +6,16 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-//
-// This class implements rendering for code coverage of source code.
-//
+///
+/// \file This class implements rendering for code coverage of source code.
+///
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_COV_SOURCECOVERAGEVIEW_H
 #define LLVM_COV_SOURCECOVERAGEVIEW_H
 
 #include "CoverageViewOptions.h"
-#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include 
 
@@ -23,7 +23,7 @@ namespace llvm {
 
 class SourceCoverageView;
 
-/// \brief A view that represents a macro or include expansion
+/// \brief A view that represents a macro or include expansion.
 struct ExpansionView {
   coverage::CounterMappingRegion Region;
   std::unique_ptr View;
@@ -48,7 +48,7 @@ struct ExpansionView {
   }
 };
 
-/// \brief A view that represents a function instantiation
+/// \brief A view that represents a function instantiation.
 struct InstantiationView {
   StringRef FunctionName;
   unsigned Line;
@@ -73,87 +73,211 @@ struct InstantiationView {
   }
 };
 
-/// \brief A code coverage view of a specific source file.
-/// It can have embedded coverage views.
-class SourceCoverageView {
-private:
-  /// \brief Coverage information for a single line.
-  struct LineCoverageInfo {
-    uint64_t ExecutionCount;
-    unsigned RegionCount;
-    bool Mapped;
+/// \brief Coverage statistics for a single line.
+struct LineCoverageStats {
+  uint64_t ExecutionCount;
+  unsigned RegionCount;
+  bool Mapped;
+
+  LineCoverageStats() : ExecutionCount(0), RegionCount(0), Mapped(false) {}
 
-    LineCoverageInfo() : ExecutionCount(0), RegionCount(0), Mapped(false) {}
+  bool isMapped() const { return Mapped; }
 
-    bool isMapped() const { return Mapped; }
+  bool hasMultipleRegions() const { return RegionCount > 1; }
 
-    bool hasMultipleRegions() const { return RegionCount > 1; }
+  void addRegionStartCount(uint64_t Count) {
+    // The max of all region starts is the most interesting value.
+    addRegionCount(RegionCount ? std::max(ExecutionCount, Count) : Count);
+    ++RegionCount;
+  }
+
+  void addRegionCount(uint64_t Count) {
+    Mapped = true;
+    ExecutionCount = Count;
+  }
+};
 
-    void addRegionStartCount(uint64_t Count) {
-      // The max of all region starts is the most interesting value.
-      addRegionCount(RegionCount ? std::max(ExecutionCount, Count) : Count);
-      ++RegionCount;
-    }
+/// \brief A file manager that handles format-aware file creation.
+class CoveragePrinter {
+  const CoverageViewOptions &Opts;
 
-    void addRegionCount(uint64_t Count) {
-      Mapped = true;
-      ExecutionCount = Count;
-    }
+public:
+  struct StreamDestructor {
+    void operator()(raw_ostream *OS) const;
   };
 
+  using OwnedStream = std::unique_ptr;
+
+protected:
+  CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {}
+
+  /// \brief Return `OutputDir/ToplevelDir/Path.Extension`. If \p InToplevel is
+  /// false, skip the ToplevelDir component. If \p Relative is false, skip the
+  /// OutputDir component.
+  std::string getOutputPath(StringRef Path, StringRef Extension,
+                            bool InToplevel, bool Relative = true);
+
+  /// \brief If directory output is enabled, create a file in that directory
+  /// at the path given by getOutputPath(). Otherwise, return stdout.
+  Expected createOutputStream(StringRef Path, StringRef Extension,
+                                           bool InToplevel);
+
+  /// \brief Return the sub-directory name for file coverage reports.
+  static StringRef getCoverageDir() { return "coverage"; }
+
+public:
+  static std::unique_ptr
+  create(const CoverageViewOptions &Opts);
+
+  virtual ~CoveragePrinter() {}
+
+  /// @name File Creation Interface
+  /// @{
+
+  /// \brief Create a file to print a coverage view into.
+  virtual Expected createViewFile(StringRef Path,
+                                               bool InToplevel) = 0;
+
+  /// \brief Close a file which has been used to print a coverage view.
+  virtual void closeViewFile(OwnedStream OS) = 0;
+
+  /// \brief Create an index which lists reports for the given source files.
+  virtual Error createIndexFile(ArrayRef SourceFiles) = 0;
+
+  /// @}
+};
+
+/// \brief A code coverage view of a source file or function.
+///
+/// A source coverage view and its nested sub-views form a file-oriented
+/// representation of code coverage data. This view can be printed out by a
+/// renderer which implements the Rendering Interface.
+class SourceCoverageView {
+  /// A function or file name.
+  StringRef SourceName;
+
+  /// A memory buffer backing the source on display.
   const MemoryBuffer &File;
+
+  /// Various options to guide the coverage renderer.
   const CoverageViewOptions &Options;
+
+  /// Complete coverage information about the source on display.
   coverage::CoverageData CoverageInfo;
+
+  /// A container for all expansions (e.g macros) in the source on display.
   std::vector ExpansionSubViews;
+
+  /// A container for all instantiations (e.g template functions) in the source
+  /// on display.
   std::vector InstantiationSubViews;
 
-  /// \brief Render a source line with highlighting.
-  void renderLine(raw_ostream &OS, StringRef Line, int64_t LineNumber,
-                  const coverage::CoverageSegment *WrappedSegment,
-                  ArrayRef Segments,
-                  unsigned ExpansionCol);
+protected:
+  struct LineRef {
+    StringRef Line;
+    int64_t LineNo;
+
+    LineRef(StringRef Line, int64_t LineNo) : Line(Line), LineNo(LineNo) {}
+  };
+
+  using CoverageSegmentArray = ArrayRef;
+
+  /// @name Rendering Interface
+  /// @{
 
-  void renderIndent(raw_ostream &OS, unsigned Level);
+  /// \brief Render a header for the view.
+  virtual void renderViewHeader(raw_ostream &OS) = 0;
 
-  void renderViewDivider(unsigned Offset, unsigned Length, raw_ostream &OS);
+  /// \brief Render a footer for the view.
+  virtual void renderViewFooter(raw_ostream &OS) = 0;
+
+  /// \brief Render the source name for the view.
+  virtual void renderSourceName(raw_ostream &OS) = 0;
+
+  /// \brief Render the line prefix at the given \p ViewDepth.
+  virtual void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) = 0;
+
+  /// \brief Render the line suffix at the given \p ViewDepth.
+  virtual void renderLineSuffix(raw_ostream &OS, unsigned ViewDepth) = 0;
+
+  /// \brief Render a view divider at the given \p ViewDepth.
+  virtual void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) = 0;
+
+  /// \brief Render a source line with highlighting.
+  virtual void renderLine(raw_ostream &OS, LineRef L,
+                          const coverage::CoverageSegment *WrappedSegment,
+                          CoverageSegmentArray Segments, unsigned ExpansionCol,
+                          unsigned ViewDepth) = 0;
 
   /// \brief Render the line's execution count column.
-  void renderLineCoverageColumn(raw_ostream &OS, const LineCoverageInfo &Line);
+  virtual void renderLineCoverageColumn(raw_ostream &OS,
+                                        const LineCoverageStats &Line) = 0;
 
   /// \brief Render the line number column.
-  void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo);
+  virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0;
 
   /// \brief Render all the region's execution counts on a line.
-  void
-  renderRegionMarkers(raw_ostream &OS,
-                      ArrayRef Segments);
+  virtual void renderRegionMarkers(raw_ostream &OS,
+                                   CoverageSegmentArray Segments,
+                                   unsigned ViewDepth) = 0;
 
-  static const unsigned LineCoverageColumnWidth = 7;
-  static const unsigned LineNumberColumnWidth = 5;
+  /// \brief Render the site of an expansion.
+  virtual void
+  renderExpansionSite(raw_ostream &OS, LineRef L,
+                      const coverage::CoverageSegment *WrappedSegment,
+                      CoverageSegmentArray Segments, unsigned ExpansionCol,
+                      unsigned ViewDepth) = 0;
 
-public:
-  SourceCoverageView(const MemoryBuffer &File,
+  /// \brief Render an expansion view and any nested views.
+  virtual void renderExpansionView(raw_ostream &OS, ExpansionView &ESV,
+                                   unsigned ViewDepth) = 0;
+
+  /// \brief Render an instantiation view and any nested views.
+  virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
+                                       unsigned ViewDepth) = 0;
+
+  /// @}
+
+  /// \brief Format a count using engineering notation with 3 significant
+  /// digits.
+  static std::string formatCount(uint64_t N);
+
+  /// \brief Check if region marker output is expected for a line.
+  bool shouldRenderRegionMarkers(bool LineHasMultipleRegions) const;
+
+  /// \brief Check if there are any sub-views attached to this view.
+  bool hasSubViews() const;
+
+  SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
                      const CoverageViewOptions &Options,
                      coverage::CoverageData &&CoverageInfo)
-      : File(File), Options(Options), CoverageInfo(std::move(CoverageInfo)) {}
+      : SourceName(SourceName), File(File), Options(Options),
+        CoverageInfo(std::move(CoverageInfo)) {}
+
+public:
+  static std::unique_ptr
+  create(StringRef SourceName, const MemoryBuffer &File,
+         const CoverageViewOptions &Options,
+         coverage::CoverageData &&CoverageInfo);
+
+  virtual ~SourceCoverageView() {}
+
+  StringRef getSourceName() const { return SourceName; }
 
   const CoverageViewOptions &getOptions() const { return Options; }
 
   /// \brief Add an expansion subview to this view.
   void addExpansion(const coverage::CounterMappingRegion &Region,
-                    std::unique_ptr View) {
-    ExpansionSubViews.emplace_back(Region, std::move(View));
-  }
+                    std::unique_ptr View);
 
   /// \brief Add a function instantiation subview to this view.
   void addInstantiation(StringRef FunctionName, unsigned Line,
-                        std::unique_ptr View) {
-    InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
-  }
+                        std::unique_ptr View);
 
-  /// \brief Print the code coverage information for a specific
-  /// portion of a source file to the output stream.
-  void render(raw_ostream &OS, bool WholeFile, unsigned IndentLevel = 0);
+  /// \brief Print the code coverage information for a specific portion of a
+  /// source file to the output stream.
+  void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName,
+             unsigned ViewDepth = 0);
 };
 
 } // namespace llvm
diff --git a/tools/llvm-cov/SourceCoverageViewHTML.cpp b/tools/llvm-cov/SourceCoverageViewHTML.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..81963e5c5447423064ae53ab39323764caeeb62a
--- /dev/null
+++ b/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -0,0 +1,436 @@
+//===- SourceCoverageViewHTML.cpp - A html code coverage view -------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file implements the html coverage renderer.
+///
+//===----------------------------------------------------------------------===//
+
+#include "SourceCoverageViewHTML.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+
+namespace {
+
+const char *BeginHeader =
+  ""
+    ""
+    "";
+
+const char *CSSForCoverage =
+  "";
+
+const char *EndHeader = "";
+
+const char *BeginCenteredDiv = "
"; + +const char *EndCenteredDiv = "
"; + +const char *BeginSourceNameDiv = "
"; + +const char *EndSourceNameDiv = "
"; + +const char *BeginCodeTD = "
"; + +const char *EndCodeTD = "
"; + +const char *EndTable = "
"; + +void emitPrelude(raw_ostream &OS) { + OS << "" + "" + << BeginHeader << CSSForCoverage << EndHeader << "" + << BeginCenteredDiv; +} + +void emitEpilog(raw_ostream &OS) { + OS << EndCenteredDiv << "" + ""; +} + +// Return a string with the special characters in \p Str escaped. +std::string escape(StringRef Str) { + std::string Result; + for (char C : Str) { + if (C == '&') + Result += "&"; + else if (C == '<') + Result += "<"; + else if (C == '>') + Result += ">"; + else if (C == '\"') + Result += """; + else + Result += C; + } + return Result; +} + +// Create a \p Name tag around \p Str, and optionally set its \p ClassName. +std::string tag(const std::string &Name, const std::string &Str, + const std::string &ClassName = "") { + std::string Tag = "<" + Name; + if (ClassName != "") + Tag += " class='" + ClassName + "'"; + return Tag + ">" + Str + ""; +} + +// Create an anchor to \p Link with the label \p Str. +std::string a(const std::string &Link, const std::string &Str) { + return "" + Str + ""; +} + +} // anonymous namespace + +Expected +CoveragePrinterHTML::createViewFile(StringRef Path, bool InToplevel) { + auto OSOrErr = createOutputStream(Path, "html", InToplevel); + if (!OSOrErr) + return OSOrErr; + + OwnedStream OS = std::move(OSOrErr.get()); + emitPrelude(*OS.get()); + return std::move(OS); +} + +void CoveragePrinterHTML::closeViewFile(OwnedStream OS) { + emitEpilog(*OS.get()); +} + +Error CoveragePrinterHTML::createIndexFile(ArrayRef SourceFiles) { + auto OSOrErr = createOutputStream("index", "html", /*InToplevel=*/true); + if (Error E = OSOrErr.takeError()) + return E; + auto OS = std::move(OSOrErr.get()); + raw_ostream &OSRef = *OS.get(); + + // Emit a table containing links to reports for each file in the covmapping. + emitPrelude(OSRef); + OSRef << BeginSourceNameDiv << "Index" << EndSourceNameDiv; + OSRef << BeginTable; + for (StringRef SF : SourceFiles) { + std::string LinkText = escape(sys::path::relative_path(SF)); + std::string LinkTarget = + escape(getOutputPath(SF, "html", /*InToplevel=*/false)); + OSRef << tag("tr", tag("td", tag("pre", a(LinkTarget, LinkText), "code"))); + } + OSRef << EndTable; + emitEpilog(OSRef); + + return Error::success(); +} + +void SourceCoverageViewHTML::renderViewHeader(raw_ostream &OS) { + OS << BeginTable; +} + +void SourceCoverageViewHTML::renderViewFooter(raw_ostream &OS) { + OS << EndTable; +} + +void SourceCoverageViewHTML::renderSourceName(raw_ostream &OS) { + OS << BeginSourceNameDiv << tag("pre", escape(getSourceName())) + << EndSourceNameDiv; +} + +void SourceCoverageViewHTML::renderLinePrefix(raw_ostream &OS, unsigned) { + OS << "
\n"; OS << ""; OS << "\n"; - for (auto FileName : Files) { + for (const auto &FileName : Files) { std::pair FC = FileCoverage[FileName]; if (FC.first == 0) { NotCoveredFilesCount++; @@ -910,7 +927,7 @@ public: if (NotCoveredFilesCount) { OS << "
Not Touched Files\n"; OS << "
FileCoverage %Hit (Total) Fns
\n"; - for (auto FileName : Files) { + for (const auto &FileName : Files) { std::pair FC = FileCoverage[FileName]; if (FC.first == 0) OS << "\n"; @@ -922,7 +939,7 @@ public: } // Source - for (auto FileName : Files) { + for (const auto &FileName : Files) { std::pair FC = FileCoverage[FileName]; if (FC.first == 0) continue; @@ -964,7 +981,7 @@ public: FileLoc Loc = FileLoc{FileName, Line}; auto It = AllFnsByLoc.find(Loc); if (It != AllFnsByLoc.end()) { - for (std::string Fn : It->second) { + for (const std::string &Fn : It->second) { OS << ""; }; @@ -1064,7 +1081,7 @@ public: std::vector> MergedCoverage; for (const auto &Pair : CoverageByObjFile) { if (findSanitizerCovFunctions(Pair.first).empty()) { - for (auto FileName : Pair.second) { + for (const auto &FileName : Pair.second) { CovFiles.erase(FileName); } @@ -1154,7 +1171,7 @@ public: // About OS << "
About\n"; OS << "Coverage files:
    "; - for (auto InputFile : CoverageFiles) { + for (const auto &InputFile : CoverageFiles) { llvm::sys::fs::file_status Status; llvm::sys::fs::status(InputFile, Status); OS << "
  • " << stripPathPrefix(InputFile) << " (" @@ -1186,7 +1203,7 @@ private: int main(int argc, char **argv) { // Print stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. @@ -1204,7 +1221,7 @@ int main(int argc, char **argv) { return 0; } else if (Action == PrintCovPointsAction) { // -print-coverage-points doesn't need coverage files. - for (std::string ObjFile : ClInputFiles) { + for (const std::string &ObjFile : ClInputFiles) { printCovPoints(ObjFile, outs()); } return 0; diff --git a/tools/sanstats/sanstats.cpp b/tools/sanstats/sanstats.cpp index 3a8cc9aea8ce0e337669a45a93059edb6ba9f1ba..b2216eab119e124d7887bb5b139d061e88cd143a 100644 --- a/tools/sanstats/sanstats.cpp +++ b/tools/sanstats/sanstats.cpp @@ -76,12 +76,12 @@ const char *ReadModule(char SizeofPtr, const char *Begin, const char *End) { if (Begin == End) return nullptr; - ErrorOr LineInfo = Symbolizer.symbolizeCode(Filename, Addr); - if (LineInfo) { + if (Expected LineInfo = + Symbolizer.symbolizeCode(Filename, Addr)) { llvm::outs() << LineInfo->FileName << ':' << LineInfo->Line << ' ' << LineInfo->FunctionName << ' '; } else { - llvm::outs() << " "; + logAllUnhandledErrors(LineInfo.takeError(), llvm::outs(), " "); } switch (KindFromData(Data, SizeofPtr)) { diff --git a/tools/verify-uselistorder/verify-uselistorder.cpp b/tools/verify-uselistorder/verify-uselistorder.cpp index c3fec1326acb0d4000319e8df9438447139d918c..b19ecdaf6698fb19d7f26e34b02d8a133948641d 100644 --- a/tools/verify-uselistorder/verify-uselistorder.cpp +++ b/tools/verify-uselistorder/verify-uselistorder.cpp @@ -191,6 +191,8 @@ ValueMapping::ValueMapping(const Module &M) { map(&G); for (const GlobalAlias &A : M.aliases()) map(&A); + for (const GlobalIFunc &IF : M.ifuncs()) + map(&IF); for (const Function &F : M) map(&F); @@ -200,6 +202,8 @@ ValueMapping::ValueMapping(const Module &M) { map(G.getInitializer()); for (const GlobalAlias &A : M.aliases()) map(A.getAliasee()); + for (const GlobalIFunc &IF : M.ifuncs()) + map(IF.getResolver()); for (const Function &F : M) { if (F.hasPrefixData()) map(F.getPrefixData()); @@ -463,6 +467,8 @@ static void changeUseLists(Module &M, Changer changeValueUseList) { changeValueUseList(&G); for (GlobalAlias &A : M.aliases()) changeValueUseList(&A); + for (GlobalIFunc &IF : M.ifuncs()) + changeValueUseList(&IF); for (Function &F : M) changeValueUseList(&F); @@ -472,6 +478,8 @@ static void changeUseLists(Module &M, Changer changeValueUseList) { changeValueUseList(G.getInitializer()); for (GlobalAlias &A : M.aliases()) changeValueUseList(A.getAliasee()); + for (GlobalIFunc &IF : M.ifuncs()) + changeValueUseList(IF.getResolver()); for (Function &F : M) { if (F.hasPrefixData()) changeValueUseList(F.getPrefixData()); @@ -518,14 +526,14 @@ static void reverseUseLists(Module &M) { } int main(int argc, char **argv) { - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); llvm::PrettyStackTraceProgram X(argc, argv); // Enable debug stream buffering. EnableDebugBuffering = true; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - LLVMContext &Context = getGlobalContext(); + LLVMContext Context; cl::ParseCommandLineOptions(argc, argv, "llvm tool to verify use-list order\n"); diff --git a/tools/xcode-toolchain/CMakeLists.txt b/tools/xcode-toolchain/CMakeLists.txt index 4eacbd320efcb4cd46037b00935dd82dcb1ba66e..92b24581962b3b64662bcd69e712aac675212453 100644 --- a/tools/xcode-toolchain/CMakeLists.txt +++ b/tools/xcode-toolchain/CMakeLists.txt @@ -69,4 +69,24 @@ add_custom_target(install-xcode-toolchain COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_PREFIX=${LLVMToolchainDir}/usr/ -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" - ${cmake_3_2_USES_TERMINAL}) + USES_TERMINAL) + +if(LLVM_DISTRIBUTION_COMPONENTS) + if(CMAKE_CONFIGURATION_TYPES) + message(FATAL_ERROR "LLVM_DISTRIBUTION_COMPONENTS cannot be specified with multi-configuration generators (i.e. Xcode or Visual Studio)") + endif() + + add_custom_target(install-distribution-toolchain + DEPENDS ${LLVMToolchainDir}/ToolchainInfo.plist distribution) + + foreach(target ${LLVM_DISTRIBUTION_COMPONENTS}) + add_custom_target(install-distribution-${target} + DEPENDS ${target} + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=${target} + -DCMAKE_INSTALL_PREFIX=${LLVMToolchainDir}/usr/ + -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" + USES_TERMINAL) + add_dependencies(install-distribution-toolchain install-distribution-${target}) + endforeach() +endif() diff --git a/tools/yaml2obj/CMakeLists.txt b/tools/yaml2obj/CMakeLists.txt index ac3fd7765c65c1f3d242bc21c3881a4162b20ef5..885a69f5d3c36b810185f45daee7f630a0b52149 100644 --- a/tools/yaml2obj/CMakeLists.txt +++ b/tools/yaml2obj/CMakeLists.txt @@ -9,4 +9,5 @@ add_llvm_tool(yaml2obj yaml2obj.cpp yaml2coff.cpp yaml2elf.cpp + yaml2macho.cpp ) diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp index ca3057de17727e729c79f577965839f9b4425aaf..8f3f52179528d083a00237795c63291b07f07696 100644 --- a/tools/yaml2obj/yaml2coff.cpp +++ b/tools/yaml2obj/yaml2coff.cpp @@ -14,12 +14,11 @@ #include "yaml2obj.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Object/COFF.h" -#include "llvm/ObjectYAML/COFFYAML.h" +#include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" @@ -533,14 +532,7 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) { return true; } -int yaml2coff(yaml::Input &YIn, raw_ostream &Out) { - COFFYAML::Object Doc; - YIn >> Doc; - if (YIn.error()) { - errs() << "yaml2obj: Failed to parse YAML file!\n"; - return 1; - } - +int yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out) { COFFParser CP(Doc); if (!CP.parse()) { errs() << "yaml2obj: Failed to parse YAML file!\n"; diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index a2ae5e2e756b0c380a476fcf18c21b8c291950ef..c98093431a7ef65c39467a044e3f753814db1b92 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -558,13 +558,7 @@ static bool isLittleEndian(const ELFYAML::Object &Doc) { return Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); } -int yaml2elf(yaml::Input &YIn, raw_ostream &Out) { - ELFYAML::Object Doc; - YIn >> Doc; - if (YIn.error()) { - errs() << "yaml2obj: Failed to parse YAML file!\n"; - return 1; - } +int yaml2elf(llvm::ELFYAML::Object &Doc, raw_ostream &Out) { using object::ELFType; typedef ELFType LE64; typedef ELFType BE64; diff --git a/tools/yaml2obj/yaml2macho.cpp b/tools/yaml2obj/yaml2macho.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb29e206be35e515b551f3130518390bacfb0cfa --- /dev/null +++ b/tools/yaml2obj/yaml2macho.cpp @@ -0,0 +1,539 @@ +//===- yaml2macho - Convert YAML to a Mach object file --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief The Mach component of yaml2obj. +/// +//===----------------------------------------------------------------------===// + +#include "yaml2obj.h" +#include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/MachO.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" + +#include "llvm/Support/Format.h" + +using namespace llvm; + +namespace { + +class MachOWriter { +public: + MachOWriter(MachOYAML::Object &Obj) : Obj(Obj), is64Bit(true), fileStart(0) { + is64Bit = Obj.Header.magic == MachO::MH_MAGIC_64 || + Obj.Header.magic == MachO::MH_CIGAM_64; + memset(reinterpret_cast(&Header), 0, sizeof(MachO::mach_header_64)); + } + + Error writeMachO(raw_ostream &OS); + +private: + Error writeHeader(raw_ostream &OS); + Error writeLoadCommands(raw_ostream &OS); + Error writeSectionData(raw_ostream &OS); + Error writeLinkEditData(raw_ostream &OS); + void writeBindOpcodes(raw_ostream &OS, + std::vector &BindOpcodes); + // LinkEdit writers + Error writeRebaseOpcodes(raw_ostream &OS); + Error writeBasicBindOpcodes(raw_ostream &OS); + Error writeWeakBindOpcodes(raw_ostream &OS); + Error writeLazyBindOpcodes(raw_ostream &OS); + Error writeNameList(raw_ostream &OS); + Error writeStringTable(raw_ostream &OS); + Error writeExportTrie(raw_ostream &OS); + + void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry); + void ZeroToOffset(raw_ostream &OS, size_t offset); + + MachOYAML::Object &Obj; + bool is64Bit; + uint64_t fileStart; + + MachO::mach_header_64 Header; +}; + +Error MachOWriter::writeMachO(raw_ostream &OS) { + fileStart = OS.tell(); + if (auto Err = writeHeader(OS)) + return Err; + if (auto Err = writeLoadCommands(OS)) + return Err; + if (auto Err = writeSectionData(OS)) + return Err; + return Error::success(); +} + +Error MachOWriter::writeHeader(raw_ostream &OS) { + Header.magic = Obj.Header.magic; + Header.cputype = Obj.Header.cputype; + Header.cpusubtype = Obj.Header.cpusubtype; + Header.filetype = Obj.Header.filetype; + Header.ncmds = Obj.Header.ncmds; + Header.sizeofcmds = Obj.Header.sizeofcmds; + Header.flags = Obj.Header.flags; + Header.reserved = Obj.Header.reserved; + + auto header_size = + is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); + OS.write((const char *)&Header, header_size); + + return Error::success(); +} + +template +SectionType constructSection(MachOYAML::Section Sec) { + SectionType TempSec; + memcpy(reinterpret_cast(&TempSec.sectname[0]), &Sec.sectname[0], 16); + memcpy(reinterpret_cast(&TempSec.segname[0]), &Sec.segname[0], 16); + TempSec.addr = Sec.addr; + TempSec.size = Sec.size; + TempSec.offset = Sec.offset; + TempSec.align = Sec.align; + TempSec.reloff = Sec.reloff; + TempSec.nreloc = Sec.nreloc; + TempSec.flags = Sec.flags; + TempSec.reserved1 = Sec.reserved1; + TempSec.reserved2 = Sec.reserved2; + return TempSec; +} + +template +size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS) { + return 0; +} + +template <> +size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, + raw_ostream &OS) { + size_t BytesWritten = 0; + for (const auto &Sec : LC.Sections) { + auto TempSec = constructSection(Sec); + OS.write(reinterpret_cast(&(TempSec)), + sizeof(MachO::section)); + BytesWritten += sizeof(MachO::section); + } + return BytesWritten; +} + +template <> +size_t +writeLoadCommandData(MachOYAML::LoadCommand &LC, + raw_ostream &OS) { + size_t BytesWritten = 0; + for (const auto &Sec : LC.Sections) { + auto TempSec = constructSection(Sec); + TempSec.reserved3 = Sec.reserved3; + OS.write(reinterpret_cast(&(TempSec)), + sizeof(MachO::section_64)); + BytesWritten += sizeof(MachO::section_64); + } + return BytesWritten; +} + +size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) { + size_t BytesWritten = 0; + if (!LC.PayloadString.empty()) { + OS.write(LC.PayloadString.c_str(), LC.PayloadString.length()); + BytesWritten = LC.PayloadString.length(); + } + return BytesWritten; +} + +template <> +size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, + raw_ostream &OS) { + return writePayloadString(LC, OS); +} + +template <> +size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, + raw_ostream &OS) { + return writePayloadString(LC, OS); +} + +template <> +size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, + raw_ostream &OS) { + return writePayloadString(LC, OS); +} + +void ZeroFillBytes(raw_ostream &OS, size_t Size) { + std::vector FillData; + FillData.insert(FillData.begin(), Size, 0); + OS.write(reinterpret_cast(FillData.data()), Size); +} + +void Fill(raw_ostream &OS, size_t Size, uint32_t Data) { + std::vector FillData; + FillData.insert(FillData.begin(), (Size / 4) + 1, Data); + OS.write(reinterpret_cast(FillData.data()), Size); +} + +void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) { + auto currOffset = OS.tell() - fileStart; + if (currOffset < Offset) + ZeroFillBytes(OS, Offset - currOffset); +} + +Error MachOWriter::writeLoadCommands(raw_ostream &OS) { + for (auto &LC : Obj.LoadCommands) { + size_t BytesWritten = 0; +#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ + case MachO::LCName: \ + OS.write(reinterpret_cast(&(LC.Data.LCStruct##_data)), \ + sizeof(MachO::LCStruct)); \ + BytesWritten = sizeof(MachO::LCStruct); \ + BytesWritten += writeLoadCommandData(LC, OS); \ + break; + + switch (LC.Data.load_command_data.cmd) { + default: + OS.write(reinterpret_cast(&(LC.Data.load_command_data)), + sizeof(MachO::load_command)); + BytesWritten = sizeof(MachO::load_command); + BytesWritten += writeLoadCommandData(LC, OS); + break; +#include "llvm/Support/MachO.def" + } + + if (LC.PayloadBytes.size() > 0) { + OS.write(reinterpret_cast(LC.PayloadBytes.data()), + LC.PayloadBytes.size()); + BytesWritten += LC.PayloadBytes.size(); + } + + if (LC.ZeroPadBytes > 0) { + ZeroFillBytes(OS, LC.ZeroPadBytes); + BytesWritten += LC.ZeroPadBytes; + } + + // Fill remaining bytes with 0. This will only get hit in partially + // specified test cases. + auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten; + if (BytesRemaining > 0) { + ZeroFillBytes(OS, BytesRemaining); + } + } + return Error::success(); +} + +Error MachOWriter::writeSectionData(raw_ostream &OS) { + for (auto &LC : Obj.LoadCommands) { + switch (LC.Data.load_command_data.cmd) { + case MachO::LC_SEGMENT: + case MachO::LC_SEGMENT_64: + auto currOffset = OS.tell() - fileStart; + auto segname = LC.Data.segment_command_data.segname; + uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff + : LC.Data.segment_command_data.fileoff; + + if (0 == strncmp(&segname[0], "__LINKEDIT", 16)) { + if (auto Err = writeLinkEditData(OS)) + return Err; + } else { + // Zero Fill any data between the end of the last thing we wrote and the + // start of this section. + if (currOffset < segOff) { + ZeroFillBytes(OS, segOff - currOffset); + } + + for (auto &Sec : LC.Sections) { + // Zero Fill any data between the end of the last thing we wrote and + // the + // start of this section. + assert( + OS.tell() - fileStart <= Sec.offset && + "Wrote too much data somewhere, section offsets don't line up."); + currOffset = OS.tell() - fileStart; + if (currOffset < Sec.offset) { + ZeroFillBytes(OS, Sec.offset - currOffset); + } + + // Fills section data with 0xDEADBEEF + Fill(OS, Sec.size, 0xDEADBEEFu); + } + } + uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize + : LC.Data.segment_command_data.filesize; + ZeroToOffset(OS, segOff + segSize); + break; + } + } + return Error::success(); +} + +void MachOWriter::writeBindOpcodes( + raw_ostream &OS, std::vector &BindOpcodes) { + + for (auto Opcode : BindOpcodes) { + uint8_t OpByte = Opcode.Opcode | Opcode.Imm; + OS.write(reinterpret_cast(&OpByte), 1); + for (auto Data : Opcode.ULEBExtraData) { + encodeULEB128(Data, OS); + } + for (auto Data : Opcode.SLEBExtraData) { + encodeSLEB128(Data, OS); + } + if (!Opcode.Symbol.empty()) { + OS.write(Opcode.Symbol.data(), Opcode.Symbol.size()); + OS.write('\0'); + } + } +} + +void MachOWriter::dumpExportEntry(raw_ostream &OS, + MachOYAML::ExportEntry &Entry) { + encodeSLEB128(Entry.TerminalSize, OS); + if (Entry.TerminalSize > 0) { + encodeSLEB128(Entry.Flags, OS); + if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) { + encodeSLEB128(Entry.Other, OS); + OS << Entry.ImportName; + OS.write('\0'); + } else { + encodeSLEB128(Entry.Address, OS); + if (Entry.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) + encodeSLEB128(Entry.Other, OS); + } + } + OS.write(static_cast(Entry.Children.size())); + for (auto EE : Entry.Children) { + OS << EE.Name; + OS.write('\0'); + encodeSLEB128(EE.NodeOffset, OS); + } + for (auto EE : Entry.Children) + dumpExportEntry(OS, EE); +} + +Error MachOWriter::writeExportTrie(raw_ostream &OS) { + dumpExportEntry(OS, Obj.LinkEdit.ExportTrie); + return Error::success(); +} + +template +void writeNListEntry(MachOYAML::NListEntry &NLE, raw_ostream &OS) { + NListType ListEntry; + ListEntry.n_strx = NLE.n_strx; + ListEntry.n_type = NLE.n_type; + ListEntry.n_sect = NLE.n_sect; + ListEntry.n_desc = NLE.n_desc; + ListEntry.n_value = NLE.n_value; + OS.write(reinterpret_cast(&ListEntry), sizeof(NListType)); +} + +Error MachOWriter::writeLinkEditData(raw_ostream &OS) { + typedef Error (MachOWriter::*writeHandler)(raw_ostream &); + typedef std::pair writeOperation; + std::vector WriteQueue; + + MachO::dyld_info_command *DyldInfoOnlyCmd = 0; + MachO::symtab_command *SymtabCmd = 0; + for (auto &LC : Obj.LoadCommands) { + switch (LC.Data.load_command_data.cmd) { + case MachO::LC_SYMTAB: + SymtabCmd = &LC.Data.symtab_command_data; + WriteQueue.push_back( + std::make_pair(SymtabCmd->symoff, &MachOWriter::writeNameList)); + WriteQueue.push_back( + std::make_pair(SymtabCmd->stroff, &MachOWriter::writeStringTable)); + break; + case MachO::LC_DYLD_INFO_ONLY: + DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data; + WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->rebase_off, + &MachOWriter::writeRebaseOpcodes)); + WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->bind_off, + &MachOWriter::writeBasicBindOpcodes)); + WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->weak_bind_off, + &MachOWriter::writeWeakBindOpcodes)); + WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->lazy_bind_off, + &MachOWriter::writeLazyBindOpcodes)); + WriteQueue.push_back(std::make_pair(DyldInfoOnlyCmd->export_off, + &MachOWriter::writeExportTrie)); + break; + } + } + + std::sort(WriteQueue.begin(), WriteQueue.end(), + [](const writeOperation &a, const writeOperation &b) { + return a.first < b.first; + }); + + for (auto writeOp : WriteQueue) { + ZeroToOffset(OS, writeOp.first); + if (auto Err = (this->*writeOp.second)(OS)) + return Err; + } + + return Error::success(); +} + +Error MachOWriter::writeRebaseOpcodes(raw_ostream &OS) { + MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit; + + for (auto Opcode : LinkEdit.RebaseOpcodes) { + uint8_t OpByte = Opcode.Opcode | Opcode.Imm; + OS.write(reinterpret_cast(&OpByte), 1); + for (auto Data : Opcode.ExtraData) { + encodeULEB128(Data, OS); + } + } + return Error::success(); +} + +Error MachOWriter::writeBasicBindOpcodes(raw_ostream &OS) { + writeBindOpcodes(OS, Obj.LinkEdit.BindOpcodes); + return Error::success(); +} + +Error MachOWriter::writeWeakBindOpcodes(raw_ostream &OS) { + writeBindOpcodes(OS, Obj.LinkEdit.WeakBindOpcodes); + return Error::success(); +} + +Error MachOWriter::writeLazyBindOpcodes(raw_ostream &OS) { + writeBindOpcodes(OS, Obj.LinkEdit.LazyBindOpcodes); + return Error::success(); +} + +Error MachOWriter::writeNameList(raw_ostream &OS) { + for (auto NLE : Obj.LinkEdit.NameList) { + if (is64Bit) + writeNListEntry(NLE, OS); + else + writeNListEntry(NLE, OS); + } + return Error::success(); +} + +Error MachOWriter::writeStringTable(raw_ostream &OS) { + for (auto Str : Obj.LinkEdit.StringTable) { + OS.write(Str.data(), Str.size()); + OS.write('\0'); + } + return Error::success(); +} + +class UniversalWriter { +public: + UniversalWriter(yaml::YamlObjectFile &ObjectFile) + : ObjectFile(ObjectFile), fileStart(0) {} + + Error writeMachO(raw_ostream &OS); + +private: + Error writeFatHeader(raw_ostream &OS); + Error writeFatArchs(raw_ostream &OS); + + void ZeroToOffset(raw_ostream &OS, size_t offset); + + yaml::YamlObjectFile &ObjectFile; + uint64_t fileStart; +}; + +Error UniversalWriter::writeMachO(raw_ostream &OS) { + fileStart = OS.tell(); + if (ObjectFile.MachO) { + MachOWriter Writer(*ObjectFile.MachO); + return Writer.writeMachO(OS); + } + if (auto Err = writeFatHeader(OS)) + return Err; + if (auto Err = writeFatArchs(OS)) + return Err; + auto &FatFile = *ObjectFile.FatMachO; + assert(FatFile.FatArchs.size() == FatFile.Slices.size()); + for (size_t i = 0; i < FatFile.Slices.size(); i++) { + ZeroToOffset(OS, FatFile.FatArchs[i].offset); + MachOWriter Writer(FatFile.Slices[i]); + if (auto Err = Writer.writeMachO(OS)) + return Err; + auto SliceEnd = FatFile.FatArchs[i].offset + FatFile.FatArchs[i].size; + ZeroToOffset(OS, SliceEnd); + } + return Error::success(); +} + +Error UniversalWriter::writeFatHeader(raw_ostream &OS) { + auto &FatFile = *ObjectFile.FatMachO; + MachO::fat_header header; + header.magic = FatFile.Header.magic; + header.nfat_arch = FatFile.Header.nfat_arch; + if (sys::IsLittleEndianHost) + swapStruct(header); + OS.write(reinterpret_cast(&header), sizeof(MachO::fat_header)); + return Error::success(); +} + +template +FatArchType constructFatArch(MachOYAML::FatArch &Arch) { + FatArchType FatArch; + FatArch.cputype = Arch.cputype; + FatArch.cpusubtype = Arch.cpusubtype; + FatArch.offset = Arch.offset; + FatArch.size = Arch.size; + FatArch.align = Arch.align; + return FatArch; +} + +template +void writeFatArch(MachOYAML::FatArch &LC, raw_ostream &OS) {} + +template <> +void writeFatArch(MachOYAML::FatArch &Arch, raw_ostream &OS) { + auto FatArch = constructFatArch(Arch); + if (sys::IsLittleEndianHost) + swapStruct(FatArch); + OS.write(reinterpret_cast(&FatArch), sizeof(MachO::fat_arch)); +} + +template <> +void writeFatArch(MachOYAML::FatArch &Arch, + raw_ostream &OS) { + auto FatArch = constructFatArch(Arch); + FatArch.reserved = Arch.reserved; + if (sys::IsLittleEndianHost) + swapStruct(FatArch); + OS.write(reinterpret_cast(&FatArch), + sizeof(MachO::fat_arch_64)); +} + +Error UniversalWriter::writeFatArchs(raw_ostream &OS) { + auto &FatFile = *ObjectFile.FatMachO; + bool is64Bit = FatFile.Header.magic == MachO::FAT_MAGIC_64; + for (auto Arch : FatFile.FatArchs) { + if (is64Bit) + writeFatArch(Arch, OS); + else + writeFatArch(Arch, OS); + } + + return Error::success(); +} + +void UniversalWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) { + auto currOffset = OS.tell() - fileStart; + if (currOffset < Offset) + ZeroFillBytes(OS, Offset - currOffset); +} + +} // end anonymous namespace + +int yaml2macho(yaml::YamlObjectFile &Doc, raw_ostream &Out) { + UniversalWriter Writer(Doc); + if (auto Err = Writer.writeMachO(Out)) { + errs() << toString(std::move(Err)); + return 1; + } + return 0; +} diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp index af4d8689067240d3a65ce3fceb41ad03ddf0fe73..f746d84a3898570a17fe377270d327327cae9cf4 100644 --- a/tools/yaml2obj/yaml2obj.cpp +++ b/tools/yaml2obj/yaml2obj.cpp @@ -16,6 +16,7 @@ #include "yaml2obj.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" @@ -32,27 +33,6 @@ using namespace llvm; static cl::opt Input(cl::Positional, cl::desc(""), cl::init("-")); -// TODO: The "right" way to tell what kind of object file a given YAML file -// corresponds to is to look at YAML "tags" (e.g. `!Foo`). Then, different -// tags (`!ELF`, `!COFF`, etc.) would be used to discriminate between them. -// Interpreting the tags is needed eventually for when writing test cases, -// so that we can e.g. have `!Archive` contain a sequence of `!ELF`, and -// just Do The Right Thing. However, interpreting these tags and acting on -// them appropriately requires some work in the YAML parser and the YAMLIO -// library. -enum YAMLObjectFormat { - YOF_COFF, - YOF_ELF -}; - -cl::opt Format( - "format", - cl::desc("Interpret input as this type of object file"), - cl::values( - clEnumValN(YOF_COFF, "coff", "COFF object file format"), - clEnumValN(YOF_ELF, "elf", "ELF object file format"), - clEnumValEnd)); - cl::opt DocNum("docnum", cl::init(1), cl::desc("Read specified document from input (default = 1)")); @@ -60,14 +40,26 @@ DocNum("docnum", cl::init(1), static cl::opt OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); -typedef int (*ConvertFuncPtr)(yaml::Input & YIn, raw_ostream &Out); - -static int convertYAML(yaml::Input &YIn, raw_ostream &Out, - ConvertFuncPtr Convert) { +static int convertYAML(yaml::Input &YIn, raw_ostream &Out) { unsigned CurDocNum = 0; do { - if (++CurDocNum == DocNum) - return Convert(YIn, Out); + if (++CurDocNum == DocNum) { + yaml::YamlObjectFile Doc; + YIn >> Doc; + if (YIn.error()) { + errs() << "yaml2obj: Failed to parse YAML file!\n"; + return 1; + } + + if (Doc.Elf) + return yaml2elf(*Doc.Elf, Out); + if (Doc.Coff) + return yaml2coff(*Doc.Coff, Out); + if (Doc.MachO || Doc.FatMachO) + return yaml2macho(Doc, Out); + errs() << "yaml2obj: Unknown document type!\n"; + return 1; + } } while (YIn.nextDocument()); errs() << "yaml2obj: Cannot find the " << DocNum @@ -77,7 +69,7 @@ static int convertYAML(yaml::Input &YIn, raw_ostream &Out, int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. @@ -97,19 +89,9 @@ int main(int argc, char **argv) { if (!Buf) return 1; - ConvertFuncPtr Convert = nullptr; - if (Format == YOF_COFF) - Convert = yaml2coff; - else if (Format == YOF_ELF) - Convert = yaml2elf; - else { - errs() << "Not yet implemented\n"; - return 1; - } - yaml::Input YIn(Buf.get()->getBuffer()); - int Res = convertYAML(YIn, Out->os(), Convert); + int Res = convertYAML(YIn, Out->os()); if (Res == 0) Out->keep(); diff --git a/tools/yaml2obj/yaml2obj.h b/tools/yaml2obj/yaml2obj.h index 7290a9af2c6498251c3be59f6e2aeefa9f70772b..b5025e860bd751281be43b9daf83b5e6af8b8bba 100644 --- a/tools/yaml2obj/yaml2obj.h +++ b/tools/yaml2obj/yaml2obj.h @@ -14,11 +14,23 @@ namespace llvm { class raw_ostream; + +namespace COFFYAML { +struct Object; +} + +namespace ELFYAML { +struct Object; +} + namespace yaml { class Input; +struct YamlObjectFile; } } -int yaml2coff(llvm::yaml::Input &YIn, llvm::raw_ostream &Out); -int yaml2elf(llvm::yaml::Input &YIn, llvm::raw_ostream &Out); + +int yaml2coff(llvm::COFFYAML::Object &Doc, llvm::raw_ostream &Out); +int yaml2elf(llvm::ELFYAML::Object &Doc, llvm::raw_ostream &Out); +int yaml2macho(llvm::yaml::YamlObjectFile &Doc, llvm::raw_ostream &Out); #endif diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index d884c8a27077241d3f314f06a29366fd6da24ee0..18734eb72b826c72173db16f10aecd5d3667ad6d 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -9,7 +9,6 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" diff --git a/unittests/ADT/APIntTest.cpp b/unittests/ADT/APIntTest.cpp index c59e695b04eafe1ac6e076c11cc332561e68abb4..b0d80c3c681910588ba05b91f4bdaac59426b9c9 100644 --- a/unittests/ADT/APIntTest.cpp +++ b/unittests/ADT/APIntTest.cpp @@ -8,10 +8,10 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "gtest/gtest.h" #include -#include using namespace llvm; @@ -388,6 +388,34 @@ TEST(APIntTest, compareWithHalfInt64Max) { EXPECT_TRUE( a.sge(edgeM1)); } +TEST(APIntTest, compareLargeIntegers) { + // Make sure all the combinations of signed comparisons work with big ints. + auto One = APInt{128, static_cast(1), true}; + auto Two = APInt{128, static_cast(2), true}; + auto MinusOne = APInt{128, static_cast(-1), true}; + auto MinusTwo = APInt{128, static_cast(-2), true}; + + EXPECT_TRUE(!One.slt(One)); + EXPECT_TRUE(!Two.slt(One)); + EXPECT_TRUE(MinusOne.slt(One)); + EXPECT_TRUE(MinusTwo.slt(One)); + + EXPECT_TRUE(One.slt(Two)); + EXPECT_TRUE(!Two.slt(Two)); + EXPECT_TRUE(MinusOne.slt(Two)); + EXPECT_TRUE(MinusTwo.slt(Two)); + + EXPECT_TRUE(!One.slt(MinusOne)); + EXPECT_TRUE(!Two.slt(MinusOne)); + EXPECT_TRUE(!MinusOne.slt(MinusOne)); + EXPECT_TRUE(MinusTwo.slt(MinusOne)); + + EXPECT_TRUE(!One.slt(MinusTwo)); + EXPECT_TRUE(!Two.slt(MinusTwo)); + EXPECT_TRUE(!MinusOne.slt(MinusTwo)); + EXPECT_TRUE(!MinusTwo.slt(MinusTwo)); +} + // Tests different div/rem varaints using scheme (a * b + c) / a void testDiv(APInt a, APInt b, APInt c) { @@ -994,6 +1022,23 @@ TEST(APIntTest, IsSplat) { EXPECT_TRUE(E.isSplat(32)); } +TEST(APIntTest, isMask) { + EXPECT_FALSE(APIntOps::isMask(APInt(32, 0x01010101))); + EXPECT_FALSE(APIntOps::isMask(APInt(32, 0xf0000000))); + EXPECT_FALSE(APIntOps::isMask(APInt(32, 0xffff0000))); + EXPECT_FALSE(APIntOps::isMask(APInt(32, 0xff << 1))); + + for (int N : { 1, 2, 3, 4, 7, 8, 16, 32, 64, 127, 128, 129, 256 }) { + EXPECT_FALSE(APIntOps::isMask(APInt(N, 0))); + + APInt One(N, 1); + for (int I = 1; I <= N; ++I) { + APInt MaskVal = One.shl(I) - 1; + EXPECT_TRUE(APIntOps::isMask(MaskVal)); + } + } +} + #if defined(__clang__) // Disable the pragma warning from versions of Clang without -Wself-move #pragma clang diagnostic push diff --git a/unittests/ADT/ArrayRefTest.cpp b/unittests/ADT/ArrayRefTest.cpp index 6cbadd6bc228fa33df0cd1b2092162f9a1e99cb4..b5b71f06f65b2206912168af0ed9ef8136c2cd54 100644 --- a/unittests/ADT/ArrayRefTest.cpp +++ b/unittests/ADT/ArrayRefTest.cpp @@ -65,6 +65,21 @@ TEST(ArrayRefTest, DropBack) { ArrayRef AR1(TheNumbers); ArrayRef AR2(TheNumbers, AR1.size() - 1); EXPECT_TRUE(AR1.drop_back().equals(AR2)); + + // Check that drop_back accepts size_t-sized numbers. + ArrayRef AR3((const char *)0x10000, SIZE_MAX - 0x10000); + EXPECT_EQ(1U, AR3.drop_back(AR3.size() - 1).size()); +} + +TEST(ArrayRefTest, DropFront) { + static const int TheNumbers[] = {4, 8, 15, 16, 23, 42}; + ArrayRef AR1(TheNumbers); + ArrayRef AR2(&TheNumbers[2], AR1.size() - 2); + EXPECT_TRUE(AR1.drop_front(2).equals(AR2)); + + // Check that drop_front accepts size_t-sized numbers. + ArrayRef AR3((const char *)0x10000, SIZE_MAX - 0x10000); + EXPECT_EQ(1U, AR3.drop_front(AR3.size() - 1).size()); } TEST(ArrayRefTest, Equals) { @@ -94,6 +109,13 @@ TEST(ArrayRefTest, EmptyEquals) { EXPECT_TRUE(ArrayRef() == ArrayRef()); } +TEST(ArrayRefTest, Slice) { + // Check that slice accepts size_t-sized numbers. + ArrayRef AR((const char *)0x10000, SIZE_MAX - 0x10000); + EXPECT_EQ(1U, AR.slice(AR.size() - 1).size()); + EXPECT_EQ(AR.size() - 1, AR.slice(1, AR.size() - 1).size()); +} + TEST(ArrayRefTest, ConstConvert) { int buf[4]; for (int i = 0; i < 4; ++i) diff --git a/unittests/ADT/BitVectorTest.cpp b/unittests/ADT/BitVectorTest.cpp index 95ff93fa9c4c8a35957f57b2115678169b52394e..78fd5ce65677cd6c941b401b09787b3fb2e5835a 100644 --- a/unittests/ADT/BitVectorTest.cpp +++ b/unittests/ADT/BitVectorTest.cpp @@ -399,5 +399,31 @@ TYPED_TEST(BitVectorTest, CompoundTestReset) { C.reset(C); EXPECT_TRUE(C.none()); } + +TYPED_TEST(BitVectorTest, MoveConstructor) { + TypeParam A(10, true); + TypeParam B(std::move(A)); + // Check that the move ctor leaves the moved-from object in a valid state. + // The following line used to crash. + A = B; + + TypeParam C(10, true); + EXPECT_EQ(C, A); + EXPECT_EQ(C, B); +} + +TYPED_TEST(BitVectorTest, MoveAssignment) { + TypeParam A(10, true); + TypeParam B; + B = std::move(A); + // Check that move assignment leaves the moved-from object in a valid state. + // The following line used to crash. + A = B; + + TypeParam C(10, true); + EXPECT_EQ(C, A); + EXPECT_EQ(C, B); +} + } #endif diff --git a/unittests/ADT/BitmaskEnumTest.cpp b/unittests/ADT/BitmaskEnumTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77635c638e9360388cd6414550d9d772dda52057 --- /dev/null +++ b/unittests/ADT/BitmaskEnumTest.cpp @@ -0,0 +1,134 @@ +//===- llvm/unittest/ADT/BitmaskEnumTest.cpp - BitmaskEnum unit tests -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/BitmaskEnum.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { +enum Flags { + F0 = 0, + F1 = 1, + F2 = 2, + F3 = 4, + F4 = 8, + LLVM_MARK_AS_BITMASK_ENUM(F4) +}; + +TEST(BitmaskEnumTest, BitwiseOr) { + Flags f = F1 | F2; + EXPECT_EQ(3, f); + + f = f | F3; + EXPECT_EQ(7, f); +} + +TEST(BitmaskEnumTest, BitwiseOrEquals) { + Flags f = F1; + f |= F3; + EXPECT_EQ(5, f); + + // |= should return a reference to the LHS. + f = F2; + (f |= F3) = F1; + EXPECT_EQ(F1, f); +} + +TEST(BitmaskEnumTest, BitwiseAnd) { + Flags f = static_cast(3) & F2; + EXPECT_EQ(F2, f); + + f = (f | F3) & (F1 | F2 | F3); + EXPECT_EQ(6, f); +} + +TEST(BitmaskEnumTest, BitwiseAndEquals) { + Flags f = F1 | F2 | F3; + f &= F1 | F2; + EXPECT_EQ(3, f); + + // &= should return a reference to the LHS. + (f &= F1) = F3; + EXPECT_EQ(F3, f); +} + +TEST(BitmaskEnumTest, BitwiseXor) { + Flags f = (F1 | F2) ^ (F2 | F3); + EXPECT_EQ(5, f); + + f = f ^ F1; + EXPECT_EQ(4, f); +} + +TEST(BitmaskEnumTest, BitwiseXorEquals) { + Flags f = (F1 | F2); + f ^= (F2 | F4); + EXPECT_EQ(9, f); + + // ^= should return a reference to the LHS. + (f ^= F4) = F3; + EXPECT_EQ(F3, f); +} + +TEST(BitmaskEnumTest, BitwiseNot) { + Flags f = ~F1; + EXPECT_EQ(14, f); // Largest value for f is 15. + EXPECT_EQ(15, ~F0); +} + +enum class FlagsClass { + F0 = 0, + F1 = 1, + F2 = 2, + F3 = 4, + LLVM_MARK_AS_BITMASK_ENUM(F3) +}; + +TEST(BitmaskEnumTest, ScopedEnum) { + FlagsClass f = (FlagsClass::F1 & ~FlagsClass::F0) | FlagsClass::F2; + f |= FlagsClass::F3; + EXPECT_EQ(7, static_cast(f)); +} + +struct Container { + enum Flags { F0 = 0, F1 = 1, F2 = 2, F3 = 4, LLVM_MARK_AS_BITMASK_ENUM(F3) }; + + static Flags getFlags() { + Flags f = F0 | F1; + f |= F2; + return f; + } +}; + +TEST(BitmaskEnumTest, EnumInStruct) { EXPECT_EQ(3, Container::getFlags()); } + +} // namespace + +namespace foo { +namespace bar { +namespace { +enum FlagsInNamespace { + F0 = 0, + F1 = 1, + F2 = 2, + F3 = 4, + LLVM_MARK_AS_BITMASK_ENUM(F3) +}; +} // namespace +} // namespace foo +} // namespace bar + +namespace { +TEST(BitmaskEnumTest, EnumInNamespace) { + foo::bar::FlagsInNamespace f = ~foo::bar::F0 & (foo::bar::F1 | foo::bar::F2); + f |= foo::bar::F3; + EXPECT_EQ(7, f); +} +} // namespace diff --git a/unittests/ADT/CMakeLists.txt b/unittests/ADT/CMakeLists.txt index 49ea73c7757717b98c6694a57c46b6f87bf969b4..ca1644b5346ee9767335e9fe05b4fbe493c88cd4 100644 --- a/unittests/ADT/CMakeLists.txt +++ b/unittests/ADT/CMakeLists.txt @@ -7,6 +7,7 @@ set(ADTSources APIntTest.cpp APSIntTest.cpp ArrayRefTest.cpp + BitmaskEnumTest.cpp BitVectorTest.cpp DAGDeltaAlgorithmTest.cpp DeltaAlgorithmTest.cpp @@ -30,8 +31,10 @@ set(ADTSources PointerSumTypeTest.cpp PointerUnionTest.cpp PostOrderIteratorTest.cpp + PriorityWorklistTest.cpp RangeAdapterTest.cpp SCCIteratorTest.cpp + SequenceTest.cpp SetVectorTest.cpp SmallPtrSetTest.cpp SmallStringTest.cpp diff --git a/unittests/ADT/DenseMapTest.cpp b/unittests/ADT/DenseMapTest.cpp index caeba4579187986d54ee6e8ef1453bf733f787f7..db00f8cf8e57aa7178d8e9dbe64d6e0d5e200d4d 100644 --- a/unittests/ADT/DenseMapTest.cpp +++ b/unittests/ADT/DenseMapTest.cpp @@ -496,6 +496,55 @@ TEST(DenseMapCustomTest, StringRefTest) { EXPECT_EQ(42, M.lookup(StringRef("a", 0))); } +struct CachedHashTest { + unsigned Val; + unsigned *Counter = nullptr; + CachedHashTest(unsigned Val) : Val(Val) {} + CachedHashTest(unsigned Val, unsigned *Counter) + : Val(Val), Counter(Counter) {} +}; +} +namespace llvm { +template <> struct DenseMapInfo { + static CachedHashTest getEmptyKey() { return ~0; } + static CachedHashTest getTombstoneKey() { return ~0U - 1; } + static unsigned getHashValue(const CachedHashTest &X) { + ++*X.Counter; + return X.Val; + } + static bool isEqual(const CachedHashTest &LHS, const CachedHashTest &RHS) { + return LHS.Val == RHS.Val; + } +}; +} +namespace { + +TEST(DenseMapCustomTest, CachedHashTest) { + unsigned Counter = 0; + CachedHashTest Val(0, &Counter); + DenseMap Map; + + Map[Val] = 0; + ASSERT_EQ(1u, Counter); + + Map.reserve(64); + ASSERT_EQ(2u, Counter); +} + +// Like above, but now cache the hash. +TEST(DenseMapCustomTest, CachedHashTest2) { + unsigned Counter = 0; + CachedHashTest Val(0, &Counter); + typedef CachedHash Cached; + DenseMap Map; + + Map[Val] = 0; + ASSERT_EQ(1u, Counter); + + Map.reserve(64); + ASSERT_EQ(1u, Counter); +} + // Key traits that allows lookup with either an unsigned or char* key; // In the latter case, "a" == 0, "b" == 1 and so on. struct TestDenseMapInfo { diff --git a/unittests/ADT/FoldingSet.cpp b/unittests/ADT/FoldingSet.cpp index 5addf27e13635e00d4e9bb5db3d92bae4fe1f9ea..927ef313cb9364fd03271f9a94fdf83c8474d3ae 100644 --- a/unittests/ADT/FoldingSet.cpp +++ b/unittests/ADT/FoldingSet.cpp @@ -35,5 +35,138 @@ TEST(FoldingSetTest, UnalignedStringTest) { EXPECT_EQ(a.ComputeHash(), b.ComputeHash()); } +struct TrivialPair : public FoldingSetNode { + unsigned Key = 0; + unsigned Value = 0; + TrivialPair(unsigned K, unsigned V) : FoldingSetNode(), Key(K), Value(V) {} + + void Profile(FoldingSetNodeID &ID) const { + ID.AddInteger(Key); + ID.AddInteger(Value); + } +}; + +TEST(FoldingSetTest, IDComparison) { + FoldingSet Trivial; + + TrivialPair T(99, 42); + Trivial.InsertNode(&T); + + void *InsertPos = nullptr; + FoldingSetNodeID ID; + T.Profile(ID); + TrivialPair *N = Trivial.FindNodeOrInsertPos(ID, InsertPos); + EXPECT_EQ(&T, N); + EXPECT_EQ(nullptr, InsertPos); +} + +TEST(FoldingSetTest, MissedIDComparison) { + FoldingSet Trivial; + + TrivialPair S(100, 42); + TrivialPair T(99, 42); + Trivial.InsertNode(&T); + + void *InsertPos = nullptr; + FoldingSetNodeID ID; + S.Profile(ID); + TrivialPair *N = Trivial.FindNodeOrInsertPos(ID, InsertPos); + EXPECT_EQ(nullptr, N); + EXPECT_NE(nullptr, InsertPos); +} + +TEST(FoldingSetTest, RemoveNodeThatIsPresent) { + FoldingSet Trivial; + + TrivialPair T(99, 42); + Trivial.InsertNode(&T); + EXPECT_EQ(Trivial.size(), 1U); + + bool WasThere = Trivial.RemoveNode(&T); + EXPECT_TRUE(WasThere); + EXPECT_EQ(0U, Trivial.size()); +} + +TEST(FoldingSetTest, RemoveNodeThatIsAbsent) { + FoldingSet Trivial; + + TrivialPair T(99, 42); + bool WasThere = Trivial.RemoveNode(&T); + EXPECT_FALSE(WasThere); + EXPECT_EQ(0U, Trivial.size()); +} + +TEST(FoldingSetTest, GetOrInsertInserting) { + FoldingSet Trivial; + + TrivialPair T(99, 42); + TrivialPair *N = Trivial.GetOrInsertNode(&T); + EXPECT_EQ(&T, N); +} + +TEST(FoldingSetTest, GetOrInsertGetting) { + FoldingSet Trivial; + + TrivialPair T(99, 42); + TrivialPair T2(99, 42); + Trivial.InsertNode(&T); + TrivialPair *N = Trivial.GetOrInsertNode(&T2); + EXPECT_EQ(&T, N); +} + +TEST(FoldingSetTest, InsertAtPos) { + FoldingSet Trivial; + + void *InsertPos = nullptr; + TrivialPair Finder(99, 42); + FoldingSetNodeID ID; + Finder.Profile(ID); + Trivial.FindNodeOrInsertPos(ID, InsertPos); + + TrivialPair T(99, 42); + Trivial.InsertNode(&T, InsertPos); + EXPECT_EQ(1U, Trivial.size()); +} + +TEST(FoldingSetTest, EmptyIsTrue) { + FoldingSet Trivial; + EXPECT_TRUE(Trivial.empty()); +} + +TEST(FoldingSetTest, EmptyIsFalse) { + FoldingSet Trivial; + TrivialPair T(99, 42); + Trivial.InsertNode(&T); + EXPECT_FALSE(Trivial.empty()); +} + +TEST(FoldingSetTest, ClearOnEmpty) { + FoldingSet Trivial; + Trivial.clear(); + EXPECT_TRUE(Trivial.empty()); +} + +TEST(FoldingSetTest, ClearOnNonEmpty) { + FoldingSet Trivial; + TrivialPair T(99, 42); + Trivial.InsertNode(&T); + Trivial.clear(); + EXPECT_TRUE(Trivial.empty()); +} + +TEST(FoldingSetTest, CapacityLargerThanReserve) { + FoldingSet Trivial; + auto OldCapacity = Trivial.capacity(); + Trivial.reserve(OldCapacity + 1); + EXPECT_GE(Trivial.capacity(), OldCapacity + 1); +} + +TEST(FoldingSetTest, SmallReserveChangesNothing) { + FoldingSet Trivial; + auto OldCapacity = Trivial.capacity(); + Trivial.reserve(OldCapacity - 1); + EXPECT_EQ(Trivial.capacity(), OldCapacity); +} + } diff --git a/unittests/ADT/PriorityWorklistTest.cpp b/unittests/ADT/PriorityWorklistTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bbe026434c6318f78c82849d72e59e1cac8c1d49 --- /dev/null +++ b/unittests/ADT/PriorityWorklistTest.cpp @@ -0,0 +1,106 @@ +//===- llvm/unittest/ADT/PriorityWorklist.cpp -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// PriorityWorklist unit tests. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/PriorityWorklist.h" +#include "gtest/gtest.h" + +namespace { + +using namespace llvm; + +template class PriorityWorklistTest : public ::testing::Test {}; +typedef ::testing::Types, SmallPriorityWorklist> + TestTypes; +TYPED_TEST_CASE(PriorityWorklistTest, TestTypes); + +TYPED_TEST(PriorityWorklistTest, Basic) { + TypeParam W; + EXPECT_TRUE(W.empty()); + EXPECT_EQ(0u, W.size()); + EXPECT_FALSE(W.count(42)); + + EXPECT_TRUE(W.insert(21)); + EXPECT_TRUE(W.insert(42)); + EXPECT_TRUE(W.insert(17)); + + EXPECT_FALSE(W.empty()); + EXPECT_EQ(3u, W.size()); + EXPECT_TRUE(W.count(42)); + + EXPECT_FALSE(W.erase(75)); + EXPECT_EQ(3u, W.size()); + EXPECT_EQ(17, W.back()); + + EXPECT_TRUE(W.erase(17)); + EXPECT_FALSE(W.count(17)); + EXPECT_EQ(2u, W.size()); + EXPECT_EQ(42, W.back()); + + W.clear(); + EXPECT_TRUE(W.empty()); + EXPECT_EQ(0u, W.size()); + + EXPECT_TRUE(W.insert(21)); + EXPECT_TRUE(W.insert(42)); + EXPECT_TRUE(W.insert(12)); + EXPECT_TRUE(W.insert(17)); + EXPECT_TRUE(W.count(12)); + EXPECT_TRUE(W.count(17)); + EXPECT_EQ(4u, W.size()); + EXPECT_EQ(17, W.back()); + EXPECT_TRUE(W.erase(12)); + EXPECT_FALSE(W.count(12)); + EXPECT_TRUE(W.count(17)); + EXPECT_EQ(3u, W.size()); + EXPECT_EQ(17, W.back()); + + EXPECT_FALSE(W.insert(42)); + EXPECT_EQ(3u, W.size()); + EXPECT_EQ(42, W.pop_back_val()); + EXPECT_EQ(17, W.pop_back_val()); + EXPECT_EQ(21, W.pop_back_val()); + EXPECT_TRUE(W.empty()); +} + +TYPED_TEST(PriorityWorklistTest, EraseIf) { + TypeParam W; + W.insert(23); + W.insert(10); + W.insert(47); + W.insert(42); + W.insert(23); + W.insert(13); + W.insert(26); + W.insert(42); + EXPECT_EQ(6u, W.size()); + + EXPECT_FALSE(W.erase_if([](int i) { return i > 100; })); + EXPECT_EQ(6u, W.size()); + EXPECT_EQ(42, W.back()); + + EXPECT_TRUE(W.erase_if([](int i) { + assert(i != 0 && "Saw a null value!"); + return (i & 1) == 0; + })); + EXPECT_EQ(3u, W.size()); + EXPECT_FALSE(W.count(42)); + EXPECT_FALSE(W.count(26)); + EXPECT_FALSE(W.count(10)); + EXPECT_FALSE(W.insert(47)); + EXPECT_FALSE(W.insert(23)); + EXPECT_EQ(23, W.pop_back_val()); + EXPECT_EQ(47, W.pop_back_val()); + EXPECT_EQ(13, W.pop_back_val()); +} + +} diff --git a/unittests/ADT/SequenceTest.cpp b/unittests/ADT/SequenceTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d82c3c2d4ef52e7121df643bd0f48e48dd586595 --- /dev/null +++ b/unittests/ADT/SequenceTest.cpp @@ -0,0 +1,39 @@ +//===- SequenceTest.cpp - Unit tests for a sequence abstraciton -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Sequence.h" +#include "gtest/gtest.h" + +#include + +using namespace llvm; + +namespace { + +TEST(SequenceTest, Basic) { + int x = 0; + for (int i : seq(0, 10)) + EXPECT_EQ(x++, i); + EXPECT_EQ(10, x); + + auto my_seq = seq(0, 4); + EXPECT_EQ(4, my_seq.end() - my_seq.begin()); + for (int i : {0, 1, 2, 3}) + EXPECT_EQ(i, (int)my_seq.begin()[i]); + + EXPECT_TRUE(my_seq.begin() < my_seq.end()); + + auto adjusted_begin = my_seq.begin() + 2; + auto adjusted_end = my_seq.end() - 2; + EXPECT_TRUE(adjusted_begin == adjusted_end); + EXPECT_EQ(2, *adjusted_begin); + EXPECT_EQ(2, *adjusted_end); +} + +} // anonymous namespace diff --git a/unittests/ADT/StringMapTest.cpp b/unittests/ADT/StringMapTest.cpp index 562126eb326d32f97a6071470b6222591a54b44f..6ca701bb23a52e03b38ddecf87ed69cf434fa40d 100644 --- a/unittests/ADT/StringMapTest.cpp +++ b/unittests/ADT/StringMapTest.cpp @@ -7,9 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "gtest/gtest.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/DataTypes.h" +#include "gtest/gtest.h" #include using namespace llvm; @@ -157,6 +158,33 @@ TEST_F(StringMapTest, SmallFullMapTest) { EXPECT_EQ(5, Map.lookup("funf")); } +TEST_F(StringMapTest, CopyCtorTest) { + llvm::StringMap Map; + + Map["eins"] = 1; + Map["zwei"] = 2; + Map["drei"] = 3; + Map.erase("drei"); + Map.erase("eins"); + Map["veir"] = 4; + Map["funf"] = 5; + + EXPECT_EQ(3u, Map.size()); + EXPECT_EQ(0, Map.lookup("eins")); + EXPECT_EQ(2, Map.lookup("zwei")); + EXPECT_EQ(0, Map.lookup("drei")); + EXPECT_EQ(4, Map.lookup("veir")); + EXPECT_EQ(5, Map.lookup("funf")); + + llvm::StringMap Map2(Map); + EXPECT_EQ(3u, Map2.size()); + EXPECT_EQ(0, Map2.lookup("eins")); + EXPECT_EQ(2, Map2.lookup("zwei")); + EXPECT_EQ(0, Map2.lookup("drei")); + EXPECT_EQ(4, Map2.lookup("veir")); + EXPECT_EQ(5, Map2.lookup("funf")); +} + // A more complex iteration test. TEST_F(StringMapTest, IterationTest) { bool visited[100]; diff --git a/unittests/ADT/TinyPtrVectorTest.cpp b/unittests/ADT/TinyPtrVectorTest.cpp index 294dfac0c6336e7b8570324a67af885ed23482ae..26189b76394fc9460023d38d1cc828d761a5755c 100644 --- a/unittests/ADT/TinyPtrVectorTest.cpp +++ b/unittests/ADT/TinyPtrVectorTest.cpp @@ -14,11 +14,9 @@ #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/Support/type_traits.h" #include "gtest/gtest.h" #include -#include #include using namespace llvm; diff --git a/unittests/ADT/TripleTest.cpp b/unittests/ADT/TripleTest.cpp index e3835422433e2059c8890201aee2627ae6e1188d..984f4a2a595a52825e32868577fba000dc9aae1f 100644 --- a/unittests/ADT/TripleTest.cpp +++ b/unittests/ADT/TripleTest.cpp @@ -93,6 +93,12 @@ TEST(TripleTest, ParsedIDs) { EXPECT_EQ(Triple::Linux, T.getOS()); EXPECT_EQ(Triple::GNU, T.getEnvironment()); + T = Triple("x86_64-pc-linux-musl"); + EXPECT_EQ(Triple::x86_64, T.getArch()); + EXPECT_EQ(Triple::PC, T.getVendor()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::Musl, T.getEnvironment()); + T = Triple("powerpc-bgp-linux"); EXPECT_EQ(Triple::ppc, T.getArch()); EXPECT_EQ(Triple::BGP, T.getVendor()); @@ -135,6 +141,12 @@ TEST(TripleTest, ParsedIDs) { EXPECT_EQ(Triple::UnknownOS, T.getOS()); EXPECT_EQ(Triple::EABI, T.getEnvironment()); + T = Triple("arm-none-linux-musleabi"); + EXPECT_EQ(Triple::arm, T.getArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::Linux, T.getOS()); + EXPECT_EQ(Triple::MuslEABI, T.getEnvironment()); + T = Triple("armv6hl-none-linux-gnueabi"); EXPECT_EQ(Triple::arm, T.getArch()); EXPECT_EQ(Triple::Linux, T.getOS()); @@ -631,6 +643,14 @@ TEST(TripleTest, EndianArchVariants) { T.setArch(Triple::arm); EXPECT_EQ(Triple::UnknownArch, T.getBigEndianArchVariant().getArch()); EXPECT_EQ(Triple::arm, T.getLittleEndianArchVariant().getArch()); + T = Triple("arm"); + EXPECT_TRUE(T.isLittleEndian()); + T = Triple("thumb"); + EXPECT_TRUE(T.isLittleEndian()); + T = Triple("armeb"); + EXPECT_FALSE(T.isLittleEndian()); + T = Triple("thumbeb"); + EXPECT_FALSE(T.isLittleEndian()); T.setArch(Triple::bpfeb); EXPECT_EQ(Triple::bpfeb, T.getBigEndianArchVariant().getArch()); diff --git a/unittests/Analysis/AliasAnalysisTest.cpp b/unittests/Analysis/AliasAnalysisTest.cpp index 2d0eaca692c3b0ca7accdbe2c96db1d2799c50c8..84a04257bc270ac4f944753fee1612c00a64b8a2 100644 --- a/unittests/Analysis/AliasAnalysisTest.cpp +++ b/unittests/Analysis/AliasAnalysisTest.cpp @@ -14,12 +14,11 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/Constants.h" -#include "llvm/IR/Instructions.h" #include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" @@ -179,12 +178,12 @@ TEST_F(AliasAnalysisTest, getModRefInfo) { auto *Load1 = new LoadInst(Addr, "load", BB); auto *Add1 = BinaryOperator::CreateAdd(Value, Value, "add", BB); auto *VAArg1 = new VAArgInst(Addr, PtrType, "vaarg", BB); - auto *CmpXChg1 = new AtomicCmpXchgInst(Addr, ConstantInt::get(IntType, 0), - ConstantInt::get(IntType, 1), - Monotonic, Monotonic, CrossThread, BB); + auto *CmpXChg1 = new AtomicCmpXchgInst( + Addr, ConstantInt::get(IntType, 0), ConstantInt::get(IntType, 1), + AtomicOrdering::Monotonic, AtomicOrdering::Monotonic, CrossThread, BB); auto *AtomicRMW = new AtomicRMWInst(AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1), - Monotonic, CrossThread, BB); + AtomicOrdering::Monotonic, CrossThread, BB); ReturnInst::Create(C, nullptr, BB); @@ -207,14 +206,13 @@ TEST_F(AliasAnalysisTest, getModRefInfo) { class AAPassInfraTest : public testing::Test { protected: - LLVMContext &C; + LLVMContext C; SMDiagnostic Err; std::unique_ptr M; public: AAPassInfraTest() - : C(getGlobalContext()), - M(parseAssemblyString("define i32 @f(i32* %x, i32* %y) {\n" + : M(parseAssemblyString("define i32 @f(i32* %x, i32* %y) {\n" "entry:\n" " %lx = load i32, i32* %x\n" " %ly = load i32, i32* %y\n" diff --git a/unittests/Analysis/BlockFrequencyInfoTest.cpp b/unittests/Analysis/BlockFrequencyInfoTest.cpp index 64516373e8e89368f8df9017214455abafb15515..b3b0fcfb049bf3b6ed63f68e15f03ae6e407d65f 100644 --- a/unittests/Analysis/BlockFrequencyInfoTest.cpp +++ b/unittests/Analysis/BlockFrequencyInfoTest.cpp @@ -30,6 +30,7 @@ protected: std::unique_ptr BPI; std::unique_ptr DT; std::unique_ptr LI; + LLVMContext C; BlockFrequencyInfo buildBFI(Function &F) { DT.reset(new DominatorTree(F)); @@ -50,7 +51,6 @@ protected: " %y2 = phi i32 [0, %bb1], [1, %bb2] \n" " ret i32 %y2\n" "}\n"; - LLVMContext &C = getGlobalContext(); SMDiagnostic Err; return parseAssemblyString(ModuleStrig, Err, C); } diff --git a/unittests/Analysis/CFGTest.cpp b/unittests/Analysis/CFGTest.cpp index 44f0fe681dffd32587d8fa2f16d8cac473df744a..c60044fa52dffd7b1614777668f61eb89045c158 100644 --- a/unittests/Analysis/CFGTest.cpp +++ b/unittests/Analysis/CFGTest.cpp @@ -31,7 +31,7 @@ class IsPotentiallyReachableTest : public testing::Test { protected: void ParseAssembly(const char *Assembly) { SMDiagnostic Error; - M = parseAssemblyString(Assembly, Error, getGlobalContext()); + M = parseAssemblyString(Assembly, Error, Context); std::string errMsg; raw_string_ostream os(errMsg); @@ -112,6 +112,7 @@ protected: PM.run(*M); } + LLVMContext Context; std::unique_ptr M; Instruction *A, *B; }; diff --git a/unittests/Analysis/CGSCCPassManagerTest.cpp b/unittests/Analysis/CGSCCPassManagerTest.cpp index 857c84d501684d46b3d0954af492d1d4451e310f..224f2df1318118ddd1985b487ee5a4e7b68492c6 100644 --- a/unittests/Analysis/CGSCCPassManagerTest.cpp +++ b/unittests/Analysis/CGSCCPassManagerTest.cpp @@ -142,9 +142,8 @@ struct TestModulePass { struct TestSCCPass { TestSCCPass(int &RunCount, int &AnalyzedInstrCount, - int &AnalyzedSCCFunctionCount, - int &AnalyzedModuleFunctionCount, - bool OnlyUseCachedResults = false) + int &AnalyzedSCCFunctionCount, int &AnalyzedModuleFunctionCount, + bool OnlyUseCachedResults = false) : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount), AnalyzedSCCFunctionCount(AnalyzedSCCFunctionCount), AnalyzedModuleFunctionCount(AnalyzedModuleFunctionCount), @@ -199,7 +198,7 @@ struct TestSCCPass { struct TestFunctionPass { TestFunctionPass(int &RunCount) : RunCount(RunCount) {} - PreservedAnalyses run(Function &M) { + PreservedAnalyses run(Function &F, AnalysisManager &) { ++RunCount; return PreservedAnalyses::none(); } @@ -210,53 +209,47 @@ struct TestFunctionPass { }; std::unique_ptr parseIR(const char *IR) { - LLVMContext &C = getGlobalContext(); + // We just use a static context here. This is never called from multiple + // threads so it is harmless no matter how it is implemented. We just need + // the context to outlive the module which it does. + static LLVMContext C; SMDiagnostic Err; return parseAssemblyString(IR, Err, C); } -class CGSCCPassManagerTest : public ::testing::Test { -protected: - std::unique_ptr M; - -public: - CGSCCPassManagerTest() - : M(parseIR("define void @f() {\n" - "entry:\n" - " call void @g()\n" - " call void @h1()\n" - " ret void\n" - "}\n" - "define void @g() {\n" - "entry:\n" - " call void @g()\n" - " call void @x()\n" - " ret void\n" - "}\n" - "define void @h1() {\n" - "entry:\n" - " call void @h2()\n" - " ret void\n" - "}\n" - "define void @h2() {\n" - "entry:\n" - " call void @h3()\n" - " call void @x()\n" - " ret void\n" - "}\n" - "define void @h3() {\n" - "entry:\n" - " call void @h1()\n" - " ret void\n" - "}\n" - "define void @x() {\n" - "entry:\n" - " ret void\n" - "}\n" - )) {} -}; - -TEST_F(CGSCCPassManagerTest, Basic) { +TEST(CGSCCPassManagerTest, Basic) { + auto M = parseIR("define void @f() {\n" + "entry:\n" + " call void @g()\n" + " call void @h1()\n" + " ret void\n" + "}\n" + "define void @g() {\n" + "entry:\n" + " call void @g()\n" + " call void @x()\n" + " ret void\n" + "}\n" + "define void @h1() {\n" + "entry:\n" + " call void @h2()\n" + " ret void\n" + "}\n" + "define void @h2() {\n" + "entry:\n" + " call void @h3()\n" + " call void @x()\n" + " ret void\n" + "}\n" + "define void @h3() {\n" + "entry:\n" + " call void @h1()\n" + " ret void\n" + "}\n" + "define void @x() {\n" + "entry:\n" + " ret void\n" + "}\n"); FunctionAnalysisManager FAM(/*DebugLogging*/ true); int FunctionAnalysisRuns = 0; FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); }); diff --git a/unittests/Analysis/CallGraphTest.cpp b/unittests/Analysis/CallGraphTest.cpp index 777907a55b11c4e653577b8e889ba1eaf17718af..af46291074c20d528dfb268554a0880f0f4ee9d0 100644 --- a/unittests/Analysis/CallGraphTest.cpp +++ b/unittests/Analysis/CallGraphTest.cpp @@ -44,14 +44,16 @@ template void canSpecializeGraphTraitsIterators(Ty *G) { } TEST(CallGraphTest, GraphTraitsSpecialization) { - Module M("", getGlobalContext()); + LLVMContext Context; + Module M("", Context); CallGraph CG(M); canSpecializeGraphTraitsIterators(&CG); } TEST(CallGraphTest, GraphTraitsConstSpecialization) { - Module M("", getGlobalContext()); + LLVMContext Context; + Module M("", Context); CallGraph CG(M); canSpecializeGraphTraitsIterators(const_cast(&CG)); diff --git a/unittests/Analysis/LazyCallGraphTest.cpp b/unittests/Analysis/LazyCallGraphTest.cpp index 457c07dc30865c6038c6be30b61caf8cfb92bdd0..224a9458cc88558a8c78ce07f027160170106d68 100644 --- a/unittests/Analysis/LazyCallGraphTest.cpp +++ b/unittests/Analysis/LazyCallGraphTest.cpp @@ -21,10 +21,10 @@ using namespace llvm; namespace { -std::unique_ptr parseAssembly(const char *Assembly) { +std::unique_ptr parseAssembly(LLVMContext &Context, + const char *Assembly) { SMDiagnostic Error; - std::unique_ptr M = - parseAssemblyString(Assembly, Error, getGlobalContext()); + std::unique_ptr M = parseAssemblyString(Assembly, Error, Context); std::string ErrMsg; raw_string_ostream OS(ErrMsg); @@ -121,7 +121,8 @@ static const char DiamondOfTriangles[] = "}\n"; TEST(LazyCallGraphTest, BasicGraphFormation) { - std::unique_ptr M = parseAssembly(DiamondOfTriangles); + LLVMContext Context; + std::unique_ptr M = parseAssembly(Context, DiamondOfTriangles); LazyCallGraph CG(*M); // The order of the entry nodes should be stable w.r.t. the source order of @@ -280,21 +281,21 @@ static Function &lookupFunction(Module &M, StringRef Name) { } TEST(LazyCallGraphTest, BasicGraphMutation) { - std::unique_ptr M = parseAssembly( - "define void @a() {\n" - "entry:\n" - " call void @b()\n" - " call void @c()\n" - " ret void\n" - "}\n" - "define void @b() {\n" - "entry:\n" - " ret void\n" - "}\n" - "define void @c() {\n" - "entry:\n" - " ret void\n" - "}\n"); + LLVMContext Context; + std::unique_ptr M = parseAssembly(Context, "define void @a() {\n" + "entry:\n" + " call void @b()\n" + " call void @c()\n" + " ret void\n" + "}\n" + "define void @b() {\n" + "entry:\n" + " ret void\n" + "}\n" + "define void @c() {\n" + "entry:\n" + " ret void\n" + "}\n"); LazyCallGraph CG(*M); LazyCallGraph::Node &A = CG.get(lookupFunction(*M, "a")); @@ -328,7 +329,8 @@ TEST(LazyCallGraphTest, BasicGraphMutation) { } TEST(LazyCallGraphTest, InnerSCCFormation) { - std::unique_ptr M = parseAssembly(DiamondOfTriangles); + LLVMContext Context; + std::unique_ptr M = parseAssembly(Context, DiamondOfTriangles); LazyCallGraph CG(*M); // Now mutate the graph to connect every node into a single RefSCC to ensure @@ -391,37 +393,37 @@ TEST(LazyCallGraphTest, InnerSCCFormation) { } TEST(LazyCallGraphTest, MultiArmSCC) { + LLVMContext Context; // Two interlocking cycles. The really useful thing about this SCC is that it // will require Tarjan's DFS to backtrack and finish processing all of the // children of each node in the SCC. Since this involves call edges, both // Tarjan implementations will have to successfully navigate the structure. - std::unique_ptr M = parseAssembly( - "define void @f1() {\n" - "entry:\n" - " call void @f2()\n" - " call void @f4()\n" - " ret void\n" - "}\n" - "define void @f2() {\n" - "entry:\n" - " call void @f3()\n" - " ret void\n" - "}\n" - "define void @f3() {\n" - "entry:\n" - " call void @f1()\n" - " ret void\n" - "}\n" - "define void @f4() {\n" - "entry:\n" - " call void @f5()\n" - " ret void\n" - "}\n" - "define void @f5() {\n" - "entry:\n" - " call void @f1()\n" - " ret void\n" - "}\n"); + std::unique_ptr M = parseAssembly(Context, "define void @f1() {\n" + "entry:\n" + " call void @f2()\n" + " call void @f4()\n" + " ret void\n" + "}\n" + "define void @f2() {\n" + "entry:\n" + " call void @f3()\n" + " ret void\n" + "}\n" + "define void @f3() {\n" + "entry:\n" + " call void @f1()\n" + " ret void\n" + "}\n" + "define void @f4() {\n" + "entry:\n" + " call void @f5()\n" + " ret void\n" + "}\n" + "define void @f5() {\n" + "entry:\n" + " call void @f1()\n" + " ret void\n" + "}\n"); LazyCallGraph CG(*M); // Force the graph to be fully expanded. @@ -451,27 +453,27 @@ TEST(LazyCallGraphTest, MultiArmSCC) { } TEST(LazyCallGraphTest, OutgoingEdgeMutation) { - std::unique_ptr M = parseAssembly( - "define void @a() {\n" - "entry:\n" - " call void @b()\n" - " call void @c()\n" - " ret void\n" - "}\n" - "define void @b() {\n" - "entry:\n" - " call void @d()\n" - " ret void\n" - "}\n" - "define void @c() {\n" - "entry:\n" - " call void @d()\n" - " ret void\n" - "}\n" - "define void @d() {\n" - "entry:\n" - " ret void\n" - "}\n"); + LLVMContext Context; + std::unique_ptr M = parseAssembly(Context, "define void @a() {\n" + "entry:\n" + " call void @b()\n" + " call void @c()\n" + " ret void\n" + "}\n" + "define void @b() {\n" + "entry:\n" + " call void @d()\n" + " ret void\n" + "}\n" + "define void @c() {\n" + "entry:\n" + " call void @d()\n" + " ret void\n" + "}\n" + "define void @d() {\n" + "entry:\n" + " ret void\n" + "}\n"); LazyCallGraph CG(*M); // Force the graph to be fully expanded. @@ -575,6 +577,7 @@ TEST(LazyCallGraphTest, OutgoingEdgeMutation) { } TEST(LazyCallGraphTest, IncomingEdgeInsertion) { + LLVMContext Context; // We want to ensure we can add edges even across complex diamond graphs, so // we use the diamond of triangles graph defined above. The ascii diagram is // repeated here for easy reference. @@ -591,7 +594,7 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertion) { // / \ | // a3--a2 | // - std::unique_ptr M = parseAssembly(DiamondOfTriangles); + std::unique_ptr M = parseAssembly(Context, DiamondOfTriangles); LazyCallGraph CG(*M); // Force the graph to be fully expanded. @@ -668,9 +671,10 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertion) { } TEST(LazyCallGraphTest, IncomingEdgeInsertionMidTraversal) { + LLVMContext Context; // This is the same fundamental test as the previous, but we perform it // having only partially walked the RefSCCs of the graph. - std::unique_ptr M = parseAssembly(DiamondOfTriangles); + std::unique_ptr M = parseAssembly(Context, DiamondOfTriangles); LazyCallGraph CG(*M); // Walk the RefSCCs until we find the one containing 'c1'. @@ -744,22 +748,22 @@ TEST(LazyCallGraphTest, IncomingEdgeInsertionMidTraversal) { } TEST(LazyCallGraphTest, InternalEdgeMutation) { - std::unique_ptr M = parseAssembly( - "define void @a() {\n" - "entry:\n" - " call void @b()\n" - " ret void\n" - "}\n" - "define void @b() {\n" - "entry:\n" - " call void @c()\n" - " ret void\n" - "}\n" - "define void @c() {\n" - "entry:\n" - " call void @a()\n" - " ret void\n" - "}\n"); + LLVMContext Context; + std::unique_ptr M = parseAssembly(Context, "define void @a() {\n" + "entry:\n" + " call void @b()\n" + " ret void\n" + "}\n" + "define void @b() {\n" + "entry:\n" + " call void @c()\n" + " ret void\n" + "}\n" + "define void @c() {\n" + "entry:\n" + " call void @a()\n" + " ret void\n" + "}\n"); LazyCallGraph CG(*M); // Force the graph to be fully expanded. @@ -824,29 +828,30 @@ TEST(LazyCallGraphTest, InternalEdgeMutation) { } TEST(LazyCallGraphTest, InternalEdgeRemoval) { + LLVMContext Context; // A nice fully connected (including self-edges) RefSCC. std::unique_ptr M = parseAssembly( - "define void @a(i8** %ptr) {\n" - "entry:\n" - " store i8* bitcast (void(i8**)* @a to i8*), i8** %ptr\n" - " store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n" - " store i8* bitcast (void(i8**)* @c to i8*), i8** %ptr\n" - " ret void\n" - "}\n" - "define void @b(i8** %ptr) {\n" - "entry:\n" - " store i8* bitcast (void(i8**)* @a to i8*), i8** %ptr\n" - " store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n" - " store i8* bitcast (void(i8**)* @c to i8*), i8** %ptr\n" - " ret void\n" - "}\n" - "define void @c(i8** %ptr) {\n" - "entry:\n" - " store i8* bitcast (void(i8**)* @a to i8*), i8** %ptr\n" - " store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n" - " store i8* bitcast (void(i8**)* @c to i8*), i8** %ptr\n" - " ret void\n" - "}\n"); + Context, "define void @a(i8** %ptr) {\n" + "entry:\n" + " store i8* bitcast (void(i8**)* @a to i8*), i8** %ptr\n" + " store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n" + " store i8* bitcast (void(i8**)* @c to i8*), i8** %ptr\n" + " ret void\n" + "}\n" + "define void @b(i8** %ptr) {\n" + "entry:\n" + " store i8* bitcast (void(i8**)* @a to i8*), i8** %ptr\n" + " store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n" + " store i8* bitcast (void(i8**)* @c to i8*), i8** %ptr\n" + " ret void\n" + "}\n" + "define void @c(i8** %ptr) {\n" + "entry:\n" + " store i8* bitcast (void(i8**)* @a to i8*), i8** %ptr\n" + " store i8* bitcast (void(i8**)* @b to i8*), i8** %ptr\n" + " store i8* bitcast (void(i8**)* @c to i8*), i8** %ptr\n" + " ret void\n" + "}\n"); LazyCallGraph CG(*M); // Force the graph to be fully expanded. @@ -882,29 +887,29 @@ TEST(LazyCallGraphTest, InternalEdgeRemoval) { } TEST(LazyCallGraphTest, InternalCallEdgeToRef) { + LLVMContext Context; // A nice fully connected (including self-edges) SCC (and RefSCC) - std::unique_ptr M = parseAssembly( - "define void @a() {\n" - "entry:\n" - " call void @a()\n" - " call void @b()\n" - " call void @c()\n" - " ret void\n" - "}\n" - "define void @b() {\n" - "entry:\n" - " call void @a()\n" - " call void @b()\n" - " call void @c()\n" - " ret void\n" - "}\n" - "define void @c() {\n" - "entry:\n" - " call void @a()\n" - " call void @b()\n" - " call void @c()\n" - " ret void\n" - "}\n"); + std::unique_ptr M = parseAssembly(Context, "define void @a() {\n" + "entry:\n" + " call void @a()\n" + " call void @b()\n" + " call void @c()\n" + " ret void\n" + "}\n" + "define void @b() {\n" + "entry:\n" + " call void @a()\n" + " call void @b()\n" + " call void @c()\n" + " ret void\n" + "}\n" + "define void @c() {\n" + "entry:\n" + " call void @a()\n" + " call void @b()\n" + " call void @c()\n" + " ret void\n" + "}\n"); LazyCallGraph CG(*M); // Force the graph to be fully expanded. @@ -964,33 +969,34 @@ TEST(LazyCallGraphTest, InternalCallEdgeToRef) { } TEST(LazyCallGraphTest, InternalRefEdgeToCall) { + LLVMContext Context; // Basic tests for making a ref edge a call. This hits the basics of the // process only. - std::unique_ptr M = parseAssembly( - "define void @a() {\n" - "entry:\n" - " call void @b()\n" - " call void @c()\n" - " store void()* @d, void()** undef\n" - " ret void\n" - "}\n" - "define void @b() {\n" - "entry:\n" - " store void()* @c, void()** undef\n" - " call void @d()\n" - " ret void\n" - "}\n" - "define void @c() {\n" - "entry:\n" - " store void()* @b, void()** undef\n" - " call void @d()\n" - " ret void\n" - "}\n" - "define void @d() {\n" - "entry:\n" - " store void()* @a, void()** undef\n" - " ret void\n" - "}\n"); + std::unique_ptr M = + parseAssembly(Context, "define void @a() {\n" + "entry:\n" + " call void @b()\n" + " call void @c()\n" + " store void()* @d, void()** undef\n" + " ret void\n" + "}\n" + "define void @b() {\n" + "entry:\n" + " store void()* @c, void()** undef\n" + " call void @d()\n" + " ret void\n" + "}\n" + "define void @c() {\n" + "entry:\n" + " store void()* @b, void()** undef\n" + " call void @d()\n" + " ret void\n" + "}\n" + "define void @d() {\n" + "entry:\n" + " store void()* @a, void()** undef\n" + " ret void\n" + "}\n"); LazyCallGraph CG(*M); // Force the graph to be fully expanded. @@ -1049,59 +1055,60 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCall) { } TEST(LazyCallGraphTest, InternalRefEdgeToCallNoCycleInterleaved) { + LLVMContext Context; // Test for having a post-order prior to changing a ref edge to a call edge // with SCCs connecting to the source and connecting to the target, but not // connecting to both, interleaved between the source and target. This // ensures we correctly partition the range rather than simply moving one or // the other. - std::unique_ptr M = parseAssembly( - "define void @a() {\n" - "entry:\n" - " call void @b1()\n" - " call void @c1()\n" - " ret void\n" - "}\n" - "define void @b1() {\n" - "entry:\n" - " call void @c1()\n" - " call void @b2()\n" - " ret void\n" - "}\n" - "define void @c1() {\n" - "entry:\n" - " call void @b2()\n" - " call void @c2()\n" - " ret void\n" - "}\n" - "define void @b2() {\n" - "entry:\n" - " call void @c2()\n" - " call void @b3()\n" - " ret void\n" - "}\n" - "define void @c2() {\n" - "entry:\n" - " call void @b3()\n" - " call void @c3()\n" - " ret void\n" - "}\n" - "define void @b3() {\n" - "entry:\n" - " call void @c3()\n" - " call void @d()\n" - " ret void\n" - "}\n" - "define void @c3() {\n" - "entry:\n" - " store void()* @b1, void()** undef\n" - " call void @d()\n" - " ret void\n" - "}\n" - "define void @d() {\n" - "entry:\n" - " store void()* @a, void()** undef\n" - " ret void\n" - "}\n"); + std::unique_ptr M = + parseAssembly(Context, "define void @a() {\n" + "entry:\n" + " call void @b1()\n" + " call void @c1()\n" + " ret void\n" + "}\n" + "define void @b1() {\n" + "entry:\n" + " call void @c1()\n" + " call void @b2()\n" + " ret void\n" + "}\n" + "define void @c1() {\n" + "entry:\n" + " call void @b2()\n" + " call void @c2()\n" + " ret void\n" + "}\n" + "define void @b2() {\n" + "entry:\n" + " call void @c2()\n" + " call void @b3()\n" + " ret void\n" + "}\n" + "define void @c2() {\n" + "entry:\n" + " call void @b3()\n" + " call void @c3()\n" + " ret void\n" + "}\n" + "define void @b3() {\n" + "entry:\n" + " call void @c3()\n" + " call void @d()\n" + " ret void\n" + "}\n" + "define void @c3() {\n" + "entry:\n" + " store void()* @b1, void()** undef\n" + " call void @d()\n" + " ret void\n" + "}\n" + "define void @d() {\n" + "entry:\n" + " store void()* @a, void()** undef\n" + " ret void\n" + "}\n"); LazyCallGraph CG(*M); // Force the graph to be fully expanded. @@ -1163,6 +1170,7 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallNoCycleInterleaved) { } TEST(LazyCallGraphTest, InternalRefEdgeToCallBothPartitionAndMerge) { + LLVMContext Context; // Test for having a postorder where between the source and target are all // three kinds of other SCCs: // 1) One connected to the target only that have to be shifted below the @@ -1190,47 +1198,47 @@ TEST(LazyCallGraphTest, InternalRefEdgeToCallBothPartitionAndMerge) { // G | G | // // And we form a cycle by connecting F to B. - std::unique_ptr M = parseAssembly( - "define void @a() {\n" - "entry:\n" - " call void @b()\n" - " call void @e()\n" - " ret void\n" - "}\n" - "define void @b() {\n" - "entry:\n" - " call void @c()\n" - " call void @d()\n" - " ret void\n" - "}\n" - "define void @c() {\n" - "entry:\n" - " call void @d()\n" - " call void @g()\n" - " ret void\n" - "}\n" - "define void @d() {\n" - "entry:\n" - " call void @e()\n" - " call void @f()\n" - " ret void\n" - "}\n" - "define void @e() {\n" - "entry:\n" - " call void @f()\n" - " ret void\n" - "}\n" - "define void @f() {\n" - "entry:\n" - " store void()* @b, void()** undef\n" - " call void @g()\n" - " ret void\n" - "}\n" - "define void @g() {\n" - "entry:\n" - " store void()* @a, void()** undef\n" - " ret void\n" - "}\n"); + std::unique_ptr M = + parseAssembly(Context, "define void @a() {\n" + "entry:\n" + " call void @b()\n" + " call void @e()\n" + " ret void\n" + "}\n" + "define void @b() {\n" + "entry:\n" + " call void @c()\n" + " call void @d()\n" + " ret void\n" + "}\n" + "define void @c() {\n" + "entry:\n" + " call void @d()\n" + " call void @g()\n" + " ret void\n" + "}\n" + "define void @d() {\n" + "entry:\n" + " call void @e()\n" + " call void @f()\n" + " ret void\n" + "}\n" + "define void @e() {\n" + "entry:\n" + " call void @f()\n" + " ret void\n" + "}\n" + "define void @f() {\n" + "entry:\n" + " store void()* @b, void()** undef\n" + " call void @g()\n" + " ret void\n" + "}\n" + "define void @g() {\n" + "entry:\n" + " store void()* @a, void()** undef\n" + " ret void\n" + "}\n"); LazyCallGraph CG(*M); // Force the graph to be fully expanded. diff --git a/unittests/Analysis/LoopPassManagerTest.cpp b/unittests/Analysis/LoopPassManagerTest.cpp index 8a620499a3ef0cd04320e829b815f0ebb413a5f0..5858e174aabb6432fb10ef71030ba1f8a25d6f39 100644 --- a/unittests/Analysis/LoopPassManagerTest.cpp +++ b/unittests/Analysis/LoopPassManagerTest.cpp @@ -92,46 +92,46 @@ public: TestLoopInvalidatingPass(StringRef LoopName) : Name(LoopName) {} PreservedAnalyses run(Loop &L, AnalysisManager &AM) { - return L.getName() == Name ? PreservedAnalyses::none() + return L.getName() == Name ? getLoopPassPreservedAnalyses() : PreservedAnalyses::all(); } static StringRef name() { return "TestLoopInvalidatingPass"; } }; -std::unique_ptr parseIR(const char *IR) { - LLVMContext &C = getGlobalContext(); +std::unique_ptr parseIR(LLVMContext &C, const char *IR) { SMDiagnostic Err; return parseAssemblyString(IR, Err, C); } class LoopPassManagerTest : public ::testing::Test { protected: + LLVMContext Context; std::unique_ptr M; public: LoopPassManagerTest() - : M(parseIR("define void @f() {\n" - "entry:\n" - " br label %loop.0\n" - "loop.0:\n" - " br i1 undef, label %loop.0.0, label %end\n" - "loop.0.0:\n" - " br i1 undef, label %loop.0.0, label %loop.0.1\n" - "loop.0.1:\n" - " br i1 undef, label %loop.0.1, label %loop.0\n" - "end:\n" - " ret void\n" - "}\n" - "\n" - "define void @g() {\n" - "entry:\n" - " br label %loop.g.0\n" - "loop.g.0:\n" - " br i1 undef, label %loop.g.0, label %end\n" - "end:\n" - " ret void\n" - "}\n")) {} + : M(parseIR(Context, "define void @f() {\n" + "entry:\n" + " br label %loop.0\n" + "loop.0:\n" + " br i1 undef, label %loop.0.0, label %end\n" + "loop.0.0:\n" + " br i1 undef, label %loop.0.0, label %loop.0.1\n" + "loop.0.1:\n" + " br i1 undef, label %loop.0.1, label %loop.0\n" + "end:\n" + " ret void\n" + "}\n" + "\n" + "define void @g() {\n" + "entry:\n" + " br label %loop.g.0\n" + "loop.g.0:\n" + " br i1 undef, label %loop.g.0, label %end\n" + "end:\n" + " ret void\n" + "}\n")) {} }; #define EXPECT_N_ELEMENTS_EQ(N, EXPECTED, ACTUAL) \ diff --git a/unittests/Analysis/UnrollAnalyzer.cpp b/unittests/Analysis/UnrollAnalyzer.cpp index 15d500a30c8838cd2f25924ad77652b87e6dab32..6d11ab1f2f1ba611dd5695e890c8903c3fff7826 100644 --- a/unittests/Analysis/UnrollAnalyzer.cpp +++ b/unittests/Analysis/UnrollAnalyzer.cpp @@ -60,11 +60,11 @@ struct UnrollAnalyzerTest : public FunctionPass { char UnrollAnalyzerTest::ID = 0; -std::unique_ptr makeLLVMModule(UnrollAnalyzerTest *P, +std::unique_ptr makeLLVMModule(LLVMContext &Context, + UnrollAnalyzerTest *P, const char *ModuleStr) { - LLVMContext &C = getGlobalContext(); SMDiagnostic Err; - return parseAssemblyString(ModuleStr, Err, C); + return parseAssemblyString(ModuleStr, Err, Context); } TEST(UnrollAnalyzerTest, BasicSimplifications) { @@ -86,7 +86,8 @@ TEST(UnrollAnalyzerTest, BasicSimplifications) { " ret i64 %x.lcssa\n" "}\n"; UnrollAnalyzerTest *P = new UnrollAnalyzerTest(); - std::unique_ptr M = makeLLVMModule(P, ModuleStr); + LLVMContext Context; + std::unique_ptr M = makeLLVMModule(Context, P, ModuleStr); legacy::PassManager Passes; Passes.add(P); Passes.run(*M); @@ -133,6 +134,7 @@ TEST(UnrollAnalyzerTest, OuterLoopSimplification) { " br label %outer.loop\n" "outer.loop:\n" " %iv.outer = phi i64 [ 0, %entry ], [ %iv.outer.next, %outer.loop.latch ]\n" + " %iv.outer.next = add nuw nsw i64 %iv.outer, 1\n" " br label %inner.loop\n" "inner.loop:\n" " %iv.inner = phi i64 [ 0, %outer.loop ], [ %iv.inner.next, %inner.loop ]\n" @@ -140,7 +142,6 @@ TEST(UnrollAnalyzerTest, OuterLoopSimplification) { " %exitcond.inner = icmp eq i64 %iv.inner.next, 1000\n" " br i1 %exitcond.inner, label %outer.loop.latch, label %inner.loop\n" "outer.loop.latch:\n" - " %iv.outer.next = add nuw nsw i64 %iv.outer, 1\n" " %exitcond.outer = icmp eq i64 %iv.outer.next, 40\n" " br i1 %exitcond.outer, label %exit, label %outer.loop\n" "exit:\n" @@ -148,7 +149,8 @@ TEST(UnrollAnalyzerTest, OuterLoopSimplification) { "}\n"; UnrollAnalyzerTest *P = new UnrollAnalyzerTest(); - std::unique_ptr M = makeLLVMModule(P, ModuleStr); + LLVMContext Context; + std::unique_ptr M = makeLLVMModule(Context, P, ModuleStr); legacy::PassManager Passes; Passes.add(P); Passes.run(*M); @@ -161,11 +163,15 @@ TEST(UnrollAnalyzerTest, OuterLoopSimplification) { BasicBlock *InnerBody = &*FI++; BasicBlock::iterator BBI = Header->begin(); - Instruction *Y1 = &*BBI++; + BBI++; + Instruction *Y1 = &*BBI; BBI = InnerBody->begin(); - Instruction *Y2 = &*BBI++; + BBI++; + Instruction *Y2 = &*BBI; // Check that we can simplify IV of the outer loop, but can't simplify the IV // of the inner loop if we only know the iteration number of the outer loop. + // + // Y1 is %iv.outer.next, Y2 is %iv.inner.next auto I1 = SimplifiedValuesVector[0].find(Y1); EXPECT_TRUE(I1 != SimplifiedValuesVector[0].end()); auto I2 = SimplifiedValuesVector[0].find(Y2); @@ -188,7 +194,8 @@ TEST(UnrollAnalyzerTest, CmpSimplifications) { " ret void\n" "}\n"; UnrollAnalyzerTest *P = new UnrollAnalyzerTest(); - std::unique_ptr M = makeLLVMModule(P, ModuleStr); + LLVMContext Context; + std::unique_ptr M = makeLLVMModule(Context, P, ModuleStr); legacy::PassManager Passes; Passes.add(P); Passes.run(*M); @@ -234,7 +241,8 @@ TEST(UnrollAnalyzerTest, PtrCmpSimplifications) { " ret void\n" "}\n"; UnrollAnalyzerTest *P = new UnrollAnalyzerTest(); - std::unique_ptr M = makeLLVMModule(P, ModuleStr); + LLVMContext Context; + std::unique_ptr M = makeLLVMModule(Context, P, ModuleStr); legacy::PassManager Passes; Passes.add(P); Passes.run(*M); @@ -279,7 +287,8 @@ TEST(UnrollAnalyzerTest, CastSimplifications) { "}\n"; UnrollAnalyzerTest *P = new UnrollAnalyzerTest(); - std::unique_ptr M = makeLLVMModule(P, ModuleStr); + LLVMContext Context; + std::unique_ptr M = makeLLVMModule(Context, P, ModuleStr); legacy::PassManager Passes; Passes.add(P); Passes.run(*M); diff --git a/unittests/Analysis/ValueTrackingTest.cpp b/unittests/Analysis/ValueTrackingTest.cpp index 3af856ea2039cad6eb8ff6f13d9ed17b515b9e6d..f429c3b991495a331f71a9938eca37671eaaaa09 100644 --- a/unittests/Analysis/ValueTrackingTest.cpp +++ b/unittests/Analysis/ValueTrackingTest.cpp @@ -25,7 +25,7 @@ class MatchSelectPatternTest : public testing::Test { protected: void parseAssembly(const char *Assembly) { SMDiagnostic Error; - M = parseAssemblyString(Assembly, Error, getGlobalContext()); + M = parseAssemblyString(Assembly, Error, Context); std::string errMsg; raw_string_ostream os(errMsg); @@ -59,6 +59,7 @@ protected: EXPECT_EQ(P.Ordered, R.Ordered); } + LLVMContext Context; std::unique_ptr M; Instruction *A, *B; }; diff --git a/unittests/AsmParser/AsmParserTest.cpp b/unittests/AsmParser/AsmParserTest.cpp index 38810cd7c7a59149da29ef5123d932f227fbd172..ddbedd05c7baa565dff440f6ed42f8645035cf99 100644 --- a/unittests/AsmParser/AsmParserTest.cpp +++ b/unittests/AsmParser/AsmParserTest.cpp @@ -21,7 +21,7 @@ using namespace llvm; namespace { TEST(AsmParserTest, NullTerminatedInput) { - LLVMContext &Ctx = getGlobalContext(); + LLVMContext Ctx; StringRef Source = "; Empty module \n"; SMDiagnostic Error; auto Mod = parseAssemblyString(Source, Error, Ctx); @@ -34,7 +34,7 @@ TEST(AsmParserTest, NullTerminatedInput) { #ifndef NDEBUG TEST(AsmParserTest, NonNullTerminatedInput) { - LLVMContext &Ctx = getGlobalContext(); + LLVMContext Ctx; StringRef Source = "; Empty module \n\1\2"; SMDiagnostic Error; std::unique_ptr Mod; @@ -47,7 +47,7 @@ TEST(AsmParserTest, NonNullTerminatedInput) { #endif TEST(AsmParserTest, SlotMappingTest) { - LLVMContext &Ctx = getGlobalContext(); + LLVMContext Ctx; StringRef Source = "@0 = global i32 0\n !0 = !{}\n !42 = !{i32 42}"; SMDiagnostic Error; SlotMapping Mapping; @@ -66,7 +66,7 @@ TEST(AsmParserTest, SlotMappingTest) { } TEST(AsmParserTest, TypeAndConstantValueParsing) { - LLVMContext &Ctx = getGlobalContext(); + LLVMContext Ctx; SMDiagnostic Error; StringRef Source = "define void @test() {\n entry:\n ret void\n}"; auto Mod = parseAssemblyString(Source, Error, Ctx); @@ -117,7 +117,7 @@ TEST(AsmParserTest, TypeAndConstantValueParsing) { } TEST(AsmParserTest, TypeAndConstantValueWithSlotMappingParsing) { - LLVMContext &Ctx = getGlobalContext(); + LLVMContext Ctx; SMDiagnostic Error; StringRef Source = "%st = type { i32, i32 }\n" @@ -153,7 +153,7 @@ TEST(AsmParserTest, TypeAndConstantValueWithSlotMappingParsing) { } TEST(AsmParserTest, TypeWithSlotMappingParsing) { - LLVMContext &Ctx = getGlobalContext(); + LLVMContext Ctx; SMDiagnostic Error; StringRef Source = "%st = type { i32, i32 }\n" @@ -277,7 +277,7 @@ TEST(AsmParserTest, TypeWithSlotMappingParsing) { } TEST(AsmParserTest, TypeAtBeginningWithSlotMappingParsing) { - LLVMContext &Ctx = getGlobalContext(); + LLVMContext Ctx; SMDiagnostic Error; StringRef Source = "%st = type { i32, i32 }\n" diff --git a/unittests/Bitcode/BitReaderTest.cpp b/unittests/Bitcode/BitReaderTest.cpp index 420aca2443bb420eeb9f690e0f3d351e0e03bdf9..d0f33d12d5bce5fd25a264f4f1a819f8a513d559 100644 --- a/unittests/Bitcode/BitReaderTest.cpp +++ b/unittests/Bitcode/BitReaderTest.cpp @@ -29,10 +29,10 @@ using namespace llvm; namespace { -std::unique_ptr parseAssembly(const char *Assembly) { +std::unique_ptr parseAssembly(LLVMContext &Context, + const char *Assembly) { SMDiagnostic Error; - std::unique_ptr M = - parseAssemblyString(Assembly, Error, getGlobalContext()); + std::unique_ptr M = parseAssemblyString(Assembly, Error, Context); std::string ErrMsg; raw_string_ostream OS(ErrMsg); @@ -54,7 +54,7 @@ static void writeModuleToBuffer(std::unique_ptr Mod, static std::unique_ptr getLazyModuleFromAssembly(LLVMContext &Context, SmallString<1024> &Mem, const char *Assembly) { - writeModuleToBuffer(parseAssembly(Assembly), Mem); + writeModuleToBuffer(parseAssembly(Context, Assembly), Mem); std::unique_ptr Buffer = MemoryBuffer::getMemBuffer(Mem.str(), "test", false); ErrorOr> ModuleOrErr = @@ -82,7 +82,7 @@ public: static std::unique_ptr getStreamedModuleFromAssembly(LLVMContext &Context, SmallString<1024> &Mem, const char *Assembly) { - writeModuleToBuffer(parseAssembly(Assembly), Mem); + writeModuleToBuffer(parseAssembly(Context, Assembly), Mem); std::unique_ptr Buffer = MemoryBuffer::getMemBuffer(Mem.str(), "test", false); auto Streamer = llvm::make_unique(std::move(Buffer)); diff --git a/unittests/CodeGen/DIEHashTest.cpp b/unittests/CodeGen/DIEHashTest.cpp index e3a9e5628276d13b50027aa14c85b61748b5d6c1..dda08fcd66549338adbbcb644b4ad84b6cd1f2f6 100644 --- a/unittests/CodeGen/DIEHashTest.cpp +++ b/unittests/CodeGen/DIEHashTest.cpp @@ -1,4 +1,4 @@ -//===- llvm/unittest/DebugInfo/DWARFFormValueTest.cpp ---------------------===// +//===- llvm/unittest/CodeGen/DIEHashTest.cpp ------------------------------===// // // The LLVM Compiler Infrastructure // diff --git a/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp b/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp index 371e2af95decff9c857f621ae63b269bd8547adf..eb9607ade16d13bb3e82972d712b2331426408ba 100644 --- a/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp +++ b/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Host.h" diff --git a/unittests/DebugInfo/PDB/CMakeLists.txt b/unittests/DebugInfo/PDB/CMakeLists.txt index 91924a5a875449e5ae43bd6d33434472d165edd8..92a85540937f291fbc825ecf8897a6312be52cd6 100644 --- a/unittests/DebugInfo/PDB/CMakeLists.txt +++ b/unittests/DebugInfo/PDB/CMakeLists.txt @@ -1,8 +1,10 @@ set(LLVM_LINK_COMPONENTS + DebugInfoCodeView DebugInfoPDB ) set(DebugInfoPDBSources + MappedBlockStreamTest.cpp PDBApiTest.cpp ) diff --git a/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp b/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd6fce237369b5c6a35e124815fea8bdfacc468f --- /dev/null +++ b/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp @@ -0,0 +1,456 @@ +//===- llvm/unittest/DebugInfo/PDB/MappedBlockStreamTest.cpp --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include + +#include "llvm/DebugInfo/CodeView/ByteStream.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/CodeView/StreamWriter.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +namespace { + +#define EXPECT_NO_ERROR(Err) \ + { \ + auto E = Err; \ + EXPECT_FALSE(static_cast(E)); \ + if (E) \ + consumeError(std::move(E)); \ + } + +#define EXPECT_ERROR(Err) \ + { \ + auto E = Err; \ + EXPECT_TRUE(static_cast(E)); \ + if (E) \ + consumeError(std::move(E)); \ + } + +static const uint32_t BlocksAry[] = {0, 1, 2, 5, 4, 3, 6, 7, 8, 9}; +static uint8_t DataAry[] = {'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H', 'I', 'J'}; + +class DiscontiguousFile : public IPDBFile { +public: + DiscontiguousFile(ArrayRef Blocks, MutableArrayRef Data) + : Blocks(Blocks.begin(), Blocks.end()), Data(Data.begin(), Data.end()) {} + + uint32_t getBlockSize() const override { return 1; } + uint32_t getBlockCount() const override { return Blocks.size(); } + uint32_t getNumStreams() const override { return 1; } + uint32_t getStreamByteSize(uint32_t StreamIndex) const override { + return getBlockCount() * getBlockSize(); + } + ArrayRef + getStreamBlockList(uint32_t StreamIndex) const override { + if (StreamIndex != 0) + return ArrayRef(); + return Blocks; + } + Expected> getBlockData(uint32_t BlockIndex, + uint32_t NumBytes) const override { + return ArrayRef(&Data[BlockIndex], NumBytes); + } + + Error setBlockData(uint32_t BlockIndex, uint32_t Offset, + ArrayRef SrcData) const override { + if (BlockIndex >= Blocks.size()) + return make_error(cv_error_code::insufficient_buffer); + if (Offset > getBlockSize() - SrcData.size()) + return make_error(cv_error_code::insufficient_buffer); + ::memcpy(&Data[BlockIndex] + Offset, SrcData.data(), SrcData.size()); + return Error::success(); + } + +private: + std::vector Blocks; + MutableArrayRef Data; +}; + +class MappedBlockStreamImpl : public MappedBlockStream { +public: + MappedBlockStreamImpl(std::unique_ptr Data, + const IPDBFile &File) + : MappedBlockStream(std::move(Data), File) {} +}; + +// Tests that a read which is entirely contained within a single block works +// and does not allocate. +TEST(MappedBlockStreamTest, ReadBeyondEndOfStreamRef) { + DiscontiguousFile F(BlocksAry, DataAry); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + StreamReader R(S); + StreamRef SR; + EXPECT_NO_ERROR(R.readStreamRef(SR, 0U)); + ArrayRef Buffer; + EXPECT_ERROR(SR.readBytes(0U, 1U, Buffer)); + EXPECT_NO_ERROR(R.readStreamRef(SR, 1U)); + EXPECT_ERROR(SR.readBytes(1U, 1U, Buffer)); +} + +// Tests that a read which outputs into a full destination buffer works and +// does not fail due to the length of the output buffer. +TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) { + DiscontiguousFile F(BlocksAry, DataAry); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + StreamReader R(S); + StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA"; + EXPECT_NO_ERROR(R.readFixedString(Str, 1)); + EXPECT_EQ(Str, StringRef("A")); + EXPECT_EQ(0U, S.getNumBytesCopied()); +} + +// Tests that a read which crosses a block boundary, but where the subsequent +// blocks are still contiguous in memory to the previous block works and does +// not allocate memory. +TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) { + DiscontiguousFile F(BlocksAry, DataAry); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + StreamReader R(S); + StringRef Str; + EXPECT_NO_ERROR(R.readFixedString(Str, 2)); + EXPECT_EQ(Str, StringRef("AB")); + EXPECT_EQ(0U, S.getNumBytesCopied()); + + R.setOffset(6); + EXPECT_NO_ERROR(R.readFixedString(Str, 4)); + EXPECT_EQ(Str, StringRef("GHIJ")); + EXPECT_EQ(0U, S.getNumBytesCopied()); +} + +// Tests that a read which crosses a block boundary and cannot be referenced +// contiguously works and allocates only the precise amount of bytes +// requested. +TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) { + DiscontiguousFile F(BlocksAry, DataAry); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + StreamReader R(S); + StringRef Str; + EXPECT_NO_ERROR(R.readFixedString(Str, 10)); + EXPECT_EQ(Str, StringRef("ABCDEFGHIJ")); + EXPECT_EQ(10U, S.getNumBytesCopied()); +} + +// Test that an out of bounds read which doesn't cross a block boundary +// fails and allocates no memory. +TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) { + DiscontiguousFile F(BlocksAry, DataAry); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + StreamReader R(S); + StringRef Str; + + R.setOffset(10); + EXPECT_ERROR(R.readFixedString(Str, 1)); + EXPECT_EQ(0U, S.getNumBytesCopied()); +} + +// Test that an out of bounds read which crosses a contiguous block boundary +// fails and allocates no memory. +TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) { + DiscontiguousFile F(BlocksAry, DataAry); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + StreamReader R(S); + StringRef Str; + + R.setOffset(6); + EXPECT_ERROR(R.readFixedString(Str, 5)); + EXPECT_EQ(0U, S.getNumBytesCopied()); +} + +// Test that an out of bounds read which crosses a discontiguous block +// boundary fails and allocates no memory. +TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) { + DiscontiguousFile F(BlocksAry, DataAry); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + StreamReader R(S); + StringRef Str; + + EXPECT_ERROR(R.readFixedString(Str, 11)); + EXPECT_EQ(0U, S.getNumBytesCopied()); +} + +// Tests that a read which is entirely contained within a single block but +// beyond the end of a StreamRef fails. +TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) { + DiscontiguousFile F(BlocksAry, DataAry); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + StreamReader R(S); + StringRef Str; + EXPECT_NO_ERROR(R.readFixedString(Str, 1)); + EXPECT_EQ(Str, StringRef("A")); + EXPECT_EQ(0U, S.getNumBytesCopied()); +} + +// Tests that a read which is not aligned on the same boundary as a previous +// cached request, but which is known to overlap that request, shares the +// previous allocation. +TEST(MappedBlockStreamTest, UnalignedOverlappingRead) { + DiscontiguousFile F(BlocksAry, DataAry); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + StreamReader R(S); + StringRef Str1; + StringRef Str2; + EXPECT_NO_ERROR(R.readFixedString(Str1, 7)); + EXPECT_EQ(Str1, StringRef("ABCDEFG")); + EXPECT_EQ(7U, S.getNumBytesCopied()); + + R.setOffset(2); + EXPECT_NO_ERROR(R.readFixedString(Str2, 3)); + EXPECT_EQ(Str2, StringRef("CDE")); + EXPECT_EQ(Str1.data() + 2, Str2.data()); + EXPECT_EQ(7U, S.getNumBytesCopied()); +} + +// Tests that a read which is not aligned on the same boundary as a previous +// cached request, but which only partially overlaps a previous cached request, +// still works correctly and allocates again from the shared pool. +TEST(MappedBlockStreamTest, UnalignedOverlappingReadFail) { + DiscontiguousFile F(BlocksAry, DataAry); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + StreamReader R(S); + StringRef Str1; + StringRef Str2; + EXPECT_NO_ERROR(R.readFixedString(Str1, 6)); + EXPECT_EQ(Str1, StringRef("ABCDEF")); + EXPECT_EQ(6U, S.getNumBytesCopied()); + + R.setOffset(4); + EXPECT_NO_ERROR(R.readFixedString(Str2, 4)); + EXPECT_EQ(Str2, StringRef("EFGH")); + EXPECT_EQ(10U, S.getNumBytesCopied()); +} + +TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) { + static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; + static uint8_t LargeBuffer[] = {'0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', 'A'}; + static uint8_t SmallBuffer[] = {'0', '1', '2'}; + static_assert(sizeof(LargeBuffer) > sizeof(Data), + "LargeBuffer is not big enough"); + + DiscontiguousFile F(BlocksAry, Data); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + ArrayRef Buffer; + + EXPECT_ERROR(S.writeBytes(0, ArrayRef(LargeBuffer))); + EXPECT_NO_ERROR(S.writeBytes(0, ArrayRef(SmallBuffer))); + EXPECT_NO_ERROR(S.writeBytes(7, ArrayRef(SmallBuffer))); + EXPECT_ERROR(S.writeBytes(8, ArrayRef(SmallBuffer))); +} + +TEST(MappedBlockStreamTest, TestWriteBytesNoBreakBoundary) { + static uint8_t Data[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; + DiscontiguousFile F(BlocksAry, Data); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + ArrayRef Buffer; + + EXPECT_NO_ERROR(S.readBytes(0, 1, Buffer)); + EXPECT_EQ(Buffer, ArrayRef('A')); + EXPECT_NO_ERROR(S.readBytes(9, 1, Buffer)); + EXPECT_EQ(Buffer, ArrayRef('J')); + + EXPECT_NO_ERROR(S.writeBytes(0, ArrayRef('J'))); + EXPECT_NO_ERROR(S.writeBytes(9, ArrayRef('A'))); + + EXPECT_NO_ERROR(S.readBytes(0, 1, Buffer)); + EXPECT_EQ(Buffer, ArrayRef('J')); + EXPECT_NO_ERROR(S.readBytes(9, 1, Buffer)); + EXPECT_EQ(Buffer, ArrayRef('A')); + + EXPECT_NO_ERROR(S.writeBytes(0, ArrayRef('A'))); + EXPECT_NO_ERROR(S.writeBytes(9, ArrayRef('J'))); + + EXPECT_NO_ERROR(S.readBytes(0, 1, Buffer)); + EXPECT_EQ(Buffer, ArrayRef('A')); + EXPECT_NO_ERROR(S.readBytes(9, 1, Buffer)); + EXPECT_EQ(Buffer, ArrayRef('J')); +} + +TEST(MappedBlockStreamTest, TestWriteBytesBreakBoundary) { + static uint8_t Data[] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0'}; + static uint8_t TestData[] = {'T', 'E', 'S', 'T', 'I', 'N', 'G', '.'}; + static uint8_t Expected[] = {'T', 'E', 'S', 'N', 'I', + 'T', 'G', '.', '0', '0'}; + + DiscontiguousFile F(BlocksAry, Data); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + ArrayRef Buffer; + + EXPECT_NO_ERROR(S.writeBytes(0, TestData)); + // First just compare the memory, then compare the result of reading the + // string out. + EXPECT_EQ(ArrayRef(Data), ArrayRef(Expected)); + + EXPECT_NO_ERROR(S.readBytes(0, 8, Buffer)); + EXPECT_EQ(Buffer, ArrayRef(TestData)); +} + +TEST(MappedBlockStreamTest, TestWriteThenRead) { + std::vector DataBytes(10); + MutableArrayRef Data(DataBytes); + const uint32_t Blocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8}; + + DiscontiguousFile F(Blocks, Data); + MappedBlockStreamImpl S(llvm::make_unique(0, F), F); + + enum class MyEnum : uint32_t { Val1 = 2908234, Val2 = 120891234 }; + using support::ulittle32_t; + + uint16_t u16[] = {31468, 0}; + uint32_t u32[] = {890723408, 0}; + MyEnum Enum[] = {MyEnum::Val1, MyEnum::Val2}; + StringRef ZStr[] = {"Zero Str", ""}; + StringRef FStr[] = {"Fixed Str", ""}; + uint8_t byteArray0[] = {'1', '2'}; + uint8_t byteArray1[] = {'0', '0'}; + ArrayRef byteArrayRef0(byteArray0); + ArrayRef byteArrayRef1(byteArray1); + ArrayRef byteArray[] = { byteArrayRef0, byteArrayRef1 }; + ArrayRef intArray[] = {{890723408, 29082234}, {0, 0}}; + + StreamReader Reader(S); + StreamWriter Writer(S); + EXPECT_NO_ERROR(Writer.writeInteger(u16[0])); + EXPECT_NO_ERROR(Reader.readInteger(u16[1])); + EXPECT_EQ(u16[0], u16[1]); + EXPECT_EQ(std::vector({0, 0x7A, 0xEC, 0, 0, 0, 0, 0, 0, 0}), + DataBytes); + + Reader.setOffset(0); + Writer.setOffset(0); + ::memset(DataBytes.data(), 0, 10); + EXPECT_NO_ERROR(Writer.writeInteger(u32[0])); + EXPECT_NO_ERROR(Reader.readInteger(u32[1])); + EXPECT_EQ(u32[0], u32[1]); + EXPECT_EQ(std::vector({0x17, 0x5C, 0x50, 0, 0, 0, 0x35, 0, 0, 0}), + DataBytes); + + Reader.setOffset(0); + Writer.setOffset(0); + ::memset(DataBytes.data(), 0, 10); + EXPECT_NO_ERROR(Writer.writeEnum(Enum[0])); + EXPECT_NO_ERROR(Reader.readEnum(Enum[1])); + EXPECT_EQ(Enum[0], Enum[1]); + EXPECT_EQ(std::vector({0x2C, 0x60, 0x4A, 0, 0, 0, 0, 0, 0, 0}), + DataBytes); + + Reader.setOffset(0); + Writer.setOffset(0); + ::memset(DataBytes.data(), 0, 10); + EXPECT_NO_ERROR(Writer.writeZeroString(ZStr[0])); + EXPECT_NO_ERROR(Reader.readZeroString(ZStr[1])); + EXPECT_EQ(ZStr[0], ZStr[1]); + EXPECT_EQ( + std::vector({'r', 'e', 'Z', ' ', 'S', 't', 'o', 'r', 0, 0}), + DataBytes); + + Reader.setOffset(0); + Writer.setOffset(0); + ::memset(DataBytes.data(), 0, 10); + EXPECT_NO_ERROR(Writer.writeFixedString(FStr[0])); + EXPECT_NO_ERROR(Reader.readFixedString(FStr[1], FStr[0].size())); + EXPECT_EQ(FStr[0], FStr[1]); + EXPECT_EQ( + std::vector({'x', 'i', 'F', 'd', ' ', 'S', 'e', 't', 0, 'r'}), + DataBytes); + + Reader.setOffset(0); + Writer.setOffset(0); + ::memset(DataBytes.data(), 0, 10); + EXPECT_NO_ERROR(Writer.writeArray(byteArray[0])); + EXPECT_NO_ERROR(Reader.readArray(byteArray[1], byteArray[0].size())); + EXPECT_EQ(byteArray[0], byteArray[1]); + EXPECT_EQ(std::vector({0, 0x32, 0x31, 0, 0, 0, 0, 0, 0, 0}), + DataBytes); + + Reader.setOffset(0); + Writer.setOffset(0); + ::memset(DataBytes.data(), 0, 10); + EXPECT_NO_ERROR(Writer.writeArray(intArray[0])); + EXPECT_NO_ERROR(Reader.readArray(intArray[1], intArray[0].size())); + EXPECT_EQ(intArray[0], intArray[1]); +} + +TEST(MappedBlockStreamTest, TestWriteContiguousStreamRef) { + std::vector DestDataBytes(10); + MutableArrayRef DestData(DestDataBytes); + const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8}; + + std::vector SrcDataBytes(10); + MutableArrayRef SrcData(SrcDataBytes); + + DiscontiguousFile F(DestBlocks, DestData); + MappedBlockStreamImpl DestStream(llvm::make_unique(0, F), + F); + + // First write "Test Str" into the source stream. + ByteStream SourceStream(SrcData); + StreamWriter SourceWriter(SourceStream); + EXPECT_NO_ERROR(SourceWriter.writeZeroString("Test Str")); + EXPECT_EQ(SrcDataBytes, std::vector( + {'T', 'e', 's', 't', ' ', 'S', 't', 'r', 0, 0})); + + // Then write the source stream into the dest stream. + StreamWriter DestWriter(DestStream); + EXPECT_NO_ERROR(DestWriter.writeStreamRef(SourceStream)); + EXPECT_EQ(DestDataBytes, std::vector( + {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0})); + + // Then read the string back out of the dest stream. + StringRef Result; + StreamReader DestReader(DestStream); + EXPECT_NO_ERROR(DestReader.readZeroString(Result)); + EXPECT_EQ(Result, "Test Str"); +} + +TEST(MappedBlockStreamTest, TestWriteDiscontiguousStreamRef) { + std::vector DestDataBytes(10); + MutableArrayRef DestData(DestDataBytes); + const uint32_t DestBlocks[] = {2, 1, 0, 6, 3, 4, 5, 7, 9, 8}; + + std::vector SrcDataBytes(10); + MutableArrayRef SrcData(SrcDataBytes); + const uint32_t SrcBlocks[] = {1, 0, 6, 3, 4, 5, 2, 7, 8, 9}; + + DiscontiguousFile DestFile(DestBlocks, DestData); + DiscontiguousFile SrcFile(SrcBlocks, SrcData); + + MappedBlockStreamImpl DestStream( + llvm::make_unique(0, DestFile), DestFile); + MappedBlockStreamImpl SrcStream( + llvm::make_unique(0, SrcFile), SrcFile); + + // First write "Test Str" into the source stream. + StreamWriter SourceWriter(SrcStream); + EXPECT_NO_ERROR(SourceWriter.writeZeroString("Test Str")); + EXPECT_EQ(SrcDataBytes, std::vector( + {'e', 'T', 't', 't', ' ', 'S', 's', 'r', 0, 0})); + + // Then write the source stream into the dest stream. + StreamWriter DestWriter(DestStream); + EXPECT_NO_ERROR(DestWriter.writeStreamRef(SrcStream)); + EXPECT_EQ(DestDataBytes, std::vector( + {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0})); + + // Then read the string back out of the dest stream. + StringRef Result; + StreamReader DestReader(DestStream); + EXPECT_NO_ERROR(DestReader.readZeroString(Result)); + EXPECT_EQ(Result, "Test Str"); +} + +} // end anonymous namespace diff --git a/unittests/DebugInfo/PDB/PDBApiTest.cpp b/unittests/DebugInfo/PDB/PDBApiTest.cpp index 736a6ccb0de3d20907a39b91d1be0428fcdd546a..cd0f928a08ab55e88edc69801f5963ce8b7c9169 100644 --- a/unittests/DebugInfo/PDB/PDBApiTest.cpp +++ b/unittests/DebugInfo/PDB/PDBApiTest.cpp @@ -50,6 +50,7 @@ #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "gtest/gtest.h" using namespace llvm; +using namespace llvm::pdb; namespace { diff --git a/unittests/ExecutionEngine/ExecutionEngineTest.cpp b/unittests/ExecutionEngine/ExecutionEngineTest.cpp index 3ffa9cd9b8f3c3aec4125ffc1ff0846787a4730a..7cad841306925755df4e4cb3ee1a4195509bc0e9 100644 --- a/unittests/ExecutionEngine/ExecutionEngineTest.cpp +++ b/unittests/ExecutionEngine/ExecutionEngineTest.cpp @@ -28,7 +28,7 @@ private: protected: ExecutionEngineTest() { - auto Owner = make_unique("
    ", getGlobalContext()); + auto Owner = make_unique("
    ", Context); M = Owner.get(); Engine.reset(EngineBuilder(std::move(Owner)).setErrorStr(&Error).create()); } @@ -44,13 +44,13 @@ protected: } std::string Error; + LLVMContext Context; Module *M; // Owned by ExecutionEngine. std::unique_ptr Engine; }; TEST_F(ExecutionEngineTest, ForwardGlobalMapping) { - GlobalVariable *G1 = - NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1"); + GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1"); int32_t Mem1 = 3; Engine->addGlobalMapping(G1, &Mem1); EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable(G1)); @@ -63,8 +63,7 @@ TEST_F(ExecutionEngineTest, ForwardGlobalMapping) { Engine->updateGlobalMapping(G1, &Mem2); EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1)); - GlobalVariable *G2 = - NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1"); + GlobalVariable *G2 = NewExtGlobal(Type::getInt32Ty(Context), "Global1"); EXPECT_EQ(nullptr, Engine->getPointerToGlobalIfAvailable(G2)) << "The NULL return shouldn't depend on having called" << " updateGlobalMapping(..., NULL)"; @@ -76,8 +75,7 @@ TEST_F(ExecutionEngineTest, ForwardGlobalMapping) { } TEST_F(ExecutionEngineTest, ReverseGlobalMapping) { - GlobalVariable *G1 = - NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1"); + GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1"); int32_t Mem1 = 3; Engine->addGlobalMapping(G1, &Mem1); @@ -87,8 +85,7 @@ TEST_F(ExecutionEngineTest, ReverseGlobalMapping) { EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1)); EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem2)); - GlobalVariable *G2 = - NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global2"); + GlobalVariable *G2 = NewExtGlobal(Type::getInt32Ty(Context), "Global2"); Engine->updateGlobalMapping(G2, &Mem1); EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1)); EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem2)); @@ -104,8 +101,7 @@ TEST_F(ExecutionEngineTest, ReverseGlobalMapping) { } TEST_F(ExecutionEngineTest, ClearModuleMappings) { - GlobalVariable *G1 = - NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1"); + GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1"); int32_t Mem1 = 3; Engine->addGlobalMapping(G1, &Mem1); @@ -115,8 +111,7 @@ TEST_F(ExecutionEngineTest, ClearModuleMappings) { EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1)); - GlobalVariable *G2 = - NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global2"); + GlobalVariable *G2 = NewExtGlobal(Type::getInt32Ty(Context), "Global2"); // After clearing the module mappings, we can assign a new GV to the // same address. Engine->addGlobalMapping(G2, &Mem1); @@ -124,8 +119,7 @@ TEST_F(ExecutionEngineTest, ClearModuleMappings) { } TEST_F(ExecutionEngineTest, DestructionRemovesGlobalMapping) { - GlobalVariable *G1 = - NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1"); + GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1"); int32_t Mem1 = 3; Engine->addGlobalMapping(G1, &Mem1); // Make sure the reverse mapping is enabled. diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h index 609ac844c47d0fe2b2d87cdb1cc9278ab7489449..e14201c2d783fe970bd243fba3a88f98eb684ddd 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h +++ b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h @@ -282,7 +282,6 @@ protected: MCJITTestBase() : TrivialModuleBuilder(HostTriple) , OptLevel(CodeGenOpt::None) - , RelocModel(Reloc::Default) , CodeModel(CodeModel::Default) , MArch("") , MM(new SectionMemoryManager) @@ -322,7 +321,6 @@ protected: .setErrorStr(&Error) .setOptLevel(CodeGenOpt::None) .setCodeModel(CodeModel::JITDefault) - .setRelocationModel(Reloc::Default) .setMArch(MArch) .setMCPU(sys::getHostCPUName()) //.setMAttrs(MAttrs) @@ -332,7 +330,6 @@ protected: } CodeGenOpt::Level OptLevel; - Reloc::Model RelocModel; CodeModel::Model CodeModel; StringRef MArch; SmallVector MAttrs; diff --git a/unittests/ExecutionEngine/Orc/CMakeLists.txt b/unittests/ExecutionEngine/Orc/CMakeLists.txt index 41fef24556b11faece4aa95fe6a9693642a6b4aa..68f6d0c28d7caab11fc85870de031dc2a6c6b13d 100644 --- a/unittests/ExecutionEngine/Orc/CMakeLists.txt +++ b/unittests/ExecutionEngine/Orc/CMakeLists.txt @@ -20,3 +20,5 @@ add_llvm_unittest(OrcJITTests OrcTestCommon.cpp RPCUtilsTest.cpp ) + +target_link_libraries(OrcJITTests ${PTHREAD_LIB}) diff --git a/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp b/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp index a27e649b616f8cc6704acae5f20784b9eadadf28..8140a1ff249392cc7f9c859d7fbee873376d8da6 100644 --- a/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/CompileOnDemandLayerTest.cpp @@ -18,19 +18,20 @@ namespace { class DummyCallbackManager : public orc::JITCompileCallbackManager { public: - DummyCallbackManager() : JITCompileCallbackManager(0) { } + DummyCallbackManager() : JITCompileCallbackManager(0) {} + public: void grow() override { llvm_unreachable("not implemented"); } }; class DummyStubsManager : public orc::IndirectStubsManager { public: - std::error_code createStub(StringRef StubName, TargetAddress InitAddr, - JITSymbolFlags Flags) override { + Error createStub(StringRef StubName, TargetAddress InitAddr, + JITSymbolFlags Flags) override { llvm_unreachable("Not implemented"); } - std::error_code createStubs(const StubInitsMap &StubInits) override { + Error createStubs(const StubInitsMap &StubInits) override { llvm_unreachable("Not implemented"); } @@ -42,22 +43,20 @@ public: llvm_unreachable("Not implemented"); } - std::error_code updatePointer(StringRef Name, - TargetAddress NewAddr) override { + Error updatePointer(StringRef Name, TargetAddress NewAddr) override { llvm_unreachable("Not implemented"); } }; TEST(CompileOnDemandLayerTest, FindSymbol) { - auto MockBaseLayer = - createMockBaseLayer(DoNothingAndReturn(0), - DoNothingAndReturn(), - [](const std::string &Name, bool) { - if (Name == "foo") - return JITSymbol(1, JITSymbolFlags::Exported); - return JITSymbol(nullptr); - }, - DoNothingAndReturn(nullptr)); + auto MockBaseLayer = createMockBaseLayer( + DoNothingAndReturn(0), DoNothingAndReturn(), + [](const std::string &Name, bool) { + if (Name == "foo") + return JITSymbol(1, JITSymbolFlags::Exported); + return JITSymbol(nullptr); + }, + DoNothingAndReturn(nullptr)); typedef decltype(MockBaseLayer) MockBaseLayerT; DummyCallbackManager CallbackMgr; @@ -68,8 +67,7 @@ TEST(CompileOnDemandLayerTest, FindSymbol) { auto Sym = COD.findSymbol("foo", true); - EXPECT_TRUE(!!Sym) - << "CompileOnDemand::findSymbol should call findSymbol in the base layer."; + EXPECT_TRUE(!!Sym) << "CompileOnDemand::findSymbol should call findSymbol in " + "the base layer."; } - } diff --git a/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp b/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp index 38b60ea7fcd471035378f6c7f14fc0065a31f2b6..ac847039d9fb2d7379a709f885e9b007372eeff3 100644 --- a/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp +++ b/unittests/ExecutionEngine/Orc/IndirectionUtilsTest.cpp @@ -17,7 +17,8 @@ using namespace llvm; namespace { TEST(IndirectionUtilsTest, MakeStub) { - ModuleBuilder MB(getGlobalContext(), "x86_64-apple-macosx10.10", ""); + LLVMContext Context; + ModuleBuilder MB(Context, "x86_64-apple-macosx10.10", ""); Function *F = MB.createFunctionDecl(""); SmallVector Attrs; Attrs.push_back( diff --git a/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp b/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp index a733bd558c8e0f0b70c69158d9c1773858ead0c4..87928347d88ed8f978b9cf688e6e08d634bcf095 100644 --- a/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp @@ -25,6 +25,7 @@ namespace { class ObjectLinkingLayerExecutionTest : public testing::Test, public OrcExecutionTest { + }; class SectionMemoryManagerWrapper : public SectionMemoryManager { @@ -64,9 +65,10 @@ TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) { ObjectLinkingLayer<> ObjLayer; - auto M = llvm::make_unique("", getGlobalContext()); + LLVMContext Context; + auto M = llvm::make_unique("", Context); M->setTargetTriple("x86_64-unknown-linux-gnu"); - Type *Int32Ty = IntegerType::get(getGlobalContext(), 32); + Type *Int32Ty = IntegerType::get(Context, 32); GlobalVariable *GV = new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage, ConstantInt::get(Int32Ty, 42), "foo"); @@ -131,14 +133,13 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) { // instance (for Module 1) which is unsafe, as it will prevent relocation of // Module 2. - ModuleBuilder MB1(getGlobalContext(), "", "dummy"); + ModuleBuilder MB1(Context, "", "dummy"); { MB1.getModule()->setDataLayout(TM->createDataLayout()); Function *BarImpl = MB1.createFunctionDecl("bar"); - BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry", - BarImpl); + BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); IRBuilder<> Builder(BarEntry); - IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32); + IntegerType *Int32Ty = IntegerType::get(Context, 32); Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42); Builder.CreateRet(FourtyTwo); } @@ -147,13 +148,12 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) { std::vector Obj1Set; Obj1Set.push_back(Obj1.getBinary()); - ModuleBuilder MB2(getGlobalContext(), "", "dummy"); + ModuleBuilder MB2(Context, "", "dummy"); { MB2.getModule()->setDataLayout(TM->createDataLayout()); Function *BarDecl = MB2.createFunctionDecl("bar"); Function *FooImpl = MB2.createFunctionDecl("foo"); - BasicBlock *FooEntry = BasicBlock::Create(getGlobalContext(), "entry", - FooImpl); + BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl); IRBuilder<> Builder(FooEntry); Builder.CreateRet(Builder.CreateCall(BarDecl)); } @@ -165,7 +165,7 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) { createLambdaResolver( [&](const std::string &Name) { if (auto Sym = ObjLayer.findSymbol(Name, true)) - return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); + return Sym.toRuntimeDyldSymbol(); return RuntimeDyld::SymbolInfo(nullptr); }, [](const std::string &Name) { @@ -203,14 +203,13 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoPrematureAllocation) { // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is // called once per object before any sections are allocated. - ModuleBuilder MB1(getGlobalContext(), "", "dummy"); + ModuleBuilder MB1(Context, "", "dummy"); { MB1.getModule()->setDataLayout(TM->createDataLayout()); Function *BarImpl = MB1.createFunctionDecl("foo"); - BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry", - BarImpl); + BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); IRBuilder<> Builder(BarEntry); - IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32); + IntegerType *Int32Ty = IntegerType::get(Context, 32); Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42); Builder.CreateRet(FourtyTwo); } @@ -219,14 +218,13 @@ TEST_F(ObjectLinkingLayerExecutionTest, NoPrematureAllocation) { std::vector Obj1Set; Obj1Set.push_back(Obj1.getBinary()); - ModuleBuilder MB2(getGlobalContext(), "", "dummy"); + ModuleBuilder MB2(Context, "", "dummy"); { MB2.getModule()->setDataLayout(TM->createDataLayout()); Function *BarImpl = MB2.createFunctionDecl("bar"); - BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry", - BarImpl); + BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); IRBuilder<> Builder(BarEntry); - IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32); + IntegerType *Int32Ty = IntegerType::get(Context, 32); Value *Seven = ConstantInt::getSigned(Int32Ty, 7); Builder.CreateRet(Seven); } diff --git a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp index 908dba11e29a1a1517e77340c48dd090bf7c1b26..e1b1f2f927815c5249fd9d957eef0fca6dba3b9b 100644 --- a/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp +++ b/unittests/ExecutionEngine/Orc/ObjectTransformLayerTest.cpp @@ -62,7 +62,8 @@ public: EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through"; size_t I = 0; for (auto &ObjPtr : Objects) { - EXPECT_EQ(MockObjects[I++] + 1, *ObjPtr) << "Transform should be applied"; + EXPECT_EQ(MockObjects[I] + 1, *ObjPtr) << "Transform should be applied"; + I++; } EXPECT_EQ(MockObjects.size(), I) << "Number of objects should match"; LastCalled = "addObjectSet"; diff --git a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp index 776d26970a311b7d163a977d5f8a7f5c55febb0b..305325b6c6ef106d20b3e362354330f69aa2627e 100644 --- a/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp +++ b/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp @@ -25,11 +25,11 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) class OrcCAPIExecutionTest : public testing::Test, public OrcExecutionTest { protected: std::unique_ptr createTestModule(const Triple &TT) { - ModuleBuilder MB(getGlobalContext(), TT.str(), ""); + ModuleBuilder MB(Context, TT.str(), ""); Function *TestFunc = MB.createFunctionDecl("testFunc"); Function *Main = MB.createFunctionDecl("main"); - Main->getBasicBlockList().push_back(BasicBlock::Create(getGlobalContext())); + Main->getBasicBlockList().push_back(BasicBlock::Create(Context)); IRBuilder<> B(&Main->back()); Value* Result = B.CreateCall(TestFunc); B.CreateRet(Result); diff --git a/unittests/ExecutionEngine/Orc/OrcTestCommon.h b/unittests/ExecutionEngine/Orc/OrcTestCommon.h index e8fab56156497cfa171757cfdadc293d64142511..fe3da88dc9d1f8f4aa2b2630cfe431472bd2d083 100644 --- a/unittests/ExecutionEngine/Orc/OrcTestCommon.h +++ b/unittests/ExecutionEngine/Orc/OrcTestCommon.h @@ -54,6 +54,7 @@ public: }; protected: + LLVMContext Context; std::unique_ptr TM; private: static bool NativeTargetInitialized; diff --git a/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp b/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp index 3b01c3828b6ec6bc42e5bcb0eeb36ce7c888b5ce..7d55641e4ce2b3fa1b3850e7b501baab601d13d9 100644 --- a/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp +++ b/unittests/ExecutionEngine/Orc/RPCUtilsTest.cpp @@ -17,123 +17,192 @@ using namespace llvm; using namespace llvm::orc; using namespace llvm::orc::remote; -class QueueChannel : public RPCChannel { +class Queue : public std::queue { public: - QueueChannel(std::queue &Queue) : Queue(Queue) {} + std::mutex &getLock() { return Lock; } + +private: + std::mutex Lock; +}; - std::error_code readBytes(char *Dst, unsigned Size) override { - while (Size--) { - *Dst++ = Queue.front(); - Queue.pop(); +class QueueChannel : public RPCChannel { +public: + QueueChannel(Queue &InQueue, Queue &OutQueue) + : InQueue(InQueue), OutQueue(OutQueue) {} + + Error readBytes(char *Dst, unsigned Size) override { + while (Size != 0) { + // If there's nothing to read then yield. + while (InQueue.empty()) + std::this_thread::yield(); + + // Lock the channel and read what we can. + std::lock_guard Lock(InQueue.getLock()); + while (!InQueue.empty() && Size) { + *Dst++ = InQueue.front(); + --Size; + InQueue.pop(); + } } - return std::error_code(); + return Error::success(); } - std::error_code appendBytes(const char *Src, unsigned Size) override { + Error appendBytes(const char *Src, unsigned Size) override { + std::lock_guard Lock(OutQueue.getLock()); while (Size--) - Queue.push(*Src++); - return std::error_code(); + OutQueue.push(*Src++); + return Error::success(); } - std::error_code send() override { return std::error_code(); } + Error send() override { return Error::success(); } private: - std::queue &Queue; + Queue &InQueue; + Queue &OutQueue; }; -class DummyRPC : public testing::Test, - public RPC { +class DummyRPC : public testing::Test, public RPC { public: - typedef Procedure<1, void(bool)> Proc1; - typedef Procedure<2, void(int8_t, uint8_t, int16_t, uint16_t, - int32_t, uint32_t, int64_t, uint64_t, - bool, std::string, std::vector)> AllTheTypes; + enum FuncId : uint32_t { + VoidBoolId = RPCFunctionIdTraits::FirstValidId, + IntIntId, + AllTheTypesId + }; + + typedef Function VoidBool; + typedef Function IntInt; + typedef Function)> + AllTheTypes; }; +TEST_F(DummyRPC, TestAsyncVoidBool) { + Queue Q1, Q2; + QueueChannel C1(Q1, Q2); + QueueChannel C2(Q2, Q1); + + // Make an async call. + auto ResOrErr = callAsyncWithSeq(C1, true); + EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed"; -TEST_F(DummyRPC, TestBasic) { - std::queue Queue; - QueueChannel C(Queue); + { + // Expect a call to Proc1. + auto EC = expect(C2, [&](bool &B) { + EXPECT_EQ(B, true) << "Bool serialization broken"; + return Error::success(); + }); + EXPECT_FALSE(EC) << "Simple expect over queue failed"; + } { - // Make a call to Proc1. - auto EC = call(C, true); - EXPECT_FALSE(EC) << "Simple call over queue failed"; + // Wait for the result. + auto EC = waitForResult(C1, ResOrErr->second, handleNone); + EXPECT_FALSE(EC) << "Could not read result."; } + // Verify that the function returned ok. + auto Val = ResOrErr->first.get(); + EXPECT_TRUE(Val) << "Remote void function failed to execute."; +} + +TEST_F(DummyRPC, TestAsyncIntInt) { + Queue Q1, Q2; + QueueChannel C1(Q1, Q2); + QueueChannel C2(Q2, Q1); + + // Make an async call. + auto ResOrErr = callAsyncWithSeq(C1, 21); + EXPECT_TRUE(!!ResOrErr) << "Simple call over queue failed"; + { // Expect a call to Proc1. - auto EC = expect(C, - [&](bool &B) { - EXPECT_EQ(B, true) - << "Bool serialization broken"; - return std::error_code(); - }); + auto EC = expect(C2, [&](int32_t I) -> Expected { + EXPECT_EQ(I, 21) << "Bool serialization broken"; + return 2 * I; + }); EXPECT_FALSE(EC) << "Simple expect over queue failed"; } + + { + // Wait for the result. + auto EC = waitForResult(C1, ResOrErr->second, handleNone); + EXPECT_FALSE(EC) << "Could not read result."; + } + + // Verify that the function returned ok. + auto Val = ResOrErr->first.get(); + EXPECT_TRUE(!!Val) << "Remote int function failed to execute."; + EXPECT_EQ(*Val, 42) << "Remote int function return wrong value."; } TEST_F(DummyRPC, TestSerialization) { - std::queue Queue; - QueueChannel C(Queue); + Queue Q1, Q2; + QueueChannel C1(Q1, Q2); + QueueChannel C2(Q2, Q1); + + // Make a call to Proc1. + std::vector v({42, 7}); + auto ResOrErr = callAsyncWithSeq( + C1, -101, 250, -10000, 10000, -1000000000, 1000000000, -10000000000, + 10000000000, true, "foo", v); + EXPECT_TRUE(!!ResOrErr) << "Big (serialization test) call over queue failed"; { - // Make a call to Proc1. - std::vector v({42, 7}); - auto EC = call(C, - -101, - 250, - -10000, - 10000, - -1000000000, - 1000000000, - -10000000000, - 10000000000, - true, - "foo", - v); + // Expect a call to Proc1. + auto EC = expect( + C2, [&](int8_t &s8, uint8_t &u8, int16_t &s16, uint16_t &u16, + int32_t &s32, uint32_t &u32, int64_t &s64, uint64_t &u64, + bool &b, std::string &s, std::vector &v) { + + EXPECT_EQ(s8, -101) << "int8_t serialization broken"; + EXPECT_EQ(u8, 250) << "uint8_t serialization broken"; + EXPECT_EQ(s16, -10000) << "int16_t serialization broken"; + EXPECT_EQ(u16, 10000) << "uint16_t serialization broken"; + EXPECT_EQ(s32, -1000000000) << "int32_t serialization broken"; + EXPECT_EQ(u32, 1000000000ULL) << "uint32_t serialization broken"; + EXPECT_EQ(s64, -10000000000) << "int64_t serialization broken"; + EXPECT_EQ(u64, 10000000000ULL) << "uint64_t serialization broken"; + EXPECT_EQ(b, true) << "bool serialization broken"; + EXPECT_EQ(s, "foo") << "std::string serialization broken"; + EXPECT_EQ(v, std::vector({42, 7})) + << "std::vector serialization broken"; + return Error::success(); + }); EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed"; } { - // Expect a call to Proc1. - auto EC = expect(C, - [&](int8_t &s8, - uint8_t &u8, - int16_t &s16, - uint16_t &u16, - int32_t &s32, - uint32_t &u32, - int64_t &s64, - uint64_t &u64, - bool &b, - std::string &s, - std::vector &v) { - - EXPECT_EQ(s8, -101) - << "int8_t serialization broken"; - EXPECT_EQ(u8, 250) - << "uint8_t serialization broken"; - EXPECT_EQ(s16, -10000) - << "int16_t serialization broken"; - EXPECT_EQ(u16, 10000) - << "uint16_t serialization broken"; - EXPECT_EQ(s32, -1000000000) - << "int32_t serialization broken"; - EXPECT_EQ(u32, 1000000000ULL) - << "uint32_t serialization broken"; - EXPECT_EQ(s64, -10000000000) - << "int64_t serialization broken"; - EXPECT_EQ(u64, 10000000000ULL) - << "uint64_t serialization broken"; - EXPECT_EQ(b, true) - << "bool serialization broken"; - EXPECT_EQ(s, "foo") - << "std::string serialization broken"; - EXPECT_EQ(v, std::vector({42, 7})) - << "std::vector serialization broken"; - return std::error_code(); - }); - EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed"; + // Wait for the result. + auto EC = waitForResult(C1, ResOrErr->second, handleNone); + EXPECT_FALSE(EC) << "Could not read result."; } + + // Verify that the function returned ok. + auto Val = ResOrErr->first.get(); + EXPECT_TRUE(Val) << "Remote void function failed to execute."; } + +// Test the synchronous call API. +// FIXME: Re-enable once deadlock encountered on S390 has been debugged / fixed, +// see http://lab.llvm.org:8011/builders/clang-s390x-linux/builds/3459 +// TEST_F(DummyRPC, TestSynchronousCall) { +// Queue Q1, Q2; +// QueueChannel C1(Q1, Q2); +// QueueChannel C2(Q2, Q1); +// +// auto ServerResult = +// std::async(std::launch::async, +// [&]() { +// return expect(C2, [&](int32_t V) { return V; }); +// }); +// +// auto ValOrErr = callST(C1, 42); +// +// EXPECT_FALSE(!!ServerResult.get()) +// << "Server returned an error."; +// EXPECT_TRUE(!!ValOrErr) +// << "callST returned an error."; +// EXPECT_EQ(*ValOrErr, 42) +// << "Incorrect callST result"; +// } diff --git a/unittests/IR/AttributesTest.cpp b/unittests/IR/AttributesTest.cpp index ebcb772bc373963f67ba3ce334fd5327dec2df64..9f8013ff181cd61d02c138c2a02a378616547d12 100644 --- a/unittests/IR/AttributesTest.cpp +++ b/unittests/IR/AttributesTest.cpp @@ -34,6 +34,15 @@ TEST(Attributes, Uniquing) { TEST(Attributes, Ordering) { LLVMContext C; + Attribute Align4 = Attribute::get(C, Attribute::Alignment, 4); + Attribute Align5 = Attribute::get(C, Attribute::Alignment, 5); + Attribute Deref4 = Attribute::get(C, Attribute::Dereferenceable, 4); + Attribute Deref5 = Attribute::get(C, Attribute::Dereferenceable, 5); + EXPECT_TRUE(Align4 < Align5); + EXPECT_TRUE(Align4 < Deref4); + EXPECT_TRUE(Align4 < Deref5); + EXPECT_TRUE(Align5 < Deref4); + AttributeSet ASs[] = { AttributeSet::get(C, 2, Attribute::ZExt), AttributeSet::get(C, 1, Attribute::SExt) diff --git a/unittests/IR/CMakeLists.txt b/unittests/IR/CMakeLists.txt index 667fcc34c179cb1a42827a925a6c523d7327f88f..2baa4370c70e92f46c418a00c803ceb640f34196 100644 --- a/unittests/IR/CMakeLists.txt +++ b/unittests/IR/CMakeLists.txt @@ -11,7 +11,9 @@ set(IRSources ConstantRangeTest.cpp ConstantsTest.cpp DebugInfoTest.cpp + DebugTypeODRUniquingTest.cpp DominatorTreeTest.cpp + FunctionTest.cpp IRBuilderTest.cpp InstructionsTest.cpp IntrinsicsTest.cpp diff --git a/unittests/IR/ConstantRangeTest.cpp b/unittests/IR/ConstantRangeTest.cpp index 953e68e0594e332fe5949aff735f786f0e1d1ffb..f7a8a82043b9c071019d139cb8cb7ea753cc650f 100644 --- a/unittests/IR/ConstantRangeTest.cpp +++ b/unittests/IR/ConstantRangeTest.cpp @@ -716,4 +716,50 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) { ConstantRange(APInt(32, 0), APInt(32, 1))); } +TEST(ConstantRange, GetEquivalentICmp) { + APInt RHS; + CmpInst::Predicate Pred; + + EXPECT_TRUE(ConstantRange(APInt::getMinValue(32), APInt(32, 100)) + .getEquivalentICmp(Pred, RHS)); + EXPECT_EQ(Pred, CmpInst::ICMP_ULT); + EXPECT_EQ(RHS, APInt(32, 100)); + + EXPECT_TRUE(ConstantRange(APInt::getSignedMinValue(32), APInt(32, 100)) + .getEquivalentICmp(Pred, RHS)); + EXPECT_EQ(Pred, CmpInst::ICMP_SLT); + EXPECT_EQ(RHS, APInt(32, 100)); + + EXPECT_TRUE(ConstantRange(APInt(32, 100), APInt::getMinValue(32)) + .getEquivalentICmp(Pred, RHS)); + EXPECT_EQ(Pred, CmpInst::ICMP_UGE); + EXPECT_EQ(RHS, APInt(32, 100)); + + EXPECT_TRUE(ConstantRange(APInt(32, 100), APInt::getSignedMinValue(32)) + .getEquivalentICmp(Pred, RHS)); + EXPECT_EQ(Pred, CmpInst::ICMP_SGE); + EXPECT_EQ(RHS, APInt(32, 100)); + + EXPECT_TRUE( + ConstantRange(32, /*isFullSet=*/true).getEquivalentICmp(Pred, RHS)); + EXPECT_EQ(Pred, CmpInst::ICMP_UGE); + EXPECT_EQ(RHS, APInt(32, 0)); + + EXPECT_TRUE( + ConstantRange(32, /*isFullSet=*/false).getEquivalentICmp(Pred, RHS)); + EXPECT_EQ(Pred, CmpInst::ICMP_ULT); + EXPECT_EQ(RHS, APInt(32, 0)); + + EXPECT_FALSE(ConstantRange(APInt(32, 100), APInt(32, 200)) + .getEquivalentICmp(Pred, RHS)); + + EXPECT_FALSE(ConstantRange(APInt::getSignedMinValue(32) - APInt(32, 100), + APInt::getSignedMinValue(32) + APInt(32, 100)) + .getEquivalentICmp(Pred, RHS)); + + EXPECT_FALSE(ConstantRange(APInt::getMinValue(32) - APInt(32, 100), + APInt::getMinValue(32) + APInt(32, 100)) + .getEquivalentICmp(Pred, RHS)); +} + } // anonymous namespace diff --git a/unittests/IR/ConstantsTest.cpp b/unittests/IR/ConstantsTest.cpp index 7471584097ddaa351571836e1d001e879c6ae849..6959ac85e49d0bf0ae302e32dfef8afcf49c59e3 100644 --- a/unittests/IR/ConstantsTest.cpp +++ b/unittests/IR/ConstantsTest.cpp @@ -22,7 +22,8 @@ namespace llvm { namespace { TEST(ConstantsTest, Integer_i1) { - IntegerType* Int1 = IntegerType::get(getGlobalContext(), 1); + LLVMContext Context; + IntegerType *Int1 = IntegerType::get(Context, 1); Constant* One = ConstantInt::get(Int1, 1, true); Constant* Zero = ConstantInt::get(Int1, 0); Constant* NegOne = ConstantInt::get(Int1, static_cast(-1), true); @@ -103,7 +104,8 @@ TEST(ConstantsTest, Integer_i1) { } TEST(ConstantsTest, IntSigns) { - IntegerType* Int8Ty = Type::getInt8Ty(getGlobalContext()); + LLVMContext Context; + IntegerType *Int8Ty = Type::getInt8Ty(Context); EXPECT_EQ(100, ConstantInt::get(Int8Ty, 100, false)->getSExtValue()); EXPECT_EQ(100, ConstantInt::get(Int8Ty, 100, true)->getSExtValue()); EXPECT_EQ(100, ConstantInt::getSigned(Int8Ty, 100)->getSExtValue()); @@ -116,16 +118,17 @@ TEST(ConstantsTest, IntSigns) { } TEST(ConstantsTest, FP128Test) { - Type *FP128Ty = Type::getFP128Ty(getGlobalContext()); + LLVMContext Context; + Type *FP128Ty = Type::getFP128Ty(Context); - IntegerType *Int128Ty = Type::getIntNTy(getGlobalContext(), 128); + IntegerType *Int128Ty = Type::getIntNTy(Context, 128); Constant *Zero128 = Constant::getNullValue(Int128Ty); Constant *X = ConstantExpr::getUIToFP(Zero128, FP128Ty); EXPECT_TRUE(isa(X)); } TEST(ConstantsTest, PointerCast) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Type *Int8PtrTy = Type::getInt8PtrTy(C); Type *Int32PtrTy = Type::getInt32PtrTy(C); Type *Int64Ty = Type::getInt64Ty(C); @@ -152,6 +155,27 @@ TEST(ConstantsTest, PointerCast) { EXPECT_EQ(Constant::getNullValue(Int32PtrVecTy), ConstantExpr::getPointerCast( Constant::getNullValue(Int8PtrVecTy), Int32PtrVecTy)); + + Type *Int32Ptr1Ty = Type::getInt32PtrTy(C, 1); + ConstantInt *K = ConstantInt::get(Type::getInt64Ty(C), 1234); + + // Make sure that addrspacecast of inttoptr is not folded away. + EXPECT_NE(K, + ConstantExpr::getAddrSpaceCast( + ConstantExpr::getIntToPtr(K, Int32PtrTy), Int32Ptr1Ty)); + EXPECT_NE(K, + ConstantExpr::getAddrSpaceCast( + ConstantExpr::getIntToPtr(K, Int32Ptr1Ty), Int32PtrTy)); + + Constant *NullInt32Ptr0 = Constant::getNullValue(Int32PtrTy); + Constant *NullInt32Ptr1 = Constant::getNullValue(Int32Ptr1Ty); + + // Make sure that addrspacecast of null is not folded away. + EXPECT_NE(Constant::getNullValue(Int32PtrTy), + ConstantExpr::getAddrSpaceCast(NullInt32Ptr0, Int32Ptr1Ty)); + + EXPECT_NE(Constant::getNullValue(Int32Ptr1Ty), + ConstantExpr::getAddrSpaceCast(NullInt32Ptr1, Int32PtrTy)); } #define CHECK(x, y) { \ @@ -165,14 +189,15 @@ TEST(ConstantsTest, PointerCast) { } TEST(ConstantsTest, AsInstructionsTest) { - std::unique_ptr M(new Module("MyModule", getGlobalContext())); + LLVMContext Context; + std::unique_ptr M(new Module("MyModule", Context)); - Type *Int64Ty = Type::getInt64Ty(getGlobalContext()); - Type *Int32Ty = Type::getInt32Ty(getGlobalContext()); - Type *Int16Ty = Type::getInt16Ty(getGlobalContext()); - Type *Int1Ty = Type::getInt1Ty(getGlobalContext()); - Type *FloatTy = Type::getFloatTy(getGlobalContext()); - Type *DoubleTy = Type::getDoubleTy(getGlobalContext()); + Type *Int64Ty = Type::getInt64Ty(Context); + Type *Int32Ty = Type::getInt32Ty(Context); + Type *Int16Ty = Type::getInt16Ty(Context); + Type *Int1Ty = Type::getInt1Ty(Context); + Type *FloatTy = Type::getFloatTy(Context); + Type *DoubleTy = Type::getDoubleTy(Context); Constant *Global = M->getOrInsertGlobal("dummy", PointerType::getUnqual(Int32Ty)); @@ -189,8 +214,7 @@ TEST(ConstantsTest, AsInstructionsTest) { Constant *One = ConstantInt::get(Int32Ty, 1); Constant *Two = ConstantInt::get(Int64Ty, 2); - Constant *Big = ConstantInt::get(getGlobalContext(), - APInt{256, uint64_t(-1), true}); + Constant *Big = ConstantInt::get(Context, APInt{256, uint64_t(-1), true}); Constant *Elt = ConstantInt::get(Int16Ty, 2015); Constant *Undef16 = UndefValue::get(Int16Ty); Constant *Undef64 = UndefValue::get(Int64Ty); @@ -278,9 +302,10 @@ TEST(ConstantsTest, AsInstructionsTest) { #ifdef GTEST_HAS_DEATH_TEST #ifndef NDEBUG TEST(ConstantsTest, ReplaceWithConstantTest) { - std::unique_ptr M(new Module("MyModule", getGlobalContext())); + LLVMContext Context; + std::unique_ptr M(new Module("MyModule", Context)); - Type *Int32Ty = Type::getInt32Ty(getGlobalContext()); + Type *Int32Ty = Type::getInt32Ty(Context); Constant *One = ConstantInt::get(Int32Ty, 1); Constant *Global = diff --git a/unittests/IR/DebugTypeODRUniquingTest.cpp b/unittests/IR/DebugTypeODRUniquingTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c899d85d1f3e6e02329cfb5008b4d9651d38209 --- /dev/null +++ b/unittests/IR/DebugTypeODRUniquingTest.cpp @@ -0,0 +1,156 @@ +//===- DebugTypeODRUniquingTest.cpp - Debug type ODR uniquing tests -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "gtest/gtest.h" +using namespace llvm; + +namespace { + +TEST(DebugTypeODRUniquingTest, enableDebugTypeODRUniquing) { + LLVMContext Context; + EXPECT_FALSE(Context.isODRUniquingDebugTypes()); + Context.enableDebugTypeODRUniquing(); + EXPECT_TRUE(Context.isODRUniquingDebugTypes()); + Context.disableDebugTypeODRUniquing(); + EXPECT_FALSE(Context.isODRUniquingDebugTypes()); +} + +TEST(DebugTypeODRUniquingTest, getODRType) { + LLVMContext Context; + MDString &UUID = *MDString::get(Context, "string"); + + // Without a type map, this should return null. + EXPECT_FALSE(DICompositeType::getODRType( + Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, + nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr)); + + // Enable the mapping. There still shouldn't be a type. + Context.enableDebugTypeODRUniquing(); + EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); + + // Create some ODR-uniqued type. + auto &CT = *DICompositeType::getODRType( + Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, + nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr); + EXPECT_EQ(UUID.getString(), CT.getIdentifier()); + + // Check that we get it back, even if we change a field. + EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID)); + EXPECT_EQ( + &CT, DICompositeType::getODRType(Context, UUID, dwarf::DW_TAG_class_type, + nullptr, nullptr, 0, nullptr, nullptr, 0, + 0, 0, 0, nullptr, 0, nullptr, nullptr)); + EXPECT_EQ(&CT, DICompositeType::getODRType( + Context, UUID, dwarf::DW_TAG_class_type, + MDString::get(Context, "name"), nullptr, 0, nullptr, + nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr)); + + // Check that it's discarded with the type map. + Context.disableDebugTypeODRUniquing(); + EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); + + // And it shouldn't magically reappear... + Context.enableDebugTypeODRUniquing(); + EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID)); +} + +TEST(DebugTypeODRUniquingTest, buildODRType) { + LLVMContext Context; + Context.enableDebugTypeODRUniquing(); + + // Build an ODR type that's a forward decl. + MDString &UUID = *MDString::get(Context, "Type"); + auto &CT = *DICompositeType::buildODRType( + Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, + nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr); + EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID)); + EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag()); + + // Update with another forward decl. This should be a no-op. + EXPECT_EQ(&CT, DICompositeType::buildODRType( + Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr, + nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr)); + EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag()); + + // Update with a definition. This time we should see a change. + EXPECT_EQ(&CT, DICompositeType::buildODRType( + Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr, + nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr)); + EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag()); + + // Further updates should be ignored. + EXPECT_EQ(&CT, DICompositeType::buildODRType( + Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, + nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr)); + EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag()); + EXPECT_EQ(&CT, DICompositeType::buildODRType( + Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr, + nullptr, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr)); + EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag()); +} + +TEST(DebugTypeODRUniquingTest, buildODRTypeFields) { + LLVMContext Context; + Context.enableDebugTypeODRUniquing(); + + // Build an ODR type that's a forward decl with no other fields set. + MDString &UUID = *MDString::get(Context, "UUID"); + auto &CT = *DICompositeType::buildODRType( + Context, UUID, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0, + DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr); + +// Create macros for running through all the fields except Identifier and Flags. +#define FOR_EACH_MDFIELD() \ + DO_FOR_FIELD(Name) \ + DO_FOR_FIELD(File) \ + DO_FOR_FIELD(Scope) \ + DO_FOR_FIELD(BaseType) \ + DO_FOR_FIELD(Elements) \ + DO_FOR_FIELD(VTableHolder) \ + DO_FOR_FIELD(TemplateParams) +#define FOR_EACH_INLINEFIELD() \ + DO_FOR_FIELD(Tag) \ + DO_FOR_FIELD(Line) \ + DO_FOR_FIELD(SizeInBits) \ + DO_FOR_FIELD(AlignInBits) \ + DO_FOR_FIELD(OffsetInBits) \ + DO_FOR_FIELD(RuntimeLang) + +// Create all the fields. +#define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X); + FOR_EACH_MDFIELD(); +#undef DO_FOR_FIELD + unsigned NonZeroInit = 0; +#define DO_FOR_FIELD(X) auto X = ++NonZeroInit; + FOR_EACH_INLINEFIELD(); +#undef DO_FOR_FIELD + + // Replace all the fields with new values that are distinct from each other. + EXPECT_EQ(&CT, + DICompositeType::buildODRType( + Context, UUID, Tag, Name, File, Line, Scope, BaseType, + SizeInBits, AlignInBits, OffsetInBits, DINode::FlagArtificial, + Elements, RuntimeLang, VTableHolder, TemplateParams)); + + // Confirm that all the right fields got updated. +#define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X()); + FOR_EACH_MDFIELD(); +#undef DO_FOR_FIELD +#undef FOR_EACH_MDFIELD +#define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X()); + FOR_EACH_INLINEFIELD(); +#undef DO_FOR_FIELD +#undef FOR_EACH_INLINEFIELD + EXPECT_EQ(DINode::FlagArtificial, CT.getFlags()); + EXPECT_EQ(&UUID, CT.getRawIdentifier()); +} + +} // end namespace diff --git a/unittests/IR/DominatorTreeTest.cpp b/unittests/IR/DominatorTreeTest.cpp index fcd6b9c65b4e2f312d58533933dd4309937a3a22..6c49deb32d94e73953110f5aeada2a3bcca65038 100644 --- a/unittests/IR/DominatorTreeTest.cpp +++ b/unittests/IR/DominatorTreeTest.cpp @@ -215,7 +215,7 @@ namespace llvm { }; char DPass::ID = 0; - std::unique_ptr makeLLVMModule(DPass *P) { + std::unique_ptr makeLLVMModule(LLVMContext &Context, DPass *P) { const char *ModuleStrig = "declare i32 @g()\n" \ "define void @f(i32 %x) personality i32 ()* @g {\n" \ @@ -239,14 +239,14 @@ namespace llvm { " %y9 = phi i32 [0, %bb2], [%y4, %bb1]\n" " ret void\n" \ "}\n"; - LLVMContext &C = getGlobalContext(); SMDiagnostic Err; - return parseAssemblyString(ModuleStrig, Err, C); + return parseAssemblyString(ModuleStrig, Err, Context); } TEST(DominatorTree, Unreachable) { DPass *P = new DPass(); - std::unique_ptr M = makeLLVMModule(P); + LLVMContext Context; + std::unique_ptr M = makeLLVMModule(Context, P); legacy::PassManager Passes; Passes.add(P); Passes.run(*M); diff --git a/unittests/IR/FunctionTest.cpp b/unittests/IR/FunctionTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb458597c37a45af4cdee5c5834e9ae9576e5dad --- /dev/null +++ b/unittests/IR/FunctionTest.cpp @@ -0,0 +1,112 @@ +//===- FunctionTest.cpp - Function unit tests -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Function.h" +#include "gtest/gtest.h" +using namespace llvm; + +namespace { + +TEST(FunctionTest, hasLazyArguments) { + LLVMContext C; + + Type *ArgTypes[] = {Type::getInt8Ty(C), Type::getInt32Ty(C)}; + FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), ArgTypes, false); + + // Functions start out with lazy arguments. + std::unique_ptr F( + Function::Create(FTy, GlobalValue::ExternalLinkage, "F")); + EXPECT_TRUE(F->hasLazyArguments()); + + // Checking for empty or size shouldn't force arguments to be instantiated. + EXPECT_FALSE(F->arg_empty()); + EXPECT_TRUE(F->hasLazyArguments()); + EXPECT_EQ(2u, F->arg_size()); + EXPECT_TRUE(F->hasLazyArguments()); + + // The argument list should be populated at first access. + (void)F->arg_begin(); + EXPECT_FALSE(F->hasLazyArguments()); +} + +TEST(FunctionTest, stealArgumentListFrom) { + LLVMContext C; + + Type *ArgTypes[] = {Type::getInt8Ty(C), Type::getInt32Ty(C)}; + FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), ArgTypes, false); + std::unique_ptr F1( + Function::Create(FTy, GlobalValue::ExternalLinkage, "F1")); + std::unique_ptr F2( + Function::Create(FTy, GlobalValue::ExternalLinkage, "F1")); + EXPECT_TRUE(F1->hasLazyArguments()); + EXPECT_TRUE(F2->hasLazyArguments()); + + // Steal arguments before they've been accessed. Nothing should change; both + // functions should still have lazy arguments. + // + // steal(empty); drop (empty) + F1->stealArgumentListFrom(*F2); + EXPECT_TRUE(F1->hasLazyArguments()); + EXPECT_TRUE(F2->hasLazyArguments()); + + // Save arguments from F1 for later assertions. F1 won't have lazy arguments + // anymore. + SmallVector Args; + for (Argument &A : F1->args()) + Args.push_back(&A); + EXPECT_EQ(2u, Args.size()); + EXPECT_FALSE(F1->hasLazyArguments()); + + // Steal arguments from F1 to F2. F1's arguments should be lazy again. + // + // steal(real); drop (empty) + F2->stealArgumentListFrom(*F1); + EXPECT_TRUE(F1->hasLazyArguments()); + EXPECT_FALSE(F2->hasLazyArguments()); + unsigned I = 0; + for (Argument &A : F2->args()) { + EXPECT_EQ(Args[I], &A); + I++; + } + EXPECT_EQ(2u, I); + + // Check that arguments in F1 don't have pointer equality with the saved ones. + // This also instantiates F1's arguments. + I = 0; + for (Argument &A : F1->args()) { + EXPECT_NE(Args[I], &A); + I++; + } + EXPECT_EQ(2u, I); + EXPECT_FALSE(F1->hasLazyArguments()); + EXPECT_FALSE(F2->hasLazyArguments()); + + // Steal back from F2. F2's arguments should be lazy again. + // + // steal(real); drop (real) + F1->stealArgumentListFrom(*F2); + EXPECT_FALSE(F1->hasLazyArguments()); + EXPECT_TRUE(F2->hasLazyArguments()); + I = 0; + for (Argument &A : F1->args()) { + EXPECT_EQ(Args[I], &A); + I++; + } + EXPECT_EQ(2u, I); + + // Steal from F2 a second time. Now both functions should have lazy + // arguments. + // + // steal(empty); drop (real) + F1->stealArgumentListFrom(*F2); + EXPECT_TRUE(F1->hasLazyArguments()); + EXPECT_TRUE(F2->hasLazyArguments()); +} + +} // end namespace diff --git a/unittests/IR/InstructionsTest.cpp b/unittests/IR/InstructionsTest.cpp index cfc55b05ab9c2af0758644ff05f010b34f63b053..0dac7c1bcfb11064033c0b7a92ec05d0497a0afe 100644 --- a/unittests/IR/InstructionsTest.cpp +++ b/unittests/IR/InstructionsTest.cpp @@ -27,7 +27,7 @@ namespace llvm { namespace { TEST(InstructionsTest, ReturnInst) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; // test for PR6589 const ReturnInst* r0 = ReturnInst::Create(C); @@ -103,7 +103,7 @@ TEST_F(ModuleWithFunctionTest, InvokeInst) { } TEST(InstructionsTest, BranchInst) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; // Make a BasicBlocks BasicBlock* bb0 = BasicBlock::Create(C); @@ -169,7 +169,7 @@ TEST(InstructionsTest, BranchInst) { } TEST(InstructionsTest, CastInst) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Type *Int8Ty = Type::getInt8Ty(C); Type *Int16Ty = Type::getInt16Ty(C); @@ -281,14 +281,18 @@ TEST(InstructionsTest, CastInst) { // First form BasicBlock *BB = BasicBlock::Create(C); Constant *NullV2I32Ptr = Constant::getNullValue(V2Int32PtrTy); - CastInst::CreatePointerCast(NullV2I32Ptr, V2Int32Ty, "foo", BB); + auto Inst1 = CastInst::CreatePointerCast(NullV2I32Ptr, V2Int32Ty, "foo", BB); // Second form - CastInst::CreatePointerCast(NullV2I32Ptr, V2Int32Ty); + auto Inst2 = CastInst::CreatePointerCast(NullV2I32Ptr, V2Int32Ty); + + delete Inst2; + Inst1->eraseFromParent(); + delete BB; } TEST(InstructionsTest, VectorGep) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; // Type Definitions Type *I8Ty = IntegerType::get(C, 8); @@ -391,7 +395,7 @@ TEST(InstructionsTest, VectorGep) { } TEST(InstructionsTest, FPMathOperator) { - LLVMContext &Context = getGlobalContext(); + LLVMContext Context; IRBuilder<> Builder(Context); MDBuilder MDHelper(Context); Instruction *I = Builder.CreatePHI(Builder.getDoubleTy(), 0); @@ -406,7 +410,7 @@ TEST(InstructionsTest, FPMathOperator) { TEST(InstructionsTest, isEliminableCastPair) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Type* Int16Ty = Type::getInt16Ty(C); Type* Int32Ty = Type::getInt32Ty(C); @@ -486,7 +490,7 @@ TEST(InstructionsTest, isEliminableCastPair) { } TEST(InstructionsTest, CloneCall) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Type *Int32Ty = Type::getInt32Ty(C); Type *ArgTys[] = {Int32Ty, Int32Ty, Int32Ty}; Type *FnTy = FunctionType::get(Int32Ty, ArgTys, /*isVarArg=*/false); @@ -519,7 +523,7 @@ TEST(InstructionsTest, CloneCall) { } TEST(InstructionsTest, AlterCallBundles) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Type *Int32Ty = Type::getInt32Ty(C); Type *FnTy = FunctionType::get(Int32Ty, Int32Ty, /*isVarArg=*/false); Value *Callee = Constant::getNullValue(FnTy->getPointerTo()); @@ -546,7 +550,7 @@ TEST(InstructionsTest, AlterCallBundles) { } TEST(InstructionsTest, AlterInvokeBundles) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Type *Int32Ty = Type::getInt32Ty(C); Type *FnTy = FunctionType::get(Int32Ty, Int32Ty, /*isVarArg=*/false); Value *Callee = Constant::getNullValue(FnTy->getPointerTo()); diff --git a/unittests/IR/LegacyPassManagerTest.cpp b/unittests/IR/LegacyPassManagerTest.cpp index 1f88283dc0ce3845295b59f653a879ecc5789432..9dceb976c9375eb21d38511b8460b4004a5801de 100644 --- a/unittests/IR/LegacyPassManagerTest.cpp +++ b/unittests/IR/LegacyPassManagerTest.cpp @@ -14,7 +14,6 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/LegacyPassManager.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopPass.h" @@ -288,7 +287,8 @@ namespace llvm { char OnTheFlyTest::ID=0; TEST(PassManager, RunOnce) { - Module M("test-once", getGlobalContext()); + LLVMContext Context; + Module M("test-once", Context); struct ModuleNDNM *mNDNM = new ModuleNDNM(); struct ModuleDNM *mDNM = new ModuleDNM(); struct ModuleNDM *mNDM = new ModuleNDM(); @@ -311,7 +311,8 @@ namespace llvm { } TEST(PassManager, ReRun) { - Module M("test-rerun", getGlobalContext()); + LLVMContext Context; + Module M("test-rerun", Context); struct ModuleNDNM *mNDNM = new ModuleNDNM(); struct ModuleDNM *mDNM = new ModuleDNM(); struct ModuleNDM *mNDM = new ModuleNDM(); @@ -334,11 +335,12 @@ namespace llvm { EXPECT_EQ(1, mDNM->run); } - Module* makeLLVMModule(); + Module *makeLLVMModule(LLVMContext &Context); template void MemoryTestHelper(int run) { - std::unique_ptr M(makeLLVMModule()); + LLVMContext Context; + std::unique_ptr M(makeLLVMModule(Context)); T *P = new T(); legacy::PassManager Passes; Passes.add(P); @@ -348,7 +350,8 @@ namespace llvm { template void MemoryTestHelper(int run, int N) { - Module *M = makeLLVMModule(); + LLVMContext Context; + Module *M = makeLLVMModule(Context); T *P = new T(); legacy::PassManager Passes; Passes.add(P); @@ -383,7 +386,8 @@ namespace llvm { } TEST(PassManager, MemoryOnTheFly) { - Module *M = makeLLVMModule(); + LLVMContext Context; + Module *M = makeLLVMModule(Context); { SCOPED_TRACE("Running OnTheFlyTest"); struct OnTheFlyTest *O = new OnTheFlyTest(); @@ -396,9 +400,9 @@ namespace llvm { delete M; } - Module* makeLLVMModule() { + Module *makeLLVMModule(LLVMContext &Context) { // Module Construction - Module* mod = new Module("test-mem", getGlobalContext()); + Module *mod = new Module("test-mem", Context); mod->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" "a:0:64-s:64:64-f80:128:128"); @@ -406,18 +410,17 @@ namespace llvm { // Type Definitions std::vectorFuncTy_0_args; - FunctionType* FuncTy_0 = FunctionType::get( - /*Result=*/IntegerType::get(getGlobalContext(), 32), - /*Params=*/FuncTy_0_args, - /*isVarArg=*/false); + FunctionType *FuncTy_0 = FunctionType::get( + /*Result=*/IntegerType::get(Context, 32), + /*Params=*/FuncTy_0_args, + /*isVarArg=*/false); std::vectorFuncTy_2_args; - FuncTy_2_args.push_back(IntegerType::get(getGlobalContext(), 1)); - FunctionType* FuncTy_2 = FunctionType::get( - /*Result=*/Type::getVoidTy(getGlobalContext()), - /*Params=*/FuncTy_2_args, - /*isVarArg=*/false); - + FuncTy_2_args.push_back(IntegerType::get(Context, 1)); + FunctionType *FuncTy_2 = FunctionType::get( + /*Result=*/Type::getVoidTy(Context), + /*Params=*/FuncTy_2_args, + /*isVarArg=*/false); // Function Declarations @@ -465,7 +468,8 @@ namespace llvm { // Function: test1 (func_test1) { - BasicBlock* label_entry = BasicBlock::Create(getGlobalContext(), "entry",func_test1,nullptr); + BasicBlock *label_entry = + BasicBlock::Create(Context, "entry", func_test1, nullptr); // Block entry (label_entry) CallInst* int32_3 = CallInst::Create(func_test2, "", label_entry); @@ -473,14 +477,14 @@ namespace llvm { int32_3->setTailCall(false);AttributeSet int32_3_PAL; int32_3->setAttributes(int32_3_PAL); - ReturnInst::Create(getGlobalContext(), int32_3, label_entry); - + ReturnInst::Create(Context, int32_3, label_entry); } // Function: test2 (func_test2) { - BasicBlock* label_entry_5 = BasicBlock::Create(getGlobalContext(), "entry",func_test2,nullptr); + BasicBlock *label_entry_5 = + BasicBlock::Create(Context, "entry", func_test2, nullptr); // Block entry (label_entry_5) CallInst* int32_6 = CallInst::Create(func_test3, "", label_entry_5); @@ -488,14 +492,14 @@ namespace llvm { int32_6->setTailCall(false);AttributeSet int32_6_PAL; int32_6->setAttributes(int32_6_PAL); - ReturnInst::Create(getGlobalContext(), int32_6, label_entry_5); - + ReturnInst::Create(Context, int32_6, label_entry_5); } // Function: test3 (func_test3) { - BasicBlock* label_entry_8 = BasicBlock::Create(getGlobalContext(), "entry",func_test3,nullptr); + BasicBlock *label_entry_8 = + BasicBlock::Create(Context, "entry", func_test3, nullptr); // Block entry (label_entry_8) CallInst* int32_9 = CallInst::Create(func_test1, "", label_entry_8); @@ -503,8 +507,7 @@ namespace llvm { int32_9->setTailCall(false);AttributeSet int32_9_PAL; int32_9->setAttributes(int32_9_PAL); - ReturnInst::Create(getGlobalContext(), int32_9, label_entry_8); - + ReturnInst::Create(Context, int32_9, label_entry_8); } // Function: test4 (func_test4) @@ -513,10 +516,14 @@ namespace llvm { Value *int1_f = &*args++; int1_f->setName("f"); - BasicBlock* label_entry_11 = BasicBlock::Create(getGlobalContext(), "entry",func_test4,nullptr); - BasicBlock* label_bb = BasicBlock::Create(getGlobalContext(), "bb",func_test4,nullptr); - BasicBlock* label_bb1 = BasicBlock::Create(getGlobalContext(), "bb1",func_test4,nullptr); - BasicBlock* label_return = BasicBlock::Create(getGlobalContext(), "return",func_test4,nullptr); + BasicBlock *label_entry_11 = + BasicBlock::Create(Context, "entry", func_test4, nullptr); + BasicBlock *label_bb = + BasicBlock::Create(Context, "bb", func_test4, nullptr); + BasicBlock *label_bb1 = + BasicBlock::Create(Context, "bb1", func_test4, nullptr); + BasicBlock *label_return = + BasicBlock::Create(Context, "return", func_test4, nullptr); // Block entry (label_entry_11) BranchInst::Create(label_bb, label_entry_11); @@ -528,8 +535,7 @@ namespace llvm { BranchInst::Create(label_bb1, label_return, int1_f, label_bb1); // Block return (label_return) - ReturnInst::Create(getGlobalContext(), label_return); - + ReturnInst::Create(Context, label_return); } return mod; } diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp index 8316c7f4190abd7a05470c31d35410ba68fff053..77a2dbaf2dfa863b3141cc2b0a2d57a8c1f99e68 100644 --- a/unittests/IR/MetadataTest.cpp +++ b/unittests/IR/MetadataTest.cpp @@ -80,26 +80,29 @@ protected: MDTuple *getTuple() { return MDTuple::getDistinct(Context, None); } DISubroutineType *getSubroutineType() { - return DISubroutineType::getDistinct(Context, 0, getNode(nullptr)); + return DISubroutineType::getDistinct(Context, 0, 0, getNode(nullptr)); } DISubprogram *getSubprogram() { return DISubprogram::getDistinct(Context, nullptr, "", "", nullptr, 0, - nullptr, false, false, 0, nullptr, 0, 0, 0, - 0); + nullptr, false, false, 0, nullptr, + 0, 0, 0, 0, false, nullptr); } - DIScopeRef getSubprogramRef() { return getSubprogram()->getRef(); } DIFile *getFile() { return DIFile::getDistinct(Context, "file.c", "/path/to/dir"); } - DITypeRef getBasicType(StringRef Name) { - return DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, Name) - ->getRef(); + DICompileUnit *getUnit() { + return DICompileUnit::getDistinct(Context, 1, getFile(), "clang", false, + "-g", 2, "", DICompileUnit::FullDebug, + getTuple(), getTuple(), getTuple(), + getTuple(), getTuple(), 0); } - DITypeRef getDerivedType() { + DIType *getBasicType(StringRef Name) { + return DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, Name); + } + DIType *getDerivedType() { return DIDerivedType::getDistinct(Context, dwarf::DW_TAG_pointer_type, "", nullptr, 0, nullptr, - getBasicType("basictype"), 1, 2, 0, 0) - ->getRef(); + getBasicType("basictype"), 1, 2, 0, 0); } Constant *getConstant() { return ConstantInt::get(Type::getInt32Ty(Context), Counter++); @@ -107,11 +110,10 @@ protected: ConstantAsMetadata *getConstantAsMetadata() { return ConstantAsMetadata::get(getConstant()); } - DITypeRef getCompositeType() { + DIType *getCompositeType() { return DICompositeType::getDistinct( - Context, dwarf::DW_TAG_structure_type, "", nullptr, 0, nullptr, - nullptr, 32, 32, 0, 0, nullptr, 0, nullptr, nullptr, "") - ->getRef(); + Context, dwarf::DW_TAG_structure_type, "", nullptr, 0, nullptr, nullptr, + 32, 32, 0, 0, nullptr, 0, nullptr, nullptr, ""); } Function *getFunction(StringRef Name) { return cast(M.getOrInsertFunction( @@ -174,8 +176,8 @@ TEST_F(MDNodeTest, Simple) { MDString *s1 = MDString::get(Context, StringRef(&x[0], 3)); MDString *s2 = MDString::get(Context, StringRef(&y[0], 3)); - ConstantAsMetadata *CI = ConstantAsMetadata::get( - ConstantInt::get(getGlobalContext(), APInt(8, 0))); + ConstantAsMetadata *CI = + ConstantAsMetadata::get(ConstantInt::get(Context, APInt(8, 0))); std::vector V; V.push_back(s1); @@ -206,8 +208,8 @@ TEST_F(MDNodeTest, Simple) { } TEST_F(MDNodeTest, Delete) { - Constant *C = ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 1); - Instruction *I = new BitCastInst(C, Type::getInt32Ty(getGlobalContext())); + Constant *C = ConstantInt::get(Type::getInt32Ty(Context), 1); + Instruction *I = new BitCastInst(C, Type::getInt32Ty(Context)); Metadata *const V = LocalAsMetadata::get(I); MDNode *n = MDNode::get(Context, V); @@ -494,20 +496,6 @@ TEST_F(MDNodeTest, isTemporary) { EXPECT_TRUE(T->isTemporary()); } -#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) - -TEST_F(MDNodeTest, deathOnNoReplaceTemporaryRAUW) { - auto Temp = MDNode::getTemporary(Context, None); - Temp->setCanReplace(false); - EXPECT_DEATH(Temp->replaceAllUsesWith(nullptr), - "Attempted to replace Metadata marked for no replacement"); - Temp->setCanReplace(true); - // Remove the references to Temp; required for teardown. - Temp->replaceAllUsesWith(nullptr); -} - -#endif - TEST_F(MDNodeTest, getDistinctWithUnresolvedOperands) { // temporary !{} auto Temp = MDTuple::getTemporary(Context, None); @@ -981,14 +969,14 @@ TEST_F(DITypeTest, setFlags) { Metadata *TypesOps[] = {nullptr}; Metadata *Types = MDTuple::get(Context, TypesOps); - DIType *D = DISubroutineType::getDistinct(Context, 0u, Types); + DIType *D = DISubroutineType::getDistinct(Context, 0u, 0, Types); EXPECT_EQ(0u, D->getFlags()); D->setFlags(DINode::FlagRValueReference); EXPECT_EQ(DINode::FlagRValueReference, D->getFlags()); D->setFlags(0u); EXPECT_EQ(0u, D->getFlags()); - TempDIType T = DISubroutineType::getTemporary(Context, 0u, Types); + TempDIType T = DISubroutineType::getTemporary(Context, 0u, 0, Types); EXPECT_EQ(0u, T->getFlags()); T->setFlags(DINode::FlagRValueReference); EXPECT_EQ(DINode::FlagRValueReference, T->getFlags()); @@ -1000,8 +988,8 @@ typedef MetadataTest DIDerivedTypeTest; TEST_F(DIDerivedTypeTest, get) { DIFile *File = getFile(); - DIScopeRef Scope = getSubprogramRef(); - DITypeRef BaseType = getBasicType("basic"); + DIScope *Scope = getSubprogram(); + DIType *BaseType = getBasicType("basic"); MDTuple *ExtraData = getTuple(); auto *N = DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "something", @@ -1034,7 +1022,7 @@ TEST_F(DIDerivedTypeTest, get) { "something", File, 2, Scope, BaseType, 2, 3, 4, 5, ExtraData)); EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, - "something", File, 1, getSubprogramRef(), + "something", File, 1, getSubprogram(), BaseType, 2, 3, 4, 5, ExtraData)); EXPECT_NE(N, DIDerivedType::get( Context, dwarf::DW_TAG_pointer_type, "something", File, 1, @@ -1061,8 +1049,8 @@ TEST_F(DIDerivedTypeTest, get) { TEST_F(DIDerivedTypeTest, getWithLargeValues) { DIFile *File = getFile(); - DIScopeRef Scope = getSubprogramRef(); - DITypeRef BaseType = getBasicType("basic"); + DIScope *Scope = getSubprogram(); + DIType *BaseType = getBasicType("basic"); MDTuple *ExtraData = getTuple(); auto *N = DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "something", @@ -1080,15 +1068,15 @@ TEST_F(DICompositeTypeTest, get) { StringRef Name = "some name"; DIFile *File = getFile(); unsigned Line = 1; - DIScopeRef Scope = getSubprogramRef(); - DITypeRef BaseType = getCompositeType(); + DIScope *Scope = getSubprogram(); + DIType *BaseType = getCompositeType(); uint64_t SizeInBits = 2; uint64_t AlignInBits = 3; uint64_t OffsetInBits = 4; unsigned Flags = 5; MDTuple *Elements = getTuple(); unsigned RuntimeLang = 6; - DITypeRef VTableHolder = getCompositeType(); + DIType *VTableHolder = getCompositeType(); MDTuple *TemplateParams = getTuple(); StringRef Identifier = "some id"; @@ -1134,7 +1122,7 @@ TEST_F(DICompositeTypeTest, get) { OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder, TemplateParams, Identifier)); EXPECT_NE(N, DICompositeType::get( - Context, Tag, Name, File, Line, getSubprogramRef(), BaseType, + Context, Tag, Name, File, Line, getSubprogram(), BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder, TemplateParams, Identifier)); EXPECT_NE(N, DICompositeType::get( @@ -1199,15 +1187,15 @@ TEST_F(DICompositeTypeTest, getWithLargeValues) { StringRef Name = "some name"; DIFile *File = getFile(); unsigned Line = 1; - DIScopeRef Scope = getSubprogramRef(); - DITypeRef BaseType = getCompositeType(); + DIScope *Scope = getSubprogram(); + DIType *BaseType = getCompositeType(); uint64_t SizeInBits = UINT64_MAX; uint64_t AlignInBits = UINT64_MAX - 1; uint64_t OffsetInBits = UINT64_MAX - 2; unsigned Flags = 5; MDTuple *Elements = getTuple(); unsigned RuntimeLang = 6; - DITypeRef VTableHolder = getCompositeType(); + DIType *VTableHolder = getCompositeType(); MDTuple *TemplateParams = getTuple(); StringRef Identifier = "some id"; @@ -1225,8 +1213,8 @@ TEST_F(DICompositeTypeTest, replaceOperands) { StringRef Name = "some name"; DIFile *File = getFile(); unsigned Line = 1; - DIScopeRef Scope = getSubprogramRef(); - DITypeRef BaseType = getCompositeType(); + DIScope *Scope = getSubprogram(); + DIType *BaseType = getCompositeType(); uint64_t SizeInBits = 2; uint64_t AlignInBits = 3; uint64_t OffsetInBits = 4; @@ -1245,7 +1233,7 @@ TEST_F(DICompositeTypeTest, replaceOperands) { N->replaceElements(nullptr); EXPECT_EQ(nullptr, N->getElements().get()); - DITypeRef VTableHolder = getCompositeType(); + DIType *VTableHolder = getCompositeType(); EXPECT_EQ(nullptr, N->getVTableHolder()); N->replaceVTableHolder(VTableHolder); EXPECT_EQ(VTableHolder, N->getVTableHolder()); @@ -1266,14 +1254,29 @@ TEST_F(DISubroutineTypeTest, get) { unsigned Flags = 1; MDTuple *TypeArray = getTuple(); - auto *N = DISubroutineType::get(Context, Flags, TypeArray); + auto *N = DISubroutineType::get(Context, Flags, 0, TypeArray); EXPECT_EQ(dwarf::DW_TAG_subroutine_type, N->getTag()); EXPECT_EQ(Flags, N->getFlags()); EXPECT_EQ(TypeArray, N->getTypeArray().get()); - EXPECT_EQ(N, DISubroutineType::get(Context, Flags, TypeArray)); - - EXPECT_NE(N, DISubroutineType::get(Context, Flags + 1, TypeArray)); - EXPECT_NE(N, DISubroutineType::get(Context, Flags, getTuple())); + EXPECT_EQ(N, DISubroutineType::get(Context, Flags, 0, TypeArray)); + + EXPECT_NE(N, DISubroutineType::get(Context, Flags + 1, 0, TypeArray)); + EXPECT_NE(N, DISubroutineType::get(Context, Flags, 0, getTuple())); + + // Test the hashing of calling conventions. + auto *Fast = DISubroutineType::get( + Context, Flags, dwarf::DW_CC_BORLAND_msfastcall, TypeArray); + auto *Std = DISubroutineType::get(Context, Flags, + dwarf::DW_CC_BORLAND_stdcall, TypeArray); + EXPECT_EQ(Fast, + DISubroutineType::get(Context, Flags, + dwarf::DW_CC_BORLAND_msfastcall, TypeArray)); + EXPECT_EQ(Std, DISubroutineType::get( + Context, Flags, dwarf::DW_CC_BORLAND_stdcall, TypeArray)); + + EXPECT_NE(N, Fast); + EXPECT_NE(N, Std); + EXPECT_NE(Fast, Std); TempDISubroutineType Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); @@ -1319,10 +1322,9 @@ TEST_F(DICompileUnitTest, get) { StringRef Flags = "flag after flag"; unsigned RuntimeVersion = 2; StringRef SplitDebugFilename = "another/file"; - unsigned EmissionKind = 3; + auto EmissionKind = DICompileUnit::FullDebug; MDTuple *EnumTypes = getTuple(); MDTuple *RetainedTypes = getTuple(); - MDTuple *Subprograms = getTuple(); MDTuple *GlobalVariables = getTuple(); MDTuple *ImportedEntities = getTuple(); uint64_t DWOId = 0x10000000c0ffee; @@ -1330,7 +1332,7 @@ TEST_F(DICompileUnitTest, get) { auto *N = DICompileUnit::getDistinct( Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, - RetainedTypes, Subprograms, GlobalVariables, ImportedEntities, Macros, + RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId); EXPECT_EQ(dwarf::DW_TAG_compile_unit, N->getTag()); @@ -1344,7 +1346,6 @@ TEST_F(DICompileUnitTest, get) { EXPECT_EQ(EmissionKind, N->getEmissionKind()); EXPECT_EQ(EnumTypes, N->getEnumTypes().get()); EXPECT_EQ(RetainedTypes, N->getRetainedTypes().get()); - EXPECT_EQ(Subprograms, N->getSubprograms().get()); EXPECT_EQ(GlobalVariables, N->getGlobalVariables().get()); EXPECT_EQ(ImportedEntities, N->getImportedEntities().get()); EXPECT_EQ(Macros, N->getMacros().get()); @@ -1362,7 +1363,6 @@ TEST_F(DICompileUnitTest, get) { EXPECT_EQ(EmissionKind, Temp->getEmissionKind()); EXPECT_EQ(EnumTypes, Temp->getEnumTypes().get()); EXPECT_EQ(RetainedTypes, Temp->getRetainedTypes().get()); - EXPECT_EQ(Subprograms, Temp->getSubprograms().get()); EXPECT_EQ(GlobalVariables, Temp->getGlobalVariables().get()); EXPECT_EQ(ImportedEntities, Temp->getImportedEntities().get()); EXPECT_EQ(Macros, Temp->getMacros().get()); @@ -1382,7 +1382,7 @@ TEST_F(DICompileUnitTest, replaceArrays) { StringRef Flags = "flag after flag"; unsigned RuntimeVersion = 2; StringRef SplitDebugFilename = "another/file"; - unsigned EmissionKind = 3; + auto EmissionKind = DICompileUnit::FullDebug; MDTuple *EnumTypes = MDTuple::getDistinct(Context, None); MDTuple *RetainedTypes = MDTuple::getDistinct(Context, None); MDTuple *ImportedEntities = MDTuple::getDistinct(Context, None); @@ -1390,14 +1390,7 @@ TEST_F(DICompileUnitTest, replaceArrays) { auto *N = DICompileUnit::getDistinct( Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, - RetainedTypes, nullptr, nullptr, ImportedEntities, nullptr, DWOId); - - auto *Subprograms = MDTuple::getDistinct(Context, None); - EXPECT_EQ(nullptr, N->getSubprograms().get()); - N->replaceSubprograms(Subprograms); - EXPECT_EQ(Subprograms, N->getSubprograms().get()); - N->replaceSubprograms(nullptr); - EXPECT_EQ(nullptr, N->getSubprograms().get()); + RetainedTypes, nullptr, ImportedEntities, nullptr, DWOId); auto *GlobalVariables = MDTuple::getDistinct(Context, None); EXPECT_EQ(nullptr, N->getGlobalVariables().get()); @@ -1417,7 +1410,7 @@ TEST_F(DICompileUnitTest, replaceArrays) { typedef MetadataTest DISubprogramTest; TEST_F(DISubprogramTest, get) { - DIScopeRef Scope = getCompositeType(); + DIScope *Scope = getCompositeType(); StringRef Name = "name"; StringRef LinkageName = "linkage"; DIFile *File = getFile(); @@ -1426,19 +1419,23 @@ TEST_F(DISubprogramTest, get) { bool IsLocalToUnit = false; bool IsDefinition = true; unsigned ScopeLine = 3; - DITypeRef ContainingType = getCompositeType(); - unsigned Virtuality = 4; + DIType *ContainingType = getCompositeType(); + unsigned Virtuality = 2; unsigned VirtualIndex = 5; + int ThisAdjustment = -3; unsigned Flags = 6; + unsigned NotFlags = (~Flags) & ((1 << 27) - 1); bool IsOptimized = false; MDTuple *TemplateParams = getTuple(); DISubprogram *Declaration = getSubprogram(); MDTuple *Variables = getTuple(); + DICompileUnit *Unit = getUnit(); - auto *N = DISubprogram::get( - Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, - IsOptimized, TemplateParams, Declaration, Variables); + auto *N = DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + ThisAdjustment, Flags, IsOptimized, Unit, + TemplateParams, Declaration, Variables); EXPECT_EQ(dwarf::DW_TAG_subprogram, N->getTag()); EXPECT_EQ(Scope, N->getScope()); @@ -1453,102 +1450,110 @@ TEST_F(DISubprogramTest, get) { EXPECT_EQ(ContainingType, N->getContainingType()); EXPECT_EQ(Virtuality, N->getVirtuality()); EXPECT_EQ(VirtualIndex, N->getVirtualIndex()); + EXPECT_EQ(ThisAdjustment, N->getThisAdjustment()); EXPECT_EQ(Flags, N->getFlags()); EXPECT_EQ(IsOptimized, N->isOptimized()); + EXPECT_EQ(Unit, N->getUnit()); EXPECT_EQ(TemplateParams, N->getTemplateParams().get()); EXPECT_EQ(Declaration, N->getDeclaration()); EXPECT_EQ(Variables, N->getVariables().get()); EXPECT_EQ(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, - Flags, IsOptimized, TemplateParams, - Declaration, Variables)); - - EXPECT_NE(N, DISubprogram::get(Context, getCompositeType(), Name, LinkageName, - File, Line, Type, IsLocalToUnit, IsDefinition, - ScopeLine, ContainingType, Virtuality, - VirtualIndex, Flags, IsOptimized, - TemplateParams, Declaration, Variables)); - EXPECT_NE(N, DISubprogram::get(Context, Scope, "other", LinkageName, File, - Line, Type, IsLocalToUnit, IsDefinition, - ScopeLine, ContainingType, Virtuality, - VirtualIndex, Flags, IsOptimized, + ThisAdjustment, Flags, IsOptimized, Unit, TemplateParams, Declaration, Variables)); + + EXPECT_NE(N, DISubprogram::get( + Context, getCompositeType(), Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, + Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized, + Unit, TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get( + Context, Scope, "other", LinkageName, File, Line, Type, + IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, + Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized, + Unit, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, "other", File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, - Flags, IsOptimized, TemplateParams, - Declaration, Variables)); - EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, getFile(), - Line, Type, IsLocalToUnit, IsDefinition, - ScopeLine, ContainingType, Virtuality, - VirtualIndex, Flags, IsOptimized, - TemplateParams, Declaration, Variables)); - EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, - Line + 1, Type, IsLocalToUnit, IsDefinition, - ScopeLine, ContainingType, Virtuality, - VirtualIndex, Flags, IsOptimized, - TemplateParams, Declaration, Variables)); - EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - getSubroutineType(), IsLocalToUnit, - IsDefinition, ScopeLine, ContainingType, - Virtuality, VirtualIndex, Flags, IsOptimized, + ThisAdjustment, Flags, IsOptimized, Unit, TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get( + Context, Scope, Name, LinkageName, getFile(), Line, Type, + IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, + Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized, + Unit, TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get( + Context, Scope, Name, LinkageName, File, Line + 1, Type, + IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, + Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized, + Unit, TemplateParams, Declaration, Variables)); + EXPECT_NE(N, + DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + getSubroutineType(), IsLocalToUnit, IsDefinition, + ScopeLine, ContainingType, Virtuality, + VirtualIndex, ThisAdjustment, Flags, IsOptimized, + Unit, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, !IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, - Flags, IsOptimized, TemplateParams, - Declaration, Variables)); + ThisAdjustment, Flags, IsOptimized, Unit, + TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, !IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, - Flags, IsOptimized, TemplateParams, - Declaration, Variables)); - EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, - ScopeLine + 1, ContainingType, Virtuality, - VirtualIndex, Flags, IsOptimized, + ThisAdjustment, Flags, IsOptimized, Unit, TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get( + Context, Scope, Name, LinkageName, File, Line, Type, + IsLocalToUnit, IsDefinition, ScopeLine + 1, ContainingType, + Virtuality, VirtualIndex, ThisAdjustment, Flags, IsOptimized, + Unit, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, getCompositeType(), Virtuality, VirtualIndex, - Flags, IsOptimized, TemplateParams, - Declaration, Variables)); + ThisAdjustment, Flags, IsOptimized, Unit, + TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality + 1, VirtualIndex, - Flags, IsOptimized, TemplateParams, - Declaration, Variables)); + ThisAdjustment, Flags, IsOptimized, Unit, + TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex + 1, - Flags, IsOptimized, TemplateParams, - Declaration, Variables)); + ThisAdjustment, Flags, IsOptimized, Unit, + TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, - ~Flags, IsOptimized, TemplateParams, - Declaration, Variables)); + ThisAdjustment, NotFlags, IsOptimized, Unit, + TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, - Flags, !IsOptimized, TemplateParams, - Declaration, Variables)); - EXPECT_NE(N, - DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, - ContainingType, Virtuality, VirtualIndex, Flags, - IsOptimized, getTuple(), Declaration, Variables)); + ThisAdjustment, Flags, !IsOptimized, Unit, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + ThisAdjustment, Flags, IsOptimized, nullptr, + TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, - Flags, IsOptimized, TemplateParams, - getSubprogram(), Variables)); + ThisAdjustment, Flags, IsOptimized, Unit, + getTuple(), Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, - Flags, IsOptimized, TemplateParams, - Declaration, getTuple())); + ThisAdjustment, Flags, IsOptimized, Unit, + TemplateParams, getSubprogram(), Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + ThisAdjustment, Flags, IsOptimized, Unit, + TemplateParams, Declaration, getTuple())); TempDISubprogram Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); @@ -1697,7 +1702,7 @@ typedef MetadataTest DITemplateTypeParameterTest; TEST_F(DITemplateTypeParameterTest, get) { StringRef Name = "template"; - DITypeRef Type = getBasicType("basic"); + DIType *Type = getBasicType("basic"); auto *N = DITemplateTypeParameter::get(Context, Name, Type); @@ -1719,7 +1724,7 @@ typedef MetadataTest DITemplateValueParameterTest; TEST_F(DITemplateValueParameterTest, get) { unsigned Tag = dwarf::DW_TAG_template_value_parameter; StringRef Name = "template"; - DITypeRef Type = getBasicType("basic"); + DIType *Type = getBasicType("basic"); Metadata *Value = getConstantAsMetadata(); auto *N = DITemplateValueParameter::get(Context, Tag, Name, Type, Value); @@ -1751,7 +1756,7 @@ TEST_F(DIGlobalVariableTest, get) { StringRef LinkageName = "linkage"; DIFile *File = getFile(); unsigned Line = 5; - DITypeRef Type = getDerivedType(); + DIType *Type = getDerivedType(); bool IsLocalToUnit = false; bool IsDefinition = true; Constant *Variable = getConstant(); @@ -1824,9 +1829,10 @@ TEST_F(DILocalVariableTest, get) { StringRef Name = "name"; DIFile *File = getFile(); unsigned Line = 5; - DITypeRef Type = getDerivedType(); + DIType *Type = getDerivedType(); unsigned Arg = 6; unsigned Flags = 7; + unsigned NotFlags = (~Flags) & ((1 << 16) - 1); auto *N = DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, Flags); @@ -1857,7 +1863,7 @@ TEST_F(DILocalVariableTest, get) { EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg + 1, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, - ~Flags)); + NotFlags)); TempDILocalVariable Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); @@ -1943,7 +1949,7 @@ TEST_F(DIObjCPropertyTest, get) { StringRef GetterName = "getter"; StringRef SetterName = "setter"; unsigned Attributes = 7; - DITypeRef Type = getBasicType("basic"); + DIType *Type = getBasicType("basic"); auto *N = DIObjCProperty::get(Context, Name, File, Line, GetterName, SetterName, Attributes, Type); @@ -1984,7 +1990,7 @@ typedef MetadataTest DIImportedEntityTest; TEST_F(DIImportedEntityTest, get) { unsigned Tag = dwarf::DW_TAG_imported_module; DIScope *Scope = getSubprogram(); - DINodeRef Entity = getCompositeType(); + DINode *Entity = getCompositeType(); unsigned Line = 5; StringRef Name = "name"; @@ -2075,8 +2081,8 @@ TEST_F(ValueAsMetadataTest, UpdatesOnRAUW) { TEST_F(ValueAsMetadataTest, TempTempReplacement) { // Create a constant. - ConstantAsMetadata *CI = ConstantAsMetadata::get( - ConstantInt::get(getGlobalContext(), APInt(8, 0))); + ConstantAsMetadata *CI = + ConstantAsMetadata::get(ConstantInt::get(Context, APInt(8, 0))); auto Temp1 = MDTuple::getTemporary(Context, None); auto Temp2 = MDTuple::getTemporary(Context, {CI}); @@ -2092,8 +2098,8 @@ TEST_F(ValueAsMetadataTest, TempTempReplacement) { TEST_F(ValueAsMetadataTest, CollidingDoubleUpdates) { // Create a constant. - ConstantAsMetadata *CI = ConstantAsMetadata::get( - ConstantInt::get(getGlobalContext(), APInt(8, 0))); + ConstantAsMetadata *CI = + ConstantAsMetadata::get(ConstantInt::get(Context, APInt(8, 0))); // Create a temporary to prevent nodes from resolving. auto Temp = MDTuple::getTemporary(Context, None); @@ -2255,44 +2261,23 @@ TEST_F(FunctionAttachmentTest, getAll) { EXPECT_EQ(T2, MDs[3].second); } -TEST_F(FunctionAttachmentTest, dropUnknownMetadata) { - Function *F = getFunction("foo"); - - MDTuple *T1 = getTuple(); - MDTuple *T2 = getTuple(); - MDTuple *P = getTuple(); - DISubprogram *SP = getSubprogram(); - - F->setMetadata("other1", T1); - F->setMetadata(LLVMContext::MD_dbg, SP); - F->setMetadata("other2", T2); - F->setMetadata(LLVMContext::MD_prof, P); - - unsigned Known[] = {Context.getMDKindID("other2"), LLVMContext::MD_prof}; - F->dropUnknownMetadata(Known); - - EXPECT_EQ(T2, F->getMetadata("other2")); - EXPECT_EQ(P, F->getMetadata(LLVMContext::MD_prof)); - EXPECT_EQ(nullptr, F->getMetadata("other1")); - EXPECT_EQ(nullptr, F->getMetadata(LLVMContext::MD_dbg)); - - F->setMetadata("other2", nullptr); - F->setMetadata(LLVMContext::MD_prof, nullptr); - EXPECT_FALSE(F->hasMetadata()); -} - TEST_F(FunctionAttachmentTest, Verifier) { Function *F = getFunction("foo"); F->setMetadata("attach", getTuple()); + F->setIsMaterializable(true); + + // Confirm this is materializable. + ASSERT_TRUE(F->isMaterializable()); - // Confirm this has no body. - ASSERT_TRUE(F->empty()); + // Materializable functions cannot have metadata attachments. + EXPECT_TRUE(verifyFunction(*F)); - // Functions without a body cannot have metadata attachments (they also can't - // be verified directly, so check that the module fails to verify). - EXPECT_TRUE(verifyModule(*F->getParent())); + // Function declarations can. + F->setIsMaterializable(false); + EXPECT_FALSE(verifyModule(*F->getParent())); + EXPECT_FALSE(verifyFunction(*F)); - // Functions with a body can. + // So can definitions. (void)new UnreachableInst(Context, BasicBlock::Create(Context, "bb", F)); EXPECT_FALSE(verifyModule(*F->getParent())); EXPECT_FALSE(verifyFunction(*F)); @@ -2318,4 +2303,81 @@ TEST_F(FunctionAttachmentTest, SubprogramAttachment) { EXPECT_EQ(SP, F->getMetadata(LLVMContext::MD_dbg)); } +typedef MetadataTest DistinctMDOperandPlaceholderTest; +TEST_F(DistinctMDOperandPlaceholderTest, getID) { + EXPECT_EQ(7u, DistinctMDOperandPlaceholder(7).getID()); } + +TEST_F(DistinctMDOperandPlaceholderTest, replaceUseWith) { + // Set up some placeholders. + DistinctMDOperandPlaceholder PH0(7); + DistinctMDOperandPlaceholder PH1(3); + DistinctMDOperandPlaceholder PH2(0); + Metadata *Ops[] = {&PH0, &PH1, &PH2}; + auto *D = MDTuple::getDistinct(Context, Ops); + ASSERT_EQ(&PH0, D->getOperand(0)); + ASSERT_EQ(&PH1, D->getOperand(1)); + ASSERT_EQ(&PH2, D->getOperand(2)); + + // Replace them. + auto *N0 = MDTuple::get(Context, None); + auto *N1 = MDTuple::get(Context, N0); + PH0.replaceUseWith(N0); + PH1.replaceUseWith(N1); + PH2.replaceUseWith(nullptr); + EXPECT_EQ(N0, D->getOperand(0)); + EXPECT_EQ(N1, D->getOperand(1)); + EXPECT_EQ(nullptr, D->getOperand(2)); +} + +TEST_F(DistinctMDOperandPlaceholderTest, replaceUseWithNoUser) { + // There is no user, but we can still call replace. + DistinctMDOperandPlaceholder(7).replaceUseWith(MDTuple::get(Context, None)); +} + +#ifndef NDEBUG +#ifdef GTEST_HAS_DEATH_TEST +TEST_F(DistinctMDOperandPlaceholderTest, MetadataAsValue) { + // This shouldn't crash. + DistinctMDOperandPlaceholder PH(7); + EXPECT_DEATH(MetadataAsValue::get(Context, &PH), + "Unexpected callback to owner"); +} + +TEST_F(DistinctMDOperandPlaceholderTest, UniquedMDNode) { + // This shouldn't crash. + DistinctMDOperandPlaceholder PH(7); + EXPECT_DEATH(MDTuple::get(Context, &PH), "Unexpected callback to owner"); +} + +TEST_F(DistinctMDOperandPlaceholderTest, SecondDistinctMDNode) { + // This shouldn't crash. + DistinctMDOperandPlaceholder PH(7); + MDTuple::getDistinct(Context, &PH); + EXPECT_DEATH(MDTuple::getDistinct(Context, &PH), + "Placeholders can only be used once"); +} + +TEST_F(DistinctMDOperandPlaceholderTest, TrackingMDRefAndDistinctMDNode) { + // TrackingMDRef doesn't install an owner callback, so it can't be detected + // as an invalid use. However, using a placeholder in a TrackingMDRef *and* + // a distinct node isn't possible and we should assert. + // + // (There's no positive test for using TrackingMDRef because it's not a + // useful thing to do.) + { + DistinctMDOperandPlaceholder PH(7); + MDTuple::getDistinct(Context, &PH); + EXPECT_DEATH(TrackingMDRef Ref(&PH), "Placeholders can only be used once"); + } + { + DistinctMDOperandPlaceholder PH(7); + TrackingMDRef Ref(&PH); + EXPECT_DEATH(MDTuple::getDistinct(Context, &PH), + "Placeholders can only be used once"); + } +} +#endif +#endif + +} // end namespace diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index 15b29d9b896edc981c29d3fea219bde067d4acdb..c2ac863260ae3d4ff50d60bb73672a270981039a 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -77,7 +77,7 @@ char TestModuleAnalysis::PassID; struct TestModulePass : PassInfoMixin { TestModulePass(int &RunCount) : RunCount(RunCount) {} - PreservedAnalyses run(Module &M) { + PreservedAnalyses run(Module &M, ModuleAnalysisManager &) { ++RunCount; return PreservedAnalyses::none(); } @@ -86,7 +86,9 @@ struct TestModulePass : PassInfoMixin { }; struct TestPreservingModulePass : PassInfoMixin { - PreservedAnalyses run(Module &M) { return PreservedAnalyses::all(); } + PreservedAnalyses run(Module &M, ModuleAnalysisManager &) { + return PreservedAnalyses::all(); + } }; struct TestMinPreservingModulePass @@ -145,7 +147,7 @@ struct TestInvalidationFunctionPass : PassInfoMixin { TestInvalidationFunctionPass(StringRef FunctionName) : Name(FunctionName) {} - PreservedAnalyses run(Function &F) { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { return F.getName() == Name ? PreservedAnalyses::none() : PreservedAnalyses::all(); } @@ -153,30 +155,30 @@ struct TestInvalidationFunctionPass StringRef Name; }; -std::unique_ptr parseIR(const char *IR) { - LLVMContext &C = getGlobalContext(); +std::unique_ptr parseIR(LLVMContext &Context, const char *IR) { SMDiagnostic Err; - return parseAssemblyString(IR, Err, C); + return parseAssemblyString(IR, Err, Context); } class PassManagerTest : public ::testing::Test { protected: + LLVMContext Context; std::unique_ptr M; public: PassManagerTest() - : M(parseIR("define void @f() {\n" - "entry:\n" - " call void @g()\n" - " call void @h()\n" - " ret void\n" - "}\n" - "define void @g() {\n" - " ret void\n" - "}\n" - "define void @h() {\n" - " ret void\n" - "}\n")) {} + : M(parseIR(Context, "define void @f() {\n" + "entry:\n" + " call void @g()\n" + " call void @h()\n" + " ret void\n" + "}\n" + "define void @g() {\n" + " ret void\n" + "}\n" + "define void @h() {\n" + " ret void\n" + "}\n")) {} }; TEST_F(PassManagerTest, BasicPreservedAnalyses) { @@ -236,8 +238,8 @@ TEST_F(PassManagerTest, Basic) { { // Pointless scope to test move assignment. FunctionPassManager NestedFPM; - NestedFPM.addPass(TestFunctionPass(FunctionPassRunCount1, AnalyzedInstrCount1, - AnalyzedFunctionCount1)); + NestedFPM.addPass(TestFunctionPass( + FunctionPassRunCount1, AnalyzedInstrCount1, AnalyzedFunctionCount1)); FPM = std::move(NestedFPM); } NestedMPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); diff --git a/unittests/IR/TypeBuilderTest.cpp b/unittests/IR/TypeBuilderTest.cpp index b7b3e45e35ede415f997ee9f7a1a946f94fbdf64..f2dccac001a4b0dd8bb0d9eb5b85a796dda37c43 100644 --- a/unittests/IR/TypeBuilderTest.cpp +++ b/unittests/IR/TypeBuilderTest.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/TypeBuilder.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/IR/LLVMContext.h" #include "gtest/gtest.h" @@ -17,141 +16,175 @@ using namespace llvm; namespace { TEST(TypeBuilderTest, Void) { - EXPECT_EQ(Type::getVoidTy(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getVoidTy(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); + LLVMContext Context; + EXPECT_EQ(Type::getVoidTy(Context), (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getVoidTy(Context), (TypeBuilder::get(Context))); // Special cases for C compatibility: - EXPECT_EQ(Type::getInt8PtrTy(getGlobalContext()), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt8PtrTy(getGlobalContext()), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt8PtrTy(getGlobalContext()), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt8PtrTy(getGlobalContext()), - (TypeBuilder::get( - getGlobalContext()))); + EXPECT_EQ(Type::getInt8PtrTy(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt8PtrTy(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt8PtrTy(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt8PtrTy(Context), + (TypeBuilder::get(Context))); } TEST(TypeBuilderTest, HostIntegers) { - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt16Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt16Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt64Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt64Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - - EXPECT_EQ(IntegerType::get(getGlobalContext(), sizeof(size_t) * CHAR_BIT), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(IntegerType::get(getGlobalContext(), sizeof(ptrdiff_t) * CHAR_BIT), - (TypeBuilder::get(getGlobalContext()))); + LLVMContext Context; + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt16Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt16Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt32Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt32Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt64Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt64Ty(Context), + (TypeBuilder::get(Context))); + + EXPECT_EQ(IntegerType::get(Context, sizeof(size_t) * CHAR_BIT), + (TypeBuilder::get(Context))); + EXPECT_EQ(IntegerType::get(Context, sizeof(ptrdiff_t) * CHAR_BIT), + (TypeBuilder::get(Context))); } TEST(TypeBuilderTest, CrossCompilableIntegers) { - EXPECT_EQ(IntegerType::get(getGlobalContext(), 1), (TypeBuilder, true>::get(getGlobalContext()))); - EXPECT_EQ(IntegerType::get(getGlobalContext(), 1), (TypeBuilder, false>::get(getGlobalContext()))); - EXPECT_EQ(IntegerType::get(getGlobalContext(), 72), (TypeBuilder, true>::get(getGlobalContext()))); - EXPECT_EQ(IntegerType::get(getGlobalContext(), 72), (TypeBuilder, false>::get(getGlobalContext()))); + LLVMContext Context; + EXPECT_EQ(IntegerType::get(Context, 1), + (TypeBuilder, true>::get(Context))); + EXPECT_EQ(IntegerType::get(Context, 1), + (TypeBuilder, false>::get(Context))); + EXPECT_EQ(IntegerType::get(Context, 72), + (TypeBuilder, true>::get(Context))); + EXPECT_EQ(IntegerType::get(Context, 72), + (TypeBuilder, false>::get(Context))); } TEST(TypeBuilderTest, Float) { - EXPECT_EQ(Type::getFloatTy(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getDoubleTy(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); + LLVMContext Context; + EXPECT_EQ(Type::getFloatTy(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getDoubleTy(Context), + (TypeBuilder::get(Context))); // long double isn't supported yet. - EXPECT_EQ(Type::getFloatTy(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getFloatTy(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getDoubleTy(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getDoubleTy(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getX86_FP80Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getX86_FP80Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getFP128Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getFP128Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getPPC_FP128Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getPPC_FP128Ty(getGlobalContext()), (TypeBuilder::get(getGlobalContext()))); + EXPECT_EQ(Type::getFloatTy(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getFloatTy(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getDoubleTy(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getDoubleTy(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getX86_FP80Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getX86_FP80Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getFP128Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getFP128Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getPPC_FP128Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getPPC_FP128Ty(Context), + (TypeBuilder::get(Context))); } TEST(TypeBuilderTest, Derived) { - EXPECT_EQ(PointerType::getUnqual(Type::getInt8PtrTy(getGlobalContext())), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 7), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 0), - (TypeBuilder::get(getGlobalContext()))); - - EXPECT_EQ(PointerType::getUnqual(Type::getInt8PtrTy(getGlobalContext())), - (TypeBuilder**, false>::get(getGlobalContext()))); - EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 7), - (TypeBuilder[7], false>::get(getGlobalContext()))); - EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 0), - (TypeBuilder[], false>::get(getGlobalContext()))); - - EXPECT_EQ(PointerType::getUnqual(Type::getInt8PtrTy(getGlobalContext())), - (TypeBuilder**, true>::get(getGlobalContext()))); - EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 7), - (TypeBuilder[7], true>::get(getGlobalContext()))); - EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 0), - (TypeBuilder[], true>::get(getGlobalContext()))); - - - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), - (TypeBuilder::get(getGlobalContext()))); - - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), - (TypeBuilder, false>::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), - (TypeBuilder, false>::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), - (TypeBuilder, false>::get(getGlobalContext()))); - - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), - (TypeBuilder, true>::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), - (TypeBuilder, true>::get(getGlobalContext()))); - EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), - (TypeBuilder, true>::get(getGlobalContext()))); - - EXPECT_EQ(Type::getInt8PtrTy(getGlobalContext()), - (TypeBuilder::get(getGlobalContext()))); + LLVMContext Context; + EXPECT_EQ(PointerType::getUnqual(Type::getInt8PtrTy(Context)), + (TypeBuilder::get(Context))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(Context), 7), + (TypeBuilder::get(Context))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(Context), 0), + (TypeBuilder::get(Context))); + + EXPECT_EQ(PointerType::getUnqual(Type::getInt8PtrTy(Context)), + (TypeBuilder **, false>::get(Context))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(Context), 7), + (TypeBuilder[7], false>::get(Context))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(Context), 0), + (TypeBuilder[], false>::get(Context))); + + EXPECT_EQ(PointerType::getUnqual(Type::getInt8PtrTy(Context)), + (TypeBuilder **, true>::get(Context))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(Context), 7), + (TypeBuilder[7], true>::get(Context))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(Context), 0), + (TypeBuilder[], true>::get(Context))); + + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder::get(Context))); + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder::get(Context))); + + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder, false>::get(Context))); + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder, false>::get(Context))); + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder, false>::get(Context))); + + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder, true>::get(Context))); + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder, true>::get(Context))); + EXPECT_EQ(Type::getInt8Ty(Context), + (TypeBuilder, true>::get(Context))); + + EXPECT_EQ(Type::getInt8PtrTy(Context), + (TypeBuilder::get( + Context))); } TEST(TypeBuilderTest, Functions) { + LLVMContext Context; std::vector params; - EXPECT_EQ(FunctionType::get(Type::getVoidTy(getGlobalContext()), params, false), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), - (TypeBuilder::get(getGlobalContext()))); - params.push_back(TypeBuilder::get(getGlobalContext())); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, false), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), - (TypeBuilder::get(getGlobalContext()))); - params.push_back(TypeBuilder::get(getGlobalContext())); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, false), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), - (TypeBuilder::get(getGlobalContext()))); - params.push_back(TypeBuilder::get(getGlobalContext())); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, false), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), - (TypeBuilder::get(getGlobalContext()))); - params.push_back(TypeBuilder::get(getGlobalContext())); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, false), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), - (TypeBuilder::get(getGlobalContext()))); - params.push_back(TypeBuilder::get(getGlobalContext())); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, false), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), - (TypeBuilder::get(getGlobalContext()))); + EXPECT_EQ(FunctionType::get(Type::getVoidTy(Context), params, false), + (TypeBuilder::get(Context))); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(Context), params, true), + (TypeBuilder::get(Context))); + params.push_back(TypeBuilder::get(Context)); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(Context), params, false), + (TypeBuilder::get(Context))); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(Context), params, true), + (TypeBuilder::get(Context))); + params.push_back(TypeBuilder::get(Context)); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(Context), params, false), + (TypeBuilder::get(Context))); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(Context), params, true), + (TypeBuilder::get(Context))); + params.push_back(TypeBuilder::get(Context)); + EXPECT_EQ( + FunctionType::get(Type::getInt8Ty(Context), params, false), + (TypeBuilder::get(Context))); + EXPECT_EQ( + FunctionType::get(Type::getInt8Ty(Context), params, true), + (TypeBuilder::get(Context))); + params.push_back(TypeBuilder::get(Context)); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(Context), params, false), + (TypeBuilder::get( + Context))); + EXPECT_EQ( + FunctionType::get(Type::getInt8Ty(Context), params, true), + (TypeBuilder::get( + Context))); + params.push_back(TypeBuilder::get(Context)); + EXPECT_EQ( + FunctionType::get(Type::getInt8Ty(Context), params, false), + (TypeBuilder::get( + Context))); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(Context), params, true), + (TypeBuilder::get(Context))); } TEST(TypeBuilderTest, Context) { @@ -230,24 +263,24 @@ public: namespace { TEST(TypeBuilderTest, Extensions) { + LLVMContext Context; EXPECT_EQ(PointerType::getUnqual(StructType::get( - TypeBuilder::get(getGlobalContext()), - TypeBuilder::get(getGlobalContext()), - TypeBuilder::get(getGlobalContext()), - (void*)nullptr)), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(PointerType::getUnqual(StructType::get( - TypeBuilder, false>::get(getGlobalContext()), - TypeBuilder*, false>::get(getGlobalContext()), - TypeBuilder*[], false>::get(getGlobalContext()), - (void*)nullptr)), - (TypeBuilder::get(getGlobalContext()))); - EXPECT_EQ(PointerType::getUnqual(StructType::get( - TypeBuilder, false>::get(getGlobalContext()), - TypeBuilder*, false>::get(getGlobalContext()), - TypeBuilder*[], false>::get(getGlobalContext()), - (void*)nullptr)), - (TypeBuilder::get(getGlobalContext()))); + TypeBuilder::get(Context), + TypeBuilder::get(Context), + TypeBuilder::get(Context), (void *)nullptr)), + (TypeBuilder::get(Context))); + EXPECT_EQ( + PointerType::getUnqual(StructType::get( + TypeBuilder, false>::get(Context), + TypeBuilder *, false>::get(Context), + TypeBuilder *[], false>::get(Context), (void *)nullptr)), + (TypeBuilder::get(Context))); + EXPECT_EQ( + PointerType::getUnqual(StructType::get( + TypeBuilder, false>::get(Context), + TypeBuilder *, false>::get(Context), + TypeBuilder *[], false>::get(Context), (void *)nullptr)), + (TypeBuilder::get(Context))); } } // anonymous namespace diff --git a/unittests/IR/UserTest.cpp b/unittests/IR/UserTest.cpp index 8d488389448a1eb6dc059e136927ca315d64c777..7d875aa80d48a45dab631715ba8758c6d26cbcda 100644 --- a/unittests/IR/UserTest.cpp +++ b/unittests/IR/UserTest.cpp @@ -94,9 +94,9 @@ TEST(UserTest, ValueOpIteration) { } TEST(UserTest, PersonalityUser) { - Module M("", getGlobalContext()); - FunctionType *RetVoidTy = - FunctionType::get(Type::getVoidTy(getGlobalContext()), false); + LLVMContext Context; + Module M("", Context); + FunctionType *RetVoidTy = FunctionType::get(Type::getVoidTy(Context), false); Function *PersonalityF = Function::Create( RetVoidTy, GlobalValue::ExternalLinkage, "PersonalityFn", &M); Function *TestF = diff --git a/unittests/IR/ValueHandleTest.cpp b/unittests/IR/ValueHandleTest.cpp index e1d598bbc58b06eabb6930fda3ce8e2c972e052d..59cd9d7ba37aee19213b1ec07a4b7de418f1b6c8 100644 --- a/unittests/IR/ValueHandleTest.cpp +++ b/unittests/IR/ValueHandleTest.cpp @@ -20,13 +20,13 @@ namespace { class ValueHandle : public testing::Test { protected: + LLVMContext Context; Constant *ConstantV; std::unique_ptr BitcastV; - ValueHandle() : - ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)), - BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(getGlobalContext()))) { - } + ValueHandle() + : ConstantV(ConstantInt::get(Type::getInt32Ty(Context), 0)), + BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(Context))) {} }; class ConcreteCallbackVH final : public CallbackVH { @@ -42,8 +42,8 @@ TEST_F(ValueHandle, WeakVH_BasicOperation) { // Make sure I can call a method on the underlying Value. It // doesn't matter which method. - EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), WVH->getType()); - EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (*WVH).getType()); + EXPECT_EQ(Type::getInt32Ty(Context), WVH->getType()); + EXPECT_EQ(Type::getInt32Ty(Context), (*WVH).getType()); } TEST_F(ValueHandle, WeakVH_Comparisons) { @@ -197,8 +197,8 @@ TEST_F(ValueHandle, CallbackVH_BasicOperation) { // Make sure I can call a method on the underlying Value. It // doesn't matter which method. - EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), CVH->getType()); - EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (*CVH).getType()); + EXPECT_EQ(Type::getInt32Ty(Context), CVH->getType()); + EXPECT_EQ(Type::getInt32Ty(Context), (*CVH).getType()); } TEST_F(ValueHandle, CallbackVH_Comparisons) { @@ -297,15 +297,17 @@ TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) { Value *AURWArgument; LLVMContext *Context; - RecoveringVH() : DeletedCalls(0), AURWArgument(nullptr), - Context(&getGlobalContext()) {} - RecoveringVH(Value *V) - : CallbackVH(V), DeletedCalls(0), AURWArgument(nullptr), - Context(&getGlobalContext()) {} + RecoveringVH(LLVMContext &TheContext) + : DeletedCalls(0), AURWArgument(nullptr), Context(&TheContext) {} + + RecoveringVH(LLVMContext &TheContext, Value *V) + : CallbackVH(V), DeletedCalls(0), AURWArgument(nullptr), + Context(&TheContext) {} private: void deleted() override { - getValPtr()->replaceAllUsesWith(Constant::getNullValue(Type::getInt32Ty(getGlobalContext()))); + getValPtr()->replaceAllUsesWith( + Constant::getNullValue(Type::getInt32Ty(*Context))); setValPtr(nullptr); } void allUsesReplacedWith(Value *new_value) override { @@ -318,15 +320,15 @@ TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) { // Normally, if a value has uses, deleting it will crash. However, we can use // a CallbackVH to remove the uses before the check for no uses. - RecoveringVH RVH; - RVH = BitcastV.get(); - std::unique_ptr BitcastUser( - BinaryOperator::CreateAdd(RVH, - Constant::getNullValue(Type::getInt32Ty(getGlobalContext())))); + RecoveringVH RVH(Context); + RVH = RecoveringVH(Context, BitcastV.get()); + std::unique_ptr BitcastUser(BinaryOperator::CreateAdd( + RVH, Constant::getNullValue(Type::getInt32Ty(Context)))); EXPECT_EQ(BitcastV.get(), BitcastUser->getOperand(0)); BitcastV.reset(); // Would crash without the ValueHandler. - EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())), RVH.AURWArgument); - EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())), + EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(Context)), + RVH.AURWArgument); + EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(Context)), BitcastUser->getOperand(0)); } diff --git a/unittests/IR/ValueMapTest.cpp b/unittests/IR/ValueMapTest.cpp index 1431a8d87de4a42c84cfd9dbf7aadd6dad3f3f2a..28633b44b11dd0a49d2b854ba9ac02bc8763f356 100644 --- a/unittests/IR/ValueMapTest.cpp +++ b/unittests/IR/ValueMapTest.cpp @@ -22,15 +22,15 @@ namespace { template class ValueMapTest : public testing::Test { protected: + LLVMContext Context; Constant *ConstantV; std::unique_ptr BitcastV; std::unique_ptr AddV; - ValueMapTest() : - ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)), - BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(getGlobalContext()))), - AddV(BinaryOperator::CreateAdd(ConstantV, ConstantV)) { - } + ValueMapTest() + : ConstantV(ConstantInt::get(Type::getInt32Ty(Context), 0)), + BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(Context))), + AddV(BinaryOperator::CreateAdd(ConstantV, ConstantV)) {} }; // Run everything on Value*, a subtype to make sure that casting works as @@ -292,4 +292,4 @@ TYPED_TEST(ValueMapTest, SurvivesModificationByConfig) { EXPECT_EQ(0u, VM.count(this->AddV.get())); } -} +} // end namespace diff --git a/unittests/IR/ValueTest.cpp b/unittests/IR/ValueTest.cpp index 9cf1306dae67d0480242a0b90e7b0087011dba6c..607b7a1bd2c9b93fc6c4b423be25aa1465c07f8b 100644 --- a/unittests/IR/ValueTest.cpp +++ b/unittests/IR/ValueTest.cpp @@ -45,7 +45,7 @@ TEST(ValueTest, UsedInBasicBlock) { } TEST(GlobalTest, CreateAddressSpace) { - LLVMContext &Ctx = getGlobalContext(); + LLVMContext Ctx; std::unique_ptr M(new Module("TestModule", Ctx)); Type *Int8Ty = Type::getInt8Ty(Ctx); Type *Int32Ty = Type::getInt32Ty(Ctx); @@ -92,7 +92,7 @@ TEST(GlobalTest, CreateAddressSpace) { #ifdef GTEST_HAS_DEATH_TEST #ifndef NDEBUG TEST(GlobalTest, AlignDeath) { - LLVMContext &Ctx = getGlobalContext(); + LLVMContext Ctx; std::unique_ptr M(new Module("TestModule", Ctx)); Type *Int32Ty = Type::getInt32Ty(Ctx); GlobalVariable *Var = diff --git a/unittests/IR/VerifierTest.cpp b/unittests/IR/VerifierTest.cpp index 1acedf38fc8fdb6123c6d19731037fdeeb8b6a57..c33c92a6f7c58d21df12500841696278fcbcdcda 100644 --- a/unittests/IR/VerifierTest.cpp +++ b/unittests/IR/VerifierTest.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/Verifier.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DerivedTypes.h" @@ -16,14 +15,16 @@ #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "gtest/gtest.h" namespace llvm { namespace { TEST(VerifierTest, Branch_i1) { - LLVMContext &C = getGlobalContext(); + LLVMContext C; Module M("M", C); FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false); Function *F = cast(M.getOrInsertFunction("foo", FTy)); @@ -46,7 +47,7 @@ TEST(VerifierTest, Branch_i1) { } TEST(VerifierTest, InvalidRetAttribute) { - LLVMContext &C = getGlobalContext(); + LLVMContext C; Module M("M", C); FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false); Function *F = cast(M.getOrInsertFunction("foo", FTy)); @@ -62,7 +63,7 @@ TEST(VerifierTest, InvalidRetAttribute) { } TEST(VerifierTest, CrossModuleRef) { - LLVMContext &C = getGlobalContext(); + LLVMContext C; Module M1("M1", C); Module M2("M2", C); Module M3("M3", C); @@ -121,7 +122,7 @@ TEST(VerifierTest, CrossModuleRef) { } TEST(VerifierTest, CrossModuleMetadataRef) { - LLVMContext &C = getGlobalContext(); + LLVMContext C; Module M1("M1", C); Module M2("M2", C); GlobalVariable *newGV = @@ -144,5 +145,80 @@ TEST(VerifierTest, CrossModuleMetadataRef) { EXPECT_TRUE(StringRef(ErrorOS.str()) .startswith("Referencing global in another module!")); } + +TEST(VerifierTest, InvalidVariableLinkage) { + LLVMContext C; + Module M("M", C); + new GlobalVariable(M, Type::getInt8Ty(C), false, + GlobalValue::LinkOnceODRLinkage, nullptr, "Some Global"); + std::string Error; + raw_string_ostream ErrorOS(Error); + EXPECT_TRUE(verifyModule(M, &ErrorOS)); + EXPECT_TRUE( + StringRef(ErrorOS.str()).startswith("Global is external, but doesn't " + "have external or weak linkage!")); +} + +TEST(VerifierTest, InvalidFunctionLinkage) { + LLVMContext C; + Module M("M", C); + + FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false); + Function::Create(FTy, GlobalValue::LinkOnceODRLinkage, "foo", &M); + std::string Error; + raw_string_ostream ErrorOS(Error); + EXPECT_TRUE(verifyModule(M, &ErrorOS)); + EXPECT_TRUE( + StringRef(ErrorOS.str()).startswith("Global is external, but doesn't " + "have external or weak linkage!")); +} + +#ifndef _MSC_VER +// FIXME: This test causes an ICE in MSVC 2013. +TEST(VerifierTest, StripInvalidDebugInfo) { + LLVMContext C; + Module M("M", C); + DIBuilder DIB(M); + DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/", + "unittest", false, "", 0); + DIB.finalize(); + EXPECT_FALSE(verifyModule(M)); + + // Now break it. + auto *File = DIB.createFile("not-a-CU.f", "."); + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu"); + NMD->addOperand(File); + EXPECT_TRUE(verifyModule(M)); + + ModulePassManager MPM(true); + MPM.addPass(VerifierPass(false)); + ModuleAnalysisManager MAM(true); + MAM.registerPass([&] { return VerifierAnalysis(); }); + MPM.run(M, MAM); + EXPECT_FALSE(verifyModule(M)); +} +#endif + +TEST(VerifierTest, StripInvalidDebugInfoLegacy) { + LLVMContext C; + Module M("M", C); + DIBuilder DIB(M); + DIB.createCompileUnit(dwarf::DW_LANG_C89, "broken.c", "/", + "unittest", false, "", 0); + DIB.finalize(); + EXPECT_FALSE(verifyModule(M)); + + // Now break it. + auto *File = DIB.createFile("not-a-CU.f", "."); + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu"); + NMD->addOperand(File); + EXPECT_TRUE(verifyModule(M)); + + legacy::PassManager Passes; + Passes.add(createVerifierPass(false)); + Passes.run(M); + EXPECT_FALSE(verifyModule(M)); +} + } // end anonymous namespace } // end namespace llvm diff --git a/unittests/IR/WaymarkTest.cpp b/unittests/IR/WaymarkTest.cpp index a8924efed3f5fc72e0595deab247fc6d4359c5a6..4d2671c06c1d9ffa4d6a96cfe2927c82f9d1ac7e 100644 --- a/unittests/IR/WaymarkTest.cpp +++ b/unittests/IR/WaymarkTest.cpp @@ -19,16 +19,14 @@ namespace llvm { namespace { -Constant *char2constant(char c) { - return ConstantInt::get(Type::getInt8Ty(getGlobalContext()), c); -} - - TEST(WaymarkTest, NativeArray) { + LLVMContext Context; static uint8_t tail[22] = "s02s33s30y2y0s1x0syxS"; Value * values[22]; - std::transform(tail, tail + 22, values, char2constant); - FunctionType *FT = FunctionType::get(Type::getVoidTy(getGlobalContext()), true); + std::transform(tail, tail + 22, values, [&](char c) { + return ConstantInt::get(Type::getInt8Ty(Context), c); + }); + FunctionType *FT = FunctionType::get(Type::getVoidTy(Context), true); std::unique_ptr F( Function::Create(FT, GlobalValue::ExternalLinkage)); const CallInst *A = CallInst::Create(F.get(), makeArrayRef(values)); diff --git a/unittests/Linker/LinkModulesTest.cpp b/unittests/Linker/LinkModulesTest.cpp index 10a89f39869af21f6619b5d24f8fdcabd6fd5613..92c483278be9d88dd14a2695f333aa10eaff05a3 100644 --- a/unittests/Linker/LinkModulesTest.cpp +++ b/unittests/Linker/LinkModulesTest.cpp @@ -306,4 +306,58 @@ TEST_F(LinkModuleTest, MoveDistinctMDs) { EXPECT_EQ(M3, M4->getOperand(0)); } +TEST_F(LinkModuleTest, RemangleIntrinsics) { + LLVMContext C; + SMDiagnostic Err; + + // We load two modules inside the same context C. In both modules there is a + // "struct.rtx_def" type. In the module loaded the second (Bar) this type will + // be renamed to "struct.rtx_def.0". Check that the intrinsics which have this + // type in the signature are properly remangled. + const char *FooStr = + "%struct.rtx_def = type { i16 }\n" + "define void @foo(%struct.rtx_def* %a, i8 %b, i32 %c) {\n" + " call void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def* %a, i8 %b, i32 %c, i32 4, i1 true)\n" + " ret void\n" + "}\n" + "declare void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def*, i8, i32, i32, i1)\n"; + + const char *BarStr = + "%struct.rtx_def = type { i16 }\n" + "define void @bar(%struct.rtx_def* %a, i8 %b, i32 %c) {\n" + " call void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def* %a, i8 %b, i32 %c, i32 4, i1 true)\n" + " ret void\n" + "}\n" + "declare void @llvm.memset.p0struct.rtx_def.i32(%struct.rtx_def*, i8, i32, i32, i1)\n"; + + std::unique_ptr Foo = parseAssemblyString(FooStr, Err, C); + assert(Foo); + ASSERT_TRUE(Foo.get()); + // Foo is loaded first, so the type and the intrinsic have theis original + // names. + ASSERT_TRUE(Foo->getFunction("llvm.memset.p0struct.rtx_def.i32")); + ASSERT_FALSE(Foo->getFunction("llvm.memset.p0struct.rtx_def.0.i32")); + + std::unique_ptr Bar = parseAssemblyString(BarStr, Err, C); + assert(Bar); + ASSERT_TRUE(Bar.get()); + // Bar is loaded after Foo, so the type is renamed to struct.rtx_def.0. Check + // that the intrinsic is also renamed. + ASSERT_FALSE(Bar->getFunction("llvm.memset.p0struct.rtx_def.i32")); + ASSERT_TRUE(Bar->getFunction("llvm.memset.p0struct.rtx_def.0.i32")); + + // Link two modules together. + auto Dst = llvm::make_unique("Linked", C); + ASSERT_TRUE(Dst.get()); + Ctx.setDiagnosticHandler(expectNoDiags); + bool Failed = Linker::linkModules(*Foo, std::move(Bar)); + ASSERT_FALSE(Failed); + + // "struct.rtx_def" from Foo and "struct.rtx_def.0" from Bar are isomorphic + // types, so they must be uniquified by linker. Check that they use the same + // intrinsic definition. + Function *F = Foo->getFunction("llvm.memset.p0struct.rtx_def.i32"); + ASSERT_EQ(F->getNumUses(), (unsigned)2); +} + } // end anonymous namespace diff --git a/unittests/MI/CMakeLists.txt b/unittests/MI/CMakeLists.txt index e8a794515d89dda59f67f758a9f945f556321737..595497f3d96034ec2c917f1d8efb0897e468e135 100644 --- a/unittests/MI/CMakeLists.txt +++ b/unittests/MI/CMakeLists.txt @@ -1,5 +1,11 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + CodeGen + Core + MC + MIRParser Support + Target ) add_llvm_unittest(MITests diff --git a/unittests/MI/LiveIntervalTest.cpp b/unittests/MI/LiveIntervalTest.cpp index 534bd0d686a5808e9e7511ef061b9eb043cc6baf..e0b3d5529afbfcccee2a2d6fb74550df9f903e41 100644 --- a/unittests/MI/LiveIntervalTest.cpp +++ b/unittests/MI/LiveIntervalTest.cpp @@ -1,6 +1,360 @@ #include "gtest/gtest.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MIRParser/MIRParser.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/IR/LegacyPassManager.h" -// FIXME: It may be removed when practical tests came. -TEST(LiveIntervalTest, DummyStub) { - EXPECT_TRUE(true); +using namespace llvm; + +namespace llvm { + void initializeTestPassPass(PassRegistry &); +} + +namespace { + +void initLLVM() { + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + + PassRegistry *Registry = PassRegistry::getPassRegistry(); + initializeCore(*Registry); + initializeCodeGen(*Registry); +} + +/// Create a TargetMachine. As we lack a dedicated always available target for +/// unittests, we go for "x86_64" which should be available in most builds. +std::unique_ptr createTargetMachine() { + Triple TargetTriple("x86_64--"); + std::string Error; + const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); + if (!T) + return nullptr; + + TargetOptions Options; + return std::unique_ptr( + T->createTargetMachine("x86_64", "", "", Options, None, + CodeModel::Default, CodeGenOpt::Aggressive)); +} + +std::unique_ptr parseMIR(LLVMContext &Context, + legacy::PassManagerBase &PM, std::unique_ptr &MIR, + const TargetMachine &TM, StringRef MIRCode, const char *FuncName) { + SMDiagnostic Diagnostic; + std::unique_ptr MBuffer = MemoryBuffer::getMemBuffer(MIRCode); + MIR = createMIRParser(std::move(MBuffer), Context); + if (!MIR) + return nullptr; + + std::unique_ptr M = MIR->parseLLVMModule(); + if (!M) + return nullptr; + + M->setDataLayout(TM.createDataLayout()); + + Function *F = M->getFunction(FuncName); + if (!F) + return nullptr; + + const LLVMTargetMachine &LLVMTM = static_cast(TM); + LLVMTM.addMachineModuleInfo(PM); + LLVMTM.addMachineFunctionAnalysis(PM, MIR.get()); + + return M; +} + +typedef std::function LiveIntervalTest; + +struct TestPass : public MachineFunctionPass { + static char ID; + TestPass() : MachineFunctionPass(ID) { + // We should never call this but always use PM.add(new TestPass(...)) + abort(); + } + TestPass(LiveIntervalTest T) : MachineFunctionPass(ID), T(T) { + initializeTestPassPass(*PassRegistry::getPassRegistry()); + } + + bool runOnMachineFunction(MachineFunction &MF) override { + LiveIntervals &LIS = getAnalysis(); + T(MF, LIS); + EXPECT_TRUE(MF.verify(this)); + return true; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + AU.addRequired(); + AU.addPreserved(); + MachineFunctionPass::getAnalysisUsage(AU); + } +private: + LiveIntervalTest T; +}; + +/** + * Move instruction number \p From in front of instruction number \p To and + * update affected liveness intervals with LiveIntervalAnalysis::handleMove(). + */ +static void testHandleMove(MachineFunction &MF, LiveIntervals &LIS, + unsigned From, unsigned To, unsigned BlockNum = 0) { + MachineBasicBlock &MBB = *MF.getBlockNumbered(BlockNum); + + unsigned I = 0; + MachineInstr *FromInstr = nullptr; + MachineInstr *ToInstr = nullptr; + for (MachineInstr &MI : MBB) { + if (I == From) + FromInstr = &MI; + if (I == To) + ToInstr = &MI; + ++I; + } + assert(FromInstr != nullptr && ToInstr != nullptr); + + MBB.splice(ToInstr->getIterator(), &MBB, FromInstr->getIterator()); + LIS.handleMove(*FromInstr, true); +} + +static void liveIntervalTest(StringRef MIRFunc, LiveIntervalTest T) { + LLVMContext Context; + std::unique_ptr TM = createTargetMachine(); + // This test is designed for the X86 backend; stop if it is not available. + if (!TM) + return; + + legacy::PassManager PM; + + SmallString<160> S; + StringRef MIRString = (Twine( +"---\n" +"...\n" +"name: func\n" +"registers:\n" +" - { id: 0, class: gr64 }\n" +"body: |\n" +" bb.0:\n" + ) + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(S); + std::unique_ptr MIR; + std::unique_ptr M = parseMIR(Context, PM, MIR, *TM, MIRString, + "func"); + + PM.add(new TestPass(T)); + + PM.run(*M); +} + +} // End of anonymous namespace. + +char TestPass::ID = 0; +INITIALIZE_PASS(TestPass, "testpass", "testpass", false, false) + +TEST(LiveIntervalTest, MoveUpDef) { + // Value defined. + liveIntervalTest( +" NOOP\n" +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpRedef) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpEarlyDef) { + liveIntervalTest( +" NOOP\n" +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpEarlyRedef) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpKill) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpKillFollowing) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit %0\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +// TODO: Construct a situation where we have intervals following a hole +// while still having connected components. + +TEST(LiveIntervalTest, MoveDownDef) { + // Value defined. + liveIntervalTest( +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownRedef) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownEarlyDef) { + liveIntervalTest( +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownEarlyRedef) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownKill) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP implicit %0\n" +" NOOP\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownKillFollowing) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit %0\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveUndefUse) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP implicit undef %0\n" +" NOOP implicit %0\n" +" NOOP\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 3); + }); +} + +TEST(LiveIntervalTest, MoveUpValNos) { + // handleMoveUp() had a bug where it would reuse the value number of the + // destination segment, even though we have no guarntee that this valno wasn't + // used in other segments. + liveIntervalTest( +" successors: %bb.1, %bb.2\n" +" %0 = IMPLICIT_DEF\n" +" JG_1 %bb.2, implicit %eflags\n" +" JMP_1 %bb.1\n" +" bb.2:\n" +" NOOP implicit %0\n" +" bb.1:\n" +" successors: %bb.2\n" +" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" JMP_1 %bb.2\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 0, 2); + }); +} + +TEST(LiveIntervalTest, MoveOverUndefUse0) { + // findLastUseBefore() used by handleMoveUp() must ignore undef operands. + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit undef %0\n" +" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 3, 1); + }); +} + +TEST(LiveIntervalTest, MoveOverUndefUse1) { + // findLastUseBefore() used by handleMoveUp() must ignore undef operands. + liveIntervalTest( +" %rax = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit undef %rax\n" +" %rax = IMPLICIT_DEF implicit %rax(tied-def 0)\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 3, 1); + }); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + initLLVM(); + return RUN_ALL_TESTS(); } diff --git a/unittests/Option/OptionParsingTest.cpp b/unittests/Option/OptionParsingTest.cpp index 5270dc940f9624618d244e79763dcf2ce8026020..b0418a71c78665b6d6d77fa1a5ec0e5950751d31 100644 --- a/unittests/Option/OptionParsingTest.cpp +++ b/unittests/Option/OptionParsingTest.cpp @@ -79,32 +79,32 @@ TEST(Option, OptionParsing) { EXPECT_TRUE(AL.hasArg(OPT_G)); // Check the values. - EXPECT_EQ(AL.getLastArgValue(OPT_B), "hi"); - EXPECT_EQ(AL.getLastArgValue(OPT_C), "bye"); - EXPECT_EQ(AL.getLastArgValue(OPT_D), "adena"); + EXPECT_EQ("hi", AL.getLastArgValue(OPT_B)); + EXPECT_EQ("bye", AL.getLastArgValue(OPT_C)); + EXPECT_EQ("adena", AL.getLastArgValue(OPT_D)); std::vector Es = AL.getAllArgValues(OPT_E); - EXPECT_EQ(Es[0], "apple"); - EXPECT_EQ(Es[1], "bloom"); - EXPECT_EQ(AL.getLastArgValue(OPT_F), "42"); + EXPECT_EQ("apple", Es[0]); + EXPECT_EQ("bloom", Es[1]); + EXPECT_EQ("42", AL.getLastArgValue(OPT_F)); std::vector Gs = AL.getAllArgValues(OPT_G); - EXPECT_EQ(Gs[0], "chuu"); - EXPECT_EQ(Gs[1], "2"); + EXPECT_EQ("chuu", Gs[0]); + EXPECT_EQ("2", Gs[1]); // Check the help text. std::string Help; raw_string_ostream RSO(Help); T.PrintHelp(RSO, "test", "title!"); - EXPECT_NE(Help.find("-A"), std::string::npos); + EXPECT_NE(std::string::npos, Help.find("-A")); // Test aliases. arg_iterator Cs = AL.filtered_begin(OPT_C); - ASSERT_NE(Cs, AL.filtered_end()); - EXPECT_EQ(StringRef((*Cs)->getValue()), "desu"); + ASSERT_NE(AL.filtered_end(), Cs); + EXPECT_EQ("desu", StringRef((*Cs)->getValue())); ArgStringList ASL; (*Cs)->render(AL, ASL); - ASSERT_EQ(ASL.size(), 2u); - EXPECT_EQ(StringRef(ASL[0]), "-C"); - EXPECT_EQ(StringRef(ASL[1]), "desu"); + ASSERT_EQ(2u, ASL.size()); + EXPECT_EQ("-C", StringRef(ASL[0])); + EXPECT_EQ("desu", StringRef(ASL[1])); } TEST(Option, ParseWithFlagExclusions) { @@ -131,8 +131,8 @@ TEST(Option, ParseWithFlagExclusions) { AL = T.ParseArgs(NewArgs, MAI, MAC); EXPECT_TRUE(AL.hasArg(OPT_SLASH_C)); EXPECT_TRUE(AL.hasArg(OPT_C)); - EXPECT_EQ(AL.getLastArgValue(OPT_SLASH_C), "foo"); - EXPECT_EQ(AL.getLastArgValue(OPT_C), "bar"); + EXPECT_EQ("foo", AL.getLastArgValue(OPT_SLASH_C)); + EXPECT_EQ("bar", AL.getLastArgValue(OPT_C)); } TEST(Option, ParseAliasInGroup) { @@ -151,8 +151,8 @@ TEST(Option, AliasArgs) { const char *MyArgs[] = { "-J", "-Joo" }; InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); EXPECT_TRUE(AL.hasArg(OPT_B)); - EXPECT_EQ(AL.getAllArgValues(OPT_B)[0], "foo"); - EXPECT_EQ(AL.getAllArgValues(OPT_B)[1], "bar"); + EXPECT_EQ("foo", AL.getAllArgValues(OPT_B)[0]); + EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]); } TEST(Option, IgnoreCase) { @@ -183,7 +183,7 @@ TEST(Option, SlurpEmpty) { InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); EXPECT_TRUE(AL.hasArg(OPT_A)); EXPECT_TRUE(AL.hasArg(OPT_Slurp)); - EXPECT_EQ(AL.getAllArgValues(OPT_Slurp).size(), 0U); + EXPECT_EQ(0U, AL.getAllArgValues(OPT_Slurp).size()); } TEST(Option, Slurp) { @@ -196,10 +196,61 @@ TEST(Option, Slurp) { EXPECT_TRUE(AL.hasArg(OPT_A)); EXPECT_FALSE(AL.hasArg(OPT_B)); EXPECT_TRUE(AL.hasArg(OPT_Slurp)); - EXPECT_EQ(AL.getAllArgValues(OPT_Slurp).size(), 3U); - EXPECT_EQ(AL.getAllArgValues(OPT_Slurp)[0], "-B"); - EXPECT_EQ(AL.getAllArgValues(OPT_Slurp)[1], "--"); - EXPECT_EQ(AL.getAllArgValues(OPT_Slurp)[2], "foo"); + EXPECT_EQ(3U, AL.getAllArgValues(OPT_Slurp).size()); + EXPECT_EQ("-B", AL.getAllArgValues(OPT_Slurp)[0]); + EXPECT_EQ("--", AL.getAllArgValues(OPT_Slurp)[1]); + EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]); +} + +TEST(Option, SlurpJoinedEmpty) { + TestOptTable T; + unsigned MAI, MAC; + + const char *MyArgs[] = { "-A", "-slurpjoined" }; + InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); + EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 0U); +} + +TEST(Option, SlurpJoinedOneJoined) { + TestOptTable T; + unsigned MAI, MAC; + + const char *MyArgs[] = { "-A", "-slurpjoinedfoo" }; + InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); + EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 1U); + EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined)[0], "foo"); +} + +TEST(Option, SlurpJoinedAndSeparate) { + TestOptTable T; + unsigned MAI, MAC; + + const char *MyArgs[] = { "-A", "-slurpjoinedfoo", "bar", "baz" }; + InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); + EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size()); + EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]); + EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]); + EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]); +} + +TEST(Option, SlurpJoinedButSeparate) { + TestOptTable T; + unsigned MAI, MAC; + + const char *MyArgs[] = { "-A", "-slurpjoined", "foo", "bar", "baz" }; + InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); + EXPECT_TRUE(AL.hasArg(OPT_A)); + EXPECT_TRUE(AL.hasArg(OPT_SlurpJoined)); + EXPECT_EQ(3U, AL.getAllArgValues(OPT_SlurpJoined).size()); + EXPECT_EQ("foo", AL.getAllArgValues(OPT_SlurpJoined)[0]); + EXPECT_EQ("bar", AL.getAllArgValues(OPT_SlurpJoined)[1]); + EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]); } TEST(Option, FlagAliasToJoined) { @@ -211,6 +262,6 @@ TEST(Option, FlagAliasToJoined) { InputArgList AL = T.ParseArgs(MyArgs, MAI, MAC); EXPECT_EQ(AL.size(), 1U); EXPECT_TRUE(AL.hasArg(OPT_B)); - EXPECT_EQ(AL.getAllArgValues(OPT_B).size(), 1U); - EXPECT_EQ(AL.getAllArgValues(OPT_B)[0], ""); + EXPECT_EQ(1U, AL.getAllArgValues(OPT_B).size()); + EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]); } diff --git a/unittests/Option/Opts.td b/unittests/Option/Opts.td index c96774a68e0b04bfdfce498e1b98d746067c7097..25c98c6f6015e99f8ea672c9db19140e967fc824 100644 --- a/unittests/Option/Opts.td +++ b/unittests/Option/Opts.td @@ -26,3 +26,5 @@ def Joo : Flag<["-"], "Joo">, Alias, AliasArgs<["bar"]>; def K : Flag<["-"], "K">, Alias; def Slurp : Option<["-"], "slurp", KIND_REMAINING_ARGS>; + +def SlurpJoined : Option<["-"], "slurpjoined", KIND_REMAINING_ARGS_JOINED>; diff --git a/unittests/ProfileData/CMakeLists.txt b/unittests/ProfileData/CMakeLists.txt index 011f8c581792b7fdc41bbb6eb0761870e576e758..dd39ca7da3ad65b02d489c2b7d19afc94d9de286 100644 --- a/unittests/ProfileData/CMakeLists.txt +++ b/unittests/ProfileData/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS Core + Coverage ProfileData Support ) diff --git a/unittests/ProfileData/CoverageMappingTest.cpp b/unittests/ProfileData/CoverageMappingTest.cpp index e1f0647e76e9d29add878d5d9c0db1c7aff8f4c5..53b40ebae85ad902b2a2cd613097636164a8c048 100644 --- a/unittests/ProfileData/CoverageMappingTest.cpp +++ b/unittests/ProfileData/CoverageMappingTest.cpp @@ -7,24 +7,24 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ProfileData/CoverageMapping.h" -#include "llvm/ProfileData/CoverageMappingReader.h" -#include "llvm/ProfileData/CoverageMappingWriter.h" +#include "llvm/ProfileData/Coverage/CoverageMapping.h" +#include "llvm/ProfileData/Coverage/CoverageMappingReader.h" +#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/ProfileData/InstrProfWriter.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" -#include +#include using namespace llvm; using namespace coverage; -static ::testing::AssertionResult NoError(std::error_code EC) { - if (!EC) +static ::testing::AssertionResult NoError(Error E) { + if (!E) return ::testing::AssertionSuccess(); - return ::testing::AssertionFailure() << "error " << EC.value() - << ": " << EC.message(); + return ::testing::AssertionFailure() << "error: " << toString(std::move(E)) + << "\n"; } namespace llvm { @@ -49,41 +49,58 @@ void PrintTo(const CoverageSegment &S, ::std::ostream *os) { namespace { -struct OneFunctionCoverageReader : CoverageMappingReader { +struct OutputFunctionCoverageData { StringRef Name; uint64_t Hash; std::vector Filenames; - ArrayRef Regions; - bool Done; - - OneFunctionCoverageReader(StringRef Name, uint64_t Hash, - ArrayRef Filenames, - ArrayRef Regions) - : Name(Name), Hash(Hash), Filenames(Filenames), Regions(Regions), - Done(false) {} - - std::error_code readNextRecord(CoverageMappingRecord &Record) override { - if (Done) - return instrprof_error::eof; - Done = true; + std::vector Regions; + void fillCoverageMappingRecord(CoverageMappingRecord &Record) const { Record.FunctionName = Name; Record.FunctionHash = Hash; Record.Filenames = Filenames; Record.Expressions = {}; Record.MappingRegions = Regions; - return instrprof_error::success; } }; +struct CoverageMappingReaderMock : CoverageMappingReader { + ArrayRef Functions; + + CoverageMappingReaderMock(ArrayRef Functions) + : Functions(Functions) {} + + Error readNextRecord(CoverageMappingRecord &Record) override { + if (Functions.empty()) + return make_error(coveragemap_error::eof); + + Functions.front().fillCoverageMappingRecord(Record); + Functions = Functions.slice(1); + + return Error::success(); + } +}; + +struct InputFunctionCoverageData { + // Maps the global file index from CoverageMappingTest.Files + // to the index of that file within this function. We can't just use + // global file indexes here because local indexes have to be dense. + // This map is used during serialization to create the virtual file mapping + // (from local fileId to global Index) in the head of the per-function + // coverage mapping data. + SmallDenseMap ReverseVirtualFileMapping; + std::string Name; + uint64_t Hash; + std::vector Regions; + + InputFunctionCoverageData(std::string Name, uint64_t Hash) + : Name(std::move(Name)), Hash(Hash) {} +}; + struct CoverageMappingTest : ::testing::Test { StringMap Files; - unsigned NextFile; - std::vector InputCMRs; - - std::vector OutputFiles; - std::vector OutputExpressions; - std::vector OutputCMRs; + std::vector InputFunctions; + std::vector OutputFunctions; InstrProfWriter ProfileWriter; std::unique_ptr ProfileReader; @@ -91,68 +108,99 @@ struct CoverageMappingTest : ::testing::Test { std::unique_ptr LoadedCoverage; void SetUp() override { - NextFile = 0; ProfileWriter.setOutputSparse(false); } - unsigned getFile(StringRef Name) { + unsigned getGlobalFileIndex(StringRef Name) { auto R = Files.find(Name); if (R != Files.end()) return R->second; - Files[Name] = NextFile; - return NextFile++; + unsigned Index = Files.size(); + Files.emplace_second(Name, Index); + return Index; + } + + // Return the file index of file 'Name' for the current function. + // Add the file into the global map if necesary. + // See also InputFunctionCoverageData::ReverseVirtualFileMapping + // for additional comments. + unsigned getFileIndexForFunction(StringRef Name) { + unsigned GlobalIndex = getGlobalFileIndex(Name); + auto &CurrentFunctionFileMapping = + InputFunctions.back().ReverseVirtualFileMapping; + auto R = CurrentFunctionFileMapping.find(GlobalIndex); + if (R != CurrentFunctionFileMapping.end()) + return R->second; + unsigned IndexInFunction = CurrentFunctionFileMapping.size(); + CurrentFunctionFileMapping.insert( + std::make_pair(GlobalIndex, IndexInFunction)); + return IndexInFunction; + } + + void startFunction(StringRef FuncName, uint64_t Hash) { + InputFunctions.emplace_back(FuncName.str(), Hash); } void addCMR(Counter C, StringRef File, unsigned LS, unsigned CS, unsigned LE, unsigned CE) { - InputCMRs.push_back( - CounterMappingRegion::makeRegion(C, getFile(File), LS, CS, LE, CE)); + InputFunctions.back().Regions.push_back(CounterMappingRegion::makeRegion( + C, getFileIndexForFunction(File), LS, CS, LE, CE)); } void addExpansionCMR(StringRef File, StringRef ExpandedFile, unsigned LS, unsigned CS, unsigned LE, unsigned CE) { - InputCMRs.push_back(CounterMappingRegion::makeExpansion( - getFile(File), getFile(ExpandedFile), LS, CS, LE, CE)); + InputFunctions.back().Regions.push_back(CounterMappingRegion::makeExpansion( + getFileIndexForFunction(File), getFileIndexForFunction(ExpandedFile), + LS, CS, LE, CE)); } - std::string writeCoverageRegions() { - SmallVector FileIDs; - for (const auto &E : Files) - FileIDs.push_back(E.getValue()); + std::string writeCoverageRegions(InputFunctionCoverageData &Data) { + SmallVector FileIDs(Data.ReverseVirtualFileMapping.size()); + for (const auto &E : Data.ReverseVirtualFileMapping) + FileIDs[E.second] = E.first; std::string Coverage; llvm::raw_string_ostream OS(Coverage); - CoverageMappingWriter(FileIDs, None, InputCMRs).write(OS); + CoverageMappingWriter(FileIDs, None, Data.Regions).write(OS); return OS.str(); } - void readCoverageRegions(std::string Coverage) { - SmallVector Filenames; + void readCoverageRegions(std::string Coverage, + OutputFunctionCoverageData &Data) { + SmallVector Filenames(Files.size()); for (const auto &E : Files) - Filenames.push_back(E.getKey()); - RawCoverageMappingReader Reader(Coverage, Filenames, OutputFiles, - OutputExpressions, OutputCMRs); + Filenames[E.getValue()] = E.getKey(); + std::vector Expressions; + RawCoverageMappingReader Reader(Coverage, Filenames, Data.Filenames, + Expressions, Data.Regions); ASSERT_TRUE(NoError(Reader.read())); } + void writeAndReadCoverageRegions(bool EmitFilenames = true) { + OutputFunctions.resize(InputFunctions.size()); + for (unsigned I = 0; I < InputFunctions.size(); ++I) { + std::string Regions = writeCoverageRegions(InputFunctions[I]); + readCoverageRegions(Regions, OutputFunctions[I]); + OutputFunctions[I].Name = InputFunctions[I].Name; + OutputFunctions[I].Hash = InputFunctions[I].Hash; + if (!EmitFilenames) + OutputFunctions[I].Filenames.clear(); + } + } + void readProfCounts() { auto Profile = ProfileWriter.writeBuffer(); auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile)); - ASSERT_TRUE(NoError(ReaderOrErr.getError())); + ASSERT_TRUE(NoError(ReaderOrErr.takeError())); ProfileReader = std::move(ReaderOrErr.get()); } - void loadCoverageMapping(StringRef FuncName, uint64_t Hash, - bool EmitFilenames = true) { - std::string Regions = writeCoverageRegions(); - readCoverageRegions(Regions); + void loadCoverageMapping(bool EmitFilenames = true) { + readProfCounts(); + writeAndReadCoverageRegions(EmitFilenames); - SmallVector Filenames; - if (EmitFilenames) - for (const auto &E : Files) - Filenames.push_back(E.getKey()); - OneFunctionCoverageReader CovReader(FuncName, Hash, Filenames, OutputCMRs); + CoverageMappingReaderMock CovReader(OutputFunctions); auto CoverageOrErr = CoverageMapping::load(CovReader, *ProfileReader); - ASSERT_TRUE(NoError(CoverageOrErr.getError())); + ASSERT_TRUE(NoError(CoverageOrErr.takeError())); LoadedCoverage = std::move(CoverageOrErr.get()); } }; @@ -167,48 +215,135 @@ struct MaybeSparseCoverageMappingTest }; TEST_P(MaybeSparseCoverageMappingTest, basic_write_read) { + startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "foo", 1, 1, 1, 1); addCMR(Counter::getCounter(1), "foo", 2, 1, 2, 2); addCMR(Counter::getZero(), "foo", 3, 1, 3, 4); addCMR(Counter::getCounter(2), "foo", 4, 1, 4, 8); addCMR(Counter::getCounter(3), "bar", 1, 2, 3, 4); - std::string Coverage = writeCoverageRegions(); - readCoverageRegions(Coverage); - size_t N = makeArrayRef(InputCMRs).size(); - ASSERT_EQ(N, OutputCMRs.size()); + writeAndReadCoverageRegions(); + ASSERT_EQ(1u, InputFunctions.size()); + ASSERT_EQ(1u, OutputFunctions.size()); + InputFunctionCoverageData &Input = InputFunctions.back(); + OutputFunctionCoverageData &Output = OutputFunctions.back(); + + size_t N = makeArrayRef(Input.Regions).size(); + ASSERT_EQ(N, Output.Regions.size()); for (size_t I = 0; I < N; ++I) { - ASSERT_EQ(InputCMRs[I].Count, OutputCMRs[I].Count); - ASSERT_EQ(InputCMRs[I].FileID, OutputCMRs[I].FileID); - ASSERT_EQ(InputCMRs[I].startLoc(), OutputCMRs[I].startLoc()); - ASSERT_EQ(InputCMRs[I].endLoc(), OutputCMRs[I].endLoc()); - ASSERT_EQ(InputCMRs[I].Kind, OutputCMRs[I].Kind); + ASSERT_EQ(Input.Regions[I].Count, Output.Regions[I].Count); + ASSERT_EQ(Input.Regions[I].FileID, Output.Regions[I].FileID); + ASSERT_EQ(Input.Regions[I].startLoc(), Output.Regions[I].startLoc()); + ASSERT_EQ(Input.Regions[I].endLoc(), Output.Regions[I].endLoc()); + ASSERT_EQ(Input.Regions[I].Kind, Output.Regions[I].Kind); + } +} + +TEST_P(MaybeSparseCoverageMappingTest, + correct_deserialize_for_more_than_two_files) { + const char *FileNames[] = {"bar", "baz", "foo"}; + static const unsigned N = array_lengthof(FileNames); + + startFunction("func", 0x1234); + for (unsigned I = 0; I < N; ++I) + // Use LineStart to hold the index of the file name + // in order to preserve that information during possible sorting of CMRs. + addCMR(Counter::getCounter(0), FileNames[I], I, 1, I, 1); + + writeAndReadCoverageRegions(); + ASSERT_EQ(1u, OutputFunctions.size()); + OutputFunctionCoverageData &Output = OutputFunctions.back(); + + ASSERT_EQ(N, Output.Regions.size()); + ASSERT_EQ(N, Output.Filenames.size()); + + for (unsigned I = 0; I < N; ++I) { + ASSERT_GT(N, Output.Regions[I].FileID); + ASSERT_GT(N, Output.Regions[I].LineStart); + EXPECT_EQ(FileNames[Output.Regions[I].LineStart], + Output.Filenames[Output.Regions[I].FileID]); + } +} + +TEST_P(MaybeSparseCoverageMappingTest, load_coverage_for_more_than_two_files) { + InstrProfRecord Record("func", 0x1234, {0}); + NoError(ProfileWriter.addRecord(std::move(Record))); + + const char *FileNames[] = {"bar", "baz", "foo"}; + static const unsigned N = array_lengthof(FileNames); + + startFunction("func", 0x1234); + for (unsigned I = 0; I < N; ++I) + // Use LineStart to hold the index of the file name + // in order to preserve that information during possible sorting of CMRs. + addCMR(Counter::getCounter(0), FileNames[I], I, 1, I, 1); + + loadCoverageMapping(); + + for (unsigned I = 0; I < N; ++I) { + CoverageData Data = LoadedCoverage->getCoverageForFile(FileNames[I]); + ASSERT_TRUE(!Data.empty()); + EXPECT_EQ(I, Data.begin()->Line); + } +} + +TEST_P(MaybeSparseCoverageMappingTest, load_coverage_for_several_functions) { + InstrProfRecord RecordFunc1("func1", 0x1234, {10}); + NoError(ProfileWriter.addRecord(std::move(RecordFunc1))); + InstrProfRecord RecordFunc2("func2", 0x2345, {20}); + NoError(ProfileWriter.addRecord(std::move(RecordFunc2))); + + startFunction("func1", 0x1234); + addCMR(Counter::getCounter(0), "foo", 1, 1, 5, 5); + + startFunction("func2", 0x2345); + addCMR(Counter::getCounter(0), "bar", 2, 2, 6, 6); + + loadCoverageMapping(); + + const auto FunctionRecords = LoadedCoverage->getCoveredFunctions(); + EXPECT_EQ(2U, std::distance(FunctionRecords.begin(), FunctionRecords.end())); + for (const auto &FunctionRecord : FunctionRecords) { + CoverageData Data = LoadedCoverage->getCoverageForFunction(FunctionRecord); + std::vector Segments(Data.begin(), Data.end()); + ASSERT_EQ(2U, Segments.size()); + if (FunctionRecord.Name == "func1") { + EXPECT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]); + EXPECT_EQ(CoverageSegment(5, 5, false), Segments[1]); + } else { + ASSERT_EQ("func2", FunctionRecord.Name); + EXPECT_EQ(CoverageSegment(2, 2, 20, true), Segments[0]); + EXPECT_EQ(CoverageSegment(6, 6, false), Segments[1]); + } } } TEST_P(MaybeSparseCoverageMappingTest, expansion_gets_first_counter) { + startFunction("func", 0x1234); addCMR(Counter::getCounter(1), "foo", 10, 1, 10, 2); // This starts earlier in "foo", so the expansion should get its counter. addCMR(Counter::getCounter(2), "foo", 1, 1, 20, 1); addExpansionCMR("bar", "foo", 3, 3, 3, 3); - std::string Coverage = writeCoverageRegions(); - readCoverageRegions(Coverage); - ASSERT_EQ(CounterMappingRegion::ExpansionRegion, OutputCMRs[2].Kind); - ASSERT_EQ(Counter::getCounter(2), OutputCMRs[2].Count); - ASSERT_EQ(3U, OutputCMRs[2].LineStart); + writeAndReadCoverageRegions(); + ASSERT_EQ(1u, OutputFunctions.size()); + OutputFunctionCoverageData &Output = OutputFunctions.back(); + + ASSERT_EQ(CounterMappingRegion::ExpansionRegion, Output.Regions[2].Kind); + ASSERT_EQ(Counter::getCounter(2), Output.Regions[2].Count); + ASSERT_EQ(3U, Output.Regions[2].LineStart); } TEST_P(MaybeSparseCoverageMappingTest, basic_coverage_iteration) { InstrProfRecord Record("func", 0x1234, {30, 20, 10, 0}); - ProfileWriter.addRecord(std::move(Record)); - readProfCounts(); + NoError(ProfileWriter.addRecord(std::move(Record))); + startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7); addCMR(Counter::getCounter(2), "file1", 5, 8, 9, 1); addCMR(Counter::getCounter(3), "file1", 10, 10, 11, 11); - loadCoverageMapping("func", 0x1234); + loadCoverageMapping(); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector Segments(Data.begin(), Data.end()); @@ -223,10 +358,9 @@ TEST_P(MaybeSparseCoverageMappingTest, basic_coverage_iteration) { } TEST_P(MaybeSparseCoverageMappingTest, uncovered_function) { - readProfCounts(); - + startFunction("func", 0x1234); addCMR(Counter::getZero(), "file1", 1, 2, 3, 4); - loadCoverageMapping("func", 0x1234); + loadCoverageMapping(); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector Segments(Data.begin(), Data.end()); @@ -236,11 +370,10 @@ TEST_P(MaybeSparseCoverageMappingTest, uncovered_function) { } TEST_P(MaybeSparseCoverageMappingTest, uncovered_function_with_mapping) { - readProfCounts(); - + startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7); - loadCoverageMapping("func", 0x1234); + loadCoverageMapping(); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector Segments(Data.begin(), Data.end()); @@ -252,13 +385,13 @@ TEST_P(MaybeSparseCoverageMappingTest, uncovered_function_with_mapping) { TEST_P(MaybeSparseCoverageMappingTest, combine_regions) { InstrProfRecord Record("func", 0x1234, {10, 20, 30}); - ProfileWriter.addRecord(std::move(Record)); - readProfCounts(); + NoError(ProfileWriter.addRecord(std::move(Record))); + startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); addCMR(Counter::getCounter(1), "file1", 3, 3, 4, 4); addCMR(Counter::getCounter(2), "file1", 3, 3, 4, 4); - loadCoverageMapping("func", 0x1234); + loadCoverageMapping(); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector Segments(Data.begin(), Data.end()); @@ -269,18 +402,40 @@ TEST_P(MaybeSparseCoverageMappingTest, combine_regions) { ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]); } +TEST_P(MaybeSparseCoverageMappingTest, + restore_combined_counter_after_nested_region) { + InstrProfRecord Record("func", 0x1234, {10, 20, 40}); + NoError(ProfileWriter.addRecord(std::move(Record))); + + startFunction("func", 0x1234); + addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(1), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(2), "file1", 3, 3, 5, 5); + loadCoverageMapping(); + + CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); + std::vector Segments(Data.begin(), Data.end()); + ASSERT_EQ(4U, Segments.size()); + EXPECT_EQ(CoverageSegment(1, 1, 30, true), Segments[0]); + EXPECT_EQ(CoverageSegment(3, 3, 40, true), Segments[1]); + EXPECT_EQ(CoverageSegment(5, 5, 30, false), Segments[2]); + EXPECT_EQ(CoverageSegment(9, 9, false), Segments[3]); +} + +// If CodeRegions and ExpansionRegions cover the same area, +// only counts of CodeRegions should be used. TEST_P(MaybeSparseCoverageMappingTest, dont_combine_expansions) { InstrProfRecord Record1("func", 0x1234, {10, 20}); InstrProfRecord Record2("func", 0x1234, {0, 0}); - ProfileWriter.addRecord(std::move(Record1)); - ProfileWriter.addRecord(std::move(Record2)); - readProfCounts(); + NoError(ProfileWriter.addRecord(std::move(Record1))); + NoError(ProfileWriter.addRecord(std::move(Record2))); + startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); addCMR(Counter::getCounter(1), "file1", 3, 3, 4, 4); addCMR(Counter::getCounter(1), "include1", 6, 6, 7, 7); addExpansionCMR("file1", "include1", 3, 3, 4, 4); - loadCoverageMapping("func", 0x1234); + loadCoverageMapping(); CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); std::vector Segments(Data.begin(), Data.end()); @@ -291,13 +446,36 @@ TEST_P(MaybeSparseCoverageMappingTest, dont_combine_expansions) { ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]); } +// If an area is covered only by ExpansionRegions, they should be combinated. +TEST_P(MaybeSparseCoverageMappingTest, combine_expansions) { + InstrProfRecord Record("func", 0x1234, {2, 3, 7}); + NoError(ProfileWriter.addRecord(std::move(Record))); + + startFunction("func", 0x1234); + addCMR(Counter::getCounter(1), "include1", 1, 1, 1, 10); + addCMR(Counter::getCounter(2), "include2", 1, 1, 1, 10); + addCMR(Counter::getCounter(0), "file", 1, 1, 5, 5); + addExpansionCMR("file", "include1", 3, 1, 3, 5); + addExpansionCMR("file", "include2", 3, 1, 3, 5); + + loadCoverageMapping(); + + CoverageData Data = LoadedCoverage->getCoverageForFile("file"); + std::vector Segments(Data.begin(), Data.end()); + ASSERT_EQ(4U, Segments.size()); + EXPECT_EQ(CoverageSegment(1, 1, 2, true), Segments[0]); + EXPECT_EQ(CoverageSegment(3, 1, 10, true), Segments[1]); + EXPECT_EQ(CoverageSegment(3, 5, 2, false), Segments[2]); + EXPECT_EQ(CoverageSegment(5, 5, false), Segments[3]); +} + TEST_P(MaybeSparseCoverageMappingTest, strip_filename_prefix) { InstrProfRecord Record("file1:func", 0x1234, {0}); - ProfileWriter.addRecord(std::move(Record)); - readProfCounts(); + NoError(ProfileWriter.addRecord(std::move(Record))); + startFunction("file1:func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); - loadCoverageMapping("file1:func", 0x1234); + loadCoverageMapping(); std::vector Names; for (const auto &Func : LoadedCoverage->getCoveredFunctions()) @@ -308,11 +486,11 @@ TEST_P(MaybeSparseCoverageMappingTest, strip_filename_prefix) { TEST_P(MaybeSparseCoverageMappingTest, strip_unknown_filename_prefix) { InstrProfRecord Record(":func", 0x1234, {0}); - ProfileWriter.addRecord(std::move(Record)); - readProfCounts(); + NoError(ProfileWriter.addRecord(std::move(Record))); + startFunction(":func", 0x1234); addCMR(Counter::getCounter(0), "", 1, 1, 9, 9); - loadCoverageMapping(":func", 0x1234, /*EmitFilenames=*/false); + loadCoverageMapping(/*EmitFilenames=*/false); std::vector Names; for (const auto &Func : LoadedCoverage->getCoveredFunctions()) @@ -321,6 +499,44 @@ TEST_P(MaybeSparseCoverageMappingTest, strip_unknown_filename_prefix) { ASSERT_EQ("func", Names[0]); } +TEST_P(MaybeSparseCoverageMappingTest, dont_detect_false_instantiations) { + InstrProfRecord Record1("foo", 0x1234, {10}); + InstrProfRecord Record2("bar", 0x2345, {20}); + NoError(ProfileWriter.addRecord(std::move(Record1))); + NoError(ProfileWriter.addRecord(std::move(Record2))); + + startFunction("foo", 0x1234); + addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10); + addExpansionCMR("main", "expanded", 4, 1, 4, 5); + + startFunction("bar", 0x2345); + addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10); + addExpansionCMR("main", "expanded", 9, 1, 9, 5); + + loadCoverageMapping(); + + std::vector Instantiations = + LoadedCoverage->getInstantiations("expanded"); + ASSERT_TRUE(Instantiations.empty()); +} + +TEST_P(MaybeSparseCoverageMappingTest, load_coverage_for_expanded_file) { + InstrProfRecord Record("func", 0x1234, {10}); + NoError(ProfileWriter.addRecord(std::move(Record))); + + startFunction("func", 0x1234); + addCMR(Counter::getCounter(0), "expanded", 1, 1, 1, 10); + addExpansionCMR("main", "expanded", 4, 1, 4, 5); + + loadCoverageMapping(); + + CoverageData Data = LoadedCoverage->getCoverageForFile("expanded"); + std::vector Segments(Data.begin(), Data.end()); + ASSERT_EQ(2U, Segments.size()); + EXPECT_EQ(CoverageSegment(1, 1, 10, true), Segments[0]); + EXPECT_EQ(CoverageSegment(1, 10, false), Segments[1]); +} + INSTANTIATE_TEST_CASE_P(MaybeSparse, MaybeSparseCoverageMappingTest, ::testing::Bool()); diff --git a/unittests/ProfileData/InstrProfTest.cpp b/unittests/ProfileData/InstrProfTest.cpp index 7dd072c849bc62f81bf2fc1cbb7ff987f20f0ec6..c13f31251de4556cf727f16f116ce71eb3fc7a55 100644 --- a/unittests/ProfileData/InstrProfTest.cpp +++ b/unittests/ProfileData/InstrProfTest.cpp @@ -19,19 +19,24 @@ using namespace llvm; -static ::testing::AssertionResult NoError(std::error_code EC) { - if (!EC) +static ::testing::AssertionResult NoError(Error E) { + if (!E) return ::testing::AssertionSuccess(); - return ::testing::AssertionFailure() << "error " << EC.value() - << ": " << EC.message(); + return ::testing::AssertionFailure() << "error: " << toString(std::move(E)) + << "\n"; } -static ::testing::AssertionResult ErrorEquals(std::error_code Expected, - std::error_code Found) { +static ::testing::AssertionResult ErrorEquals(instrprof_error Expected, + Error E) { + instrprof_error Found; + std::string FoundMsg; + handleAllErrors(std::move(E), [&](const InstrProfError &IPE) { + Found = IPE.get(); + FoundMsg = IPE.message(); + }); if (Expected == Found) return ::testing::AssertionSuccess(); - return ::testing::AssertionFailure() << "error " << Found.value() - << ": " << Found.message(); + return ::testing::AssertionFailure() << "error: " << FoundMsg << "\n"; } namespace { @@ -44,7 +49,7 @@ struct InstrProfTest : ::testing::Test { void readProfile(std::unique_ptr Profile) { auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile)); - ASSERT_TRUE(NoError(ReaderOrErr.getError())); + ASSERT_TRUE(NoError(ReaderOrErr.takeError())); Reader = std::move(ReaderOrErr.get()); } }; @@ -66,7 +71,7 @@ TEST_P(MaybeSparseInstrProfTest, write_and_read_empty_profile) { TEST_P(MaybeSparseInstrProfTest, write_and_read_one_function) { InstrProfRecord Record("foo", 0x1234, {1, 2, 3, 4}); - Writer.addRecord(std::move(Record)); + NoError(Writer.addRecord(std::move(Record))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); @@ -85,35 +90,35 @@ TEST_P(MaybeSparseInstrProfTest, write_and_read_one_function) { TEST_P(MaybeSparseInstrProfTest, get_instr_prof_record) { InstrProfRecord Record1("foo", 0x1234, {1, 2}); InstrProfRecord Record2("foo", 0x1235, {3, 4}); - Writer.addRecord(std::move(Record1)); - Writer.addRecord(std::move(Record2)); + NoError(Writer.addRecord(std::move(Record1))); + NoError(Writer.addRecord(std::move(Record2))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("foo", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("foo", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(2U, R->Counts.size()); ASSERT_EQ(1U, R->Counts[0]); ASSERT_EQ(2U, R->Counts[1]); R = Reader->getInstrProfRecord("foo", 0x1235); - ASSERT_TRUE(NoError(R.getError())); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(2U, R->Counts.size()); ASSERT_EQ(3U, R->Counts[0]); ASSERT_EQ(4U, R->Counts[1]); R = Reader->getInstrProfRecord("foo", 0x5678); - ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, R.getError())); + ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, R.takeError())); R = Reader->getInstrProfRecord("bar", 0x1234); - ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, R.getError())); + ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, R.takeError())); } TEST_P(MaybeSparseInstrProfTest, get_function_counts) { InstrProfRecord Record1("foo", 0x1234, {1, 2}); InstrProfRecord Record2("foo", 0x1235, {3, 4}); - Writer.addRecord(std::move(Record1)); - Writer.addRecord(std::move(Record2)); + NoError(Writer.addRecord(std::move(Record1))); + NoError(Writer.addRecord(std::move(Record2))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); @@ -128,12 +133,11 @@ TEST_P(MaybeSparseInstrProfTest, get_function_counts) { ASSERT_EQ(3U, Counts[0]); ASSERT_EQ(4U, Counts[1]); - std::error_code EC; - EC = Reader->getFunctionCounts("foo", 0x5678, Counts); - ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, EC)); + Error E1 = Reader->getFunctionCounts("foo", 0x5678, Counts); + ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, std::move(E1))); - EC = Reader->getFunctionCounts("bar", 0x1234, Counts); - ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, EC)); + Error E2 = Reader->getFunctionCounts("bar", 0x1234, Counts); + ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, std::move(E2))); } // Profile data is copied from general.proftext @@ -145,17 +149,18 @@ TEST_F(InstrProfTest, get_profile_summary) { 576460752303423488, 288230376151711744, 144115188075855872, 72057594037927936}); InstrProfRecord Record4("func4", 0x1234, {0}); - Writer.addRecord(std::move(Record1)); - Writer.addRecord(std::move(Record2)); - Writer.addRecord(std::move(Record3)); - Writer.addRecord(std::move(Record4)); + NoError(Writer.addRecord(std::move(Record1))); + NoError(Writer.addRecord(std::move(Record2))); + NoError(Writer.addRecord(std::move(Record3))); + NoError(Writer.addRecord(std::move(Record4))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - auto VerifySummary = [](InstrProfSummary &IPS) mutable { + auto VerifySummary = [](ProfileSummary &IPS) mutable { + ASSERT_EQ(ProfileSummary::PSK_Instr, IPS.getKind()); ASSERT_EQ(2305843009213693952U, IPS.getMaxFunctionCount()); - ASSERT_EQ(2305843009213693952U, IPS.getMaxBlockCount()); - ASSERT_EQ(10U, IPS.getNumBlocks()); + ASSERT_EQ(2305843009213693952U, IPS.getMaxCount()); + ASSERT_EQ(10U, IPS.getNumCounts()); ASSERT_EQ(4539628424389557499U, IPS.getTotalCount()); std::vector &Details = IPS.getDetailedSummary(); uint32_t Cutoff = 800000; @@ -176,32 +181,36 @@ TEST_F(InstrProfTest, get_profile_summary) { ASSERT_EQ(288230376151711744U, NinetyFivePerc->MinCount); ASSERT_EQ(72057594037927936U, NinetyNinePerc->MinCount); }; - InstrProfSummary &PS = Reader->getSummary(); + ProfileSummary &PS = Reader->getSummary(); VerifySummary(PS); // Test that conversion of summary to and from Metadata works. - Metadata *MD = PS.getMD(getGlobalContext()); + LLVMContext Context; + Metadata *MD = PS.getMD(Context); ASSERT_TRUE(MD); ProfileSummary *PSFromMD = ProfileSummary::getFromMD(MD); ASSERT_TRUE(PSFromMD); - ASSERT_TRUE(isa(PSFromMD)); - InstrProfSummary *IPS = cast(PSFromMD); - VerifySummary(*IPS); - delete IPS; + VerifySummary(*PSFromMD); + delete PSFromMD; // Test that summary can be attached to and read back from module. - Module M("my_module", getGlobalContext()); + Module M("my_module", Context); M.setProfileSummary(MD); MD = M.getProfileSummary(); ASSERT_TRUE(MD); PSFromMD = ProfileSummary::getFromMD(MD); ASSERT_TRUE(PSFromMD); - ASSERT_TRUE(isa(PSFromMD)); - IPS = cast(PSFromMD); - VerifySummary(*IPS); - delete IPS; + VerifySummary(*PSFromMD); + delete PSFromMD; } +static const char callee1[] = "callee1"; +static const char callee2[] = "callee2"; +static const char callee3[] = "callee3"; +static const char callee4[] = "callee4"; +static const char callee5[] = "callee5"; +static const char callee6[] = "callee6"; + TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write) { InstrProfRecord Record1("caller", 0x1234, {1, 2}); InstrProfRecord Record2("callee1", 0x1235, {3, 4}); @@ -210,27 +219,25 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write) { // 4 value sites. Record1.reserveSites(IPVK_IndirectCallTarget, 4); - InstrProfValueData VD0[] = {{(uint64_t) "callee1", 1}, - {(uint64_t) "callee2", 2}, - {(uint64_t) "callee3", 3}}; + InstrProfValueData VD0[] = { + {(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}, {(uint64_t)callee3, 3}}; Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, 3, nullptr); // No value profile data at the second site. Record1.addValueData(IPVK_IndirectCallTarget, 1, nullptr, 0, nullptr); - InstrProfValueData VD2[] = {{(uint64_t) "callee1", 1}, - {(uint64_t) "callee2", 2}}; + InstrProfValueData VD2[] = {{(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}}; Record1.addValueData(IPVK_IndirectCallTarget, 2, VD2, 2, nullptr); - InstrProfValueData VD3[] = {{(uint64_t) "callee1", 1}}; + InstrProfValueData VD3[] = {{(uint64_t)callee1, 1}}; Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr); - Writer.addRecord(std::move(Record1)); - Writer.addRecord(std::move(Record2)); - Writer.addRecord(std::move(Record3)); - Writer.addRecord(std::move(Record4)); + NoError(Writer.addRecord(std::move(Record1))); + NoError(Writer.addRecord(std::move(Record2))); + NoError(Writer.addRecord(std::move(Record3))); + NoError(Writer.addRecord(std::move(Record4))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -257,11 +264,11 @@ TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) { InstrProfValueData VD0[] = {{1000, 1}, {2000, 2}, {3000, 3}, {5000, 5}, {4000, 4}, {6000, 6}}; Record.addValueData(IPVK_IndirectCallTarget, 0, VD0, 6, nullptr); - Writer.addRecord(std::move(Record)); + NoError(Writer.addRecord(std::move(Record))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); LLVMContext Ctx; std::unique_ptr M(new Module("MyModule", Ctx)); @@ -330,7 +337,8 @@ TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) { // Annotate with 4 records. InstrProfValueData VD0Sorted[] = {{1000, 6}, {2000, 5}, {3000, 4}, {4000, 3}, {5000, 2}, {6000, 1}}; - annotateValueSite(*M, *Inst, &VD0Sorted[2], 4, 10, IPVK_IndirectCallTarget, 5); + annotateValueSite(*M, *Inst, makeArrayRef(VD0Sorted).slice(2), 10, + IPVK_IndirectCallTarget, 5); Res = getValueProfDataFromInst(*Inst, IPVK_IndirectCallTarget, 5, ValueData, N, T); ASSERT_TRUE(Res); @@ -354,27 +362,25 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_with_weight) { // 4 value sites. Record1.reserveSites(IPVK_IndirectCallTarget, 4); - InstrProfValueData VD0[] = {{(uint64_t) "callee1", 1}, - {(uint64_t) "callee2", 2}, - {(uint64_t) "callee3", 3}}; + InstrProfValueData VD0[] = { + {(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}, {(uint64_t)callee3, 3}}; Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, 3, nullptr); // No value profile data at the second site. Record1.addValueData(IPVK_IndirectCallTarget, 1, nullptr, 0, nullptr); - InstrProfValueData VD2[] = {{(uint64_t) "callee1", 1}, - {(uint64_t) "callee2", 2}}; + InstrProfValueData VD2[] = {{(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}}; Record1.addValueData(IPVK_IndirectCallTarget, 2, VD2, 2, nullptr); - InstrProfValueData VD3[] = {{(uint64_t) "callee1", 1}}; + InstrProfValueData VD3[] = {{(uint64_t)callee1, 1}}; Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr); - Writer.addRecord(std::move(Record1), 10); - Writer.addRecord(std::move(Record2)); - Writer.addRecord(std::move(Record3)); - Writer.addRecord(std::move(Record4)); + NoError(Writer.addRecord(std::move(Record1), 10)); + NoError(Writer.addRecord(std::move(Record2))); + NoError(Writer.addRecord(std::move(Record3))); + NoError(Writer.addRecord(std::move(Record4))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -402,22 +408,20 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) { // 4 value sites. Record1.reserveSites(IPVK_IndirectCallTarget, 4); - InstrProfValueData VD0[] = {{(uint64_t) "callee1", 1}, - {(uint64_t) "callee2", 2}, - {(uint64_t) "callee3", 3}}; + InstrProfValueData VD0[] = { + {(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}, {(uint64_t)callee3, 3}}; Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, 3, nullptr); // No value profile data at the second site. Record1.addValueData(IPVK_IndirectCallTarget, 1, nullptr, 0, nullptr); - InstrProfValueData VD2[] = {{(uint64_t) "callee1", 1}, - {(uint64_t) "callee2", 2}}; + InstrProfValueData VD2[] = {{(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}}; Record1.addValueData(IPVK_IndirectCallTarget, 2, VD2, 2, nullptr); - InstrProfValueData VD3[] = {{(uint64_t) "callee1", 1}}; + InstrProfValueData VD3[] = {{(uint64_t)callee1, 1}}; Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr); - Writer.addRecord(std::move(Record1)); - Writer.addRecord(std::move(Record2)); - Writer.addRecord(std::move(Record3)); - Writer.addRecord(std::move(Record4)); + NoError(Writer.addRecord(std::move(Record1))); + NoError(Writer.addRecord(std::move(Record2))); + NoError(Writer.addRecord(std::move(Record3))); + NoError(Writer.addRecord(std::move(Record4))); // Set big endian output. Writer.setValueProfDataEndianness(support::big); @@ -428,8 +432,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) { // Set big endian input. Reader->setValueProfDataEndianness(support::big); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -448,11 +452,6 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) { TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) { static const char caller[] = "caller"; - static const char callee1[] = "callee1"; - static const char callee2[] = "callee2"; - static const char callee3[] = "callee3"; - static const char callee4[] = "callee4"; - InstrProfRecord Record11(caller, 0x1234, {1, 2}); InstrProfRecord Record12(caller, 0x1234, {1, 2}); InstrProfRecord Record2(callee1, 0x1235, {3, 4}); @@ -484,7 +483,7 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) { {uint64_t(callee3), 3}}; Record11.addValueData(IPVK_IndirectCallTarget, 4, VD4, 3, nullptr); - // A differnt record for the same caller. + // A different record for the same caller. Record12.reserveSites(IPVK_IndirectCallTarget, 5); InstrProfValueData VD02[] = {{uint64_t(callee2), 5}, {uint64_t(callee3), 3}}; Record12.addValueData(IPVK_IndirectCallTarget, 0, VD02, 2, nullptr); @@ -503,20 +502,20 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) { {uint64_t(callee3), 3}}; Record12.addValueData(IPVK_IndirectCallTarget, 4, VD42, 3, nullptr); - Writer.addRecord(std::move(Record11)); + NoError(Writer.addRecord(std::move(Record11))); // Merge profile data. - Writer.addRecord(std::move(Record12)); + NoError(Writer.addRecord(std::move(Record12))); - Writer.addRecord(std::move(Record2)); - Writer.addRecord(std::move(Record3)); - Writer.addRecord(std::move(Record4)); - Writer.addRecord(std::move(Record5)); - Writer.addRecord(std::move(Record6)); + NoError(Writer.addRecord(std::move(Record2))); + NoError(Writer.addRecord(std::move(Record3))); + NoError(Writer.addRecord(std::move(Record4))); + NoError(Writer.addRecord(std::move(Record5))); + NoError(Writer.addRecord(std::move(Record6))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); ASSERT_EQ(5U, R->getNumValueSites(IPVK_IndirectCallTarget)); ASSERT_EQ(4U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1)); @@ -568,23 +567,27 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1_saturation) { InstrProfRecord Record1("foo", 0x1234, {1}); auto Result1 = Writer.addRecord(std::move(Record1)); - ASSERT_EQ(Result1, instrprof_error::success); + ASSERT_EQ(InstrProfError::take(std::move(Result1)), + instrprof_error::success); // Verify counter overflow. InstrProfRecord Record2("foo", 0x1234, {Max}); auto Result2 = Writer.addRecord(std::move(Record2)); - ASSERT_EQ(Result2, instrprof_error::counter_overflow); + ASSERT_EQ(InstrProfError::take(std::move(Result2)), + instrprof_error::counter_overflow); InstrProfRecord Record3(bar, 0x9012, {8}); auto Result3 = Writer.addRecord(std::move(Record3)); - ASSERT_EQ(Result3, instrprof_error::success); + ASSERT_EQ(InstrProfError::take(std::move(Result3)), + instrprof_error::success); InstrProfRecord Record4("baz", 0x5678, {3, 4}); Record4.reserveSites(IPVK_IndirectCallTarget, 1); InstrProfValueData VD4[] = {{uint64_t(bar), 1}}; Record4.addValueData(IPVK_IndirectCallTarget, 0, VD4, 1, nullptr); auto Result4 = Writer.addRecord(std::move(Record4)); - ASSERT_EQ(Result4, instrprof_error::success); + ASSERT_EQ(InstrProfError::take(std::move(Result4)), + instrprof_error::success); // Verify value data counter overflow. InstrProfRecord Record5("baz", 0x5678, {5, 6}); @@ -592,19 +595,21 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1_saturation) { InstrProfValueData VD5[] = {{uint64_t(bar), Max}}; Record5.addValueData(IPVK_IndirectCallTarget, 0, VD5, 1, nullptr); auto Result5 = Writer.addRecord(std::move(Record5)); - ASSERT_EQ(Result5, instrprof_error::counter_overflow); + ASSERT_EQ(InstrProfError::take(std::move(Result5)), + instrprof_error::counter_overflow); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); // Verify saturation of counts. - ErrorOr ReadRecord1 = + Expected ReadRecord1 = Reader->getInstrProfRecord("foo", 0x1234); - ASSERT_TRUE(NoError(ReadRecord1.getError())); + ASSERT_TRUE(NoError(ReadRecord1.takeError())); ASSERT_EQ(Max, ReadRecord1->Counts[0]); - ErrorOr ReadRecord2 = + Expected ReadRecord2 = Reader->getInstrProfRecord("baz", 0x5678); + ASSERT_TRUE(bool(ReadRecord2)); ASSERT_EQ(1U, ReadRecord2->getNumValueSites(IPVK_IndirectCallTarget)); std::unique_ptr VD = ReadRecord2->getValueForSite(IPVK_IndirectCallTarget, 0); @@ -642,15 +647,15 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge_site_trunc) { Record12.addValueData(IPVK_IndirectCallTarget, 0, VD1, 255, nullptr); Record12.addValueData(IPVK_IndirectCallTarget, 1, nullptr, 0, nullptr); - Writer.addRecord(std::move(Record11)); + NoError(Writer.addRecord(std::move(Record11))); // Merge profile data. - Writer.addRecord(std::move(Record12)); + NoError(Writer.addRecord(std::move(Record12))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); - ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234); - ASSERT_TRUE(NoError(R.getError())); + Expected R = Reader->getInstrProfRecord("caller", 0x1234); + ASSERT_TRUE(NoError(R.takeError())); std::unique_ptr VD( R->getValueForSite(IPVK_IndirectCallTarget, 0)); ASSERT_EQ(2U, R->getNumValueSites(IPVK_IndirectCallTarget)); @@ -661,39 +666,36 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge_site_trunc) { } } -// Synthesize runtime value profile data. -ValueProfNode Site1Values[5] = {{{uint64_t("callee1"), 400}, &Site1Values[1]}, - {{uint64_t("callee2"), 1000}, &Site1Values[2]}, - {{uint64_t("callee3"), 500}, &Site1Values[3]}, - {{uint64_t("callee4"), 300}, &Site1Values[4]}, - {{uint64_t("callee5"), 100}, nullptr}}; - -ValueProfNode Site2Values[4] = {{{uint64_t("callee5"), 800}, &Site2Values[1]}, - {{uint64_t("callee3"), 1000}, &Site2Values[2]}, - {{uint64_t("callee2"), 2500}, &Site2Values[3]}, - {{uint64_t("callee1"), 1300}, nullptr}}; - -ValueProfNode Site3Values[3] = {{{uint64_t("callee6"), 800}, &Site3Values[1]}, - {{uint64_t("callee3"), 1000}, &Site3Values[2]}, - {{uint64_t("callee4"), 5500}, nullptr}}; - -ValueProfNode Site4Values[2] = {{{uint64_t("callee2"), 1800}, &Site4Values[1]}, - {{uint64_t("callee3"), 2000}, nullptr}}; - -static ValueProfNode *ValueProfNodes[5] = {&Site1Values[0], &Site2Values[0], - &Site3Values[0], &Site4Values[0], - nullptr}; - -static uint16_t NumValueSites[IPVK_Last + 1] = {5}; -TEST_P(MaybeSparseInstrProfTest, runtime_value_prof_data_read_write) { - ValueProfRuntimeRecord RTRecord; - initializeValueProfRuntimeRecord(&RTRecord, &NumValueSites[0], - &ValueProfNodes[0]); +static void addValueProfData(InstrProfRecord &Record) { + Record.reserveSites(IPVK_IndirectCallTarget, 5); + InstrProfValueData VD0[] = {{uint64_t(callee1), 400}, + {uint64_t(callee2), 1000}, + {uint64_t(callee3), 500}, + {uint64_t(callee4), 300}, + {uint64_t(callee5), 100}}; + Record.addValueData(IPVK_IndirectCallTarget, 0, VD0, 5, nullptr); + InstrProfValueData VD1[] = {{uint64_t(callee5), 800}, + {uint64_t(callee3), 1000}, + {uint64_t(callee2), 2500}, + {uint64_t(callee1), 1300}}; + Record.addValueData(IPVK_IndirectCallTarget, 1, VD1, 4, nullptr); + InstrProfValueData VD2[] = {{uint64_t(callee6), 800}, + {uint64_t(callee3), 1000}, + {uint64_t(callee4), 5500}}; + Record.addValueData(IPVK_IndirectCallTarget, 2, VD2, 3, nullptr); + InstrProfValueData VD3[] = {{uint64_t(callee2), 1800}, + {uint64_t(callee3), 2000}}; + Record.addValueData(IPVK_IndirectCallTarget, 3, VD3, 2, nullptr); + Record.addValueData(IPVK_IndirectCallTarget, 4, nullptr, 0, nullptr); +} - ValueProfData *VPData = serializeValueProfDataFromRT(&RTRecord, nullptr); +TEST_P(MaybeSparseInstrProfTest, value_prof_data_read_write) { + InstrProfRecord SrcRecord("caller", 0x1234, {1ULL << 31, 2}); + addValueProfData(SrcRecord); + std::unique_ptr VPData = + ValueProfData::serializeFrom(SrcRecord); InstrProfRecord Record("caller", 0x1234, {1ULL << 31, 2}); - VPData->deserializeTo(Record, nullptr); // Now read data from Record and sanity check the data @@ -750,18 +752,54 @@ TEST_P(MaybeSparseInstrProfTest, runtime_value_prof_data_read_write) { ASSERT_EQ(2000U, VD_3[0].Count); ASSERT_EQ(StringRef((const char *)VD_3[1].Value, 7), StringRef("callee2")); ASSERT_EQ(1800U, VD_3[1].Count); +} + +TEST_P(MaybeSparseInstrProfTest, value_prof_data_read_write_mapping) { + + InstrProfRecord SrcRecord("caller", 0x1234, {1ULL << 31, 2}); + addValueProfData(SrcRecord); + std::unique_ptr VPData = + ValueProfData::serializeFrom(SrcRecord); + + InstrProfRecord Record("caller", 0x1234, {1ULL << 31, 2}); + InstrProfSymtab Symtab; + Symtab.mapAddress(uint64_t(callee1), 0x1000ULL); + Symtab.mapAddress(uint64_t(callee2), 0x2000ULL); + Symtab.mapAddress(uint64_t(callee3), 0x3000ULL); + Symtab.mapAddress(uint64_t(callee4), 0x4000ULL); + // Missing mapping for callee5 + Symtab.finalizeSymtab(); + + VPData->deserializeTo(Record, &Symtab.getAddrHashMap()); + + // Now read data from Record and sanity check the data + ASSERT_EQ(5U, Record.getNumValueSites(IPVK_IndirectCallTarget)); + ASSERT_EQ(5U, Record.getNumValueDataForSite(IPVK_IndirectCallTarget, 0)); + + auto Cmp = [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) { + return VD1.Count > VD2.Count; + }; + std::unique_ptr VD_0( + Record.getValueForSite(IPVK_IndirectCallTarget, 0)); + std::sort(&VD_0[0], &VD_0[5], Cmp); + ASSERT_EQ(VD_0[0].Value, 0x2000ULL); + ASSERT_EQ(1000U, VD_0[0].Count); + ASSERT_EQ(VD_0[1].Value, 0x3000ULL); + ASSERT_EQ(500U, VD_0[1].Count); + ASSERT_EQ(VD_0[2].Value, 0x1000ULL); + ASSERT_EQ(400U, VD_0[2].Count); - finalizeValueProfRuntimeRecord(&RTRecord); - free(VPData); + // callee5 does not have a mapped value -- default to 0. + ASSERT_EQ(VD_0[4].Value, 0ULL); } TEST_P(MaybeSparseInstrProfTest, get_max_function_count) { InstrProfRecord Record1("foo", 0x1234, {1ULL << 31, 2}); InstrProfRecord Record2("bar", 0, {1ULL << 63}); InstrProfRecord Record3("baz", 0x5678, {0, 0, 0, 0}); - Writer.addRecord(std::move(Record1)); - Writer.addRecord(std::move(Record2)); - Writer.addRecord(std::move(Record3)); + NoError(Writer.addRecord(std::move(Record1))); + NoError(Writer.addRecord(std::move(Record2))); + NoError(Writer.addRecord(std::move(Record3))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); @@ -771,8 +809,8 @@ TEST_P(MaybeSparseInstrProfTest, get_max_function_count) { TEST_P(MaybeSparseInstrProfTest, get_weighted_function_counts) { InstrProfRecord Record1("foo", 0x1234, {1, 2}); InstrProfRecord Record2("foo", 0x1235, {3, 4}); - Writer.addRecord(std::move(Record1), 3); - Writer.addRecord(std::move(Record2), 5); + NoError(Writer.addRecord(std::move(Record1), 3)); + NoError(Writer.addRecord(std::move(Record2), 5)); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); @@ -906,13 +944,13 @@ TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_compression_test) { for (bool DoCompression : {false, true}) { // Compressing: std::string FuncNameStrings1; - collectPGOFuncNameStrings( - FuncNames1, (DoCompression && zlib::isAvailable()), FuncNameStrings1); + NoError(collectPGOFuncNameStrings( + FuncNames1, (DoCompression && zlib::isAvailable()), FuncNameStrings1)); // Compressing: std::string FuncNameStrings2; - collectPGOFuncNameStrings( - FuncNames2, (DoCompression && zlib::isAvailable()), FuncNameStrings2); + NoError(collectPGOFuncNameStrings( + FuncNames2, (DoCompression && zlib::isAvailable()), FuncNameStrings2)); for (int Padding = 0; Padding < 2; Padding++) { // Join with paddings : @@ -924,7 +962,7 @@ TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_compression_test) { // Now decompress: InstrProfSymtab Symtab; - Symtab.create(StringRef(FuncNameStrings)); + NoError(Symtab.create(StringRef(FuncNameStrings))); // Now do the checks: // First sampling some data points: @@ -952,9 +990,9 @@ TEST_F(SparseInstrProfTest, preserve_no_records) { InstrProfRecord Record2("bar", 0x4321, {0, 0}); InstrProfRecord Record3("bar", 0x4321, {0, 0, 0}); - Writer.addRecord(std::move(Record1)); - Writer.addRecord(std::move(Record2)); - Writer.addRecord(std::move(Record3)); + NoError(Writer.addRecord(std::move(Record1))); + NoError(Writer.addRecord(std::move(Record2))); + NoError(Writer.addRecord(std::move(Record3))); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); diff --git a/unittests/ProfileData/SampleProfTest.cpp b/unittests/ProfileData/SampleProfTest.cpp index 12533fa6656256231d0e893624c05c66d574d051..175852b93fb20e8af003034bd61d25eb636d00c1 100644 --- a/unittests/ProfileData/SampleProfTest.cpp +++ b/unittests/ProfileData/SampleProfTest.cpp @@ -1,5 +1,4 @@ -//===- unittest/ProfileData/SampleProfTest.cpp -------------------*- C++ -//-*-===// +//===- unittest/ProfileData/SampleProfTest.cpp ------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -8,12 +7,27 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" +#include "llvm/ProfileData/ProfileCommon.h" +#include "llvm/ProfileData/SampleProf.h" #include "llvm/ProfileData/SampleProfReader.h" #include "llvm/ProfileData/SampleProfWriter.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" - -#include +#include +#include +#include +#include +#include +#include +#include using namespace llvm; using namespace sampleprof; @@ -29,6 +43,7 @@ namespace { struct SampleProfTest : ::testing::Test { std::string Data; + LLVMContext Context; std::unique_ptr OS; std::unique_ptr Writer; std::unique_ptr Reader; @@ -43,7 +58,7 @@ struct SampleProfTest : ::testing::Test { } void readProfile(std::unique_ptr &Profile) { - auto ReaderOrErr = SampleProfileReader::create(Profile, getGlobalContext()); + auto ReaderOrErr = SampleProfileReader::create(Profile, Context); ASSERT_TRUE(NoError(ReaderOrErr.getError())); Reader = std::move(ReaderOrErr.get()); } @@ -96,12 +111,13 @@ struct SampleProfTest : ::testing::Test { ASSERT_EQ(20301u, ReadBarSamples.getTotalSamples()); ASSERT_EQ(1437u, ReadBarSamples.getHeadSamples()); - auto VerifySummary = [](SampleProfileSummary &Summary) mutable { - ASSERT_EQ(123603u, Summary.getTotalSamples()); - ASSERT_EQ(6u, Summary.getNumLinesWithSamples()); + auto VerifySummary = [](ProfileSummary &Summary) mutable { + ASSERT_EQ(ProfileSummary::PSK_Sample, Summary.getKind()); + ASSERT_EQ(123603u, Summary.getTotalCount()); + ASSERT_EQ(6u, Summary.getNumCounts()); ASSERT_EQ(2u, Summary.getNumFunctions()); ASSERT_EQ(1437u, Summary.getMaxFunctionCount()); - ASSERT_EQ(60351u, Summary.getMaxSamplesPerLine()); + ASSERT_EQ(60351u, Summary.getMaxCount()); uint32_t Cutoff = 800000; auto Predicate = [&Cutoff](const ProfileSummaryEntry &PE) { @@ -123,30 +139,26 @@ struct SampleProfTest : ::testing::Test { ASSERT_EQ(610u, NinetyNinePerc->MinCount); }; - SampleProfileSummary &Summary = Reader->getSummary(); + ProfileSummary &Summary = Reader->getSummary(); VerifySummary(Summary); // Test that conversion of summary to and from Metadata works. - Metadata *MD = Summary.getMD(getGlobalContext()); + Metadata *MD = Summary.getMD(Context); ASSERT_TRUE(MD); ProfileSummary *PS = ProfileSummary::getFromMD(MD); ASSERT_TRUE(PS); - ASSERT_TRUE(isa(PS)); - SampleProfileSummary *SPS = cast(PS); - VerifySummary(*SPS); - delete SPS; + VerifySummary(*PS); + delete PS; // Test that summary can be attached to and read back from module. - Module M("my_module", getGlobalContext()); + Module M("my_module", Context); M.setProfileSummary(MD); MD = M.getProfileSummary(); ASSERT_TRUE(MD); PS = ProfileSummary::getFromMD(MD); ASSERT_TRUE(PS); - ASSERT_TRUE(isa(PS)); - SPS = cast(PS); - VerifySummary(*SPS); - delete SPS; + VerifySummary(*PS); + delete PS; } }; diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt index f02d501538bc6c741423343ac97615423209453c..9a4a144509115f5a71e625a8c57c2e199538fe5d 100644 --- a/unittests/Support/CMakeLists.txt +++ b/unittests/Support/CMakeLists.txt @@ -52,6 +52,7 @@ add_llvm_unittest(SupportTests formatted_raw_ostream_test.cpp raw_ostream_test.cpp raw_pwrite_stream_test.cpp + raw_sha1_ostream_test.cpp ) # ManagedStatic.cpp uses . diff --git a/unittests/Support/CommandLineTest.cpp b/unittests/Support/CommandLineTest.cpp index eac669f467b7d2637ba9473a0ad881c4836d9ab5..9b24c1e40bcadc9a1665f3e22fb0bdb2803f0feb 100644 --- a/unittests/Support/CommandLineTest.cpp +++ b/unittests/Support/CommandLineTest.cpp @@ -67,6 +67,22 @@ public: : Base(M0, M1, M2, M3) {} ~StackOption() override { this->removeArgument(); } + + template StackOption &operator=(const DT &V) { + this->setValue(V); + return *this; + } +}; + +class StackSubCommand : public cl::SubCommand { +public: + StackSubCommand(const char *const Name, + const char *const Description = nullptr) + : SubCommand(Name, Description) {} + + StackSubCommand() : SubCommand() {} + + ~StackSubCommand() { unregisterSubCommand(); } }; @@ -78,7 +94,8 @@ TEST(CommandLineTest, ModifyExisitingOption) { const char ArgString[] = "new-test-option"; const char ValueString[] = "Integer"; - StringMap &Map = cl::getRegisteredOptions(); + StringMap &Map = + cl::getRegisteredOptions(*cl::TopLevelSubCommand); ASSERT_TRUE(Map.count("test-option") == 1) << "Could not find option in map."; @@ -165,11 +182,12 @@ void testCommandLineTokenizer(ParserFunction *parse, const char *Input, } TEST(CommandLineTest, TokenizeGNUCommandLine) { - const char *Input = "foo\\ bar \"foo bar\" \'foo bar\' 'foo\\\\bar' " - "foo\"bar\"baz C:\\src\\foo.cpp \"C:\\src\\foo.cpp\""; - const char *const Output[] = { "foo bar", "foo bar", "foo bar", "foo\\bar", - "foobarbaz", "C:\\src\\foo.cpp", - "C:\\src\\foo.cpp" }; + const char *Input = + "foo\\ bar \"foo bar\" \'foo bar\' 'foo\\\\bar' -DFOO=bar\\(\\) " + "foo\"bar\"baz C:\\\\src\\\\foo.cpp \"C:\\src\\foo.cpp\""; + const char *const Output[] = { + "foo bar", "foo bar", "foo bar", "foo\\bar", + "-DFOO=bar()", "foobarbaz", "C:\\src\\foo.cpp", "C:srcfoo.cpp"}; testCommandLineTokenizer(cl::TokenizeGNUCommandLine, Input, Output, array_lengthof(Output)); } @@ -236,7 +254,8 @@ TEST(CommandLineTest, HideUnrelatedOptions) { ASSERT_EQ(cl::NotHidden, TestOption2.getOptionHiddenFlag()) << "Hid extra option that should be visable."; - StringMap &Map = cl::getRegisteredOptions(); + StringMap &Map = + cl::getRegisteredOptions(*cl::TopLevelSubCommand); ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag()) << "Hid default option that should be visable."; } @@ -260,9 +279,201 @@ TEST(CommandLineTest, HideUnrelatedOptionsMulti) { ASSERT_EQ(cl::NotHidden, TestOption3.getOptionHiddenFlag()) << "Hid extra option that should be visable."; - StringMap &Map = cl::getRegisteredOptions(); + StringMap &Map = + cl::getRegisteredOptions(*cl::TopLevelSubCommand); ASSERT_EQ(cl::NotHidden, Map["help"]->getOptionHiddenFlag()) << "Hid default option that should be visable."; } +TEST(CommandLineTest, SetValueInSubcategories) { + cl::ResetCommandLineParser(); + + StackSubCommand SC1("sc1", "First subcommand"); + StackSubCommand SC2("sc2", "Second subcommand"); + + StackOption TopLevelOpt("top-level", cl::init(false)); + StackOption SC1Opt("sc1", cl::sub(SC1), cl::init(false)); + StackOption SC2Opt("sc2", cl::sub(SC2), cl::init(false)); + + EXPECT_FALSE(TopLevelOpt); + EXPECT_FALSE(SC1Opt); + EXPECT_FALSE(SC2Opt); + const char *args[] = {"prog", "-top-level"}; + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true)); + EXPECT_TRUE(TopLevelOpt); + EXPECT_FALSE(SC1Opt); + EXPECT_FALSE(SC2Opt); + + TopLevelOpt = false; + + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(TopLevelOpt); + EXPECT_FALSE(SC1Opt); + EXPECT_FALSE(SC2Opt); + const char *args2[] = {"prog", "sc1", "-sc1"}; + EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, nullptr, true)); + EXPECT_FALSE(TopLevelOpt); + EXPECT_TRUE(SC1Opt); + EXPECT_FALSE(SC2Opt); + + SC1Opt = false; + + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(TopLevelOpt); + EXPECT_FALSE(SC1Opt); + EXPECT_FALSE(SC2Opt); + const char *args3[] = {"prog", "sc2", "-sc2"}; + EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, nullptr, true)); + EXPECT_FALSE(TopLevelOpt); + EXPECT_FALSE(SC1Opt); + EXPECT_TRUE(SC2Opt); +} + +TEST(CommandLineTest, LookupFailsInWrongSubCommand) { + cl::ResetCommandLineParser(); + + StackSubCommand SC1("sc1", "First subcommand"); + StackSubCommand SC2("sc2", "Second subcommand"); + + StackOption SC1Opt("sc1", cl::sub(SC1), cl::init(false)); + StackOption SC2Opt("sc2", cl::sub(SC2), cl::init(false)); + + const char *args[] = {"prog", "sc1", "-sc2"}; + EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, nullptr, true)); +} + +TEST(CommandLineTest, AddToAllSubCommands) { + cl::ResetCommandLineParser(); + + StackSubCommand SC1("sc1", "First subcommand"); + StackOption AllOpt("everywhere", cl::sub(*cl::AllSubCommands), + cl::init(false)); + StackSubCommand SC2("sc2", "Second subcommand"); + + const char *args[] = {"prog", "-everywhere"}; + const char *args2[] = {"prog", "sc1", "-everywhere"}; + const char *args3[] = {"prog", "sc2", "-everywhere"}; + + EXPECT_FALSE(AllOpt); + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true)); + EXPECT_TRUE(AllOpt); + + AllOpt = false; + + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(AllOpt); + EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, nullptr, true)); + EXPECT_TRUE(AllOpt); + + AllOpt = false; + + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(AllOpt); + EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, nullptr, true)); + EXPECT_TRUE(AllOpt); +} + +TEST(CommandLineTest, ReparseCommandLineOptions) { + cl::ResetCommandLineParser(); + + StackOption TopLevelOpt("top-level", cl::sub(*cl::TopLevelSubCommand), + cl::init(false)); + + const char *args[] = {"prog", "-top-level"}; + + EXPECT_FALSE(TopLevelOpt); + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true)); + EXPECT_TRUE(TopLevelOpt); + + TopLevelOpt = false; + + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(TopLevelOpt); + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true)); + EXPECT_TRUE(TopLevelOpt); +} + +TEST(CommandLineTest, RemoveFromRegularSubCommand) { + cl::ResetCommandLineParser(); + + StackSubCommand SC("sc", "Subcommand"); + StackOption RemoveOption("remove-option", cl::sub(SC), cl::init(false)); + StackOption KeepOption("keep-option", cl::sub(SC), cl::init(false)); + + const char *args[] = {"prog", "sc", "-remove-option"}; + + EXPECT_FALSE(RemoveOption); + EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, nullptr, true)); + EXPECT_TRUE(RemoveOption); + + RemoveOption.removeArgument(); + + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, nullptr, true)); +} + +TEST(CommandLineTest, RemoveFromTopLevelSubCommand) { + cl::ResetCommandLineParser(); + + StackOption TopLevelRemove( + "top-level-remove", cl::sub(*cl::TopLevelSubCommand), cl::init(false)); + StackOption TopLevelKeep( + "top-level-keep", cl::sub(*cl::TopLevelSubCommand), cl::init(false)); + + const char *args[] = {"prog", "-top-level-remove"}; + + EXPECT_FALSE(TopLevelRemove); + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, nullptr, true)); + EXPECT_TRUE(TopLevelRemove); + + TopLevelRemove.removeArgument(); + + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, nullptr, true)); +} + +TEST(CommandLineTest, RemoveFromAllSubCommands) { + cl::ResetCommandLineParser(); + + StackSubCommand SC1("sc1", "First Subcommand"); + StackSubCommand SC2("sc2", "Second Subcommand"); + StackOption RemoveOption("remove-option", cl::sub(*cl::AllSubCommands), + cl::init(false)); + StackOption KeepOption("keep-option", cl::sub(*cl::AllSubCommands), + cl::init(false)); + + const char *args0[] = {"prog", "-remove-option"}; + const char *args1[] = {"prog", "sc1", "-remove-option"}; + const char *args2[] = {"prog", "sc2", "-remove-option"}; + + // It should work for all subcommands including the top-level. + EXPECT_FALSE(RemoveOption); + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, nullptr, true)); + EXPECT_TRUE(RemoveOption); + + RemoveOption = false; + + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(RemoveOption); + EXPECT_TRUE(cl::ParseCommandLineOptions(3, args1, nullptr, true)); + EXPECT_TRUE(RemoveOption); + + RemoveOption = false; + + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(RemoveOption); + EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, nullptr, true)); + EXPECT_TRUE(RemoveOption); + + RemoveOption.removeArgument(); + + // It should not work for any subcommands including the top-level. + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(cl::ParseCommandLineOptions(2, args0, nullptr, true)); + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(cl::ParseCommandLineOptions(3, args1, nullptr, true)); + cl::ResetAllOptionOccurrences(); + EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, nullptr, true)); +} + } // anonymous namespace diff --git a/unittests/Support/ConvertUTFTest.cpp b/unittests/Support/ConvertUTFTest.cpp index 61ed252d6273d5a9e5347bf8a4f3d4ae7df1b245..0af09e98a2178cdffad35454ab195372d54c1b92 100644 --- a/unittests/Support/ConvertUTFTest.cpp +++ b/unittests/Support/ConvertUTFTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ConvertUTF.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Format.h" #include "gtest/gtest.h" #include diff --git a/unittests/Support/ErrorTest.cpp b/unittests/Support/ErrorTest.cpp index 7d714777c6584c8074c6c51bb7206aed9a65f4d2..205092683744023544a5242720c2d607ed7ebe0c 100644 --- a/unittests/Support/ErrorTest.cpp +++ b/unittests/Support/ErrorTest.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Error.h" + +#include "llvm/ADT/Twine.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "gtest/gtest.h" @@ -312,6 +314,51 @@ TEST(Error, CheckJoinErrors) { EXPECT_TRUE(CustomErrorInfo1 == 7 && CustomErrorInfo2 == 42 && CustomErrorExtraInfo == 7) << "Failed handling compound Error."; + + // Test appending a single item to a list. + { + int Sum = 0; + handleAllErrors( + joinErrors( + joinErrors(make_error(7), + make_error(7)), + make_error(7)), + [&](const CustomError &CE) { + Sum += CE.getInfo(); + }); + EXPECT_EQ(Sum, 21) << "Failed to correctly append error to error list."; + } + + // Test prepending a single item to a list. + { + int Sum = 0; + handleAllErrors( + joinErrors( + make_error(7), + joinErrors(make_error(7), + make_error(7))), + [&](const CustomError &CE) { + Sum += CE.getInfo(); + }); + EXPECT_EQ(Sum, 21) << "Failed to correctly prepend error to error list."; + } + + // Test concatenating two error lists. + { + int Sum = 0; + handleAllErrors( + joinErrors( + joinErrors( + make_error(7), + make_error(7)), + joinErrors( + make_error(7), + make_error(7))), + [&](const CustomError &CE) { + Sum += CE.getInfo(); + }); + EXPECT_EQ(Sum, 28) << "Failed to correctly concatenate erorr lists."; + } } // Test that we can consume success values. @@ -376,6 +423,20 @@ TEST(Error, CatchErrorFromHandler) { << "Failed to handle Error returned from handleErrors."; } +TEST(Error, StringError) { + std::string Msg; + raw_string_ostream S(Msg); + logAllUnhandledErrors(make_error("foo" + Twine(42), + inconvertibleErrorCode()), + S, ""); + EXPECT_EQ(S.str(), "foo42\n") << "Unexpected StringError log result"; + + auto EC = + errorToErrorCode(make_error("", errc::invalid_argument)); + EXPECT_EQ(EC, errc::invalid_argument) + << "Failed to convert StringError to error_code."; +} + // Test that the ExitOnError utility works as expected. TEST(Error, ExitOnError) { ExitOnError ExitOnErr; @@ -391,6 +452,10 @@ TEST(Error, ExitOnError) { EXPECT_EQ(ExitOnErr(Expected(7)), 7) << "exitOnError returned an invalid value for Expected"; + int A = 7; + int &B = ExitOnErr(Expected(A)); + EXPECT_EQ(&A, &B) << "ExitOnError failed to propagate reference"; + // Exit tests. EXPECT_EXIT(ExitOnErr(make_error(7)), ::testing::ExitedWithCode(1), "Error in tool:") @@ -401,13 +466,57 @@ TEST(Error, ExitOnError) { << "exitOnError returned an unexpected error result"; } -// Test Expected in success mode. -TEST(Error, ExpectedInSuccessMode) { +// Test Checked Expected in success mode. +TEST(Error, CheckedExpectedInSuccessMode) { Expected A = 7; EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'"; + // Access is safe in second test, since we checked the error in the first. EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value"; } +// Test Expected with reference type. +TEST(Error, ExpectedWithReferenceType) { + int A = 7; + Expected B = A; + // 'Check' B. + (void)!!B; + int &C = *B; + EXPECT_EQ(&A, &C) << "Expected failed to propagate reference"; +} + +// Test Unchecked Expected in success mode. +// We expect this to blow up the same way Error would. +// Test runs in debug mode only. +#ifndef NDEBUG +TEST(Error, UncheckedExpectedInSuccessModeDestruction) { + EXPECT_DEATH({ Expected A = 7; }, + "Expected must be checked before access or destruction.") + << "Unchecekd Expected success value did not cause an abort()."; +} +#endif + +// Test Unchecked Expected in success mode. +// We expect this to blow up the same way Error would. +// Test runs in debug mode only. +#ifndef NDEBUG +TEST(Error, UncheckedExpectedInSuccessModeAccess) { + EXPECT_DEATH({ Expected A = 7; *A; }, + "Expected must be checked before access or destruction.") + << "Unchecekd Expected success value did not cause an abort()."; +} +#endif + +// Test Unchecked Expected in success mode. +// We expect this to blow up the same way Error would. +// Test runs in debug mode only. +#ifndef NDEBUG +TEST(Error, UncheckedExpectedInSuccessModeAssignment) { + EXPECT_DEATH({ Expected A = 7; A = 7; }, + "Expected must be checked before access or destruction.") + << "Unchecekd Expected success value did not cause an abort()."; +} +#endif + // Test Expected in failure mode. TEST(Error, ExpectedInFailureMode) { Expected A = make_error(42); @@ -423,7 +532,7 @@ TEST(Error, ExpectedInFailureMode) { #ifndef NDEBUG TEST(Error, AccessExpectedInFailureMode) { Expected A = make_error(42); - EXPECT_DEATH(*A, "!HasError && \"Cannot get value when an error exists!\"") + EXPECT_DEATH(*A, "Expected must be checked before access or destruction.") << "Incorrect Expected error value"; consumeError(A.takeError()); } @@ -435,7 +544,7 @@ TEST(Error, AccessExpectedInFailureMode) { #ifndef NDEBUG TEST(Error, UnhandledExpectedInFailureMode) { EXPECT_DEATH({ Expected A = make_error(42); }, - "Program aborted due to an unhandled Error:") + "Expected must be checked before access or destruction.") << "Unchecked Expected failure value did not cause an abort()"; } #endif @@ -446,10 +555,18 @@ TEST(Error, ExpectedCovariance) { class D : public B {}; Expected A1(Expected(nullptr)); + // Check A1 by converting to bool before assigning to it. + (void)!!A1; A1 = Expected(nullptr); + // Check A1 again before destruction. + (void)!!A1; Expected> A2(Expected>(nullptr)); + // Check A2 by converting to bool before assigning to it. + (void)!!A2; A2 = Expected>(nullptr); + // Check A2 again before destruction. + (void)!!A2; } TEST(Error, ErrorCodeConversions) { @@ -488,4 +605,23 @@ TEST(Error, ErrorCodeConversions) { } } +// Test that error messages work. +TEST(Error, ErrorMessage) { + EXPECT_EQ(toString(Error::success()).compare(""), 0); + + Error E1 = make_error(0); + EXPECT_EQ(toString(std::move(E1)).compare("CustomError { 0}"), 0); + + Error E2 = make_error(0); + handleAllErrors(std::move(E2), [](const CustomError &CE) { + EXPECT_EQ(CE.message().compare("CustomError { 0}"), 0); + }); + + Error E3 = joinErrors(make_error(0), make_error(1)); + EXPECT_EQ(toString(std::move(E3)) + .compare("CustomError { 0}\n" + "CustomError { 1}"), + 0); +} + } // end anon namespace diff --git a/unittests/Support/MathExtrasTest.cpp b/unittests/Support/MathExtrasTest.cpp index 042f640ba8421a05747344cac62f62bd8cc5021e..04e16628e64b138595d4f2cbc2530e6efbe302e1 100644 --- a/unittests/Support/MathExtrasTest.cpp +++ b/unittests/Support/MathExtrasTest.cpp @@ -106,6 +106,35 @@ TEST(MathExtras, findLastSet) { EXPECT_EQ(5u, findLastSet(NZ64)); } +TEST(MathExtras, isIntN) { + EXPECT_TRUE(isIntN(16, 32767)); + EXPECT_FALSE(isIntN(16, 32768)); +} + +TEST(MathExtras, isUIntN) { + EXPECT_TRUE(isUIntN(16, 65535)); + EXPECT_FALSE(isUIntN(16, 65536)); + EXPECT_TRUE(isUIntN(1, 0)); + EXPECT_TRUE(isUIntN(6, 63)); +} + +TEST(MathExtras, maxIntN) { + EXPECT_EQ(32767, maxIntN(16)); + EXPECT_EQ(2147483647, maxIntN(32)); +} + +TEST(MathExtras, minIntN) { + EXPECT_EQ(-32768LL, minIntN(16)); + EXPECT_EQ(-64LL, minIntN(7)); +} + +TEST(MathExtras, maxUIntN) { + EXPECT_EQ(0xffffULL, maxUIntN(16)); + EXPECT_EQ(0xffffffffULL, maxUIntN(32)); + EXPECT_EQ(1ULL, maxUIntN(1)); + EXPECT_EQ(0x0fULL, maxUIntN(4)); +} + TEST(MathExtras, reverseBits) { uint8_t NZ8 = 42; uint16_t NZ16 = 42; diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp index 1653ac028d2e2ca8e71866cd85da2f9717b68391..1a6ffa50e983ef4d9f26ec53226ab26fe15391bd 100644 --- a/unittests/Support/Path.cpp +++ b/unittests/Support/Path.cpp @@ -17,6 +17,7 @@ #include "gtest/gtest.h" #ifdef LLVM_ON_WIN32 +#include "llvm/ADT/ArrayRef.h" #include #include #endif @@ -715,6 +716,20 @@ TEST_F(FileSystemTest, DirectoryIteration) { ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/z0/za1")); ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/z0")); ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive")); + + // Test recursive_directory_iterator level() + ASSERT_NO_ERROR( + fs::create_directories(Twine(TestDirectory) + "/reclevel/a/b/c")); + fs::recursive_directory_iterator I(Twine(TestDirectory) + "/reclevel", ec), E; + for (int l = 0; I != E; I.increment(ec), ++l) { + ASSERT_NO_ERROR(ec); + EXPECT_EQ(I.level(), l); + } + EXPECT_EQ(I, E); + ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a/b/c")); + ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a/b")); + ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a")); + ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel")); } const char archive[] = "!\x0A"; @@ -725,7 +740,7 @@ const char coff_bigobj[] = "\x00\x00\xff\xff\x00\x02......" const char coff_import_library[] = "\x00\x00\xff\xff...."; const char elf_relocatable[] = { 0x7f, 'E', 'L', 'F', 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; -const char macho_universal_binary[] = "\xca\xfe\xba\xbe...\0x00"; +const char macho_universal_binary[] = "\xca\xfe\xba\xbe...\x00"; const char macho_object[] = "\xfe\xed\xfa\xce........\x00\x00\x00\x01............"; const char macho_executable[] = @@ -955,4 +970,145 @@ TEST(Support, RemoveDots) { EXPECT_EQ("c", Path1); #endif } + +TEST(Support, ReplacePathPrefix) { + SmallString<64> Path1("/foo"); + SmallString<64> Path2("/old/foo"); + SmallString<64> OldPrefix("/old"); + SmallString<64> NewPrefix("/new"); + SmallString<64> NewPrefix2("/longernew"); + SmallString<64> EmptyPrefix(""); + + SmallString<64> Path = Path1; + path::replace_path_prefix(Path, OldPrefix, NewPrefix); + EXPECT_EQ(Path, "/foo"); + Path = Path2; + path::replace_path_prefix(Path, OldPrefix, NewPrefix); + EXPECT_EQ(Path, "/new/foo"); + Path = Path2; + path::replace_path_prefix(Path, OldPrefix, NewPrefix2); + EXPECT_EQ(Path, "/longernew/foo"); + Path = Path1; + path::replace_path_prefix(Path, EmptyPrefix, NewPrefix); + EXPECT_EQ(Path, "/new/foo"); + Path = Path2; + path::replace_path_prefix(Path, OldPrefix, EmptyPrefix); + EXPECT_EQ(Path, "/foo"); +} + +TEST_F(FileSystemTest, PathFromFD) { + // Create a temp file. + int FileDescriptor; + SmallString<64> TempPath; + ASSERT_NO_ERROR( + fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath)); + + // Make sure it exists. + ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); + + // Try to get the path from the file descriptor + SmallString<64> ResultPath; + std::error_code ErrorCode = + fs::getPathFromOpenFD(FileDescriptor, ResultPath); + + // If we succeeded, check that the paths are the same (modulo case): + if (!ErrorCode) { + // The paths returned by createTemporaryFile and getPathFromOpenFD + // should reference the same file on disk. + fs::UniqueID D1, D2; + ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1)); + ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2)); + ASSERT_EQ(D1, D2); + } + + ::close(FileDescriptor); +} + +TEST_F(FileSystemTest, PathFromFDWin32) { + // Create a temp file. + int FileDescriptor; + SmallString<64> TempPath; + ASSERT_NO_ERROR( + fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath)); + + // Make sure it exists. + ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); + + SmallVector ResultPath; + std::error_code ErrorCode = + fs::getPathFromOpenFD(FileDescriptor, ResultPath); + + if (!ErrorCode) { + // Now that we know how much space is required for the path, create a path + // buffer with exactly enough space (sans null terminator, which should not + // be present), and call getPathFromOpenFD again to ensure that the API + // properly handles exactly-sized buffers. + SmallVector ExactSizedPath(ResultPath.size()); + ErrorCode = fs::getPathFromOpenFD(FileDescriptor, ExactSizedPath); + ResultPath = ExactSizedPath; + } + + if (!ErrorCode) { + fs::UniqueID D1, D2; + ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1)); + ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2)); + ASSERT_EQ(D1, D2); + } + ::close(FileDescriptor); +} + +TEST_F(FileSystemTest, PathFromFDUnicode) { + // Create a temp file. + int FileDescriptor; + SmallString<64> TempPath; + + // Test Unicode: "/(pi)r^2.aleth.0" + ASSERT_NO_ERROR( + fs::createTemporaryFile("\xCF\x80r\xC2\xB2", + "\xE2\x84\xB5.0", FileDescriptor, TempPath)); + + // Make sure it exists. + ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); + + SmallVector ResultPath; + std::error_code ErrorCode = + fs::getPathFromOpenFD(FileDescriptor, ResultPath); + + if (!ErrorCode) { + fs::UniqueID D1, D2; + ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1)); + ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2)); + ASSERT_EQ(D1, D2); + } + ::close(FileDescriptor); +} + +TEST_F(FileSystemTest, OpenFileForRead) { + // Create a temp file. + int FileDescriptor; + SmallString<64> TempPath; + ASSERT_NO_ERROR( + fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath)); + + // Make sure it exists. + ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); + + // Open the file for read + int FileDescriptor2; + SmallString<64> ResultPath; + ASSERT_NO_ERROR( + fs::openFileForRead(Twine(TempPath), FileDescriptor2, &ResultPath)) + + // If we succeeded, check that the paths are the same (modulo case): + if (!ResultPath.empty()) { + // The paths returned by createTemporaryFile and getPathFromOpenFD + // should reference the same file on disk. + fs::UniqueID D1, D2; + ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1)); + ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2)); + ASSERT_EQ(D1, D2); + } + + ::close(FileDescriptor); +} } // anonymous namespace diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp index deadaadec1df276d0f4f72c99e0b853978745f7f..886ead8305bc1cb32896697ae74cabe27fdd3588 100644 --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -231,7 +231,7 @@ TEST_F(ProgramEnvTest, TestExecuteNoWait) { // LoopCount should only be incremented once. while (true) { ++LoopCount; - ProcessInfo WaitResult = Wait(PI1, 0, true, &Error); + ProcessInfo WaitResult = llvm::sys::Wait(PI1, 0, true, &Error); ASSERT_TRUE(Error.empty()); if (WaitResult.Pid == PI1.Pid) break; @@ -248,7 +248,7 @@ TEST_F(ProgramEnvTest, TestExecuteNoWait) { // cse, LoopCount should be greater than 1 (more than one increment occurs). while (true) { ++LoopCount; - ProcessInfo WaitResult = Wait(PI2, 0, false, &Error); + ProcessInfo WaitResult = llvm::sys::Wait(PI2, 0, false, &Error); ASSERT_TRUE(Error.empty()); if (WaitResult.Pid == PI2.Pid) break; diff --git a/unittests/Support/TargetParserTest.cpp b/unittests/Support/TargetParserTest.cpp index 4bdf03aa861a366415c744bfb54815318ddf3e26..21994f27b73cd8396cc16803a5f5d86a12456e6a 100644 --- a/unittests/Support/TargetParserTest.cpp +++ b/unittests/Support/TargetParserTest.cpp @@ -13,6 +13,20 @@ using namespace llvm; namespace { +static const unsigned kAArch64ArchKinds[] = { +#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, \ + ARCH_BASE_EXT) \ + llvm::ARM::ID, +#include "llvm/Support/AArch64TargetParser.def" +#undef AARCH64_ARCH +}; + +template +bool contains(const T (&array)[N], const T element) { + return std::find(std::begin(array), std::end(array), element) != + std::end(array); +} + TEST(TargetParserTest, ARMArchName) { for (ARM::ArchKind AK = static_cast(0); AK <= ARM::ArchKind::AK_LAST; @@ -47,5 +61,32 @@ TEST(TargetParserTest, ARMFPUName) { EXPECT_TRUE(FK == ARM::FK_LAST ? ARM::getFPUName(FK).empty() : !ARM::getFPUName(FK).empty()); } + +TEST(TargetParserTest, AArch64ArchName) { + for (ARM::ArchKind AK = static_cast(0); + AK <= ARM::ArchKind::AK_LAST; + AK = static_cast(static_cast(AK) + 1)) + EXPECT_TRUE(contains(kAArch64ArchKinds, static_cast(AK)) + ? !AArch64::getArchName(AK).empty() + : AArch64::getArchName(AK).empty()); +} + +TEST(TargetParserTest, AArch64CPUAttr) { + for (ARM::ArchKind AK = static_cast(0); + AK <= ARM::ArchKind::AK_LAST; + AK = static_cast(static_cast(AK) + 1)) + EXPECT_TRUE(contains(kAArch64ArchKinds, static_cast(AK)) + ? !AArch64::getCPUAttr(AK).empty() + : AArch64::getCPUAttr(AK).empty()); +} + +TEST(TargetParserTest, AArch64SubArch) { + for (ARM::ArchKind AK = static_cast(0); + AK <= ARM::ArchKind::AK_LAST; + AK = static_cast(static_cast(AK) + 1)) + EXPECT_TRUE(contains(kAArch64ArchKinds, static_cast(AK)) + ? !AArch64::getSubArch(AK).empty() + : AArch64::getSubArch(AK).empty()); +} } diff --git a/unittests/Support/ThreadPool.cpp b/unittests/Support/ThreadPool.cpp index 0f36c383d494cf4dc2db25706a834d55f678dcbe..69a24bc5444c05e597b5171c87ed0cef8e0a4cf8 100644 --- a/unittests/Support/ThreadPool.cpp +++ b/unittests/Support/ThreadPool.cpp @@ -135,7 +135,7 @@ TEST_F(ThreadPoolTest, Async) { TEST_F(ThreadPoolTest, GetFuture) { CHECK_UNSUPPORTED(); - ThreadPool Pool; + ThreadPool Pool{2}; std::atomic_int i{0}; Pool.async([this, &i] { waitForMainThread(); diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp index e7affa1698dcc7989ca59bdf23549f9164fac76d..5f35a802caa5ea8440f5c3dea3a9c0c2948f8579 100644 --- a/unittests/Support/YAMLIOTest.cpp +++ b/unittests/Support/YAMLIOTest.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/Format.h" #include "llvm/Support/YAMLTraits.h" #include "gtest/gtest.h" @@ -389,6 +389,111 @@ TEST(YAMLIO, TestReadWriteBuiltInTypes) { } } +//===----------------------------------------------------------------------===// +// Test endian-aware types +//===----------------------------------------------------------------------===// + +struct EndianTypes { + typedef llvm::support::detail::packed_endian_specific_integral< + float, llvm::support::little, llvm::support::unaligned> + ulittle_float; + typedef llvm::support::detail::packed_endian_specific_integral< + double, llvm::support::little, llvm::support::unaligned> + ulittle_double; + + llvm::support::ulittle64_t u64; + llvm::support::ulittle32_t u32; + llvm::support::ulittle16_t u16; + llvm::support::little64_t s64; + llvm::support::little32_t s32; + llvm::support::little16_t s16; + ulittle_float f; + ulittle_double d; +}; + +namespace llvm { +namespace yaml { +template <> struct MappingTraits { + static void mapping(IO &io, EndianTypes &et) { + io.mapRequired("u64", et.u64); + io.mapRequired("u32", et.u32); + io.mapRequired("u16", et.u16); + io.mapRequired("s64", et.s64); + io.mapRequired("s32", et.s32); + io.mapRequired("s16", et.s16); + io.mapRequired("f", et.f); + io.mapRequired("d", et.d); + } +}; +} +} + +// +// Test the reading of all endian scalar conversions +// +TEST(YAMLIO, TestReadEndianTypes) { + EndianTypes map; + Input yin("---\n" + "u64: 5000000000\n" + "u32: 4000000000\n" + "u16: 65000\n" + "s64: -5000000000\n" + "s32: -2000000000\n" + "s16: -32000\n" + "f: 3.25\n" + "d: -2.8625\n" + "...\n"); + yin >> map; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(map.u64, 5000000000ULL); + EXPECT_EQ(map.u32, 4000000000U); + EXPECT_EQ(map.u16, 65000); + EXPECT_EQ(map.s64, -5000000000LL); + EXPECT_EQ(map.s32, -2000000000L); + EXPECT_EQ(map.s16, -32000); + EXPECT_EQ(map.f, 3.25f); + EXPECT_EQ(map.d, -2.8625); +} + +// +// Test writing then reading back all endian-aware scalar types +// +TEST(YAMLIO, TestReadWriteEndianTypes) { + std::string intermediate; + { + EndianTypes map; + map.u64 = 6000000000ULL; + map.u32 = 3000000000U; + map.u16 = 50000; + map.s64 = -6000000000LL; + map.s32 = -2000000000; + map.s16 = -32000; + map.f = 3.25f; + map.d = -2.8625; + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << map; + } + + { + Input yin(intermediate); + EndianTypes map; + yin >> map; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(map.u64, 6000000000ULL); + EXPECT_EQ(map.u32, 3000000000U); + EXPECT_EQ(map.u16, 50000); + EXPECT_EQ(map.s64, -6000000000LL); + EXPECT_EQ(map.s32, -2000000000L); + EXPECT_EQ(map.s16, -32000); + EXPECT_EQ(map.f, 3.25f); + EXPECT_EQ(map.d, -2.8625); + } +} + struct StringTypes { llvm::StringRef str1; llvm::StringRef str2; diff --git a/unittests/Support/YAMLParserTest.cpp b/unittests/Support/YAMLParserTest.cpp index 41ad649699caa01d2f7dd9987c084c8339ae3141..3f12a53fd9c59d05ba62f6e0ff16a3cc853dedf8 100644 --- a/unittests/Support/YAMLParserTest.cpp +++ b/unittests/Support/YAMLParserTest.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Casting.h" #include "llvm/Support/MemoryBuffer.h" diff --git a/unittests/Support/raw_sha1_ostream_test.cpp b/unittests/Support/raw_sha1_ostream_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db2a3e9ab643e5c7333901d6c889d169652066ba --- /dev/null +++ b/unittests/Support/raw_sha1_ostream_test.cpp @@ -0,0 +1,71 @@ +//===- llvm/unittest/Support/raw_ostream_test.cpp - raw_ostream tests -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_sha1_ostream.h" + +#include + +using namespace llvm; + +static std::string toHex(StringRef Input) { + static const char *const LUT = "0123456789ABCDEF"; + size_t Length = Input.size(); + + std::string Output; + Output.reserve(2 * Length); + for (size_t i = 0; i < Length; ++i) { + const unsigned char c = Input[i]; + Output.push_back(LUT[c >> 4]); + Output.push_back(LUT[c & 15]); + } + return Output; +} + +TEST(raw_sha1_ostreamTest, Basic) { + llvm::raw_sha1_ostream Sha1Stream; + Sha1Stream << "Hello World!"; + auto Hash = toHex(Sha1Stream.sha1()); + + ASSERT_EQ("2EF7BDE608CE5404E97D5F042F95F89F1C232871", Hash); +} + +// Check that getting the intermediate hash in the middle of the stream does +// not invalidate the final result. +TEST(raw_sha1_ostreamTest, Intermediate) { + llvm::raw_sha1_ostream Sha1Stream; + Sha1Stream << "Hello"; + auto Hash = toHex(Sha1Stream.sha1()); + + ASSERT_EQ("F7FF9E8B7BB2E09B70935A5D785E0CC5D9D0ABF0", Hash); + Sha1Stream << " World!"; + Hash = toHex(Sha1Stream.sha1()); + + // Compute the non-split hash separately as a reference. + llvm::raw_sha1_ostream NonSplitSha1Stream; + NonSplitSha1Stream << "Hello World!"; + auto NonSplitHash = toHex(NonSplitSha1Stream.sha1()); + + ASSERT_EQ(NonSplitHash, Hash); +} + +TEST(raw_sha1_ostreamTest, Reset) { + llvm::raw_sha1_ostream Sha1Stream; + Sha1Stream << "Hello"; + auto Hash = toHex(Sha1Stream.sha1()); + + ASSERT_EQ("F7FF9E8B7BB2E09B70935A5D785E0CC5D9D0ABF0", Hash); + + Sha1Stream.resetHash(); + Sha1Stream << " World!"; + Hash = toHex(Sha1Stream.sha1()); + + ASSERT_EQ("7447F2A5A42185C8CF91E632789C431830B59067", Hash); +} diff --git a/unittests/Transforms/IPO/CMakeLists.txt b/unittests/Transforms/IPO/CMakeLists.txt index 445f70354e71e0a29f44bfa7a9df772c2f89afe5..ee33a5fcd1b39aed74bec730d30c0c945e45e776 100644 --- a/unittests/Transforms/IPO/CMakeLists.txt +++ b/unittests/Transforms/IPO/CMakeLists.txt @@ -5,6 +5,6 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_unittest(IPOTests - LowerBitSets.cpp + LowerTypeTests.cpp WholeProgramDevirt.cpp ) diff --git a/unittests/Transforms/IPO/LowerBitSets.cpp b/unittests/Transforms/IPO/LowerTypeTests.cpp similarity index 93% rename from unittests/Transforms/IPO/LowerBitSets.cpp rename to unittests/Transforms/IPO/LowerTypeTests.cpp index 49a42cd20d7a940696375ded372e63c6f8ea8934..66c9de6bd662015afc054d94f68f56a4344c712d 100644 --- a/unittests/Transforms/IPO/LowerBitSets.cpp +++ b/unittests/Transforms/IPO/LowerTypeTests.cpp @@ -1,4 +1,4 @@ -//===- LowerBitSets.cpp - Unit tests for bitset lowering ------------------===// +//===- LowerTypeTests.cpp - Unit tests for type test lowering -------------===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,13 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/IPO/LowerBitSets.h" +#include "llvm/Transforms/IPO/LowerTypeTests.h" #include "gtest/gtest.h" using namespace llvm; +using namespace lowertypetests; -TEST(LowerBitSets, BitSetBuilder) { +TEST(LowerTypeTests, BitSetBuilder) { struct { std::vector Offsets; std::set Bits; @@ -79,7 +80,7 @@ TEST(LowerBitSets, BitSetBuilder) { } } -TEST(LowerBitSets, GlobalLayoutBuilder) { +TEST(LowerTypeTests, GlobalLayoutBuilder) { struct { uint64_t NumObjects; std::vector> Fragments; @@ -106,7 +107,7 @@ TEST(LowerBitSets, GlobalLayoutBuilder) { } } -TEST(LowerBitSets, ByteArrayBuilder) { +TEST(LowerTypeTests, ByteArrayBuilder) { struct BABAlloc { std::set Bits; uint64_t BitSize; diff --git a/unittests/Transforms/IPO/WholeProgramDevirt.cpp b/unittests/Transforms/IPO/WholeProgramDevirt.cpp index 2a79f02f83d2093b4e8a51e7f34c8c37cf1c5464..7e7a6bf459641037a270f2b18cfb95fd41ccebe1 100644 --- a/unittests/Transforms/IPO/WholeProgramDevirt.cpp +++ b/unittests/Transforms/IPO/WholeProgramDevirt.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO/WholeProgramDevirt.h" +#include "llvm/ADT/ArrayRef.h" #include "gtest/gtest.h" using namespace llvm; @@ -24,11 +25,11 @@ TEST(WholeProgramDevirt, findLowestOffset) { VT2.Before.BytesUsed = {1 << 1}; VT2.After.BytesUsed = {1 << 0}; - BitSetInfo BS1{&VT1, 0}; - BitSetInfo BS2{&VT2, 0}; + TypeMemberInfo TM1{&VT1, 0}; + TypeMemberInfo TM2{&VT2, 0}; VirtualCallTarget Targets[] = { - {&BS1, /*IsBigEndian=*/false}, - {&BS2, /*IsBigEndian=*/false}, + {&TM1, /*IsBigEndian=*/false}, + {&TM2, /*IsBigEndian=*/false}, }; EXPECT_EQ(2ull, findLowestOffset(Targets, /*IsAfter=*/false, 1)); @@ -37,15 +38,15 @@ TEST(WholeProgramDevirt, findLowestOffset) { EXPECT_EQ(8ull, findLowestOffset(Targets, /*IsAfter=*/false, 8)); EXPECT_EQ(72ull, findLowestOffset(Targets, /*IsAfter=*/true, 8)); - BS1.Offset = 4; + TM1.Offset = 4; EXPECT_EQ(33ull, findLowestOffset(Targets, /*IsAfter=*/false, 1)); EXPECT_EQ(65ull, findLowestOffset(Targets, /*IsAfter=*/true, 1)); EXPECT_EQ(40ull, findLowestOffset(Targets, /*IsAfter=*/false, 8)); EXPECT_EQ(72ull, findLowestOffset(Targets, /*IsAfter=*/true, 8)); - BS1.Offset = 8; - BS2.Offset = 8; + TM1.Offset = 8; + TM2.Offset = 8; EXPECT_EQ(66ull, findLowestOffset(Targets, /*IsAfter=*/false, 1)); EXPECT_EQ(2ull, findLowestOffset(Targets, /*IsAfter=*/true, 1)); @@ -65,15 +66,15 @@ TEST(WholeProgramDevirt, setReturnValues) { VTableBits VT2; VT2.ObjectSize = 8; - BitSetInfo BS1{&VT1, 0}; - BitSetInfo BS2{&VT2, 0}; + TypeMemberInfo TM1{&VT1, 0}; + TypeMemberInfo TM2{&VT2, 0}; VirtualCallTarget Targets[] = { - {&BS1, /*IsBigEndian=*/false}, - {&BS2, /*IsBigEndian=*/false}, + {&TM1, /*IsBigEndian=*/false}, + {&TM2, /*IsBigEndian=*/false}, }; - BS1.Offset = 4; - BS2.Offset = 4; + TM1.Offset = 4; + TM2.Offset = 4; int64_t OffsetByte; uint64_t OffsetBit; diff --git a/unittests/Transforms/Utils/Cloning.cpp b/unittests/Transforms/Utils/Cloning.cpp index b761e4e220ef7462fc57ceb757596d65d6747c18..f53e0a95e94dccac15a68c3d902d513897731b33 100644 --- a/unittests/Transforms/Utils/Cloning.cpp +++ b/unittests/Transforms/Utils/Cloning.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/Argument.h" @@ -275,8 +274,7 @@ protected: void CreateNewFunc() { ValueToValueMapTy VMap; - NewFunc = CloneFunction(OldFunc, VMap, true, nullptr); - M->getFunctionList().push_back(NewFunc); + NewFunc = CloneFunction(OldFunc, VMap, nullptr); } void SetupFinder() { @@ -302,31 +300,13 @@ TEST_F(CloneFunc, Subprogram) { EXPECT_FALSE(verifyModule(*M)); unsigned SubprogramCount = Finder->subprogram_count(); - EXPECT_EQ(2U, SubprogramCount); + EXPECT_EQ(1U, SubprogramCount); auto Iter = Finder->subprograms().begin(); - auto *Sub1 = cast(*Iter); - Iter++; - auto *Sub2 = cast(*Iter); + auto *Sub = cast(*Iter); - EXPECT_TRUE( - (Sub1 == OldFunc->getSubprogram() && Sub2 == NewFunc->getSubprogram()) || - (Sub1 == NewFunc->getSubprogram() && Sub2 == OldFunc->getSubprogram())); -} - -// Test that the new subprogram entry was not added to the CU which doesn't -// contain the old subprogram entry. -TEST_F(CloneFunc, SubprogramInRightCU) { - EXPECT_FALSE(verifyModule(*M)); - - EXPECT_EQ(2U, Finder->compile_unit_count()); - - auto Iter = Finder->compile_units().begin(); - auto *CU1 = cast(*Iter); - Iter++; - auto *CU2 = cast(*Iter); - EXPECT_TRUE(CU1->getSubprograms().size() == 0 || - CU2->getSubprograms().size() == 0); + EXPECT_TRUE(Sub == OldFunc->getSubprogram()); + EXPECT_TRUE(Sub == NewFunc->getSubprogram()); } // Test that instructions in the old function still belong to it in the @@ -464,6 +444,12 @@ TEST_F(CloneModule, Verify) { EXPECT_FALSE(verifyModule(*NewM)); } +TEST_F(CloneModule, OldModuleUnchanged) { + DebugInfoFinder Finder; + Finder.processModule(*OldM); + EXPECT_EQ(1U, Finder.subprogram_count()); +} + TEST_F(CloneModule, Subprogram) { Function *NewF = NewM->getFunction("f"); DISubprogram *SP = NewF->getSubprogram(); diff --git a/unittests/Transforms/Utils/IntegerDivision.cpp b/unittests/Transforms/Utils/IntegerDivision.cpp index 4cda2b4e58927ff26f1158a617df92f8810a96af..b6b1b1665ab1f2b7be25bea1c111850469fbf890 100644 --- a/unittests/Transforms/Utils/IntegerDivision.cpp +++ b/unittests/Transforms/Utils/IntegerDivision.cpp @@ -21,7 +21,7 @@ namespace { TEST(IntegerDivision, SDiv) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Module M("test division", C); IRBuilder<> Builder(C); @@ -51,7 +51,7 @@ TEST(IntegerDivision, SDiv) { } TEST(IntegerDivision, UDiv) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Module M("test division", C); IRBuilder<> Builder(C); @@ -81,7 +81,7 @@ TEST(IntegerDivision, UDiv) { } TEST(IntegerDivision, SRem) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Module M("test remainder", C); IRBuilder<> Builder(C); @@ -111,7 +111,7 @@ TEST(IntegerDivision, SRem) { } TEST(IntegerDivision, URem) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Module M("test remainder", C); IRBuilder<> Builder(C); @@ -142,7 +142,7 @@ TEST(IntegerDivision, URem) { TEST(IntegerDivision, SDiv64) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Module M("test division", C); IRBuilder<> Builder(C); @@ -172,7 +172,7 @@ TEST(IntegerDivision, SDiv64) { } TEST(IntegerDivision, UDiv64) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Module M("test division", C); IRBuilder<> Builder(C); @@ -202,7 +202,7 @@ TEST(IntegerDivision, UDiv64) { } TEST(IntegerDivision, SRem64) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Module M("test remainder", C); IRBuilder<> Builder(C); @@ -232,7 +232,7 @@ TEST(IntegerDivision, SRem64) { } TEST(IntegerDivision, URem64) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; Module M("test remainder", C); IRBuilder<> Builder(C); diff --git a/unittests/Transforms/Utils/Local.cpp b/unittests/Transforms/Utils/Local.cpp index 2ff560475551678d7f8ed85318ec6db7a1d418e7..5164bdbb2a4efd7d59219d5b2caf0f03e8925d22 100644 --- a/unittests/Transforms/Utils/Local.cpp +++ b/unittests/Transforms/Utils/Local.cpp @@ -17,7 +17,7 @@ using namespace llvm; TEST(Local, RecursivelyDeleteDeadPHINodes) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; IRBuilder<> builder(C); @@ -60,7 +60,7 @@ TEST(Local, RecursivelyDeleteDeadPHINodes) { } TEST(Local, RemoveDuplicatePHINodes) { - LLVMContext &C(getGlobalContext()); + LLVMContext C; IRBuilder<> B(C); std::unique_ptr F( diff --git a/unittests/Transforms/Utils/MemorySSA.cpp b/unittests/Transforms/Utils/MemorySSA.cpp index 48bbe476a302f39a8dfba03b29277c61b4a40b96..c21121f78705fdbc35a625c1086985f41ebb51c5 100644 --- a/unittests/Transforms/Utils/MemorySSA.cpp +++ b/unittests/Transforms/Utils/MemorySSA.cpp @@ -6,11 +6,11 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -#include "llvm/IR/DataLayout.h" #include "llvm/Transforms/Utils/MemorySSA.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/IR/BasicBlock.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" @@ -19,20 +19,100 @@ using namespace llvm; -TEST(MemorySSA, RemoveMemoryAccess) { - LLVMContext &C(getGlobalContext()); - std::unique_ptr M(new Module("Remove memory access", C)); - IRBuilder<> B(C); - DataLayout DL("e-i64:64-f80:128-n8:16:32:64-S128"); +const static char DLString[] = "e-i64:64-f80:128-n8:16:32:64-S128"; + +/// There's a lot of common setup between these tests. This fixture helps reduce +/// that. Tests should mock up a function, store it in F, and then call +/// setupAnalyses(). +class MemorySSATest : public testing::Test { +protected: + // N.B. Many of these members depend on each other (e.g. the Module depends on + // the Context, etc.). So, order matters here (and in TestAnalyses). + LLVMContext C; + Module M; + IRBuilder<> B; + DataLayout DL; TargetLibraryInfoImpl TLII; - TargetLibraryInfo TLI(TLII); + TargetLibraryInfo TLI; + Function *F; + + // Things that we need to build after the function is created. + struct TestAnalyses { + DominatorTree DT; + AssumptionCache AC; + AAResults AA; + BasicAAResult BAA; + MemorySSA MSSA; + MemorySSAWalker *Walker; + + TestAnalyses(MemorySSATest &Test) + : DT(*Test.F), AC(*Test.F), AA(Test.TLI), + BAA(Test.DL, Test.TLI, AC, &DT), MSSA(*Test.F, &AA, &DT) { + AA.addAAResult(BAA); + Walker = MSSA.getWalker(); + } + }; + + std::unique_ptr Analyses; + + void setupAnalyses() { + assert(F); + Analyses.reset(new TestAnalyses(*this)); + } + +public: + MemorySSATest() + : M("MemorySSATest", C), B(C), DL(DLString), TLI(TLII), F(nullptr) {} +}; + +TEST_F(MemorySSATest, CreateALoadAndPhi) { + // We create a diamond where there is a store on one side, and then after + // running memory ssa, create a load after the merge point, and use it to test + // updating by creating an access for the load and a memoryphi. + F = Function::Create( + FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false), + GlobalValue::ExternalLinkage, "F", &M); + BasicBlock *Entry(BasicBlock::Create(C, "", F)); + BasicBlock *Left(BasicBlock::Create(C, "", F)); + BasicBlock *Right(BasicBlock::Create(C, "", F)); + BasicBlock *Merge(BasicBlock::Create(C, "", F)); + B.SetInsertPoint(Entry); + B.CreateCondBr(B.getTrue(), Left, Right); + B.SetInsertPoint(Left); + Argument *PointerArg = &*F->arg_begin(); + StoreInst *StoreInst = B.CreateStore(B.getInt8(16), PointerArg); + BranchInst::Create(Merge, Left); + BranchInst::Create(Merge, Right); + + setupAnalyses(); + MemorySSA &MSSA = Analyses->MSSA; + // Add the load + B.SetInsertPoint(Merge); + LoadInst *LoadInst = B.CreateLoad(PointerArg); + // Should be no phi to start + EXPECT_EQ(MSSA.getMemoryAccess(Merge), nullptr); + + // Create the phi + MemoryPhi *MP = MSSA.createMemoryPhi(Merge); + MemoryDef *StoreAccess = cast(MSSA.getMemoryAccess(StoreInst)); + MP->addIncoming(StoreAccess, Left); + MP->addIncoming(MSSA.getLiveOnEntryDef(), Right); + + // Create the load memory acccess + MemoryUse *LoadAccess = cast( + MSSA.createMemoryAccessInBB(LoadInst, MP, Merge, MemorySSA::Beginning)); + MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess(); + EXPECT_TRUE(isa(DefiningAccess)); + MSSA.verifyMemorySSA(); +} +TEST_F(MemorySSATest, RemoveAPhi) { // We create a diamond where there is a store on one side, and then a load // after the merge point. This enables us to test a bunch of different // removal cases. - Function *F = Function::Create( + F = Function::Create( FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false), - GlobalValue::ExternalLinkage, "F", M.get()); + GlobalValue::ExternalLinkage, "F", &M); BasicBlock *Entry(BasicBlock::Create(C, "", F)); BasicBlock *Left(BasicBlock::Create(C, "", F)); BasicBlock *Right(BasicBlock::Create(C, "", F)); @@ -47,24 +127,64 @@ TEST(MemorySSA, RemoveMemoryAccess) { B.SetInsertPoint(Merge); LoadInst *LoadInst = B.CreateLoad(PointerArg); - std::unique_ptr MSSA(new MemorySSA(*F)); - std::unique_ptr DT(new DominatorTree(*F)); - std::unique_ptr AC(new AssumptionCache(*F)); - AAResults AA(TLI); - BasicAAResult BAA(DL, TLI, *AC, &*DT); - AA.addAAResult(BAA); - std::unique_ptr Walker(MSSA->buildMemorySSA(&AA, &*DT)); + setupAnalyses(); + MemorySSA &MSSA = Analyses->MSSA; + // Before, the load will be a use of a phi. + MemoryUse *LoadAccess = cast(MSSA.getMemoryAccess(LoadInst)); + MemoryDef *StoreAccess = cast(MSSA.getMemoryAccess(StoreInst)); + MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess(); + EXPECT_TRUE(isa(DefiningAccess)); + // Kill the store + MSSA.removeMemoryAccess(StoreAccess); + MemoryPhi *MP = cast(DefiningAccess); + // Verify the phi ended up as liveonentry, liveonentry + for (auto &Op : MP->incoming_values()) + EXPECT_TRUE(MSSA.isLiveOnEntryDef(cast(Op.get()))); + // Replace the phi uses with the live on entry def + MP->replaceAllUsesWith(MSSA.getLiveOnEntryDef()); + // Verify the load is now defined by liveOnEntryDef + EXPECT_TRUE(MSSA.isLiveOnEntryDef(LoadAccess->getDefiningAccess())); + // Remove the PHI + MSSA.removeMemoryAccess(MP); + MSSA.verifyMemorySSA(); +} + +TEST_F(MemorySSATest, RemoveMemoryAccess) { + // We create a diamond where there is a store on one side, and then a load + // after the merge point. This enables us to test a bunch of different + // removal cases. + F = Function::Create( + FunctionType::get(B.getVoidTy(), {B.getInt8PtrTy()}, false), + GlobalValue::ExternalLinkage, "F", &M); + BasicBlock *Entry(BasicBlock::Create(C, "", F)); + BasicBlock *Left(BasicBlock::Create(C, "", F)); + BasicBlock *Right(BasicBlock::Create(C, "", F)); + BasicBlock *Merge(BasicBlock::Create(C, "", F)); + B.SetInsertPoint(Entry); + B.CreateCondBr(B.getTrue(), Left, Right); + B.SetInsertPoint(Left); + Argument *PointerArg = &*F->arg_begin(); + StoreInst *StoreInst = B.CreateStore(B.getInt8(16), PointerArg); + BranchInst::Create(Merge, Left); + BranchInst::Create(Merge, Right); + B.SetInsertPoint(Merge); + LoadInst *LoadInst = B.CreateLoad(PointerArg); + + setupAnalyses(); + MemorySSA &MSSA = Analyses->MSSA; + MemorySSAWalker *Walker = Analyses->Walker; + // Before, the load will be a use of a phi. It should be // the same after. - MemoryUse *LoadAccess = cast(MSSA->getMemoryAccess(LoadInst)); - MemoryDef *StoreAccess = cast(MSSA->getMemoryAccess(StoreInst)); + MemoryUse *LoadAccess = cast(MSSA.getMemoryAccess(LoadInst)); + MemoryDef *StoreAccess = cast(MSSA.getMemoryAccess(StoreInst)); MemoryAccess *DefiningAccess = LoadAccess->getDefiningAccess(); EXPECT_TRUE(isa(DefiningAccess)); // The load is currently clobbered by one of the phi arguments, so the walker // should determine the clobbering access as the phi. EXPECT_EQ(DefiningAccess, Walker->getClobberingMemoryAccess(LoadInst)); - MSSA->removeMemoryAccess(StoreAccess); - MSSA->verifyMemorySSA(); + MSSA.removeMemoryAccess(StoreAccess); + MSSA.verifyMemorySSA(); // After the removeaccess, let's see if we got the right accesses // The load should still point to the phi ... EXPECT_EQ(DefiningAccess, LoadAccess->getDefiningAccess()); @@ -72,17 +192,119 @@ TEST(MemorySSA, RemoveMemoryAccess) { // load, since it will walk past the phi node since every argument is the // same. EXPECT_TRUE( - MSSA->isLiveOnEntryDef(Walker->getClobberingMemoryAccess(LoadInst))); + MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(LoadInst))); // The phi should now be a two entry phi with two live on entry defs. for (const auto &Op : DefiningAccess->operands()) { MemoryAccess *Operand = cast(&*Op); - EXPECT_TRUE(MSSA->isLiveOnEntryDef(Operand)); + EXPECT_TRUE(MSSA.isLiveOnEntryDef(Operand)); } // Now we try to remove the single valued phi - MSSA->removeMemoryAccess(DefiningAccess); - MSSA->verifyMemorySSA(); + MSSA.removeMemoryAccess(DefiningAccess); + MSSA.verifyMemorySSA(); // Now the load should be a load of live on entry. - EXPECT_TRUE(MSSA->isLiveOnEntryDef(LoadAccess->getDefiningAccess())); + EXPECT_TRUE(MSSA.isLiveOnEntryDef(LoadAccess->getDefiningAccess())); +} + +// We had a bug with caching where the walker would report MemoryDef#3's clobber +// (below) was MemoryDef#1. +// +// define void @F(i8*) { +// %A = alloca i8, i8 1 +// ; 1 = MemoryDef(liveOnEntry) +// store i8 0, i8* %A +// ; 2 = MemoryDef(1) +// store i8 1, i8* %A +// ; 3 = MemoryDef(2) +// store i8 2, i8* %A +// } +TEST_F(MemorySSATest, TestTripleStore) { + F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false), + GlobalValue::ExternalLinkage, "F", &M); + B.SetInsertPoint(BasicBlock::Create(C, "", F)); + Type *Int8 = Type::getInt8Ty(C); + Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A"); + StoreInst *S1 = B.CreateStore(ConstantInt::get(Int8, 0), Alloca); + StoreInst *S2 = B.CreateStore(ConstantInt::get(Int8, 1), Alloca); + StoreInst *S3 = B.CreateStore(ConstantInt::get(Int8, 2), Alloca); + + setupAnalyses(); + MemorySSA &MSSA = Analyses->MSSA; + MemorySSAWalker *Walker = Analyses->Walker; + + unsigned I = 0; + for (StoreInst *V : {S1, S2, S3}) { + // Everything should be clobbered by its defining access + MemoryAccess *DefiningAccess = + cast(MSSA.getMemoryAccess(V))->getDefiningAccess(); + MemoryAccess *WalkerClobber = Walker->getClobberingMemoryAccess(V); + EXPECT_EQ(DefiningAccess, WalkerClobber) + << "Store " << I << " doesn't have the correct clobbering access"; + // EXPECT_EQ expands such that if we increment I above, it won't get + // incremented except when we try to print the error message. + ++I; + } +} + +// ...And fixing the above bug made it obvious that, when walking, MemorySSA's +// walker was caching the initial node it walked. This was fine (albeit +// mostly redundant) unless the initial node being walked is a clobber for the +// query. In that case, we'd cache that the node clobbered itself. +TEST_F(MemorySSATest, TestStoreAndLoad) { + F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false), + GlobalValue::ExternalLinkage, "F", &M); + B.SetInsertPoint(BasicBlock::Create(C, "", F)); + Type *Int8 = Type::getInt8Ty(C); + Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A"); + Instruction *SI = B.CreateStore(ConstantInt::get(Int8, 0), Alloca); + Instruction *LI = B.CreateLoad(Alloca); + + setupAnalyses(); + MemorySSA &MSSA = Analyses->MSSA; + MemorySSAWalker *Walker = Analyses->Walker; + + MemoryAccess *LoadClobber = Walker->getClobberingMemoryAccess(LI); + EXPECT_EQ(LoadClobber, MSSA.getMemoryAccess(SI)); + EXPECT_TRUE(MSSA.isLiveOnEntryDef(Walker->getClobberingMemoryAccess(SI))); +} + +// Another bug (related to the above two fixes): It was noted that, given the +// following code: +// ; 1 = MemoryDef(liveOnEntry) +// store i8 0, i8* %1 +// +// ...A query to getClobberingMemoryAccess(MemoryAccess*, MemoryLocation) would +// hand back the store (correctly). A later call to +// getClobberingMemoryAccess(const Instruction*) would also hand back the store +// (incorrectly; it should return liveOnEntry). +// +// This test checks that repeated calls to either function returns what they're +// meant to. +TEST_F(MemorySSATest, TestStoreDoubleQuery) { + F = Function::Create(FunctionType::get(B.getVoidTy(), {}, false), + GlobalValue::ExternalLinkage, "F", &M); + B.SetInsertPoint(BasicBlock::Create(C, "", F)); + Type *Int8 = Type::getInt8Ty(C); + Value *Alloca = B.CreateAlloca(Int8, ConstantInt::get(Int8, 1), "A"); + StoreInst *SI = B.CreateStore(ConstantInt::get(Int8, 0), Alloca); + + setupAnalyses(); + MemorySSA &MSSA = Analyses->MSSA; + MemorySSAWalker *Walker = Analyses->Walker; + + MemoryAccess *StoreAccess = MSSA.getMemoryAccess(SI); + MemoryLocation StoreLoc = MemoryLocation::get(SI); + MemoryAccess *Clobber = + Walker->getClobberingMemoryAccess(StoreAccess, StoreLoc); + MemoryAccess *LiveOnEntry = Walker->getClobberingMemoryAccess(SI); + + EXPECT_EQ(Clobber, StoreAccess); + EXPECT_TRUE(MSSA.isLiveOnEntryDef(LiveOnEntry)); + + // Try again (with entries in the cache already) for good measure... + Clobber = Walker->getClobberingMemoryAccess(StoreAccess, StoreLoc); + LiveOnEntry = Walker->getClobberingMemoryAccess(SI); + EXPECT_EQ(Clobber, StoreAccess); + EXPECT_TRUE(MSSA.isLiveOnEntryDef(LiveOnEntry)); } diff --git a/unittests/Transforms/Utils/ValueMapperTest.cpp b/unittests/Transforms/Utils/ValueMapperTest.cpp index 9dbe4dbc56de8634c90beb2e59271e461560f3de..34b62bb930d9860a1f0f0e2cb459df31f2116c8c 100644 --- a/unittests/Transforms/Utils/ValueMapperTest.cpp +++ b/unittests/Transforms/Utils/ValueMapperTest.cpp @@ -7,6 +7,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/Transforms/Utils/ValueMapper.h" @@ -16,31 +19,117 @@ using namespace llvm; namespace { -TEST(ValueMapperTest, MapMetadataUnresolved) { +TEST(ValueMapperTest, mapMDNode) { + LLVMContext Context; + auto *U = MDTuple::get(Context, None); + + // The node should be unchanged. + ValueToValueMapTy VM; + EXPECT_EQ(U, ValueMapper(VM).mapMDNode(*U)); +} + +TEST(ValueMapperTest, mapMDNodeCycle) { + LLVMContext Context; + MDNode *U0; + MDNode *U1; + { + Metadata *Ops[] = {nullptr}; + auto T = MDTuple::getTemporary(Context, Ops); + Ops[0] = T.get(); + U0 = MDTuple::get(Context, Ops); + T->replaceOperandWith(0, U0); + U1 = MDNode::replaceWithUniqued(std::move(T)); + U0->resolveCycles(); + } + + EXPECT_TRUE(U0->isResolved()); + EXPECT_TRUE(U0->isUniqued()); + EXPECT_TRUE(U1->isResolved()); + EXPECT_TRUE(U1->isUniqued()); + EXPECT_EQ(U1, U0->getOperand(0)); + EXPECT_EQ(U0, U1->getOperand(0)); + + // Cycles shouldn't be duplicated. + { + ValueToValueMapTy VM; + EXPECT_EQ(U0, ValueMapper(VM).mapMDNode(*U0)); + EXPECT_EQ(U1, ValueMapper(VM).mapMDNode(*U1)); + } + + // Check the other order. + { + ValueToValueMapTy VM; + EXPECT_EQ(U1, ValueMapper(VM).mapMDNode(*U1)); + EXPECT_EQ(U0, ValueMapper(VM).mapMDNode(*U0)); + } +} + +TEST(ValueMapperTest, mapMDNodeDuplicatedCycle) { + LLVMContext Context; + auto *PtrTy = Type::getInt8Ty(Context)->getPointerTo(); + std::unique_ptr G0 = llvm::make_unique( + PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "G0"); + std::unique_ptr G1 = llvm::make_unique( + PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "G1"); + + // Create a cycle that references G0. + MDNode *N0; // !0 = !{!1} + MDNode *N1; // !1 = !{!0, i8* @G0} + { + auto T0 = MDTuple::getTemporary(Context, nullptr); + Metadata *Ops1[] = {T0.get(), ConstantAsMetadata::get(G0.get())}; + N1 = MDTuple::get(Context, Ops1); + T0->replaceOperandWith(0, N1); + N0 = MDNode::replaceWithUniqued(std::move(T0)); + } + + // Resolve N0 and N1. + ASSERT_FALSE(N0->isResolved()); + ASSERT_FALSE(N1->isResolved()); + N0->resolveCycles(); + ASSERT_TRUE(N0->isResolved()); + ASSERT_TRUE(N1->isResolved()); + + // Seed the value map to map G0 to G1 and map the nodes. The output should + // have new nodes that reference G1 (instead of G0). + ValueToValueMapTy VM; + VM[G0.get()] = G1.get(); + MDNode *MappedN0 = ValueMapper(VM).mapMDNode(*N0); + MDNode *MappedN1 = ValueMapper(VM).mapMDNode(*N1); + EXPECT_NE(N0, MappedN0); + EXPECT_NE(N1, MappedN1); + EXPECT_EQ(ConstantAsMetadata::get(G1.get()), MappedN1->getOperand(1)); + + // Check that the output nodes are resolved. + EXPECT_TRUE(MappedN0->isResolved()); + EXPECT_TRUE(MappedN1->isResolved()); +} + +TEST(ValueMapperTest, mapMDNodeUnresolved) { LLVMContext Context; TempMDTuple T = MDTuple::getTemporary(Context, None); ValueToValueMapTy VM; - EXPECT_EQ(T.get(), MapMetadata(T.get(), VM, RF_NoModuleLevelChanges)); + EXPECT_EQ(T.get(), ValueMapper(VM, RF_NoModuleLevelChanges).mapMDNode(*T)); } -TEST(ValueMapperTest, MapMetadataDistinct) { +TEST(ValueMapperTest, mapMDNodeDistinct) { LLVMContext Context; auto *D = MDTuple::getDistinct(Context, None); { // The node should be cloned. ValueToValueMapTy VM; - EXPECT_NE(D, MapMetadata(D, VM, RF_None)); + EXPECT_NE(D, ValueMapper(VM).mapMDNode(*D)); } { // The node should be moved. ValueToValueMapTy VM; - EXPECT_EQ(D, MapMetadata(D, VM, RF_MoveDistinctMDs)); + EXPECT_EQ(D, ValueMapper(VM, RF_MoveDistinctMDs).mapMDNode(*D)); } } -TEST(ValueMapperTest, MapMetadataDistinctOperands) { +TEST(ValueMapperTest, mapMDNodeDistinctOperands) { LLVMContext Context; Metadata *Old = MDTuple::getDistinct(Context, None); auto *D = MDTuple::getDistinct(Context, Old); @@ -51,8 +140,211 @@ TEST(ValueMapperTest, MapMetadataDistinctOperands) { VM.MD()[Old].reset(New); // Make sure operands are updated. - EXPECT_EQ(D, MapMetadata(D, VM, RF_MoveDistinctMDs)); + EXPECT_EQ(D, ValueMapper(VM, RF_MoveDistinctMDs).mapMDNode(*D)); EXPECT_EQ(New, D->getOperand(0)); } +TEST(ValueMapperTest, mapMDNodeSeeded) { + LLVMContext Context; + auto *D = MDTuple::getDistinct(Context, None); + + // The node should be moved. + ValueToValueMapTy VM; + EXPECT_EQ(None, VM.getMappedMD(D)); + + VM.MD().insert(std::make_pair(D, TrackingMDRef(D))); + EXPECT_EQ(D, *VM.getMappedMD(D)); + EXPECT_EQ(D, ValueMapper(VM).mapMDNode(*D)); +} + +TEST(ValueMapperTest, mapMDNodeSeededWithNull) { + LLVMContext Context; + auto *D = MDTuple::getDistinct(Context, None); + + // The node should be moved. + ValueToValueMapTy VM; + EXPECT_EQ(None, VM.getMappedMD(D)); + + VM.MD().insert(std::make_pair(D, TrackingMDRef())); + EXPECT_EQ(nullptr, *VM.getMappedMD(D)); + EXPECT_EQ(nullptr, ValueMapper(VM).mapMDNode(*D)); } + +TEST(ValueMapperTest, mapMetadataNullMapGlobalWithIgnoreMissingLocals) { + LLVMContext C; + FunctionType *FTy = + FunctionType::get(Type::getVoidTy(C), Type::getInt8Ty(C), false); + std::unique_ptr F( + Function::Create(FTy, GlobalValue::ExternalLinkage, "F")); + + ValueToValueMapTy VM; + RemapFlags Flags = RF_IgnoreMissingLocals | RF_NullMapMissingGlobalValues; + EXPECT_EQ(nullptr, ValueMapper(VM, Flags).mapValue(*F)); +} + +TEST(ValueMapperTest, mapMetadataMDString) { + LLVMContext C; + auto *S1 = MDString::get(C, "S1"); + ValueToValueMapTy VM; + + // Make sure S1 maps to itself, but isn't memoized. + EXPECT_EQ(S1, ValueMapper(VM).mapMetadata(*S1)); + EXPECT_EQ(None, VM.getMappedMD(S1)); + + // We still expect VM.MD() to be respected. + auto *S2 = MDString::get(C, "S2"); + VM.MD()[S1].reset(S2); + EXPECT_EQ(S2, ValueMapper(VM).mapMetadata(*S1)); +} + +TEST(ValueMapperTest, mapMetadataGetMappedMD) { + LLVMContext C; + auto *N0 = MDTuple::get(C, None); + auto *N1 = MDTuple::get(C, N0); + + // Make sure hasMD and getMappedMD work correctly. + ValueToValueMapTy VM; + EXPECT_FALSE(VM.hasMD()); + EXPECT_EQ(N0, ValueMapper(VM).mapMetadata(*N0)); + EXPECT_EQ(N1, ValueMapper(VM).mapMetadata(*N1)); + EXPECT_TRUE(VM.hasMD()); + ASSERT_NE(None, VM.getMappedMD(N0)); + ASSERT_NE(None, VM.getMappedMD(N1)); + EXPECT_EQ(N0, *VM.getMappedMD(N0)); + EXPECT_EQ(N1, *VM.getMappedMD(N1)); +} + +TEST(ValueMapperTest, mapMetadataNoModuleLevelChanges) { + LLVMContext C; + auto *N0 = MDTuple::get(C, None); + auto *N1 = MDTuple::get(C, N0); + + // Nothing should be memoized when RF_NoModuleLevelChanges. + ValueToValueMapTy VM; + EXPECT_FALSE(VM.hasMD()); + EXPECT_EQ(N0, ValueMapper(VM, RF_NoModuleLevelChanges).mapMetadata(*N0)); + EXPECT_EQ(N1, ValueMapper(VM, RF_NoModuleLevelChanges).mapMetadata(*N1)); + EXPECT_FALSE(VM.hasMD()); + EXPECT_EQ(None, VM.getMappedMD(N0)); + EXPECT_EQ(None, VM.getMappedMD(N1)); +} + +TEST(ValueMapperTest, mapMetadataConstantAsMetadata) { + LLVMContext C; + FunctionType *FTy = + FunctionType::get(Type::getVoidTy(C), Type::getInt8Ty(C), false); + std::unique_ptr F( + Function::Create(FTy, GlobalValue::ExternalLinkage, "F")); + + auto *CAM = ConstantAsMetadata::get(F.get()); + { + // ConstantAsMetadata shouldn't be memoized. + ValueToValueMapTy VM; + EXPECT_EQ(CAM, ValueMapper(VM).mapMetadata(*CAM)); + EXPECT_FALSE(VM.MD().count(CAM)); + EXPECT_EQ(CAM, ValueMapper(VM, RF_IgnoreMissingLocals).mapMetadata(*CAM)); + EXPECT_FALSE(VM.MD().count(CAM)); + + // But it should respect a mapping that gets seeded. + auto *N = MDTuple::get(C, None); + VM.MD()[CAM].reset(N); + EXPECT_EQ(N, ValueMapper(VM).mapMetadata(*CAM)); + EXPECT_EQ(N, ValueMapper(VM, RF_IgnoreMissingLocals).mapMetadata(*CAM)); + } + + std::unique_ptr F2( + Function::Create(FTy, GlobalValue::ExternalLinkage, "F2")); + ValueToValueMapTy VM; + VM[F.get()] = F2.get(); + auto *F2MD = ValueMapper(VM).mapMetadata(*CAM); + EXPECT_FALSE(VM.MD().count(CAM)); + EXPECT_TRUE(F2MD); + EXPECT_EQ(F2.get(), cast(F2MD)->getValue()); +} + +#ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG +TEST(ValueMapperTest, mapMetadataLocalAsMetadata) { + LLVMContext C; + FunctionType *FTy = + FunctionType::get(Type::getVoidTy(C), Type::getInt8Ty(C), false); + std::unique_ptr F( + Function::Create(FTy, GlobalValue::ExternalLinkage, "F")); + Argument &A = *F->arg_begin(); + + // mapMetadata doesn't support LocalAsMetadata. The only valid container for + // LocalAsMetadata is a MetadataAsValue instance, so use it directly. + auto *LAM = LocalAsMetadata::get(&A); + ValueToValueMapTy VM; + EXPECT_DEATH(ValueMapper(VM).mapMetadata(*LAM), "Unexpected local metadata"); + EXPECT_DEATH(ValueMapper(VM, RF_IgnoreMissingLocals).mapMetadata(*LAM), + "Unexpected local metadata"); +} +#endif +#endif + +TEST(ValueMapperTest, mapValueLocalAsMetadata) { + LLVMContext C; + FunctionType *FTy = + FunctionType::get(Type::getVoidTy(C), Type::getInt8Ty(C), false); + std::unique_ptr F( + Function::Create(FTy, GlobalValue::ExternalLinkage, "F")); + Argument &A = *F->arg_begin(); + + auto *LAM = LocalAsMetadata::get(&A); + auto *MAV = MetadataAsValue::get(C, LAM); + + // The principled answer to a LocalAsMetadata of an unmapped SSA value would + // be to return nullptr (regardless of RF_IgnoreMissingLocals). + // + // However, algorithms that use RemapInstruction assume that each instruction + // only references SSA values from previous instructions. Arguments of + // such as "metadata i32 %x" don't currently successfully maintain that + // property. To keep RemapInstruction from crashing we need a non-null + // return here, but we also shouldn't reference the unmapped local. Use + // "metadata !{}". + auto *N0 = MDTuple::get(C, None); + auto *N0AV = MetadataAsValue::get(C, N0); + ValueToValueMapTy VM; + EXPECT_EQ(N0AV, ValueMapper(VM).mapValue(*MAV)); + EXPECT_EQ(nullptr, ValueMapper(VM, RF_IgnoreMissingLocals).mapValue(*MAV)); + EXPECT_FALSE(VM.count(MAV)); + EXPECT_FALSE(VM.count(&A)); + EXPECT_EQ(None, VM.getMappedMD(LAM)); + + VM[MAV] = MAV; + EXPECT_EQ(MAV, ValueMapper(VM).mapValue(*MAV)); + EXPECT_EQ(MAV, ValueMapper(VM, RF_IgnoreMissingLocals).mapValue(*MAV)); + EXPECT_TRUE(VM.count(MAV)); + EXPECT_FALSE(VM.count(&A)); + + VM[MAV] = &A; + EXPECT_EQ(&A, ValueMapper(VM).mapValue(*MAV)); + EXPECT_EQ(&A, ValueMapper(VM, RF_IgnoreMissingLocals).mapValue(*MAV)); + EXPECT_TRUE(VM.count(MAV)); + EXPECT_FALSE(VM.count(&A)); +} + +TEST(ValueMapperTest, mapValueLocalAsMetadataToConstant) { + LLVMContext Context; + auto *Int8 = Type::getInt8Ty(Context); + FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), Int8, false); + std::unique_ptr F( + Function::Create(FTy, GlobalValue::ExternalLinkage, "F")); + + // Map a local value to a constant. + Argument &A = *F->arg_begin(); + Constant &C = *ConstantInt::get(Int8, 42); + ValueToValueMapTy VM; + VM[&A] = &C; + + // Look up the metadata-as-value wrapper. Don't crash. + auto *MDA = MetadataAsValue::get(Context, ValueAsMetadata::get(&A)); + auto *MDC = MetadataAsValue::get(Context, ValueAsMetadata::get(&C)); + EXPECT_TRUE(isa(MDA->getMetadata())); + EXPECT_TRUE(isa(MDC->getMetadata())); + EXPECT_EQ(&C, ValueMapper(VM).mapValue(A)); + EXPECT_EQ(MDC, ValueMapper(VM).mapValue(*MDA)); +} + +} // end namespace diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index 69f9302031740c8545ef07b56f4b99779da78051..6c9b62d5b244247ac5fa3eafe15ccf920d8e442c 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -45,6 +45,11 @@ InputFilename("input-file", cl::desc("File to check (defaults to stdin)"), static cl::list CheckPrefixes("check-prefix", cl::desc("Prefix to use from check file (defaults to 'CHECK')")); +static cl::alias CheckPrefixesAlias( + "check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated, + cl::NotHidden, + cl::desc( + "Alias for -check-prefix permitting multiple comma separated values")); static cl::opt NoCanonicalizeWhiteSpace("strict-whitespace", @@ -1298,8 +1303,15 @@ static void AddCheckPrefixIfNeeded() { CheckPrefixes.push_back("CHECK"); } +static void DumpCommandLine(int argc, char **argv) { + errs() << "FileCheck command line: "; + for (int I = 0; I < argc; I++) + errs() << " " << argv[I]; + errs() << "\n"; +} + int main(int argc, char **argv) { - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); @@ -1331,6 +1343,7 @@ int main(int argc, char **argv) { if (File->getBufferSize() == 0 && !AllowEmptyInput) { errs() << "FileCheck error: '" << InputFilename << "' is empty.\n"; + DumpCommandLine(argc, argv); return 2; } diff --git a/utils/GenLibDeps.pl b/utils/GenLibDeps.pl index 7748cabdab5b2db5645d74ad31e06550186051f3..9b65e900c53e8d0b931fc8eb6c5248e6cd7ef228 100755 --- a/utils/GenLibDeps.pl +++ b/utils/GenLibDeps.pl @@ -96,7 +96,6 @@ if ($PEROBJ) { $libpath =~ s/^AsmPrinter/CodeGen\/AsmPrinter/; $libpath =~ s/^BitReader/Bitcode\/Reader/; $libpath =~ s/^BitWriter/Bitcode\/Writer/; - $libpath =~ s/^CppBackend/Target\/CppBackend/; $libpath =~ s/^MSIL/Target\/MSIL/; $libpath =~ s/^Core/IR/; $libpath =~ s/^Instrumentation/Transforms\/Instrumentation/; @@ -137,7 +136,6 @@ if ($PEROBJ) { $libpath =~ s/^AsmPrinter/CodeGen\/AsmPrinter/; $libpath =~ s/^BitReader/Bitcode\/Reader/; $libpath =~ s/^BitWriter/Bitcode\/Writer/; - $libpath =~ s/^CppBackend/Target\/CppBackend/; $libpath =~ s/^MSIL/Target\/MSIL/; $libpath =~ s/^Core/VMCore/; $libpath =~ s/^Instrumentation/Transforms\/Instrumentation/; diff --git a/utils/KillTheDoctor/KillTheDoctor.cpp b/utils/KillTheDoctor/KillTheDoctor.cpp index 6c2242aafdfe74a28f708beae5939a067e5aa7d9..c9e96617f37fc39aa09ccb84ac552e1e5f0473c9 100644 --- a/utils/KillTheDoctor/KillTheDoctor.cpp +++ b/utils/KillTheDoctor/KillTheDoctor.cpp @@ -296,7 +296,7 @@ static StringRef ExceptionCodeToString(DWORD ExceptionCode) { int main(int argc, char **argv) { // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. @@ -337,7 +337,7 @@ int main(int argc, char **argv) { errs() << ToolName << ": Program Image Path: " << ProgramToRun << '\n' << ToolName << ": Command Line: " << CommandLine << '\n'; - STARTUPINFO StartupInfo; + STARTUPINFOA StartupInfo; PROCESS_INFORMATION ProcessInfo; std::memset(&StartupInfo, 0, sizeof(StartupInfo)); StartupInfo.cb = sizeof(StartupInfo); diff --git a/utils/LLVMVisualizers/llvm.natvis b/utils/LLVMVisualizers/llvm.natvis index 0ab921c480382b756409f36c185e46bfd8d48d1b..6d8475a1c72e1b63cab4f50713684cf92e3897bf 100644 --- a/utils/LLVMVisualizers/llvm.natvis +++ b/utils/LLVMVisualizers/llvm.natvis @@ -8,8 +8,8 @@ For Visual Studio 2013 only, put this file into For later versions of Visual Studio, no setup is required. --> - - + + empty {{ size={($T1*)EndX - ($T1*)BeginX} }} @@ -21,7 +21,40 @@ For later versions of Visual Studio, no setup is required. - + + + + {(($T1*)BeginX)[0]}{*this,view(elt1)} + + , {(($T1*)BeginX)[1]}{*this,view(elt2)} + + , {(($T1*)BeginX)[2]}{*this,view(elt3)} + + , {(($T1*)BeginX)[2]}{*this,view(elt4)} + + , /* {(($T1*)EndX - ($T1*)BeginX) - 4} more*/ + empty + {{{*this,view(elt0)}}} + + ($T1*)EndX - ($T1*)BeginX + ($T1*)CapacityX - ($T1*)BeginX + + ($T1*)EndX - ($T1*)BeginX + ($T1*)BeginX + + + + + empty + {{ size={Length} }} + + Length + + Length + Data + + + {BeginX,s} BeginX,s @@ -168,4 +201,46 @@ For later versions of Visual Studio, no setup is required. *(($T1 *)(unsigned char *)storage.buffer) + + + + + {{little endian value = {*(($T1*)(unsigned char *)Value.buffer)} }} + + (unsigned char *)Value.buffer,1 + (unsigned char *)Value.buffer,2 + (unsigned char *)Value.buffer,4 + (unsigned char *)Value.buffer,8 + + + + + + {{ big endian value = {*(unsigned char *)Value.buffer} }} + {{ big endian value = {(($T1)(*(unsigned char *)Value.buffer) << 8) + | ($T1)(*((unsigned char *)Value.buffer+1))} }} + {{ big endian value = {(($T1)(*(unsigned char *)Value.buffer) << 24) + | (($T1)(*((unsigned char *)Value.buffer+1)) << 16) + | (($T1)(*((unsigned char *)Value.buffer+2)) << 8) + | ($T1)(*((unsigned char *)Value.buffer+3))} }} + {{ big endian value = {(($T1)(*(unsigned char *)Value.buffer) << 56) + | (($T1)(*((unsigned char *)Value.buffer+1)) << 48) + | (($T1)(*((unsigned char *)Value.buffer+2)) << 40) + | (($T1)(*((unsigned char *)Value.buffer+3)) << 32) + | (($T1)(*((unsigned char *)Value.buffer+4)) << 24) + | (($T1)(*((unsigned char *)Value.buffer+5)) << 16) + | (($T1)(*((unsigned char *)Value.buffer+6)) << 8) + | ($T1)(*((unsigned char *)Value.buffer+7))} }} + + (unsigned char *)Value.buffer,1 + (unsigned char *)Value.buffer,2 + (unsigned char *)Value.buffer,4 + (unsigned char *)Value.buffer,8 + + diff --git a/utils/Misc/mergefunctions.clang.svn.patch b/utils/Misc/mergefunctions.clang.svn.patch deleted file mode 100644 index 6e2f0f5227985469cac6b4fa491c7fbcb88a8204..0000000000000000000000000000000000000000 --- a/utils/Misc/mergefunctions.clang.svn.patch +++ /dev/null @@ -1,14 +0,0 @@ -Index: lib/CodeGen/BackendUtil.cpp -=================================================================== ---- lib/CodeGen/BackendUtil.cpp (revision 191330) -+++ lib/CodeGen/BackendUtil.cpp (working copy) -@@ -336,6 +336,9 @@ - MPM->add(createStripSymbolsPass(true)); - } - -+ // Force MergeFunctions pass. -+ MPM->add(createMergeFunctionsPass()); -+ - PMBuilder.populateModulePassManager(*MPM); - } - diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 799f20d0b9450743efc97c328dcced860d067708..76228e0b6581eb6847ba0de451d142753924f129 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -112,10 +112,9 @@ #include "llvm/TableGen/TableGenBackend.h" #include #include +#include #include #include -#include -#include using namespace llvm; @@ -204,6 +203,10 @@ struct ClassInfo { /// Is this operand optional and not always required. bool IsOptional; + /// DefaultMethod - The name of the method that returns the default operand + /// for optional operand + std::string DefaultMethod; + public: /// isRegisterClass() - Check if this is a register class. bool isRegisterClass() const { @@ -576,8 +579,8 @@ struct MatchableInfo { /// operator< - Compare two matchables. bool operator<(const MatchableInfo &RHS) const { // The primary comparator is the instruction mnemonic. - if (Mnemonic != RHS.Mnemonic) - return Mnemonic < RHS.Mnemonic; + if (int Cmp = Mnemonic.compare(RHS.Mnemonic)) + return Cmp == -1; if (AsmOperands.size() != RHS.AsmOperands.size()) return AsmOperands.size() < RHS.AsmOperands.size(); @@ -769,6 +772,12 @@ public: RecordKeeper &getRecords() const { return Records; } + + bool hasOptionalOperands() const { + return std::find_if(Classes.begin(), Classes.end(), + [](const ClassInfo& Class){ return Class.IsOptional; }) + != Classes.end(); + } }; } // end anonymous namespace @@ -1120,6 +1129,7 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) { Entry->ParserMethod = ""; Entry->DiagnosticType = ""; Entry->IsOptional = false; + Entry->DefaultMethod = ""; } return Entry; @@ -1255,6 +1265,7 @@ buildRegisterClasses(SmallPtrSetImpl &SingletonRegisters) { // FIXME: diagnostic type. CI->DiagnosticType = ""; CI->IsOptional = false; + CI->DefaultMethod = ""; // unused RegisterSetClasses.insert(std::make_pair(RS, CI)); ++Index; } @@ -1373,6 +1384,15 @@ void AsmMatcherInfo::buildOperandClasses() { if (BitInit *BI = dyn_cast(IsOptional)) CI->IsOptional = BI->getValue(); + // Get or construct the default method name. + Init *DMName = Rec->getValueInit("DefaultMethod"); + if (StringInit *SI = dyn_cast(DMName)) { + CI->DefaultMethod = SI->getValue(); + } else { + assert(isa(DMName) && "Unexpected DefaultMethod field!"); + CI->DefaultMethod = "default" + CI->ClassName + "Operands"; + } + ++Index; } } @@ -1809,7 +1829,8 @@ static unsigned getConverterOperandID(const std::string &Name, static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, std::vector> &Infos, - bool HasMnemonicFirst, raw_ostream &OS) { + bool HasMnemonicFirst, bool HasOptionalOperands, + raw_ostream &OS) { SmallSetVector OperandConversionKinds; SmallSetVector InstructionConversionKinds; std::vector > ConversionTable; @@ -1824,24 +1845,40 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, std::string ConvertFnBody; raw_string_ostream CvtOS(ConvertFnBody); // Start the unified conversion function. - CvtOS << "void " << Target.getName() << ClassName << "::\n" - << "convertToMCInst(unsigned Kind, MCInst &Inst, " - << "unsigned Opcode,\n" - << " const OperandVector" - << " &Operands) {\n" - << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n" - << " const uint8_t *Converter = ConversionTable[Kind];\n" - << " Inst.setOpcode(Opcode);\n" - << " for (const uint8_t *p = Converter; *p; p+= 2) {\n" - << " switch (*p) {\n" - << " default: llvm_unreachable(\"invalid conversion entry!\");\n" - << " case CVT_Reg:\n" - << " static_cast<" << TargetOperandClass - << "&>(*Operands[*(p + 1)]).addRegOperands(Inst, 1);\n" - << " break;\n" - << " case CVT_Tied:\n" - << " Inst.addOperand(Inst.getOperand(*(p + 1)));\n" - << " break;\n"; + if (HasOptionalOperands) { + CvtOS << "void " << Target.getName() << ClassName << "::\n" + << "convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands,\n" + << " const SmallBitVector &OptionalOperandsMask) {\n"; + } else { + CvtOS << "void " << Target.getName() << ClassName << "::\n" + << "convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands) {\n"; + } + CvtOS << " assert(Kind < CVT_NUM_SIGNATURES && \"Invalid signature!\");\n"; + CvtOS << " const uint8_t *Converter = ConversionTable[Kind];\n"; + if (HasOptionalOperands) { + CvtOS << " unsigned NumDefaults = 0;\n"; + } + CvtOS << " unsigned OpIdx;\n"; + CvtOS << " Inst.setOpcode(Opcode);\n"; + CvtOS << " for (const uint8_t *p = Converter; *p; p+= 2) {\n"; + if (HasOptionalOperands) { + CvtOS << " OpIdx = *(p + 1) - NumDefaults;\n"; + } else { + CvtOS << " OpIdx = *(p + 1);\n"; + } + CvtOS << " switch (*p) {\n"; + CvtOS << " default: llvm_unreachable(\"invalid conversion entry!\");\n"; + CvtOS << " case CVT_Reg:\n"; + CvtOS << " static_cast<" << TargetOperandClass + << "&>(*Operands[OpIdx]).addRegOperands(Inst, 1);\n"; + CvtOS << " break;\n"; + CvtOS << " case CVT_Tied:\n"; + CvtOS << " Inst.addOperand(Inst.getOperand(OpIdx));\n"; + CvtOS << " break;\n"; std::string OperandFnBody; raw_string_ostream OpOS(OperandFnBody); @@ -1935,6 +1972,11 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // the index of its entry in the vector). std::string Name = "CVT_" + (Op.Class->isRegisterClass() ? "Reg" : Op.Class->RenderMethod); + if (Op.Class->IsOptional) { + // For optional operands we must also care about DefaultMethod + assert(HasOptionalOperands); + Name += "_" + Op.Class->DefaultMethod; + } Name = getEnumNameForToken(Name); bool IsNewConverter = false; @@ -1950,11 +1992,27 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, // This is a new operand kind. Add a handler for it to the // converter driver. - CvtOS << " case " << Name << ":\n" - << " static_cast<" << TargetOperandClass - << "&>(*Operands[*(p + 1)])." << Op.Class->RenderMethod - << "(Inst, " << OpInfo.MINumOperands << ");\n" - << " break;\n"; + CvtOS << " case " << Name << ":\n"; + if (Op.Class->IsOptional) { + // If optional operand is not present in actual instruction then we + // should call its DefaultMethod before RenderMethod + assert(HasOptionalOperands); + CvtOS << " if (OptionalOperandsMask[*(p + 1) - 1]) {\n" + << " " << Op.Class->DefaultMethod << "()" + << "->" << Op.Class->RenderMethod << "(Inst, " + << OpInfo.MINumOperands << ");\n" + << " ++NumDefaults;\n" + << " } else {\n" + << " static_cast<" << TargetOperandClass + << "&>(*Operands[OpIdx])." << Op.Class->RenderMethod + << "(Inst, " << OpInfo.MINumOperands << ");\n" + << " }\n"; + } else { + CvtOS << " static_cast<" << TargetOperandClass + << "&>(*Operands[OpIdx])." << Op.Class->RenderMethod + << "(Inst, " << OpInfo.MINumOperands << ");\n"; + } + CvtOS << " break;\n"; // Add a handler for the operand number lookup. OpOS << " case " << Name << ":\n" @@ -2153,19 +2211,23 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info, // Check the user classes. We don't care what order since we're only // actually matching against one of them. + OS << " switch (Kind) {\n" + " default: break;\n"; for (const auto &CI : Info.Classes) { if (!CI.isUserClass()) continue; OS << " // '" << CI.ClassName << "' class\n"; - OS << " if (Kind == " << CI.Name << ") {\n"; + OS << " case " << CI.Name << ":\n"; OS << " if (Operand." << CI.PredicateMethod << "())\n"; OS << " return MCTargetAsmParser::Match_Success;\n"; if (!CI.DiagnosticType.empty()) OS << " return " << Info.Target.getName() << "AsmParser::Match_" << CI.DiagnosticType << ";\n"; - OS << " }\n\n"; + else + OS << " break;\n"; } + OS << " } // end switch (Kind)\n\n"; // Check for register operands, including sub-classes. OS << " if (Operand.isReg()) {\n"; @@ -2803,6 +2865,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { Info.buildOperandMatchInfo(); bool HasMnemonicFirst = AsmParser->getValueAsBit("HasMnemonicFirst"); + bool HasOptionalOperands = Info.hasOptionalOperands(); // Write the output. @@ -2812,10 +2875,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " // This should be included into the middle of the declaration of\n"; OS << " // your subclasses implementation of MCTargetAsmParser.\n"; OS << " uint64_t ComputeAvailableFeatures(const FeatureBitset& FB) const;\n"; - OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " - << "unsigned Opcode,\n" - << " const OperandVector " - << "&Operands);\n"; + if (HasOptionalOperands) { + OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands,\n" + << " const SmallBitVector &OptionalOperandsMask);\n"; + } else { + OS << " void convertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const OperandVector &Operands);\n"; + } OS << " void convertToMapAndConstraints(unsigned Kind,\n "; OS << " const OperandVector &Operands) override;\n"; if (HasMnemonicFirst) @@ -2882,7 +2951,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Generate the convertToMCInst function to convert operands into an MCInst. // Also, generate the convertToMapAndConstraints function for MS-style inline // assembly. The latter doesn't actually generate a MCInst. - emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst, OS); + emitConvertFuncs(Target, ClassName, Info.Matchables, HasMnemonicFirst, + HasOptionalOperands, OS); // Emit the enumeration for classes which participate in matching. emitMatchClassEnumeration(Target, Info.Classes, OS); @@ -3064,6 +3134,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " bool HadMatchOtherThanPredicate = false;\n"; OS << " unsigned RetCode = Match_InvalidOperand;\n"; OS << " uint64_t MissingFeatures = ~0ULL;\n"; + if (HasOptionalOperands) { + OS << " SmallBitVector OptionalOperandsMask(" << MaxNumOperands << ");\n"; + } OS << " // Set ErrorInfo to the operand that mismatches if it is\n"; OS << " // wrong for all instances of the instruction.\n"; OS << " ErrorInfo = ~0ULL;\n"; @@ -3108,6 +3181,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Emit check that the subclasses match. OS << " bool OperandsValid = true;\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.reset(0, " << MaxNumOperands << ");\n"; + } OS << " for (unsigned FormalIdx = " << (HasMnemonicFirst ? "0" : "SIndex") << ", ActualIdx = " << (HasMnemonicFirst ? "1" : "SIndex") << "; FormalIdx != " << MaxNumOperands << "; ++FormalIdx) {\n"; @@ -3117,6 +3193,10 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " OperandsValid = (Formal == " <<"InvalidMatchClass) || " "isSubclass(Formal, OptionalMatchClass);\n"; OS << " if (!OperandsValid) ErrorInfo = ActualIdx;\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.set(FormalIdx, " << MaxNumOperands + << ");\n"; + } OS << " break;\n"; OS << " }\n"; OS << " MCParsedAsmOperand &Actual = *Operands[ActualIdx];\n"; @@ -3137,8 +3217,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " // If current formal operand wasn't matched and it is optional\n" << " // then try to match next formal operand\n"; OS << " if (Diag == Match_InvalidOperand " - << "&& isSubclass(Formal, OptionalMatchClass))\n"; + << "&& isSubclass(Formal, OptionalMatchClass)) {\n"; + if (HasOptionalOperands) { + OS << " OptionalOperandsMask.set(FormalIdx);\n"; + } OS << " continue;\n"; + OS << " }\n"; OS << " // If this operand is broken for all of the instances of this\n"; OS << " // mnemonic, keep track of it so we can report loc info.\n"; OS << " // If we already had a match that only failed due to a\n"; @@ -3177,7 +3261,12 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " }\n\n"; OS << " // We have selected a definite instruction, convert the parsed\n" << " // operands into the appropriate MCInst.\n"; - OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n"; + if (HasOptionalOperands) { + OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands,\n" + << " OptionalOperandsMask);\n"; + } else { + OS << " convertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n"; + } OS << "\n"; // Verify the instruction with the target-specific match predicate function. diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index d7d4bc60605d6662e4add9e9ae70568f4407d973..fc2138f7e8ea36a6106f533fcb72988df7f976bf 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include using namespace llvm; @@ -575,7 +576,7 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { O << " switch(AltIdx) {\n" << " default: llvm_unreachable(\"Invalid register alt name index!\");\n"; for (const Record *R : AltNameIndices) { - std::string AltName(R->getName()); + const std::string &AltName = R->getName(); std::string Prefix = !Namespace.empty() ? Namespace + "::" : ""; O << " case " << Prefix << AltName << ":\n" << " assert(*(AsmStrs" << AltName << "+RegAsmOffset" @@ -600,12 +601,12 @@ namespace { class IAPrinter { std::vector Conds; std::map> OpMap; - SmallVector ReqFeatures; std::string Result; std::string AsmString; public: - IAPrinter(std::string R, std::string AS) : Result(R), AsmString(AS) {} + IAPrinter(std::string R, std::string AS) + : Result(std::move(R)), AsmString(std::move(AS)) {} void addCond(const std::string &C) { Conds.push_back(C); } @@ -646,7 +647,7 @@ public: } void print(raw_ostream &O) { - if (Conds.empty() && ReqFeatures.empty()) { + if (Conds.empty()) { O.indent(6) << "return true;\n"; return; } @@ -796,6 +797,18 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { IAPrinter IAP(CGA.Result->getAsString(), CGA.AsmString); + std::string Namespace = Target.getName(); + std::vector ReqFeatures; + if (PassSubtarget) { + // We only consider ReqFeatures predicates if PassSubtarget + std::vector RF = + CGA.TheDef->getValueAsListOfDefs("Predicates"); + std::copy_if(RF.begin(), RF.end(), std::back_inserter(ReqFeatures), + [](Record *R) { + return R->getValueAsBit("AssemblerMatcherPredicate"); + }); + } + unsigned NumMIOps = 0; for (auto &Operand : CGA.ResultOperands) NumMIOps += Operand.getMINumOperands(); @@ -900,6 +913,27 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { } if (CantHandle) continue; + + for (auto I = ReqFeatures.cbegin(); I != ReqFeatures.cend(); I++) { + Record *R = *I; + std::string AsmCondString = R->getValueAsString("AssemblerCondString"); + + // AsmCondString has syntax [!]F(,[!]F)* + SmallVector Ops; + SplitString(AsmCondString, Ops, ","); + assert(!Ops.empty() && "AssemblerCondString cannot be empty"); + + for (auto &Op : Ops) { + assert(!Op.empty() && "Empty operator"); + if (Op[0] == '!') + Cond = "!STI.getFeatureBits()[" + Namespace + "::" + + Op.substr(1).str() + "]"; + else + Cond = "STI.getFeatureBits()[" + Namespace + "::" + Op.str() + "]"; + IAP.addCond(Cond); + } + } + IAPrinterMap[Aliases.first].push_back(std::move(IAP)); } } @@ -973,13 +1007,14 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { // Code that prints the alias, replacing the operands with the ones from the // MCInst. O << " unsigned I = 0;\n"; - O << " while (AsmString[I] != ' ' && AsmString[I] != '\t' &&\n"; - O << " AsmString[I] != '\\0')\n"; + O << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n"; + O << " AsmString[I] != '$' && AsmString[I] != '\\0')\n"; O << " ++I;\n"; O << " OS << '\\t' << StringRef(AsmString, I);\n"; O << " if (AsmString[I] != '\\0') {\n"; - O << " OS << '\\t';\n"; + O << " if (AsmString[I] == ' ' || AsmString[I] == '\\t')"; + O << " OS << '\\t';\n"; O << " do {\n"; O << " if (AsmString[I] == '$') {\n"; O << " ++I;\n"; @@ -1043,7 +1078,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { for (unsigned i = 0; i < MCOpPredicates.size(); ++i) { Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate"); - if (StringInit *SI = dyn_cast(MCOpPred)) { + if (CodeInit *SI = dyn_cast(MCOpPred)) { O << " case " << i + 1 << ": {\n" << SI->getValue() << "\n" << " }\n"; diff --git a/utils/TableGen/Attributes.cpp b/utils/TableGen/Attributes.cpp index 7b001bf14de588a4ee6831d2da740e70b26c9cfa..58dbe5767adab61362df3f8b99490f07b874b1e3 100644 --- a/utils/TableGen/Attributes.cpp +++ b/utils/TableGen/Attributes.cpp @@ -27,6 +27,7 @@ public: private: void emitTargetIndependentEnums(raw_ostream &OS); + void emitConversionFn(raw_ostream &OS); void emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr); void printEnumAttrClasses(raw_ostream &OS, @@ -52,6 +53,27 @@ void Attributes::emitTargetIndependentEnums(raw_ostream &OS) { OS << "#endif\n"; } +void Attributes::emitConversionFn(raw_ostream &OS) { + OS << "#ifdef GET_ATTR_KIND_FROM_NAME\n"; + OS << "#undef GET_ATTR_KIND_FROM_NAME\n"; + + std::vector Attrs = + Records.getAllDerivedDefinitions("EnumAttr"); + + OS << "static Attribute::AttrKind getAttrKindFromName(StringRef AttrName) {\n"; + OS << " return StringSwitch(AttrName)\n"; + + for (auto A : Attrs) { + OS << " .Case(\"" << A->getValueAsString("AttrString"); + OS << "\", Attribute::" << A->getName() << ")\n"; + } + + OS << " .Default(Attribute::None);\n"; + OS << "}\n\n"; + + OS << "#endif\n"; +} + void Attributes::emitFnAttrCompatCheck(raw_ostream &OS, bool IsStringAttr) { OS << "#ifdef GET_ATTR_COMPAT_FUNC\n"; OS << "#undef GET_ATTR_COMPAT_FUNC\n"; @@ -144,6 +166,7 @@ void Attributes::printStrBoolAttrClasses(raw_ostream &OS, void Attributes::emit(raw_ostream &OS) { emitTargetIndependentEnums(OS); + emitConversionFn(OS); emitFnAttrCompatCheck(OS, false); } diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index eef1540424dd18a10a145d08de1b2d72f348d780..e8fe30f5ac704cbac5a32dd31f5388d0480607a7 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -27,6 +27,7 @@ add_tablegen(llvm-tblgen LLVM OptParserEmitter.cpp PseudoLoweringEmitter.cpp RegisterInfoEmitter.cpp + SearchableTableEmitter.cpp SubtargetEmitter.cpp TableGen.cpp X86DisassemblerTables.cpp diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp index c74f80e4617587076e40e0c2528e68969c9badad..400913e327459773a4ffdb14435ab9e633748aa2 100644 --- a/utils/TableGen/CodeEmitterGen.cpp +++ b/utils/TableGen/CodeEmitterGen.cpp @@ -15,7 +15,6 @@ #include "CodeGenTarget.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 0de3b61adf2bd3052ff0c71054068cfad6ef6b16..c2bb55f3dd42808838b04f692cad598c2123876c 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -2816,14 +2816,14 @@ public: if (const CodeGenIntrinsic *IntInfo = N->getIntrinsicInfo(CDP)) { // If this is an intrinsic, analyze it. - if (IntInfo->ModRef >= CodeGenIntrinsic::ReadArgMem) + if (IntInfo->ModRef & CodeGenIntrinsic::MR_Ref) mayLoad = true;// These may load memory. - if (IntInfo->ModRef >= CodeGenIntrinsic::ReadWriteArgMem) + if (IntInfo->ModRef & CodeGenIntrinsic::MR_Mod) mayStore = true;// Intrinsics that can write to memory are 'mayStore'. if (IntInfo->ModRef >= CodeGenIntrinsic::ReadWriteMem) - // WriteMem intrinsics can have other strange effects. + // ReadWriteMem intrinsics can have other strange effects. hasSideEffects = true; } } @@ -2974,9 +2974,16 @@ const DAGInstruction &CodeGenDAGPatterns::parseInstructionPattern( // fill in the InstResults map. for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) { TreePatternNode *Pat = I->getTree(j); - if (Pat->getNumTypes() != 0) + if (Pat->getNumTypes() != 0) { + std::string Types; + for (unsigned k = 0, ke = Pat->getNumTypes(); k != ke; ++k) { + if (k > 0) + Types += ", "; + Types += Pat->getExtType(k).getName(); + } I->error("Top-level forms in instruction pattern should have" - " void types"); + " void types, has types " + Types); + } // Find inputs and outputs, and verify the structure of the uses/defs. FindPatternInputsAndOutputs(I, Pat, InstInputs, InstResults, diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h index bfdc2c62dce1aeff3b2b2c11fe4251ec866e38c3..8e5a03d7b7439543ff9257b23fa51c520305ef5a 100644 --- a/utils/TableGen/CodeGenInstruction.h +++ b/utils/TableGen/CodeGenInstruction.h @@ -14,7 +14,6 @@ #ifndef LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H #define LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/Support/SMLoc.h" @@ -23,10 +22,10 @@ #include namespace llvm { +template class ArrayRef; class Record; class DagInit; class CodeGenTarget; - class StringRef; class CGIOperandList { public: @@ -317,7 +316,8 @@ namespace llvm { K_Reg } Kind; - ResultOperand(std::string N, Record *r) : Name(N), R(r), Kind(K_Record) {} + ResultOperand(std::string N, Record *r) + : Name(std::move(N)), R(r), Kind(K_Record) {} ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {} ResultOperand(Record *r) : R(r), Kind(K_Reg) {} diff --git a/utils/TableGen/CodeGenIntrinsics.h b/utils/TableGen/CodeGenIntrinsics.h index 7bdb7e1bc537cc7f621f6ac8b4ebcabc9dc8aca9..76554a52a15c14899fb0be479a8d81b2898872f5 100644 --- a/utils/TableGen/CodeGenIntrinsics.h +++ b/utils/TableGen/CodeGenIntrinsics.h @@ -19,85 +19,104 @@ #include namespace llvm { - class Record; - class RecordKeeper; - class CodeGenTarget; - - struct CodeGenIntrinsic { - Record *TheDef; // The actual record defining this intrinsic. - std::string Name; // The name of the LLVM function "llvm.bswap.i32" - std::string EnumName; // The name of the enum "bswap_i32" - std::string GCCBuiltinName;// Name of the corresponding GCC builtin, or "". - std::string MSBuiltinName; // Name of the corresponding MS builtin, or "". - std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics. - - /// IntrinsicSignature - This structure holds the return values and - /// parameter values of an intrinsic. If the number of return values is > 1, - /// then the intrinsic implicitly returns a first-class aggregate. The - /// numbering of the types starts at 0 with the first return value and - /// continues from there through the parameter list. This is useful for - /// "matching" types. - struct IntrinsicSignature { - /// RetVTs - The MVT::SimpleValueType for each return type. Note that this - /// list is only populated when in the context of a target .td file. When - /// building Intrinsics.td, this isn't available, because we don't know - /// the target pointer size. - std::vector RetVTs; - - /// RetTypeDefs - The records for each return type. - std::vector RetTypeDefs; - - /// ParamVTs - The MVT::SimpleValueType for each parameter type. Note that - /// this list is only populated when in the context of a target .td file. - /// When building Intrinsics.td, this isn't available, because we don't - /// know the target pointer size. - std::vector ParamVTs; - - /// ParamTypeDefs - The records for each parameter type. - std::vector ParamTypeDefs; - }; - - IntrinsicSignature IS; - - // Memory mod/ref behavior of this intrinsic. - enum ModRefKind { - NoMem, ReadArgMem, ReadMem, ReadWriteArgMem, ReadWriteMem - }; - ModRefKind ModRef; - - /// This is set to true if the intrinsic is overloaded by its argument - /// types. - bool isOverloaded; - - /// isCommutative - True if the intrinsic is commutative. - bool isCommutative; - - /// canThrow - True if the intrinsic can throw. - bool canThrow; - - /// isNoDuplicate - True if the intrinsic is marked as noduplicate. - bool isNoDuplicate; - - /// isNoReturn - True if the intrinsic is no-return. - bool isNoReturn; - - /// isConvergent - True if the intrinsic is marked as convergent. - bool isConvergent; - - enum ArgAttribute { - NoCapture, - ReadOnly, - ReadNone - }; - std::vector > ArgumentAttributes; - - CodeGenIntrinsic(Record *R); +class Record; +class RecordKeeper; +class CodeGenTarget; + +struct CodeGenIntrinsic { + Record *TheDef; // The actual record defining this intrinsic. + std::string Name; // The name of the LLVM function "llvm.bswap.i32" + std::string EnumName; // The name of the enum "bswap_i32" + std::string GCCBuiltinName; // Name of the corresponding GCC builtin, or "". + std::string MSBuiltinName; // Name of the corresponding MS builtin, or "". + std::string TargetPrefix; // Target prefix, e.g. "ppc" for t-s intrinsics. + + /// This structure holds the return values and parameter values of an + /// intrinsic. If the number of return values is > 1, then the intrinsic + /// implicitly returns a first-class aggregate. The numbering of the types + /// starts at 0 with the first return value and continues from there through + /// the parameter list. This is useful for "matching" types. + struct IntrinsicSignature { + /// The MVT::SimpleValueType for each return type. Note that this list is + /// only populated when in the context of a target .td file. When building + /// Intrinsics.td, this isn't available, because we don't know the target + /// pointer size. + std::vector RetVTs; + + /// The records for each return type. + std::vector RetTypeDefs; + + /// The MVT::SimpleValueType for each parameter type. Note that this list is + /// only populated when in the context of a target .td file. When building + /// Intrinsics.td, this isn't available, because we don't know the target + /// pointer size. + std::vector ParamVTs; + + /// The records for each parameter type. + std::vector ParamTypeDefs; }; - /// LoadIntrinsics - Read all of the intrinsics defined in the specified - /// .td file. - std::vector LoadIntrinsics(const RecordKeeper &RC, - bool TargetOnly); + IntrinsicSignature IS; + + /// Bit flags describing the type (ref/mod) and location of memory + /// accesses that may be performed by the intrinsics. Analogous to + /// \c FunctionModRefBehaviour. + enum ModRefBits { + /// The intrinsic may access memory anywhere, i.e. it is not restricted + /// to access through pointer arguments. + MR_Anywhere = 1, + + /// The intrinsic may read memory. + MR_Ref = 2, + + /// The intrinsic may write memory. + MR_Mod = 4, + + /// The intrinsic may both read and write memory. + MR_ModRef = MR_Ref | MR_Mod, + }; + + /// Memory mod/ref behavior of this intrinsic, corresponding to intrinsic + /// properties (IntrReadMem, IntrArgMemOnly, etc.). + enum ModRefBehavior { + NoMem = 0, + ReadArgMem = MR_Ref, + ReadMem = MR_Ref | MR_Anywhere, + WriteArgMem = MR_Mod, + WriteMem = MR_Mod | MR_Anywhere, + ReadWriteArgMem = MR_ModRef, + ReadWriteMem = MR_ModRef | MR_Anywhere, + }; + ModRefBehavior ModRef; + + /// This is set to true if the intrinsic is overloaded by its argument + /// types. + bool isOverloaded; + + /// True if the intrinsic is commutative. + bool isCommutative; + + /// True if the intrinsic can throw. + bool canThrow; + + /// True if the intrinsic is marked as noduplicate. + bool isNoDuplicate; + + /// True if the intrinsic is no-return. + bool isNoReturn; + + /// True if the intrinsic is marked as convergent. + bool isConvergent; + + enum ArgAttribute { NoCapture, Returned, ReadOnly, WriteOnly, ReadNone }; + std::vector> ArgumentAttributes; + + CodeGenIntrinsic(Record *R); +}; + +/// Read all of the intrinsics defined in the specified .td file. +std::vector LoadIntrinsics(const RecordKeeper &RC, + bool TargetOnly); } #endif diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp index 0633d47e99e929f52c543db7b513e390b7152798..626144fbe855a2b8a7540fc63eedf3057e399b0f 100644 --- a/utils/TableGen/CodeGenRegisters.cpp +++ b/utils/TableGen/CodeGenRegisters.cpp @@ -1192,45 +1192,57 @@ void CodeGenRegBank::computeSubRegLaneMasks() { for (const auto &Idx : SubRegIndices) { const auto &Composites = Idx.getComposites(); auto &LaneTransforms = Idx.CompositionLaneMaskTransform; - // Go through all leaf subregisters and find the ones that compose with Idx. - // These make out all possible valid bits in the lane mask we want to - // transform. Looking only at the leafs ensure that only a single bit in - // the mask is set. - unsigned NextBit = 0; - for (auto &Idx2 : SubRegIndices) { - // Skip non-leaf subregisters. - if (!Idx2.getComposites().empty()) - continue; - // Replicate the behaviour from the lane mask generation loop above. - unsigned SrcBit = NextBit; - unsigned SrcMask = 1u << SrcBit; - if (NextBit < 31) - ++NextBit; - assert(Idx2.LaneMask == SrcMask); - - // Get the composed subregister if there is any. - auto C = Composites.find(&Idx2); - if (C == Composites.end()) - continue; - const CodeGenSubRegIndex *Composite = C->second; - // The Composed subreg should be a leaf subreg too - assert(Composite->getComposites().empty()); - - // Create Mask+Rotate operation and merge with existing ops if possible. - unsigned DstBit = Log2_32(Composite->LaneMask); - int Shift = DstBit - SrcBit; - uint8_t RotateLeft = Shift >= 0 ? (uint8_t)Shift : 32+Shift; - for (auto &I : LaneTransforms) { - if (I.RotateLeft == RotateLeft) { - I.Mask |= SrcMask; - SrcMask = 0; + + if (Composites.empty()) { + // Moving from a class with no subregisters we just had a single lane: + // The subregister must be a leaf subregister and only occupies 1 bit. + // Move the bit from the class without subregisters into that position. + unsigned DstBit = Log2_32(Idx.LaneMask); + assert(Idx.LaneMask == 1u << DstBit && "Must be a leaf subregister"); + MaskRolPair MaskRol = { 1, (uint8_t)DstBit }; + LaneTransforms.push_back(MaskRol); + } else { + // Go through all leaf subregisters and find the ones that compose with + // Idx. These make out all possible valid bits in the lane mask we want to + // transform. Looking only at the leafs ensure that only a single bit in + // the mask is set. + unsigned NextBit = 0; + for (auto &Idx2 : SubRegIndices) { + // Skip non-leaf subregisters. + if (!Idx2.getComposites().empty()) + continue; + // Replicate the behaviour from the lane mask generation loop above. + unsigned SrcBit = NextBit; + unsigned SrcMask = 1u << SrcBit; + if (NextBit < 31) + ++NextBit; + assert(Idx2.LaneMask == SrcMask); + + // Get the composed subregister if there is any. + auto C = Composites.find(&Idx2); + if (C == Composites.end()) + continue; + const CodeGenSubRegIndex *Composite = C->second; + // The Composed subreg should be a leaf subreg too + assert(Composite->getComposites().empty()); + + // Create Mask+Rotate operation and merge with existing ops if possible. + unsigned DstBit = Log2_32(Composite->LaneMask); + int Shift = DstBit - SrcBit; + uint8_t RotateLeft = Shift >= 0 ? (uint8_t)Shift : 32+Shift; + for (auto &I : LaneTransforms) { + if (I.RotateLeft == RotateLeft) { + I.Mask |= SrcMask; + SrcMask = 0; + } + } + if (SrcMask != 0) { + MaskRolPair MaskRol = { SrcMask, RotateLeft }; + LaneTransforms.push_back(MaskRol); } - } - if (SrcMask != 0) { - MaskRolPair MaskRol = { SrcMask, RotateLeft }; - LaneTransforms.push_back(MaskRol); } } + // Optimize if the transformation consists of one step only: Set mask to // 0xffffffff (including some irrelevant invalid bits) so that it should // merge with more entries later while compressing the table. @@ -1267,10 +1279,10 @@ void CodeGenRegBank::computeSubRegLaneMasks() { LaneMask |= SubRegIndex.LaneMask; } - // For classes without any subregisters set LaneMask to ~0u instead of 0. + // For classes without any subregisters set LaneMask to 1 instead of 0. // This makes it easier for client code to handle classes uniformly. if (LaneMask == 0) - LaneMask = ~0u; + LaneMask = 1; RegClass.LaneMask = LaneMask; } @@ -1817,11 +1829,14 @@ void CodeGenRegBank::computeDerivedInfo() { computeRegUnitLaneMasks(); - // Compute register class HasDisjunctSubRegs flag. + // Compute register class HasDisjunctSubRegs/CoveredBySubRegs flag. for (CodeGenRegisterClass &RC : RegClasses) { RC.HasDisjunctSubRegs = false; - for (const CodeGenRegister *Reg : RC.getMembers()) + RC.CoveredBySubRegs = true; + for (const CodeGenRegister *Reg : RC.getMembers()) { RC.HasDisjunctSubRegs |= Reg->HasDisjunctSubRegs; + RC.CoveredBySubRegs &= Reg->CoveredBySubRegs; + } } // Get the weight of each set. diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h index dc441436537db399cfb1d4f1d3a5501106f86277..b8d47aa4ff82d4e4cc39ca625d3822cdc5c450f8 100644 --- a/utils/TableGen/CodeGenRegisters.h +++ b/utils/TableGen/CodeGenRegisters.h @@ -19,22 +19,21 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SparseBitVector.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/SetTheory.h" #include +#include #include #include -#include #include #include -#include namespace llvm { class CodeGenRegBank; + template class SetVector; /// Used to encode a step in a register lane mask transformation. /// Mask the bits specified in Mask, then rotate them Rol bits to the left @@ -311,6 +310,7 @@ namespace llvm { unsigned LaneMask; /// True if there are at least 2 subregisters which do not interfere. bool HasDisjunctSubRegs; + bool CoveredBySubRegs; // Return the Record that defined this class, or NULL if the class was // created by TableGen. diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index c52d3b0e9fc92ef9735f5b72d6ed349facf0f990..d1b141e3160f562fd08b83d1d04cc67def721115 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -120,6 +120,10 @@ CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, // (For per-operand resources mapped to itinerary classes). collectProcItinRW(); + // Find UnsupportedFeatures records for each processor. + // (For per-operand resources mapped to itinerary classes). + collectProcUnsupportedFeatures(); + // Infer new SchedClasses from SchedVariant. inferSchedClasses(); @@ -829,6 +833,15 @@ void CodeGenSchedModels::collectProcItinRW() { } } +// Gather the unsupported features for processor models. +void CodeGenSchedModels::collectProcUnsupportedFeatures() { + for (CodeGenProcModel &ProcModel : ProcModels) { + for (Record *Pred : ProcModel.ModelDef->getValueAsListOfDefs("UnsupportedFeatures")) { + ProcModel.UnsupportedFeaturesDefs.push_back(Pred); + } + } +} + /// Infer new classes from existing classes. In the process, this may create new /// SchedWrites from sequences of existing SchedWrites. void CodeGenSchedModels::inferSchedClasses() { @@ -1429,6 +1442,9 @@ void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) { // Collect and sort WriteRes, ReadAdvance, and ProcResources. void CodeGenSchedModels::collectProcResources() { + ProcResourceDefs = Records.getAllDerivedDefinitions("ProcResourceUnits"); + ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup"); + // Add any subtarget-specific SchedReadWrites that are directly associated // with processor resources. Refer to the parent SchedClass's ProcIndices to // determine which processors they apply to. @@ -1523,6 +1539,9 @@ void CodeGenSchedModels::collectProcResources() { dbgs() << '\n'); verifyProcResourceGroups(PM); } + + ProcResourceDefs.clear(); + ProcResGroups.clear(); } void CodeGenSchedModels::checkCompleteness() { @@ -1534,6 +1553,8 @@ void CodeGenSchedModels::checkCompleteness() { for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue()) { if (Inst->hasNoSchedulingInfo) continue; + if (ProcModel.isUnsupported(*Inst)) + continue; unsigned SCIdx = getSchedClassIdx(*Inst); if (!SCIdx) { if (Inst->TheDef->isValueUnset("SchedRW") && !HadCompleteModel) { @@ -1569,7 +1590,10 @@ void CodeGenSchedModels::checkCompleteness() { << "- Consider setting 'CompleteModel = 0' while developing new models.\n" << "- Pseudo instructions can be marked with 'hasNoSchedulingInfo = 1'.\n" << "- Instructions should usually have Sched<[...]> as a superclass, " - "you may temporarily use an empty list.\n\n"; + "you may temporarily use an empty list.\n" + << "- Instructions related to unsupported features can be excluded with " + "list UnsupportedFeatures = [HasA,..,HasY]; in the " + "processor model.\n\n"; PrintFatalError("Incomplete schedule model"); } } @@ -1652,8 +1676,8 @@ Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind, return ProcResKind; Record *ProcUnitDef = nullptr; - RecVec ProcResourceDefs = - Records.getAllDerivedDefinitions("ProcResourceUnits"); + assert(!ProcResourceDefs.empty()); + assert(!ProcResGroups.empty()); for (RecIter RI = ProcResourceDefs.begin(), RE = ProcResourceDefs.end(); RI != RE; ++RI) { @@ -1668,7 +1692,6 @@ Record *CodeGenSchedModels::findProcResUnits(Record *ProcResKind, ProcUnitDef = *RI; } } - RecVec ProcResGroups = Records.getAllDerivedDefinitions("ProcResGroup"); for (RecIter RI = ProcResGroups.begin(), RE = ProcResGroups.end(); RI != RE; ++RI) { @@ -1751,6 +1774,16 @@ unsigned CodeGenProcModel::getProcResourceIdx(Record *PRDef) const { return 1 + (PRPos - ProcResourceDefs.begin()); } +bool CodeGenProcModel::isUnsupported(const CodeGenInstruction &Inst) const { + for (const Record *TheDef : UnsupportedFeaturesDefs) { + for (const Record *PredDef : Inst.TheDef->getValueAsListOfDefs("Predicates")) { + if (TheDef->getName() == PredDef->getName()) + return true; + } + } + return false; +} + #ifndef NDEBUG void CodeGenProcModel::dump() const { dbgs() << Index << ": " << ModelName << " " diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h index 62601d941bcd453f1437e54ce4e838274ab5f9ed..755ffd25b0cbc92b6696acb52ab4db4dd8576c10 100644 --- a/utils/TableGen/CodeGenSchedule.h +++ b/utils/TableGen/CodeGenSchedule.h @@ -189,6 +189,10 @@ struct CodeGenProcModel { // This list is empty if no ItinRW refers to this Processor. RecVec ItinRWDefs; + // List of unsupported feature. + // This list is empty if the Processor has no UnsupportedFeatures. + RecVec UnsupportedFeaturesDefs; + // All read/write resources associated with this processor. RecVec WriteResDefs; RecVec ReadAdvanceDefs; @@ -211,6 +215,8 @@ struct CodeGenProcModel { unsigned getProcResourceIdx(Record *PRDef) const; + bool isUnsupported(const CodeGenInstruction &Inst) const; + #ifndef NDEBUG void dump() const; #endif @@ -241,6 +247,9 @@ class CodeGenSchedModels { // Any inferred SchedClass has an index greater than NumInstrSchedClassses. unsigned NumInstrSchedClasses; + RecVec ProcResourceDefs; + RecVec ProcResGroups; + // Map each instruction to its unique SchedClass index considering the // combination of it's itinerary class, SchedRW list, and InstRW records. typedef DenseMap InstClassMapTy; @@ -399,6 +408,8 @@ private: void collectProcItinRW(); + void collectProcUnsupportedFeatures(); + void inferSchedClasses(); void checkCompleteness(); diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index 167ed761781e94a32d8cd061982194bdd507929c..08bb332b1359dcc15949f3d162413f9b790b1b4c 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -39,7 +39,7 @@ MVT::SimpleValueType llvm::getValueType(Record *Rec) { return (MVT::SimpleValueType)Rec->getValueAsInt("Value"); } -std::string llvm::getName(MVT::SimpleValueType T) { +StringRef llvm::getName(MVT::SimpleValueType T) { switch (T) { case MVT::Other: return "UNKNOWN"; case MVT::iPTR: return "TLI.getPointerTy()"; @@ -48,7 +48,7 @@ std::string llvm::getName(MVT::SimpleValueType T) { } } -std::string llvm::getEnumName(MVT::SimpleValueType T) { +StringRef llvm::getEnumName(MVT::SimpleValueType T) { switch (T) { case MVT::Other: return "MVT::Other"; case MVT::i1: return "MVT::i1"; @@ -352,9 +352,9 @@ void CodeGenTarget::reverseBitsForLittleEndianEncoding() { BitsInit *BI = R->getValueAsBitsInit("Inst"); unsigned numBits = BI->getNumBits(); - + SmallVector NewBits(numBits); - + for (unsigned bit = 0, end = numBits / 2; bit != end; ++bit) { unsigned bitSwapIdx = numBits - bit - 1; Init *OrigBit = BI->getBit(bit); @@ -428,15 +428,15 @@ ComplexPattern::ComplexPattern(Record *R) { std::vector llvm::LoadIntrinsics(const RecordKeeper &RC, bool TargetOnly) { - std::vector I = RC.getAllDerivedDefinitions("Intrinsic"); + std::vector Defs = RC.getAllDerivedDefinitions("Intrinsic"); std::vector Result; - Result.reserve(I.size()); + Result.reserve(Defs.size()); - for (unsigned i = 0, e = I.size(); i != e; ++i) { - bool isTarget = I[i]->getValueAsBit("isTarget"); + for (unsigned I = 0, e = Defs.size(); I != e; ++I) { + bool isTarget = Defs[I]->getValueAsBit("isTarget"); if (isTarget == TargetOnly) - Result.push_back(CodeGenIntrinsic(I[i])); + Result.push_back(CodeGenIntrinsic(Defs[I])); } std::sort(Result.begin(), Result.end(), [](const CodeGenIntrinsic& LHS, const CodeGenIntrinsic& RHS) { @@ -573,12 +573,12 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { if (Property->getName() == "IntrNoMem") ModRef = NoMem; - else if (Property->getName() == "IntrReadArgMem") - ModRef = ReadArgMem; else if (Property->getName() == "IntrReadMem") - ModRef = ReadMem; - else if (Property->getName() == "IntrReadWriteArgMem") - ModRef = ReadWriteArgMem; + ModRef = ModRefBehavior(ModRef & ~MR_Mod); + else if (Property->getName() == "IntrWriteMem") + ModRef = ModRefBehavior(ModRef & ~MR_Ref); + else if (Property->getName() == "IntrArgMemOnly") + ModRef = ModRefBehavior(ModRef & ~MR_Anywhere); else if (Property->getName() == "Commutative") isCommutative = true; else if (Property->getName() == "Throws") @@ -592,9 +592,15 @@ CodeGenIntrinsic::CodeGenIntrinsic(Record *R) { else if (Property->isSubClassOf("NoCapture")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture)); + } else if (Property->isSubClassOf("Returned")) { + unsigned ArgNo = Property->getValueAsInt("ArgNo"); + ArgumentAttributes.push_back(std::make_pair(ArgNo, Returned)); } else if (Property->isSubClassOf("ReadOnly")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadOnly)); + } else if (Property->isSubClassOf("WriteOnly")) { + unsigned ArgNo = Property->getValueAsInt("ArgNo"); + ArgumentAttributes.push_back(std::make_pair(ArgNo, WriteOnly)); } else if (Property->isSubClassOf("ReadNone")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadNone)); diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h index 72145133aa72faeaa47d13ab1df54d4f71616c28..85a8c1b18878577618e30c683eceb7dd5a5e6ea3 100644 --- a/utils/TableGen/CodeGenTarget.h +++ b/utils/TableGen/CodeGenTarget.h @@ -52,8 +52,8 @@ enum SDNP { /// record corresponds to. MVT::SimpleValueType getValueType(Record *Rec); -std::string getName(MVT::SimpleValueType T); -std::string getEnumName(MVT::SimpleValueType T); +StringRef getName(MVT::SimpleValueType T); +StringRef getEnumName(MVT::SimpleValueType T); /// getQualifiedName - Return the name of the specified record, with a /// namespace qualifier if the record contains one. diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp index 9c4079906a383e7e9d79872ec595e7fc6761f419..6ac3958e0f4301fd2c3f602ac1eb40f564e542e2 100644 --- a/utils/TableGen/DAGISelMatcher.cpp +++ b/utils/TableGen/DAGISelMatcher.cpp @@ -225,12 +225,14 @@ void CheckFoldableChainNodeMatcher::printImpl(raw_ostream &OS, } void EmitIntegerMatcher::printImpl(raw_ostream &OS, unsigned indent) const { - OS.indent(indent) << "EmitInteger " << Val << " VT=" << VT << '\n'; + OS.indent(indent) << "EmitInteger " << Val << " VT=" << getEnumName(VT) + << '\n'; } void EmitStringIntegerMatcher:: printImpl(raw_ostream &OS, unsigned indent) const { - OS.indent(indent) << "EmitStringInteger " << Val << " VT=" << VT << '\n'; + OS.indent(indent) << "EmitStringInteger " << Val << " VT=" << getEnumName(VT) + << '\n'; } void EmitRegisterMatcher::printImpl(raw_ostream &OS, unsigned indent) const { @@ -239,7 +241,7 @@ void EmitRegisterMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS << Reg->getName(); else OS << "zero_reg"; - OS << " VT=" << VT << '\n'; + OS << " VT=" << getEnumName(VT) << '\n'; } void EmitConvertToTargetMatcher:: @@ -275,54 +277,12 @@ void EmitNodeMatcherCommon::printImpl(raw_ostream &OS, unsigned indent) const { OS << ")\n"; } -void MarkGlueResultsMatcher::printImpl(raw_ostream &OS, unsigned indent) const { - OS.indent(indent) << "MarkGlueResults \n"; -} - void CompleteMatchMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CompleteMatch \n"; OS.indent(indent) << "Src = " << *Pattern.getSrcPattern() << "\n"; OS.indent(indent) << "Dst = " << *Pattern.getDstPattern() << "\n"; } -// getHashImpl Implementation. - -unsigned CheckPatternPredicateMatcher::getHashImpl() const { - return HashString(Predicate); -} - -unsigned CheckPredicateMatcher::getHashImpl() const { - return HashString(getPredicate().getFnName()); -} - -unsigned CheckOpcodeMatcher::getHashImpl() const { - return HashString(Opcode.getEnumName()); -} - -unsigned CheckCondCodeMatcher::getHashImpl() const { - return HashString(CondCodeName); -} - -unsigned CheckValueTypeMatcher::getHashImpl() const { - return HashString(TypeName); -} - -unsigned EmitStringIntegerMatcher::getHashImpl() const { - return HashString(Val) ^ VT; -} - -template -static unsigned HashUnsigneds(It I, It E) { - unsigned Result = 0; - for (; I != E; ++I) - Result = (Result<<3) ^ *I; - return Result; -} - -unsigned EmitMergeInputChainsMatcher::getHashImpl() const { - return HashUnsigneds(ChainNodes.begin(), ChainNodes.end()); -} - bool CheckOpcodeMatcher::isEqualImpl(const Matcher *M) const { // Note: pointer equality isn't enough here, we have to check the enum names // to ensure that the nodes are for the same opcode. @@ -339,24 +299,10 @@ bool EmitNodeMatcherCommon::isEqualImpl(const Matcher *m) const { M->NumFixedArityOperands == NumFixedArityOperands; } -unsigned EmitNodeMatcherCommon::getHashImpl() const { - return (HashString(OpcodeName) << 4) | Operands.size(); -} - - void EmitNodeMatcher::anchor() { } void MorphNodeToMatcher::anchor() { } -unsigned MarkGlueResultsMatcher::getHashImpl() const { - return HashUnsigneds(GlueResultNodes.begin(), GlueResultNodes.end()); -} - -unsigned CompleteMatchMatcher::getHashImpl() const { - return HashUnsigneds(Results.begin(), Results.end()) ^ - ((unsigned)(intptr_t)&Pattern << 8); -} - // isContradictoryImpl Implementations. static bool TypesAreContradictory(MVT::SimpleValueType T1, diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h index a8a6ba5c32e15dc0a81c980eec105790f1ec2d54..6bda9ca5f96fac084d4ec8ea1143218bcd2aee1f 100644 --- a/utils/TableGen/DAGISelMatcher.h +++ b/utils/TableGen/DAGISelMatcher.h @@ -82,7 +82,6 @@ public: EmitCopyToReg, // Emit a copytoreg into a physreg. EmitNode, // Create a DAG node EmitNodeXForm, // Run a SDNodeXForm - MarkGlueResults, // Indicate which interior nodes have glue results. CompleteMatch, // Finish a match and update the results. MorphNodeTo // Build a node, finish a match and update results. }; @@ -107,17 +106,6 @@ public: return isEqualImpl(M); } - unsigned getHash() const { - // Clear the high bit so we don't conflict with tombstones etc. - return ((getHashImpl() << 4) ^ getKind()) & (~0U>>1); - } - - /// isSafeToReorderWithPatternPredicate - Return true if it is safe to sink a - /// PatternPredicate node past this one. - virtual bool isSafeToReorderWithPatternPredicate() const { - return false; - } - /// isSimplePredicateNode - Return true if this is a simple predicate that /// operates on the node or its children without potential side effects or a /// change of the current node. @@ -181,7 +169,6 @@ public: protected: virtual void printImpl(raw_ostream &OS, unsigned indent) const = 0; virtual bool isEqualImpl(const Matcher *M) const = 0; - virtual unsigned getHashImpl() const = 0; virtual bool isContradictoryImpl(const Matcher *M) const { return false; } }; @@ -228,7 +215,6 @@ public: private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return false; } - unsigned getHashImpl() const override { return 12312; } }; /// RecordMatcher - Save the current node in the operand list. @@ -251,11 +237,9 @@ public: return N->getKind() == RecordNode; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return true; } - unsigned getHashImpl() const override { return 0; } }; /// RecordChildMatcher - Save a numbered child of the current node, or fail @@ -285,14 +269,11 @@ public: return N->getKind() == RecordChild; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->getChildNo() == getChildNo(); } - unsigned getHashImpl() const override { return getChildNo(); } }; /// RecordMemRefMatcher - Save the current node's memref. @@ -304,12 +285,9 @@ public: return N->getKind() == RecordMemRef; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return true; } - unsigned getHashImpl() const override { return 0; } }; @@ -323,12 +301,9 @@ public: return N->getKind() == CaptureGlueInput; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return true; } - unsigned getHashImpl() const override { return 0; } }; /// MoveChildMatcher - This tells the interpreter to move into the @@ -344,14 +319,11 @@ public: return N->getKind() == MoveChild; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->getChildNo() == getChildNo(); } - unsigned getHashImpl() const override { return getChildNo(); } }; /// MoveParentMatcher - This tells the interpreter to move to the parent @@ -364,12 +336,9 @@ public: return N->getKind() == MoveParent; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return true; } - unsigned getHashImpl() const override { return 0; } }; /// CheckSameMatcher - This checks to see if this node is exactly the same @@ -387,14 +356,11 @@ public: return N->getKind() == CheckSame; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->getMatchNumber() == getMatchNumber(); } - unsigned getHashImpl() const override { return getMatchNumber(); } }; /// CheckChildSameMatcher - This checks to see if child node is exactly the same @@ -414,15 +380,12 @@ public: return N->getKind() == CheckChildSame; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->ChildNo == ChildNo && cast(M)->MatchNumber == MatchNumber; } - unsigned getHashImpl() const override { return (MatchNumber << 2) | ChildNo; } }; /// CheckPatternPredicateMatcher - This checks the target-specific predicate @@ -440,14 +403,11 @@ public: return N->getKind() == CheckPatternPredicate; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->getPredicate() == Predicate; } - unsigned getHashImpl() const override; }; /// CheckPredicateMatcher - This checks the target-specific predicate to @@ -463,15 +423,11 @@ public: return N->getKind() == CheckPredicate; } - // TODO: Ok? - //virtual bool isSafeToReorderWithPatternPredicate() const { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->Pred == Pred; } - unsigned getHashImpl() const override; }; @@ -489,12 +445,9 @@ public: return N->getKind() == CheckOpcode; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override; - unsigned getHashImpl() const override; bool isContradictoryImpl(const Matcher *M) const override; }; @@ -522,7 +475,6 @@ public: private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return false; } - unsigned getHashImpl() const override { return 4123; } }; /// CheckTypeMatcher - This checks to see if the current node has the @@ -541,14 +493,11 @@ public: return N->getKind() == CheckType; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->Type == Type; } - unsigned getHashImpl() const override { return Type; } bool isContradictoryImpl(const Matcher *M) const override; }; @@ -576,7 +525,6 @@ public: private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return false; } - unsigned getHashImpl() const override { return 4123; } }; @@ -596,15 +544,12 @@ public: return N->getKind() == CheckChildType; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->ChildNo == ChildNo && cast(M)->Type == Type; } - unsigned getHashImpl() const override { return (Type << 3) | ChildNo; } bool isContradictoryImpl(const Matcher *M) const override; }; @@ -623,14 +568,11 @@ public: return N->getKind() == CheckInteger; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->Value == Value; } - unsigned getHashImpl() const override { return Value; } bool isContradictoryImpl(const Matcher *M) const override; }; @@ -650,15 +592,12 @@ public: return N->getKind() == CheckChildInteger; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->ChildNo == ChildNo && cast(M)->Value == Value; } - unsigned getHashImpl() const override { return (Value << 3) | ChildNo; } bool isContradictoryImpl(const Matcher *M) const override; }; @@ -676,14 +615,11 @@ public: return N->getKind() == CheckCondCode; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->CondCodeName == CondCodeName; } - unsigned getHashImpl() const override; }; /// CheckValueTypeMatcher - This checks to see if the current node is a @@ -700,14 +636,11 @@ public: return N->getKind() == CheckValueType; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->TypeName == TypeName; } - unsigned getHashImpl() const override; bool isContradictoryImpl(const Matcher *M) const override; }; @@ -744,18 +677,12 @@ public: return N->getKind() == CheckComplexPat; } - // Not safe to move a pattern predicate past a complex pattern. - bool isSafeToReorderWithPatternPredicate() const override { return false; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return &cast(M)->Pattern == &Pattern && cast(M)->MatchNumber == MatchNumber; } - unsigned getHashImpl() const override { - return (unsigned)(intptr_t)&Pattern ^ MatchNumber; - } }; /// CheckAndImmMatcher - This checks to see if the current node is an 'and' @@ -772,14 +699,11 @@ public: return N->getKind() == CheckAndImm; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->Value == Value; } - unsigned getHashImpl() const override { return Value; } }; /// CheckOrImmMatcher - This checks to see if the current node is an 'and' @@ -796,14 +720,11 @@ public: return N->getKind() == CheckOrImm; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return cast(M)->Value == Value; } - unsigned getHashImpl() const override { return Value; } }; /// CheckFoldableChainNodeMatcher - This checks to see if the current node @@ -817,12 +738,9 @@ public: return N->getKind() == CheckFoldableChainNode; } - bool isSafeToReorderWithPatternPredicate() const override { return true; } - private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override { return true; } - unsigned getHashImpl() const override { return 0; } }; /// EmitIntegerMatcher - This creates a new TargetConstant. @@ -846,7 +764,6 @@ private: return cast(M)->Val == Val && cast(M)->VT == VT; } - unsigned getHashImpl() const override { return (Val << 4) | VT; } }; /// EmitStringIntegerMatcher - A target constant whose value is represented @@ -871,7 +788,6 @@ private: return cast(M)->Val == Val && cast(M)->VT == VT; } - unsigned getHashImpl() const override; }; /// EmitRegisterMatcher - This creates a new TargetConstant. @@ -897,9 +813,6 @@ private: return cast(M)->Reg == Reg && cast(M)->VT == VT; } - unsigned getHashImpl() const override { - return ((unsigned)(intptr_t)Reg) << 4 | VT; - } }; /// EmitConvertToTargetMatcher - Emit an operation that reads a specified @@ -922,7 +835,6 @@ private: bool isEqualImpl(const Matcher *M) const override { return cast(M)->Slot == Slot; } - unsigned getHashImpl() const override { return Slot; } }; /// EmitMergeInputChainsMatcher - Emit a node that merges a list of input @@ -951,7 +863,6 @@ private: bool isEqualImpl(const Matcher *M) const override { return cast(M)->ChainNodes == ChainNodes; } - unsigned getHashImpl() const override; }; /// EmitCopyToRegMatcher - Emit a CopyToReg node from a value to a physreg, @@ -977,9 +888,6 @@ private: return cast(M)->SrcSlot == SrcSlot && cast(M)->DestPhysReg == DestPhysReg; } - unsigned getHashImpl() const override { - return SrcSlot ^ ((unsigned)(intptr_t)DestPhysReg << 4); - } }; @@ -1006,9 +914,6 @@ private: return cast(M)->Slot == Slot && cast(M)->NodeXForm == NodeXForm; } - unsigned getHashImpl() const override { - return Slot ^ ((unsigned)(intptr_t)NodeXForm << 4); - } }; /// EmitNodeMatcherCommon - Common class shared between EmitNode and @@ -1066,7 +971,6 @@ public: private: void printImpl(raw_ostream &OS, unsigned indent) const override; bool isEqualImpl(const Matcher *M) const override; - unsigned getHashImpl() const override; }; /// EmitNodeMatcher - This signals a successful match and generates a node. @@ -1116,34 +1020,6 @@ public: } }; -/// MarkGlueResultsMatcher - This node indicates which non-root nodes in the -/// pattern produce glue. This allows CompleteMatchMatcher to update them -/// with the output glue of the resultant code. -class MarkGlueResultsMatcher : public Matcher { - SmallVector GlueResultNodes; -public: - MarkGlueResultsMatcher(ArrayRef nodes) - : Matcher(MarkGlueResults), GlueResultNodes(nodes.begin(), nodes.end()) {} - - unsigned getNumNodes() const { return GlueResultNodes.size(); } - - unsigned getNode(unsigned i) const { - assert(i < GlueResultNodes.size()); - return GlueResultNodes[i]; - } - - static inline bool classof(const Matcher *N) { - return N->getKind() == MarkGlueResults; - } - -private: - void printImpl(raw_ostream &OS, unsigned indent) const override; - bool isEqualImpl(const Matcher *M) const override { - return cast(M)->GlueResultNodes == GlueResultNodes; - } - unsigned getHashImpl() const override; -}; - /// CompleteMatchMatcher - Complete a match by replacing the results of the /// pattern with the newly generated nodes. This also prints a comment /// indicating the source and dest patterns. @@ -1170,7 +1046,6 @@ private: return cast(M)->Results == Results && &cast(M)->Pattern == &Pattern; } - unsigned getHashImpl() const override; }; } // end namespace llvm diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp index 4f944beaa50b9dde928be8ba320ff41c210f7eb5..d30fc5131cbaf2fdf808ec42a1131d5466bd400f 100644 --- a/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -247,9 +247,16 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, OS << "OPC_CaptureGlueInput,\n"; return 1; - case Matcher::MoveChild: - OS << "OPC_MoveChild, " << cast(N)->getChildNo() << ",\n"; - return 2; + case Matcher::MoveChild: { + const auto *MCM = cast(N); + + OS << "OPC_MoveChild"; + // Handle the specialized forms. + if (MCM->getChildNo() >= 8) + OS << ", "; + OS << MCM->getChildNo() << ",\n"; + return (MCM->getChildNo() >= 8) ? 2 : 1; + } case Matcher::MoveParent: OS << "OPC_MoveParent,\n"; @@ -532,6 +539,10 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, case Matcher::MorphNodeTo: { const EmitNodeMatcherCommon *EN = cast(N); OS << (isa(EN) ? "OPC_EmitNode" : "OPC_MorphNodeTo"); + bool CompressVTs = EN->getNumVTs() < 3; + if (CompressVTs) + OS << EN->getNumVTs(); + OS << ", TARGET_VAL(" << EN->getOpcodeName() << "), 0"; if (EN->hasChain()) OS << "|OPFL_Chain"; @@ -542,10 +553,13 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, OS << "|OPFL_Variadic" << EN->getNumFixedArityOperands(); OS << ",\n"; - OS.PadToColumn(Indent*2+4) << EN->getNumVTs(); - if (!OmitComments) - OS << "/*#VTs*/"; - OS << ", "; + OS.PadToColumn(Indent*2+4); + if (!CompressVTs) { + OS << EN->getNumVTs(); + if (!OmitComments) + OS << "/*#VTs*/"; + OS << ", "; + } for (unsigned i = 0, e = EN->getNumVTs(); i != e; ++i) OS << getEnumName(EN->getVT(i)) << ", "; @@ -579,16 +593,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, } else OS << '\n'; - return 6+EN->getNumVTs()+NumOperandBytes; - } - case Matcher::MarkGlueResults: { - const MarkGlueResultsMatcher *CFR = cast(N); - OS << "OPC_MarkGlueResults, " << CFR->getNumNodes() << ", "; - unsigned NumOperandBytes = 0; - for (unsigned i = 0, e = CFR->getNumNodes(); i != e; ++i) - NumOperandBytes += EmitVBRValue(CFR->getNode(i), OS); - OS << '\n'; - return 2+NumOperandBytes; + return 5 + !CompressVTs + EN->getNumVTs() + NumOperandBytes; } case Matcher::CompleteMatch: { const CompleteMatchMatcher *CM = cast(N); @@ -807,7 +812,6 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M, case Matcher::EmitNode: OS << "OPC_EmitNode"; break; case Matcher::MorphNodeTo: OS << "OPC_MorphNodeTo"; break; case Matcher::EmitNodeXForm: OS << "OPC_EmitNodeXForm"; break; - case Matcher::MarkGlueResults: OS << "OPC_MarkGlueResults"; break; case Matcher::CompleteMatch: OS << "OPC_CompleteMatch"; break; } @@ -837,8 +841,9 @@ void llvm::EmitMatcherTable(const Matcher *TheMatcher, MatcherEmitter.EmitHistogram(TheMatcher, OS); OS << " #undef TARGET_VAL\n"; - OS << " return SelectCodeCommon(N, MatcherTable,sizeof(MatcherTable));\n}\n"; - OS << '\n'; + OS << " SelectCodeCommon(N, MatcherTable,sizeof(MatcherTable));\n"; + OS << " return nullptr;\n"; + OS << "}\n"; // Next up, emit the function for node and pattern predicates: MatcherEmitter.EmitPredicateFunctions(OS); diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp index 9663b71d6620da06b69e4bfd3e03f81a7c7188d5..4110e9725b5a8a1865c54184eb118a859a3f9e08 100644 --- a/utils/TableGen/DAGISelMatcherGen.cpp +++ b/utils/TableGen/DAGISelMatcherGen.cpp @@ -10,7 +10,6 @@ #include "DAGISelMatcher.h" #include "CodeGenDAGPatterns.h" #include "CodeGenRegisters.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/TableGen/Error.h" @@ -76,10 +75,6 @@ namespace { /// array of all of the recorded input nodes that have chains. SmallVector MatchedChainNodes; - /// MatchedGlueResultNodes - This maintains the position in the recorded - /// nodes array of all of the recorded input nodes that have glue results. - SmallVector MatchedGlueResultNodes; - /// MatchedComplexPatterns - This maintains a list of all of the /// ComplexPatterns that we need to check. The second element of each pair /// is the recorded operand number of the input node. @@ -121,7 +116,7 @@ namespace { /// If this is the first time a node with unique identifier Name has been /// seen, record it. Otherwise, emit a check to make sure this is the same /// node. Returns true if this is the first encounter. - bool recordUniqueNode(std::string Name); + bool recordUniqueNode(const std::string &Name); // Result Code Generation. unsigned getNamedArgumentSlot(StringRef Name) { @@ -426,8 +421,6 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, AddMatcher(new RecordMatcher("'" + N->getOperator()->getName() + "' glue output node", NextRecordedOperandNo)); - // Remember all of the nodes with output glue our pattern will match. - MatchedGlueResultNodes.push_back(NextRecordedOperandNo++); } // If this node is known to have an input glue or if it *might* have an input @@ -445,7 +438,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, } } -bool MatcherGen::recordUniqueNode(std::string Name) { +bool MatcherGen::recordUniqueNode(const std::string &Name) { unsigned &VarMapEntry = VariableMap[Name]; if (VarMapEntry == 0) { // If it is a named node, we must emit a 'Record' opcode. @@ -989,11 +982,6 @@ void MatcherGen::EmitResultCode() { assert(Ops.size() >= NumSrcResults && "Didn't provide enough results"); Ops.resize(NumSrcResults); - // If the matched pattern covers nodes which define a glue result, emit a node - // that tells the matcher about them so that it can update their results. - if (!MatchedGlueResultNodes.empty()) - AddMatcher(new MarkGlueResultsMatcher(MatchedGlueResultNodes)); - AddMatcher(new CompleteMatchMatcher(Ops, Pattern)); } diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp index c9ee371e3e2fe9fdc1a6a1482ec136d27798f62e..ad385fac043895fde25691db24276c2a20aea33f 100644 --- a/utils/TableGen/DAGISelMatcherOpt.cpp +++ b/utils/TableGen/DAGISelMatcherOpt.cpp @@ -13,7 +13,6 @@ #include "DAGISelMatcher.h" #include "CodeGenDAGPatterns.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -79,24 +78,6 @@ static void ContractNodes(std::unique_ptr &MatcherPtr, return ContractNodes(MatcherPtr, CGP); } - // Turn EmitNode->MarkFlagResults->CompleteMatch into - // MarkFlagResults->EmitNode->CompleteMatch when we can to encourage - // MorphNodeTo formation. This is safe because MarkFlagResults never refers - // to the root of the pattern. - if (isa(N) && isa(N->getNext()) && - isa(N->getNext()->getNext())) { - // Unlink the two nodes from the list. - Matcher *EmitNode = MatcherPtr.release(); - Matcher *MFR = EmitNode->takeNext(); - Matcher *Tail = MFR->takeNext(); - - // Relink them. - MatcherPtr.reset(MFR); - MFR->setNext(EmitNode); - EmitNode->setNext(Tail); - return ContractNodes(MatcherPtr, CGP); - } - // Turn EmitNode->CompleteMatch into MorphNodeTo if we can. if (EmitNodeMatcher *EN = dyn_cast(N)) if (CompleteMatchMatcher *CM = @@ -177,59 +158,6 @@ static void ContractNodes(std::unique_ptr &MatcherPtr, } } -/// SinkPatternPredicates - Pattern predicates can be checked at any level of -/// the matching tree. The generator dumps them at the top level of the pattern -/// though, which prevents factoring from being able to see past them. This -/// optimization sinks them as far down into the pattern as possible. -/// -/// Conceptually, we'd like to sink these predicates all the way to the last -/// matcher predicate in the series. However, it turns out that some -/// ComplexPatterns have side effects on the graph, so we really don't want to -/// run a complex pattern if the pattern predicate will fail. For this -/// reason, we refuse to sink the pattern predicate past a ComplexPattern. -/// -static void SinkPatternPredicates(std::unique_ptr &MatcherPtr) { - // Recursively scan for a PatternPredicate. - // If we reached the end of the chain, we're done. - Matcher *N = MatcherPtr.get(); - if (!N) return; - - // Walk down all members of a scope node. - if (ScopeMatcher *Scope = dyn_cast(N)) { - for (unsigned i = 0, e = Scope->getNumChildren(); i != e; ++i) { - std::unique_ptr Child(Scope->takeChild(i)); - SinkPatternPredicates(Child); - Scope->resetChild(i, Child.release()); - } - return; - } - - // If this node isn't a CheckPatternPredicateMatcher we keep scanning until - // we find one. - CheckPatternPredicateMatcher *CPPM =dyn_cast(N); - if (!CPPM) - return SinkPatternPredicates(N->getNextPtr()); - - // Ok, we found one, lets try to sink it. Check if we can sink it past the - // next node in the chain. If not, we won't be able to change anything and - // might as well bail. - if (!CPPM->getNext()->isSafeToReorderWithPatternPredicate()) - return; - - // Okay, we know we can sink it past at least one node. Unlink it from the - // chain and scan for the new insertion point. - MatcherPtr.release(); // Don't delete CPPM. - MatcherPtr.reset(CPPM->takeNext()); - - N = MatcherPtr.get(); - while (N->getNext()->isSafeToReorderWithPatternPredicate()) - N = N->getNext(); - - // At this point, we want to insert CPPM after N. - CPPM->setNext(N->takeNext()); - N->setNext(CPPM); -} - /// FindNodeWithKind - Scan a series of matchers looking for a matcher with a /// specified kind. Return null if we didn't find one otherwise return the /// matcher. @@ -264,8 +192,7 @@ static void FactorNodes(std::unique_ptr &MatcherPtr) { return FactorNodes(N->getNextPtr()); // Okay, pull together the children of the scope node into a vector so we can - // inspect it more easily. While we're at it, bucket them up by the hash - // code of their first predicate. + // inspect it more easily. SmallVector OptionsToMatch; for (unsigned i = 0, e = Scope->getNumChildren(); i != e; ++i) { @@ -456,7 +383,8 @@ static void FactorNodes(std::unique_ptr &MatcherPtr) { CheckOpcodeMatcher *COM = cast(NewOptionsToMatch[i]); assert(Opcodes.insert(COM->getOpcode().getEnumName()).second && "Duplicate opcodes not factored?"); - Cases.push_back(std::make_pair(&COM->getOpcode(), COM->getNext())); + Cases.push_back(std::make_pair(&COM->getOpcode(), COM->takeNext())); + delete COM; } MatcherPtr.reset(new SwitchOpcodeMatcher(Cases)); @@ -486,7 +414,9 @@ static void FactorNodes(std::unique_ptr &MatcherPtr) { } Matcher *Entries[2] = { PrevMatcher, MatcherWithoutCTM }; - Cases[Entry-1].second = new ScopeMatcher(Entries); + std::unique_ptr Case(new ScopeMatcher(Entries)); + FactorNodes(Case); + Cases[Entry-1].second = Case.release(); continue; } @@ -515,6 +445,5 @@ void llvm::OptimizeMatcher(std::unique_ptr &MatcherPtr, const CodeGenDAGPatterns &CGP) { ContractNodes(MatcherPtr, CGP); - SinkPatternPredicates(MatcherPtr); FactorNodes(MatcherPtr); } diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp index 17e9e40acd488640de9109c0a4226a22676fae78..e31caaf3c98c674e3f3af9f63f0b470b1e04880d 100644 --- a/utils/TableGen/DFAPacketizerEmitter.cpp +++ b/utils/TableGen/DFAPacketizerEmitter.cpp @@ -24,7 +24,6 @@ #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include "llvm/Support/Debug.h" -#include #include #include #include @@ -710,7 +709,7 @@ int DFAPacketizerEmitter::collectAllComboFuncs( Record *ComboFunc = FuncData->getValueAsDef("TheComboFunc"); const std::vector &FuncList = FuncData->getValueAsListOfDefs("FuncList"); - std::string ComboFuncName = ComboFunc->getName(); + const std::string &ComboFuncName = ComboFunc->getName(); unsigned ComboBit = FUNameToBitsMap[ComboFuncName]; unsigned ComboResources = ComboBit; DEBUG(dbgs() << " combo: " << ComboFuncName diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp index b6a2b1c7f5d45840d375cfb11c04a2934702f1a7..44815b05f274f1aed81bc648ab2f05c13c1cb6b9 100644 --- a/utils/TableGen/DisassemblerEmitter.cpp +++ b/utils/TableGen/DisassemblerEmitter.cpp @@ -96,12 +96,11 @@ using namespace llvm::X86Disassembler; namespace llvm { extern void EmitFixedLenDecoder(RecordKeeper &RK, raw_ostream &OS, - std::string PredicateNamespace, - std::string GPrefix, - std::string GPostfix, - std::string ROK, - std::string RFail, - std::string L); + const std::string &PredicateNamespace, + const std::string &GPrefix, + const std::string &GPostfix, + const std::string &ROK, + const std::string &RFail, const std::string &L); void EmitDisassembler(RecordKeeper &Records, raw_ostream &OS) { CodeGenTarget Target(Records); diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index 748c923477838cf2eef0b4c148fe8e483779aecd..debb12c4f5110561128eff9717adb83ce61804d2 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -18,13 +18,13 @@ //===----------------------------------------------------------------------===// #include "CodeGenDAGPatterns.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" +#include using namespace llvm; @@ -417,9 +417,7 @@ static std::string getLegalCName(std::string OpName) { return OpName; } -FastISelMap::FastISelMap(std::string instns) - : InstNS(instns) { -} +FastISelMap::FastISelMap(std::string instns) : InstNS(std::move(instns)) {} static std::string PhyRegForNode(TreePatternNode *Op, const CodeGenTarget &Target) { diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp index 15ca5590296dcd4fea521fa57247a11b4f8873ff..0506400b90f651fdf9e085c6d3dca5d47d0e783d 100644 --- a/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -28,6 +28,7 @@ #include "llvm/TableGen/Record.h" #include #include +#include #include using namespace llvm; @@ -47,7 +48,7 @@ struct OperandInfo { bool HasCompleteDecoder; OperandInfo(std::string D, bool HCD) - : Decoder(D), HasCompleteDecoder(HCD) { } + : Decoder(std::move(D)), HasCompleteDecoder(HCD) {} void addField(unsigned Base, unsigned Width, unsigned Offset) { Fields.push_back(EncodingField(Base, Width, Offset)); @@ -83,17 +84,16 @@ public: // Defaults preserved here for documentation, even though they aren't // strictly necessary given the way that this is currently being called. - FixedLenDecoderEmitter(RecordKeeper &R, - std::string PredicateNamespace, - std::string GPrefix = "if (", + FixedLenDecoderEmitter(RecordKeeper &R, std::string PredicateNamespace, + std::string GPrefix = "if (", std::string GPostfix = " == MCDisassembler::Fail)", - std::string ROK = "MCDisassembler::Success", - std::string RFail = "MCDisassembler::Fail", - std::string L = "") : - Target(R), - PredicateNamespace(PredicateNamespace), - GuardPrefix(GPrefix), GuardPostfix(GPostfix), - ReturnOK(ROK), ReturnFail(RFail), Locals(L) {} + std::string ROK = "MCDisassembler::Success", + std::string RFail = "MCDisassembler::Fail", + std::string L = "") + : Target(R), PredicateNamespace(std::move(PredicateNamespace)), + GuardPrefix(std::move(GPrefix)), GuardPostfix(std::move(GPostfix)), + ReturnOK(std::move(ROK)), ReturnFail(std::move(RFail)), + Locals(std::move(L)) {} // Emit the decoder state machine table. void emitTable(formatted_raw_ostream &o, DecoderTable &Table, @@ -410,9 +410,6 @@ protected: return Filters[BestIndex]; } - // Called from Filter::recurse() when singleton exists. For debug purpose. - void SingletonExists(unsigned Opc) const; - bool PositionFiltered(unsigned i) const { return ValueSet(FilterBitValues[i]); } @@ -559,7 +556,6 @@ void Filter::recurse() { // No need to recurse for a singleton filtered instruction. // See also Filter::emit*(). if (getNumFiltered() == 1) { - //Owner->SingletonExists(LastOpcFiltered); assert(FilterChooserMap.size() == 1); return; } @@ -977,30 +973,6 @@ void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) const { } } -// Called from Filter::recurse() when singleton exists. For debug purpose. -void FilterChooser::SingletonExists(unsigned Opc) const { - insn_t Insn0; - insnWithID(Insn0, Opc); - - errs() << "Singleton exists: " << nameWithID(Opc) - << " with its decoding dominating "; - for (unsigned i = 0; i < Opcodes.size(); ++i) { - if (Opcodes[i] == Opc) continue; - errs() << nameWithID(Opcodes[i]) << ' '; - } - errs() << '\n'; - - dumpStack(errs(), "\t\t"); - for (unsigned i = 0; i < Opcodes.size(); ++i) { - const std::string &Name = nameWithID(Opcodes[i]); - - errs() << '\t' << Name << " "; - dumpBits(errs(), - getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); - errs() << '\n'; - } -} - // Calculates the island(s) needed to decode the instruction. // This returns a list of undecoded bits of an instructions, for example, // Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be @@ -2324,12 +2296,10 @@ void FixedLenDecoderEmitter::run(raw_ostream &o) { namespace llvm { void EmitFixedLenDecoder(RecordKeeper &RK, raw_ostream &OS, - std::string PredicateNamespace, - std::string GPrefix, - std::string GPostfix, - std::string ROK, - std::string RFail, - std::string L) { + const std::string &PredicateNamespace, + const std::string &GPrefix, + const std::string &GPostfix, const std::string &ROK, + const std::string &RFail, const std::string &L) { FixedLenDecoderEmitter(RK, PredicateNamespace, GPrefix, GPostfix, ROK, RFail, L).run(OS); } diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index 044e9e211516acf2e1a8ea6bafbe8cc8581a7d6e..02461cc0508dd7e46f0d5d4ca29af2bb24d9ed3f 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -428,7 +428,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "namespace llvm {\n"; OS << "struct " << ClassName << " : public TargetInstrInfo {\n" << " explicit " << ClassName - << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1);\n" + << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1, int ReturnOpcode = -1);\n" << " ~" << ClassName << "() override {}\n" << "};\n"; OS << "} // end llvm namespace\n"; @@ -443,8 +443,8 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n"; OS << "extern const char " << TargetName << "InstrNameData[];\n"; OS << ClassName << "::" << ClassName - << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode)\n" - << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode) {\n" + << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode, int ReturnOpcode)\n" + << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, ReturnOpcode) {\n" << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, " << NumberedInstructions.size() << ");\n}\n"; diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index dcb70e19ba8499be5234e1d959dfb9f67ddccf76..062d25c6a4e929c64a183e67bb0947bd338eb6cb 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -462,8 +462,8 @@ struct AttributeComparator { return R->isConvergent; // Try to order by readonly/readnone attribute. - CodeGenIntrinsic::ModRefKind LK = L->ModRef; - CodeGenIntrinsic::ModRefKind RK = R->ModRef; + CodeGenIntrinsic::ModRefBehavior LK = L->ModRef; + CodeGenIntrinsic::ModRefBehavior RK = R->ModRef; if (LK != RK) return (LK > RK); // Order by argument attributes. @@ -548,12 +548,24 @@ EmitAttributes(const std::vector &Ints, raw_ostream &OS) { OS << "Attribute::NoCapture"; addComma = true; break; + case CodeGenIntrinsic::Returned: + if (addComma) + OS << ","; + OS << "Attribute::Returned"; + addComma = true; + break; case CodeGenIntrinsic::ReadOnly: if (addComma) OS << ","; OS << "Attribute::ReadOnly"; addComma = true; break; + case CodeGenIntrinsic::WriteOnly: + if (addComma) + OS << ","; + OS << "Attribute::WriteOnly"; + addComma = true; + break; case CodeGenIntrinsic::ReadNone: if (addComma) OS << ","; @@ -616,6 +628,17 @@ EmitAttributes(const std::vector &Ints, raw_ostream &OS) { OS << ","; OS << "Attribute::ReadOnly"; break; + case CodeGenIntrinsic::WriteArgMem: + if (addComma) + OS << ","; + OS << "Attribute::WriteOnly,"; + OS << "Attribute::ArgMemOnly"; + break; + case CodeGenIntrinsic::WriteMem: + if (addComma) + OS << ","; + OS << "Attribute::WriteOnly"; + break; case CodeGenIntrinsic::ReadWriteArgMem: if (addComma) OS << ","; diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index b727df75626f22ce1318c21a6855a5cef3aaffda..9bb988f30f18aac47e87b0984a198922646047ba 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -16,22 +16,38 @@ #include "CodeGenRegisters.h" #include "CodeGenTarget.h" #include "SequenceToOffsetTable.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SparseBitVector.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/MachineValueType.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" +#include "llvm/TableGen/SetTheory.h" #include "llvm/TableGen/TableGenBackend.h" #include +#include +#include +#include +#include +#include #include +#include #include + using namespace llvm; namespace { + class RegisterInfoEmitter { RecordKeeper &Records; + public: RegisterInfoEmitter(RecordKeeper &R) : Records(R) {} @@ -65,7 +81,8 @@ private: void emitComposeSubRegIndexLaneMask(raw_ostream &OS, CodeGenRegBank &RegBank, const std::string &ClassName); }; -} // End anonymous namespace + +} // end anonymous namespace // runEnums - Print out enum values for all of the registers. void RegisterInfoEmitter::runEnums(raw_ostream &OS, @@ -81,7 +98,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, emitSourceFileHeader("Target Register Enum Values", OS); OS << "\n#ifdef GET_REGINFO_ENUM\n"; - OS << "#undef GET_REGINFO_ENUM\n"; + OS << "#undef GET_REGINFO_ENUM\n\n"; OS << "namespace llvm {\n\n"; @@ -100,7 +117,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, OS << " NUM_TARGET_REGS \t// " << Registers.size()+1 << "\n"; OS << "};\n"; if (!Namespace.empty()) - OS << "}\n"; + OS << "} // end namespace " << Namespace << "\n"; const auto &RegisterClasses = Bank.getRegClasses(); if (!RegisterClasses.empty()) { @@ -109,7 +126,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, assert(RegisterClasses.size() <= 0xffff && "Too many register classes to fit in tables"); - OS << "\n// Register classes\n"; + OS << "\n// Register classes\n\n"; if (!Namespace.empty()) OS << "namespace " << Namespace << " {\n"; OS << "enum {\n"; @@ -118,14 +135,14 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, << " = " << RC.EnumValue << ",\n"; OS << "\n };\n"; if (!Namespace.empty()) - OS << "}\n"; + OS << "} // end namespace " << Namespace << "\n\n"; } const std::vector &RegAltNameIndices = Target.getRegAltNameIndices(); // If the only definition is the default NoRegAltName, we don't need to // emit anything. if (RegAltNameIndices.size() > 1) { - OS << "\n// Register alternate name indices\n"; + OS << "\n// Register alternate name indices\n\n"; if (!Namespace.empty()) OS << "namespace " << Namespace << " {\n"; OS << "enum {\n"; @@ -134,12 +151,12 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, OS << " NUM_TARGET_REG_ALT_NAMES = " << RegAltNameIndices.size() << "\n"; OS << "};\n"; if (!Namespace.empty()) - OS << "}\n"; + OS << "} // end namespace " << Namespace << "\n\n"; } auto &SubRegIndices = Bank.getSubRegIndices(); if (!SubRegIndices.empty()) { - OS << "\n// Subregister indices\n"; + OS << "\n// Subregister indices\n\n"; std::string Namespace = SubRegIndices.front().getNamespace(); if (!Namespace.empty()) OS << "namespace " << Namespace << " {\n"; @@ -149,10 +166,10 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS, OS << " " << Idx.getName() << ",\t// " << ++i << "\n"; OS << " NUM_TARGET_SUBREGS\n};\n"; if (!Namespace.empty()) - OS << "}\n"; + OS << "} // end namespace " << Namespace << "\n\n"; } - OS << "} // End llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_REGINFO_ENUM\n\n"; } @@ -728,15 +745,11 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, SubReg2SequenceIndexMap.push_back(Found); } - OS << "unsigned " << ClName - << "::composeSubRegIndexLaneMaskImpl(unsigned IdxA, unsigned LaneMask)" - " const {\n"; - OS << " struct MaskRolOp {\n" " unsigned Mask;\n" " uint8_t RotateLeft;\n" " };\n" - " static const MaskRolOp Seqs[] = {\n"; + " static const MaskRolOp LaneMaskComposeSequences[] = {\n"; unsigned Idx = 0; for (size_t s = 0, se = Sequences.size(); s != se; ++s) { OS << " "; @@ -756,24 +769,43 @@ RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, for (size_t i = 0, e = SubRegIndices.size(); i != e; ++i) { OS << " "; unsigned Idx = SubReg2SequenceIndexMap[i]; - OS << format("&Seqs[%u]", Idx); + OS << format("&LaneMaskComposeSequences[%u]", Idx); if (i+1 != e) OS << ","; OS << " // to " << SubRegIndices[i].getName() << "\n"; } OS << " };\n\n"; - OS << " --IdxA; assert(IdxA < " << SubRegIndices.size() + OS << "LaneBitmask " << ClName + << "::composeSubRegIndexLaneMaskImpl(unsigned IdxA, LaneBitmask LaneMask)" + " const {\n" + " --IdxA; assert(IdxA < " << SubRegIndices.size() << " && \"Subregister index out of bounds\");\n" - " unsigned Result = 0;\n" + " LaneBitmask Result = 0;\n" " for (const MaskRolOp *Ops = CompositeSequences[IdxA]; Ops->Mask != 0; ++Ops)" " {\n" - " unsigned Masked = LaneMask & Ops->Mask;\n" + " LaneBitmask Masked = LaneMask & Ops->Mask;\n" " Result |= (Masked << Ops->RotateLeft) & 0xFFFFFFFF;\n" " Result |= (Masked >> ((32 - Ops->RotateLeft) & 0x1F));\n" " }\n" " return Result;\n" - "}\n"; + "}\n\n"; + + OS << "LaneBitmask " << ClName + << "::reverseComposeSubRegIndexLaneMaskImpl(unsigned IdxA, " + " LaneBitmask LaneMask) const {\n" + " LaneMask &= getSubRegIndexLaneMask(IdxA);\n" + " --IdxA; assert(IdxA < " << SubRegIndices.size() + << " && \"Subregister index out of bounds\");\n" + " LaneBitmask Result = 0;\n" + " for (const MaskRolOp *Ops = CompositeSequences[IdxA]; Ops->Mask != 0; ++Ops)" + " {\n" + " LaneBitmask Rotated = (LaneMask >> Ops->RotateLeft) |\n" + " ((LaneMask << ((32 - Ops->RotateLeft) & 0x1F)) & 0xFFFFFFFF);\n" + " Result |= Rotated & Ops->Mask;\n" + " }\n" + " return Result;\n" + "}\n\n"; } // @@ -785,7 +817,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, emitSourceFileHeader("MC Register Information", OS); OS << "\n#ifdef GET_REGINFO_MC_DESC\n"; - OS << "#undef GET_REGINFO_MC_DESC\n"; + OS << "#undef GET_REGINFO_MC_DESC\n\n"; const auto &Regs = RegBank.getRegisters(); @@ -958,7 +990,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, ArrayRef Order = RC.getOrder(); // Give the register class a legal C name if it's anonymous. - std::string Name = RC.getName(); + const std::string &Name = RC.getName(); RegClassStrings.add(Name); @@ -984,7 +1016,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "\n };\n\n"; } - OS << "}\n\n"; + OS << "} // end anonymous namespace\n\n"; RegClassStrings.layout(); OS << "extern const char " << TargetName << "RegClassStrings[] = {\n"; @@ -1008,7 +1040,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, << RC.SpillSize/8 << ", " << RC.SpillAlignment/8 << ", " << RC.CopyCost << ", " - << RC.Allocatable << " },\n"; + << ( RC.Allocatable ? "true" : "false" ) << " },\n"; } OS << "};\n\n"; @@ -1051,7 +1083,7 @@ RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "}\n\n"; - OS << "} // End llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_REGINFO_MC_DESC\n\n"; } @@ -1061,7 +1093,7 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, emitSourceFileHeader("Register Information Header Fragment", OS); OS << "\n#ifdef GET_REGINFO_HEADER\n"; - OS << "#undef GET_REGINFO_HEADER\n"; + OS << "#undef GET_REGINFO_HEADER\n\n"; const std::string &TargetName = Target.getName(); std::string ClassName = TargetName + "GenRegisterInfo"; @@ -1078,8 +1110,10 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, if (!RegBank.getSubRegIndices().empty()) { OS << " unsigned composeSubRegIndicesImpl" << "(unsigned, unsigned) const override;\n" - << " unsigned composeSubRegIndexLaneMaskImpl" - << "(unsigned, unsigned) const override;\n" + << " LaneBitmask composeSubRegIndexLaneMaskImpl" + << "(unsigned, LaneBitmask) const override;\n" + << " LaneBitmask reverseComposeSubRegIndexLaneMaskImpl" + << "(unsigned, LaneBitmask) const override;\n" << " const TargetRegisterClass *getSubClassWithSubReg" << "(const TargetRegisterClass*, unsigned) const override;\n"; } @@ -1113,9 +1147,9 @@ RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, // Output the extern for the instance. OS << " extern const TargetRegisterClass " << Name << "RegClass;\n"; } - OS << "} // end of namespace " << TargetName << "\n\n"; + OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n\n"; } - OS << "} // End llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_REGINFO_HEADER\n\n"; } @@ -1128,7 +1162,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, emitSourceFileHeader("Target Register and Register Classes Information", OS); OS << "\n#ifdef GET_REGINFO_TARGET_DESC\n"; - OS << "#undef GET_REGINFO_TARGET_DESC\n"; + OS << "#undef GET_REGINFO_TARGET_DESC\n\n"; OS << "namespace llvm {\n\n"; @@ -1294,7 +1328,9 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, << format("0x%08x,\n ", RC.LaneMask) << (unsigned)RC.AllocationPriority << ",\n " << (RC.HasDisjunctSubRegs?"true":"false") - << ", /* HasDisjunctSubRegs */\n "; + << ", /* HasDisjunctSubRegs */\n " + << (RC.CoveredBySubRegs?"true":"false") + << ", /* CoveredBySubRegs */\n "; if (RC.getSuperClasses().empty()) OS << "NullRegClasses,\n "; else @@ -1306,7 +1342,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, OS << " };\n\n"; } - OS << "}\n"; + OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n"; } OS << "\nnamespace {\n"; @@ -1314,19 +1350,20 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, for (const auto &RC : RegisterClasses) OS << " &" << RC.getQualifiedName() << "RegClass,\n"; OS << " };\n"; - OS << "}\n"; // End of anonymous namespace... + OS << "} // end anonymous namespace\n"; // Emit extra information about registers. const std::string &TargetName = Target.getName(); OS << "\nstatic const TargetRegisterInfoDesc " << TargetName << "RegInfoDesc[] = { // Extra Descriptors\n"; - OS << " { 0, 0 },\n"; + OS << " { 0, false },\n"; const auto &Regs = RegBank.getRegisters(); for (const auto &Reg : Regs) { OS << " { "; OS << Reg.CostPerUse << ", " - << int(AllocatableRegs.count(Reg.TheDef)) << " },\n"; + << ( AllocatableRegs.count(Reg.TheDef) != 0 ? "true" : "false" ) + << " },\n"; } OS << "};\n"; // End of register descriptors... @@ -1414,7 +1451,6 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, OS << "}\n\n"; - // Emit CalleeSavedRegs information. std::vector CSRSets = Records.getAllDerivedDefinitions("CalleeSavedRegs"); @@ -1482,7 +1518,7 @@ RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, << " MF.getSubtarget().getFrameLowering());\n" << "}\n\n"; - OS << "} // End llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_REGINFO_TARGET_DESC\n\n"; } @@ -1503,4 +1539,4 @@ void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS) { RegisterInfoEmitter(RK).run(OS); } -} // End llvm namespace +} // end namespace llvm diff --git a/utils/TableGen/SearchableTableEmitter.cpp b/utils/TableGen/SearchableTableEmitter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c1b8804d1741feb890da1c6b4f02252259bdf3c --- /dev/null +++ b/utils/TableGen/SearchableTableEmitter.cpp @@ -0,0 +1,320 @@ +//===- SearchableTableEmitter.cpp - Generate efficiently searchable tables -==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits a generic array initialized by specified fields, +// together with companion index tables and lookup functions (binary search, +// currently). +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include +#include +#include +#include +using namespace llvm; + +#define DEBUG_TYPE "searchable-table-emitter" + +namespace { + +class SearchableTableEmitter { + RecordKeeper &Records; + +public: + SearchableTableEmitter(RecordKeeper &R) : Records(R) {} + + void run(raw_ostream &OS); + +private: + typedef std::pair SearchTableEntry; + + int getAsInt(BitsInit *B) { + return cast(B->convertInitializerTo(IntRecTy::get()))->getValue(); + } + int getInt(Record *R, StringRef Field) { + return getAsInt(R->getValueAsBitsInit(Field)); + } + + std::string primaryRepresentation(Init *I) { + if (StringInit *SI = dyn_cast(I)) + return SI->getAsString(); + else if (BitsInit *BI = dyn_cast(I)) + return "0x" + utohexstr(getAsInt(BI)); + else if (BitInit *BI = dyn_cast(I)) + return BI->getValue() ? "true" : "false"; + else if (CodeInit *CI = dyn_cast(I)) { + return CI->getValue(); + } + PrintFatalError(SMLoc(), + "invalid field type, expected: string, bits, bit or code"); + } + + std::string searchRepresentation(Init *I) { + std::string PrimaryRep = primaryRepresentation(I); + if (!isa(I)) + return PrimaryRep; + return StringRef(PrimaryRep).upper(); + } + + std::string searchableFieldType(Init *I) { + if (isa(I)) + return "const char *"; + else if (BitsInit *BI = dyn_cast(I)) { + unsigned NumBits = BI->getNumBits(); + if (NumBits <= 8) + NumBits = 8; + else if (NumBits <= 16) + NumBits = 16; + else if (NumBits <= 32) + NumBits = 32; + else if (NumBits <= 64) + NumBits = 64; + else + PrintFatalError(SMLoc(), "bitfield too large to search"); + return "uint" + utostr(NumBits) + "_t"; + } + PrintFatalError(SMLoc(), "Unknown type to search by"); + } + + void emitMapping(Record *MappingDesc, raw_ostream &OS); + void emitMappingEnum(std::vector &Items, Record *InstanceClass, + raw_ostream &OS); + void + emitPrimaryTable(StringRef Name, std::vector &FieldNames, + std::vector &SearchFieldNames, + std::vector> &SearchTables, + std::vector &Items, raw_ostream &OS); + void emitSearchTable(StringRef Name, StringRef Field, + std::vector &SearchTable, + raw_ostream &OS); + void emitLookupDeclaration(StringRef Name, StringRef Field, Init *I, + raw_ostream &OS); + void emitLookupFunction(StringRef Name, StringRef Field, Init *I, + raw_ostream &OS); +}; + +} // End anonymous namespace. + +/// Emit an enum providing symbolic access to some preferred field from +/// C++. +void SearchableTableEmitter::emitMappingEnum(std::vector &Items, + Record *InstanceClass, + raw_ostream &OS) { + std::string EnumNameField = InstanceClass->getValueAsString("EnumNameField"); + std::string EnumValueField; + if (!InstanceClass->isValueUnset("EnumValueField")) + EnumValueField = InstanceClass->getValueAsString("EnumValueField"); + + OS << "enum " << InstanceClass->getName() << "Values {\n"; + for (auto Item : Items) { + OS << " " << Item->getValueAsString(EnumNameField); + if (EnumValueField != StringRef()) + OS << " = " << getInt(Item, EnumValueField); + OS << ",\n"; + } + OS << "};\n\n"; +} + +void SearchableTableEmitter::emitPrimaryTable( + StringRef Name, std::vector &FieldNames, + std::vector &SearchFieldNames, + std::vector> &SearchTables, + std::vector &Items, raw_ostream &OS) { + OS << "const " << Name << " " << Name << "sList[] = {\n"; + + for (auto Item : Items) { + OS << " { "; + for (unsigned i = 0; i < FieldNames.size(); ++i) { + OS << primaryRepresentation(Item->getValueInit(FieldNames[i])); + if (i != FieldNames.size() - 1) + OS << ", "; + } + OS << "},\n"; + } + OS << "};\n\n"; +} + +void SearchableTableEmitter::emitSearchTable( + StringRef Name, StringRef Field, std::vector &SearchTable, + raw_ostream &OS) { + OS << "const std::pair<" << searchableFieldType(SearchTable[0].first) + << ", int> " << Name << "sBy" << Field << "[] = {\n"; + + if (isa(SearchTable[0].first)) { + std::stable_sort(SearchTable.begin(), SearchTable.end(), + [this](const SearchTableEntry &LHS, + const SearchTableEntry &RHS) { + return getAsInt(cast(LHS.first)) < + getAsInt(cast(RHS.first)); + }); + } else { + std::stable_sort(SearchTable.begin(), SearchTable.end(), + [this](const SearchTableEntry &LHS, + const SearchTableEntry &RHS) { + return searchRepresentation(LHS.first) < + searchRepresentation(RHS.first); + }); + } + + for (auto Entry : SearchTable) { + OS << " { " << searchRepresentation(Entry.first) << ", " << Entry.second + << " },\n"; + } + OS << "};\n\n"; +} + +void SearchableTableEmitter::emitLookupFunction(StringRef Name, StringRef Field, + Init *I, raw_ostream &OS) { + bool IsIntegral = isa(I); + std::string FieldType = searchableFieldType(I); + std::string PairType = "std::pair<" + FieldType + ", int>"; + + // const SysRegs *lookupSysRegByName(const char *Name) { + OS << "const " << Name << " *" + << "lookup" << Name << "By" << Field; + OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field + << ") {\n"; + + if (IsIntegral) { + OS << " auto CanonicalVal = " << Field << ";\n"; + OS << " " << PairType << " Val = {CanonicalVal, 0};\n"; + } else { + // Make sure the result is null terminated because it's going via "char *". + OS << " std::string CanonicalVal = " << Field << ".upper();\n"; + OS << " " << PairType << " Val = {CanonicalVal.data(), 0};\n"; + } + + OS << " ArrayRef<" << PairType << "> Table(" << Name << "sBy" << Field + << ");\n"; + OS << " auto Idx = std::lower_bound(Table.begin(), Table.end(), Val"; + + if (IsIntegral) + OS << ");\n"; + else { + OS << ",\n "; + OS << "[](const " << PairType << " &LHS, const " << PairType + << " &RHS) {\n"; + OS << " return StringRef(LHS.first) < StringRef(RHS.first);\n"; + OS << " });\n\n"; + } + + OS << " if (Idx == Table.end() || CanonicalVal != Idx->first)\n"; + OS << " return nullptr;\n"; + + OS << " return &" << Name << "sList[Idx->second];\n"; + OS << "}\n\n"; +} + +void SearchableTableEmitter::emitLookupDeclaration(StringRef Name, + StringRef Field, Init *I, + raw_ostream &OS) { + bool IsIntegral = isa(I); + std::string FieldType = searchableFieldType(I); + OS << "const " << Name << " *" + << "lookup" << Name << "By" << Field; + OS << "(" << (IsIntegral ? FieldType : "StringRef") << " " << Field + << ");\n\n"; +} + +void SearchableTableEmitter::emitMapping(Record *InstanceClass, + raw_ostream &OS) { + const std::string &TableName = InstanceClass->getName(); + std::vector Items = Records.getAllDerivedDefinitions(TableName); + + // Gather all the records we're going to need for this particular mapping. + std::vector> SearchTables; + std::vector SearchFieldNames; + + std::vector FieldNames; + for (const RecordVal &Field : InstanceClass->getValues()) { + std::string FieldName = Field.getName(); + + // Skip uninteresting fields: either built-in, special to us, or injected + // template parameters (if they contain a ':'). + if (FieldName.find(':') != std::string::npos || FieldName == "NAME" || + FieldName == "SearchableFields" || FieldName == "EnumNameField" || + FieldName == "EnumValueField") + continue; + + FieldNames.push_back(FieldName); + } + + for (auto *Field : *InstanceClass->getValueAsListInit("SearchableFields")) { + SearchTables.emplace_back(); + SearchFieldNames.push_back(Field->getAsUnquotedString()); + } + + int Idx = 0; + for (Record *Item : Items) { + for (unsigned i = 0; i < SearchFieldNames.size(); ++i) { + Init *SearchVal = Item->getValueInit(SearchFieldNames[i]); + SearchTables[i].emplace_back(SearchVal, Idx); + } + ++Idx; + } + + OS << "#ifdef GET_" << StringRef(TableName).upper() << "_DECL\n"; + OS << "#undef GET_" << StringRef(TableName).upper() << "_DECL\n"; + + // Next emit the enum containing the top-level names for use in C++ code if + // requested + if (!InstanceClass->isValueUnset("EnumNameField")) { + emitMappingEnum(Items, InstanceClass, OS); + } + + // And the declarations for the functions that will perform lookup. + for (unsigned i = 0; i < SearchFieldNames.size(); ++i) + emitLookupDeclaration(TableName, SearchFieldNames[i], + SearchTables[i][0].first, OS); + + OS << "#endif\n\n"; + + OS << "#ifdef GET_" << StringRef(TableName).upper() << "_IMPL\n"; + OS << "#undef GET_" << StringRef(TableName).upper() << "_IMPL\n"; + + // The primary data table contains all the fields defined for this map. + emitPrimaryTable(TableName, FieldNames, SearchFieldNames, SearchTables, Items, + OS); + + // Indexes are sorted "{ Thing, PrimaryIdx }" arrays, so that a binary + // search can be performed by "Thing". + for (unsigned i = 0; i < SearchTables.size(); ++i) { + emitSearchTable(TableName, SearchFieldNames[i], SearchTables[i], OS); + emitLookupFunction(TableName, SearchFieldNames[i], SearchTables[i][0].first, + OS); + } + + OS << "#endif\n"; +} + +void SearchableTableEmitter::run(raw_ostream &OS) { + // Tables are defined to be the direct descendents of "SearchableEntry". + Record *SearchableTable = Records.getClass("SearchableTable"); + for (auto &NameRec : Records.getClasses()) { + Record *Class = NameRec.second.get(); + if (Class->getSuperClasses().size() != 1 || + !Class->isSubClassOf(SearchableTable)) + continue; + emitMapping(Class, OS); + } +} + +namespace llvm { + +void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS) { + SearchableTableEmitter(RK).run(OS); +} + +} // End llvm namespace. diff --git a/utils/TableGen/SequenceToOffsetTable.h b/utils/TableGen/SequenceToOffsetTable.h index 66506ea0638f0bc6618923180b20ca168e6d6c5d..e026b1c9fbf024b2fd712700455275159c1c9825 100644 --- a/utils/TableGen/SequenceToOffsetTable.h +++ b/utils/TableGen/SequenceToOffsetTable.h @@ -22,7 +22,6 @@ #include #include #include -#include namespace llvm { diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index f6ff4bc6982f716bbe6fd5c8cda692d4e612a836..228882177bdf6ab352d1bfea2d6dafefedeeb396 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -13,16 +13,20 @@ #include "CodeGenTarget.h" #include "CodeGenSchedule.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCInstrItineraries.h" +#include "llvm/MC/MCSchedule.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include +#include +#include #include #include #include @@ -32,6 +36,7 @@ using namespace llvm; #define DEBUG_TYPE "subtarget-emitter" namespace { + class SubtargetEmitter { // Each processor has a SchedClassDesc table with an entry for each SchedClass. // The SchedClassDesc table indexes into a global write resource table, write @@ -96,7 +101,7 @@ class SubtargetEmitter { void EmitSchedClassTables(SchedClassTables &SchedTables, raw_ostream &OS); void EmitProcessorModels(raw_ostream &OS); void EmitProcessorLookup(raw_ostream &OS); - void EmitSchedModelHelpers(std::string ClassName, raw_ostream &OS); + void EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS); void EmitSchedModel(raw_ostream &OS); void ParseFeaturesFunction(raw_ostream &OS, unsigned NumFeatures, unsigned NumProcs); @@ -107,6 +112,7 @@ public: void run(raw_ostream &o); }; + } // end anonymous namespace // @@ -142,7 +148,8 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS) { } // Close enumeration and namespace - OS << "};\n}\n"; + OS << "};\n"; + OS << "} // end namespace " << Target << "\n"; } // @@ -374,7 +381,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, OS << " const unsigned " << FUs[j]->getName() << " = 1 << " << j << ";\n"; - OS << "}\n"; + OS << "} // end namespace " << Name << "FU\n"; std::vector BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); if (!BPs.empty()) { @@ -386,7 +393,7 @@ EmitStageAndOperandCycleData(raw_ostream &OS, OS << " const unsigned " << BPs[j]->getName() << " = 1 << " << j << ";\n"; - OS << "}\n"; + OS << "} // end namespace " << Name << "Bypass\n"; } } @@ -1114,7 +1121,7 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, && "invalid class not first"); OS << " {DBGFIELD(\"InvalidSchedClass\") " << MCSchedClassDesc::InvalidNumMicroOps - << ", 0, 0, 0, 0, 0, 0, 0, 0},\n"; + << ", false, false, 0, 0, 0, 0, 0, 0},\n"; for (unsigned SCIdx = 1, SCEnd = SCTab.size(); SCIdx != SCEnd; ++SCIdx) { MCSchedClassDesc &MCDesc = SCTab[SCIdx]; @@ -1123,7 +1130,8 @@ void SubtargetEmitter::EmitSchedClassTables(SchedClassTables &SchedTables, if (SchedClass.Name.size() < 18) OS.indent(18 - SchedClass.Name.size()); OS << MCDesc.NumMicroOps - << ", " << MCDesc.BeginGroup << ", " << MCDesc.EndGroup + << ", " << ( MCDesc.BeginGroup ? "true" : "false" ) + << ", " << ( MCDesc.EndGroup ? "true" : "false" ) << ", " << format("%2d", MCDesc.WriteProcResIdx) << ", " << MCDesc.NumWriteProcResEntries << ", " << format("%2d", MCDesc.WriteLatencyIdx) @@ -1158,13 +1166,17 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) { EmitProcessorProp(OS, PM.ModelDef, "HighLatency", ','); EmitProcessorProp(OS, PM.ModelDef, "MispredictPenalty", ','); - OS << " " << (bool)(PM.ModelDef ? - PM.ModelDef->getValueAsBit("PostRAScheduler") : 0) - << ", // " << "PostRAScheduler\n"; + bool PostRAScheduler = + (PM.ModelDef ? PM.ModelDef->getValueAsBit("PostRAScheduler") : false); - OS << " " << (bool)(PM.ModelDef ? - PM.ModelDef->getValueAsBit("CompleteModel") : 0) - << ", // " << "CompleteModel\n"; + OS << " " << (PostRAScheduler ? "true" : "false") << ", // " + << "PostRAScheduler\n"; + + bool CompleteModel = + (PM.ModelDef ? PM.ModelDef->getValueAsBit("CompleteModel") : false); + + OS << " " << (CompleteModel ? "true" : "false") << ", // " + << "CompleteModel\n"; OS << " " << PM.Index << ", // Processor ID\n"; if (PM.hasInstrSchedModel()) @@ -1256,7 +1268,7 @@ void SubtargetEmitter::EmitSchedModel(raw_ostream &OS) { OS << "#undef DBGFIELD"; } -void SubtargetEmitter::EmitSchedModelHelpers(std::string ClassName, +void SubtargetEmitter::EmitSchedModelHelpers(const std::string &ClassName, raw_ostream &OS) { OS << "unsigned " << ClassName << "\n::resolveSchedClass(unsigned SchedClass, const MachineInstr *MI," @@ -1376,15 +1388,15 @@ void SubtargetEmitter::run(raw_ostream &OS) { emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n"; - OS << "#undef GET_SUBTARGETINFO_ENUM\n"; + OS << "#undef GET_SUBTARGETINFO_ENUM\n\n"; OS << "namespace llvm {\n"; Enumeration(OS); - OS << "} // end llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n"; OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n"; - OS << "#undef GET_SUBTARGETINFO_MC_DESC\n"; + OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n"; OS << "namespace llvm {\n"; #if 0 @@ -1397,7 +1409,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { EmitSchedModel(OS); OS << "\n"; #if 0 - OS << "}\n"; + OS << "} // end anonymous namespace\n\n"; #endif // MCInstrInfo initialization routine. @@ -1427,22 +1439,22 @@ void SubtargetEmitter::run(raw_ostream &OS) { OS << "0, 0, 0"; OS << ");\n}\n\n"; - OS << "} // end llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n"; OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n"; - OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n"; + OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n"; OS << "#include \"llvm/Support/Debug.h\"\n"; - OS << "#include \"llvm/Support/raw_ostream.h\"\n"; + OS << "#include \"llvm/Support/raw_ostream.h\"\n\n"; ParseFeaturesFunction(OS, NumFeatures, NumProcs); OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n"; // Create a TargetSubtargetInfo subclass to hide the MC layer initialization. OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n"; - OS << "#undef GET_SUBTARGETINFO_HEADER\n"; + OS << "#undef GET_SUBTARGETINFO_HEADER\n\n"; std::string ClassName = Target + "GenSubtargetInfo"; OS << "namespace llvm {\n"; @@ -1457,14 +1469,14 @@ void SubtargetEmitter::run(raw_ostream &OS) { << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)" << " const;\n" << "};\n"; - OS << "} // end llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n"; OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n"; - OS << "#undef GET_SUBTARGETINFO_CTOR\n"; + OS << "#undef GET_SUBTARGETINFO_CTOR\n\n"; - OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n"; + OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n"; OS << "namespace llvm {\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n"; OS << "extern const llvm::SubtargetFeatureKV " << Target << "SubTypeKV[];\n"; @@ -1509,7 +1521,7 @@ void SubtargetEmitter::run(raw_ostream &OS) { EmitSchedModelHelpers(ClassName, OS); - OS << "} // end llvm namespace\n"; + OS << "} // end namespace llvm\n\n"; OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n"; } @@ -1521,4 +1533,4 @@ void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS) { SubtargetEmitter(RK, CGTarget).run(OS); } -} // end llvm namespace +} // end namespace llvm diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index bcc594d69a1d90f70b7db0654ce901b0f66c6529..24dbe5d3a2801e46030aaac1af6f18c2db4e5695 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -43,7 +43,8 @@ enum ActionType { PrintSets, GenOptParserDefs, GenCTags, - GenAttributes + GenAttributes, + GenSearchableTables, }; namespace { @@ -89,6 +90,8 @@ namespace { "Generate ctags-compatible index"), clEnumValN(GenAttributes, "gen-attrs", "Generate attributes"), + clEnumValN(GenSearchableTables, "gen-searchable-tables", + "Generate generic binary-searchable table"), clEnumValEnd)); cl::opt @@ -172,6 +175,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenAttributes: EmitAttributes(Records, OS); break; + case GenSearchableTables: + EmitSearchableTables(Records, OS); + break; } return false; @@ -179,7 +185,7 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { } int main(int argc, char **argv) { - sys::PrintStackTraceOnErrorSignal(); + sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h index d9dd3d157697beb54da5678d597bd8221591634d..51e017fe6594293cff378af1b7b95e96060bf9f1 100644 --- a/utils/TableGen/TableGenBackends.h +++ b/utils/TableGen/TableGenBackends.h @@ -79,6 +79,7 @@ void EmitMapTable(RecordKeeper &RK, raw_ostream &OS); void EmitOptParser(RecordKeeper &RK, raw_ostream &OS); void EmitCTags(RecordKeeper &RK, raw_ostream &OS); void EmitAttributes(RecordKeeper &RK, raw_ostream &OS); +void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index ad36dc427a562a1c954c8677aea38cfb00f5a435..5b710e4461507ffc68c4827e2f665e8d80d46041 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -285,7 +285,7 @@ static inline bool inheritsFrom(InstructionContext child, return false; case IC_EVEX_L_W_K: case IC_EVEX_L_W_B: - case IC_EVEX_L_W_K_B: + case IC_EVEX_L_W_K_B: case IC_EVEX_L_W_XS_K: case IC_EVEX_L_W_XS_B: case IC_EVEX_L_W_XS_K_B: diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h index d25eeea501890fa11406198e5f2ba174628a8320..f6f50065f7049088b663f4e17e8e13e18e61b986 100644 --- a/utils/TableGen/X86RecognizableInstr.h +++ b/utils/TableGen/X86RecognizableInstr.h @@ -19,7 +19,6 @@ #include "CodeGenTarget.h" #include "X86DisassemblerTables.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/Support/DataTypes.h" #include "llvm/TableGen/Record.h" diff --git a/utils/TableGen/module.modulemap b/utils/TableGen/module.modulemap deleted file mode 100644 index 8871bbfd4a2f7282fd4be0b697fa8dc8476dddae..0000000000000000000000000000000000000000 --- a/utils/TableGen/module.modulemap +++ /dev/null @@ -1,4 +0,0 @@ -module TableGen { - umbrella "." - module * { export * } -} diff --git a/utils/extract_symbols.py b/utils/extract_symbols.py new file mode 100755 index 0000000000000000000000000000000000000000..9f467a7d0556bf463dd3bc7a3ca6bcc77ce2b423 --- /dev/null +++ b/utils/extract_symbols.py @@ -0,0 +1,496 @@ +#!/usr/bin/env python + +"""A tool for extracting a list of symbols to export + +When exporting symbols from a dll or exe we either need to mark the symbols in +the source code as __declspec(dllexport) or supply a list of symbols to the +linker. This program automates the latter by inspecting the symbol tables of a +list of link inputs and deciding which of those symbols need to be exported. + +We can't just export all the defined symbols, as there's a limit of 65535 +exported symbols and in clang we go way over that, particularly in a debug +build. Therefore a large part of the work is pruning symbols either which can't +be imported, or which we think are things that have definitions in public header +files (i.e. template instantiations) and we would get defined in the thing +importing these symbols anyway. +""" + +from __future__ import print_function +import sys +import re +import os +import subprocess +import multiprocessing +import argparse + +# Define functions which extract a list of symbols from a library using several +# different tools. We use subprocess.Popen and yield a symbol at a time instead +# of using subprocess.check_output and returning a list as, especially on +# Windows, waiting for the entire output to be ready can take a significant +# amount of time. + +def dumpbin_get_symbols(lib): + process = subprocess.Popen(['dumpbin','/symbols',lib], bufsize=1, + stdout=subprocess.PIPE, stdin=subprocess.PIPE, + universal_newlines=True) + process.stdin.close() + for line in process.stdout: + # Look for external symbols that are defined in some section + match = re.match("^.+SECT.+External\s+\|\s+(\S+).*$", line) + if match: + yield match.group(1) + process.wait() + +def nm_get_symbols(lib): + process = subprocess.Popen(['nm',lib], bufsize=1, + stdout=subprocess.PIPE, stdin=subprocess.PIPE, + universal_newlines=True) + process.stdin.close() + for line in process.stdout: + # Look for external symbols that are defined in some section + match = re.match("^\S+\s+[BDGRSTVW]\s+(\S+)$", line) + if match: + yield match.group(1) + process.wait() + +def readobj_get_symbols(lib): + process = subprocess.Popen(['llvm-readobj','-symbols',lib], bufsize=1, + stdout=subprocess.PIPE, stdin=subprocess.PIPE, + universal_newlines=True) + process.stdin.close() + for line in process.stdout: + # When looking through the output of llvm-readobj we expect to see Name, + # Section, then StorageClass, so record Name and Section when we see + # them and decide if this is a defined external symbol when we see + # StorageClass. + match = re.search('Name: (\S+)', line) + if match: + name = match.group(1) + match = re.search('Section: (\S+)', line) + if match: + section = match.group(1) + match = re.search('StorageClass: (\S+)', line) + if match: + storageclass = match.group(1) + if section != 'IMAGE_SYM_ABSOLUTE' and \ + section != 'IMAGE_SYM_UNDEFINED' and \ + storageclass == 'External': + yield name + process.wait() + +# Define functions which determine if the target is 32-bit Windows (as that's +# where calling convention name decoration happens). + +def dumpbin_is_32bit_windows(lib): + # dumpbin /headers can output a huge amount of data (>100MB in a debug + # build) so we read only up to the 'machine' line then close the output. + process = subprocess.Popen(['dumpbin','/headers',lib], bufsize=1, + stdout=subprocess.PIPE, stdin=subprocess.PIPE, + universal_newlines=True) + process.stdin.close() + retval = False + for line in process.stdout: + match = re.match('.+machine \((\S+)\)', line) + if match: + retval = (match.group(1) == 'x86') + break + process.stdout.close() + process.wait() + return retval + +def objdump_is_32bit_windows(lib): + output = subprocess.check_output(['objdump','-f',lib], + universal_newlines=True) + for line in output: + match = re.match('.+file format (\S+)', line) + if match: + return (match.group(1) == 'pe-i386') + return False + +def readobj_is_32bit_windows(lib): + output = subprocess.check_output(['llvm-readobj','-file-headers',lib], + universal_newlines=True) + for line in output: + match = re.match('Format: (\S+)', line) + if match: + return (match.group(1) == 'COFF-i386') + return False + +# MSVC mangles names to ?@. By examining the +# identifier/type mangling we can decide which symbols could possibly be +# required and which we can discard. +def should_keep_microsoft_symbol(symbol, calling_convention_decoration): + # Keep unmangled (i.e. extern "C") names + if not '?' in symbol: + if calling_convention_decoration: + # Remove calling convention decoration from names + match = re.match('[_@]([^@]+)', symbol) + if match: + return match.group(1) + return symbol + # Function template instantiations start with ?$, discard them as it's + # assumed that the definition is public + elif symbol.startswith('??$'): + return None + # Deleting destructors start with ?_G or ?_E and can be discarded because + # link.exe gives you a warning telling you they can't be exported if you + # don't + elif symbol.startswith('??_G') or symbol.startswith('??_E'): + return None + # Constructors (?0) and destructors (?1) of templates (?$) are assumed to be + # defined in headers and not required to be kept + elif symbol.startswith('??0?$') or symbol.startswith('??1?$'): + return None + # An anonymous namespace is mangled as ?A(maybe hex number)@. Any symbol + # that mentions an anonymous namespace can be discarded, as the anonymous + # namespace doesn't exist outside of that translation unit. + elif re.search('\?A(0x\w+)?@', symbol): + return None + # Keep mangled llvm:: and clang:: function symbols. How we detect these is a + # bit of a mess and imprecise, but that avoids having to completely demangle + # the symbol name. The outermost namespace is at the end of the identifier + # mangling, and the identifier mangling is followed by the type mangling, so + # we look for (llvm|clang)@@ followed by something that looks like a + # function type mangling. To spot a function type we use (this is derived + # from clang/lib/AST/MicrosoftMangle.cpp): + # ::= + # + # + # ::= [A-Z] + # ::= [A-Z0-9_]* + # ::= [A-JQ] + # ::= .+ + # ::= X (void) + # ::= .+@ (list of types) + # ::= .*Z (list of types, varargs) + # ::= exceptions are not allowed + elif re.search('(llvm|clang)@@[A-Z][A-Z0-9_]*[A-JQ].+(X|.+@|.*Z)$', symbol): + return symbol + return None + +# Itanium manglings are of the form _Z. We +# demangle the identifier mangling to identify symbols that can be safely +# discarded. +def should_keep_itanium_symbol(symbol, calling_convention_decoration): + # Start by removing any calling convention decoration (which we expect to + # see on all symbols, even mangled C++ symbols) + if calling_convention_decoration and symbol.startswith('_'): + symbol = symbol[1:] + # Keep unmangled names + if not symbol.startswith('_') and not symbol.startswith('.'): + return symbol + # Discard manglings that aren't nested names + match = re.match('_Z(T[VTIS])?(N.+)', symbol) + if not match: + return None + # Demangle the name. If the name is too complex then we don't need to keep + # it, but it the demangling fails then keep the symbol just in case. + try: + names, _ = parse_itanium_nested_name(match.group(2)) + except TooComplexName: + return None + if not names: + return symbol + # Constructors and destructors of templates classes are assumed to be + # defined in headers and not required to be kept + if re.match('[CD][123]', names[-1][0]) and names[-2][1]: + return None + # Discard function template instantiations as it's assumed that the + # definition is public + elif names[-1][1]: + return None + # Keep llvm:: and clang:: names + elif names[0][0] == '4llvm' or names[0][0] == '5clang': + return symbol + # Discard everything else + else: + return None + +# Certain kinds of complex manglings we assume cannot be part of a public +# interface, and we handle them by raising an exception. +class TooComplexName(Exception): + pass + +# Parse an itanium mangled name from the start of a string and return a +# (name, rest of string) pair. +def parse_itanium_name(arg): + # Check for a normal name + match = re.match('(\d+)(.+)', arg) + if match: + n = int(match.group(1)) + name = match.group(1)+match.group(2)[:n] + rest = match.group(2)[n:] + return name, rest + # Check for constructor/destructor names + match = re.match('([CD][123])(.+)', arg) + if match: + return match.group(1), match.group(2) + # Assume that a sequence of characters that doesn't end a nesting is an + # operator (this is very imprecise, but appears to be good enough) + match = re.match('([^E]+)(.+)', arg) + if match: + return match.group(1), match.group(2) + # Anything else: we can't handle it + return None, arg + +# Parse an itanium mangled template argument list from the start of a string +# and throw it away, returning the rest of the string. +def skip_itanium_template(arg): + # A template argument list starts with I + assert arg.startswith('I'), arg + tmp = arg[1:] + while tmp: + # Check for names + match = re.match('(\d+)(.+)', tmp) + if match: + n = int(match.group(1)) + tmp = match.group(2)[n:] + continue + # Check for substitutions + match = re.match('S[A-Z0-9]*_(.+)', tmp) + if match: + tmp = match.group(1) + # Start of a template + elif tmp.startswith('I'): + tmp = skip_itanium_template(tmp) + # Start of a nested name + elif tmp.startswith('N'): + _, tmp = parse_itanium_nested_name(tmp) + # Start of an expression: assume that it's too complicated + elif tmp.startswith('L') or tmp.startswith('X'): + raise TooComplexName + # End of the template + elif tmp.startswith('E'): + return tmp[1:] + # Something else: probably a type, skip it + else: + tmp = tmp[1:] + return None + +# Parse an itanium mangled nested name and transform it into a list of pairs of +# (name, is_template), returning (list, rest of string). +def parse_itanium_nested_name(arg): + # A nested name starts with N + assert arg.startswith('N'), arg + ret = [] + + # Skip past the N, and possibly a substitution + match = re.match('NS[A-Z0-9]*_(.+)', arg) + if match: + tmp = match.group(1) + else: + tmp = arg[1:] + + # Skip past CV-qualifiers and ref qualifiers + match = re.match('[rVKRO]*(.+)', tmp); + if match: + tmp = match.group(1) + + # Repeatedly parse names from the string until we reach the end of the + # nested name + while tmp: + # An E ends the nested name + if tmp.startswith('E'): + return ret, tmp[1:] + # Parse a name + name_part, tmp = parse_itanium_name(tmp) + if not name_part: + # If we failed then we don't know how to demangle this + return None, None + is_template = False + # If this name is a template record that, then skip the template + # arguments + if tmp.startswith('I'): + tmp = skip_itanium_template(tmp) + is_template = True + # Add the name to the list + ret.append((name_part, is_template)) + + # If we get here then something went wrong + return None, None + +def extract_symbols(arg): + get_symbols, should_keep_symbol, calling_convention_decoration, lib = arg + symbols = dict() + for symbol in get_symbols(lib): + symbol = should_keep_symbol(symbol, calling_convention_decoration) + if symbol: + symbols[symbol] = 1 + symbols.setdefault(symbol,0) + return symbols + +if __name__ == '__main__': + tool_exes = ['dumpbin','nm','objdump','llvm-readobj'] + parser = argparse.ArgumentParser( + description='Extract symbols to export from libraries') + parser.add_argument('--mangling', choices=['itanium','microsoft'], + required=True, help='expected symbol mangling scheme') + parser.add_argument('--tools', choices=tool_exes, nargs='*', + help='tools to use to extract symbols and determine the' + ' target') + parser.add_argument('libs', metavar='lib', type=str, nargs='+', + help='libraries to extract symbols from') + parser.add_argument('-o', metavar='file', type=str, help='output to file') + args = parser.parse_args() + + # Determine the function to use to get the list of symbols from the inputs, + # and the function to use to determine if the target is 32-bit windows. + tools = { 'dumpbin' : (dumpbin_get_symbols, dumpbin_is_32bit_windows), + 'nm' : (nm_get_symbols, None), + 'objdump' : (None, objdump_is_32bit_windows), + 'llvm-readobj' : (readobj_get_symbols, readobj_is_32bit_windows) } + get_symbols = None + is_32bit_windows = None + # If we have a tools argument then use that for the list of tools to check + if args.tools: + tool_exes = args.tools + # Find a tool to use by trying each in turn until we find one that exists + # (subprocess.call will throw OSError when the program does not exist) + get_symbols = None + for exe in tool_exes: + try: + # Close std streams as we don't want any output and we don't + # want the process to wait for something on stdin. + p = subprocess.Popen([exe], stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + universal_newlines=True) + p.stdout.close() + p.stderr.close() + p.stdin.close() + p.wait() + # Keep going until we have a tool to use for both get_symbols and + # is_32bit_windows + if not get_symbols: + get_symbols = tools[exe][0] + if not is_32bit_windows: + is_32bit_windows = tools[exe][1] + if get_symbols and is_32bit_windows: + break + except OSError: + continue + if not get_symbols: + print("Couldn't find a program to read symbols with", file=sys.stderr) + exit(1) + if not is_32bit_windows: + print("Couldn't find a program to determing the target", file=sys.stderr) + exit(1) + + # How we determine which symbols to keep and which to discard depends on + # the mangling scheme + if args.mangling == 'microsoft': + should_keep_symbol = should_keep_microsoft_symbol + else: + should_keep_symbol = should_keep_itanium_symbol + + # Get the list of libraries to extract symbols from + libs = list() + for lib in args.libs: + # When invoked by cmake the arguments are the cmake target names of the + # libraries, so we need to add .lib/.a to the end and maybe lib to the + # start to get the filename. Also allow objects. + suffixes = ['.lib','.a','.obj','.o'] + if not any([lib.endswith(s) for s in suffixes]): + for s in suffixes: + if os.path.exists(lib+s): + lib = lib+s + break + if os.path.exists('lib'+lib+s): + lib = 'lib'+lib+s + break + if not any([lib.endswith(s) for s in suffixes]): + print("Don't know what to do with argument "+lib, file=sys.stderr) + exit(1) + libs.append(lib) + + # Check if calling convention decoration is used by inspecting the first + # library in the list + calling_convention_decoration = is_32bit_windows(libs[0]) + + # Extract symbols from libraries in parallel. This is a huge time saver when + # doing a debug build, as there are hundreds of thousands of symbols in each + # library. + pool = multiprocessing.Pool() + try: + # Only one argument can be passed to the mapping function, and we can't + # use a lambda or local function definition as that doesn't work on + # windows, so create a list of tuples which duplicates the arguments + # that are the same in all calls. + vals = [(get_symbols, should_keep_symbol, calling_convention_decoration, x) for x in libs] + # Do an async map then wait for the result to make sure that + # KeyboardInterrupt gets caught correctly (see + # http://bugs.python.org/issue8296) + result = pool.map_async(extract_symbols, vals) + pool.close() + libs_symbols = result.get(3600) + except KeyboardInterrupt: + # On Ctrl-C terminate everything and exit + pool.terminate() + pool.join() + exit(1) + + # Merge everything into a single dict + symbols = dict() + for this_lib_symbols in libs_symbols: + for k,v in list(this_lib_symbols.items()): + symbols[k] = v + symbols.setdefault(k,0) + + # Count instances of member functions of template classes, and map the + # symbol name to the function+class. We do this under the assumption that if + # a member function of a template class is instantiated many times it's + # probably declared in a public header file. + template_function_count = dict() + template_function_mapping = dict() + template_function_count[""] = 0 + for k in symbols: + name = None + if args.mangling == 'microsoft': + # Member functions of templates start with + # ?@?$@, so we map to @?$. + # As manglings go from the innermost scope to the outermost scope + # this means: + # * When we have a function member of a subclass of a template + # class then will actually contain the mangling of + # both the subclass and the function member. This is fine. + # * When we have a function member of a template subclass of a + # (possibly template) class then it's the innermost template + # subclass that becomes . This should be OK so long + # as we don't have multiple classes with a template subclass of + # the same name. + match = re.search("^\?(\??\w+\@\?\$\w+)\@", k) + if match: + name = match.group(1) + else: + # Find member functions of templates by demangling the name and + # checking if the second-to-last name in the list is a template. + match = re.match('_Z(T[VTIS])?(N.+)', k) + if match: + try: + names, _ = parse_itanium_nested_name(match.group(2)) + if names and names[-2][1]: + name = ''.join([x for x,_ in names]) + except TooComplexName: + # Manglings that are too complex should already have been + # filtered out, but if we happen to somehow see one here + # just leave it as-is. + pass + if name: + old_count = template_function_count.setdefault(name,0) + template_function_count[name] = old_count + 1 + template_function_mapping[k] = name + else: + template_function_mapping[k] = "" + + # Print symbols which both: + # * Appear in exactly one input, as symbols defined in multiple + # objects/libraries are assumed to have public definitions. + # * Aren't instances of member functions of templates which have been + # instantiated 100 times or more, which are assumed to have public + # definitions. (100 is an arbitrary guess here.) + if args.o: + outfile = open(args.o,'w') + else: + outfile = sys.stdout + for k,v in list(symbols.items()): + template_count = template_function_count[template_function_mapping[k]] + if v == 1 and template_count < 100: + print(k, file=outfile) diff --git a/utils/findoptdiff b/utils/findoptdiff index 7a2eab05d71a54857f629cb336719dde0c9b99c8..9a8803184384e444a9f3e659ca3ec36a41bfbda7 100755 --- a/utils/findoptdiff +++ b/utils/findoptdiff @@ -70,7 +70,7 @@ dis2="$llvm2/Debug/bin/llvm-dis" opt1="$llvm1/Debug/bin/opt" opt2="$llvm2/Debug/bin/opt" -all_switches="-verify -lowersetjmp -simplifycfg -mem2reg -globalopt -globaldce -ipconstprop -deadargelim -instcombine -simplifycfg -prune-eh -inline -simplify-libcalls -argpromotion -tailduplicate -simplifycfg -scalarrepl -instcombine -predsimplify -condprop -tailcallelim -simplifycfg -reassociate -licm -loop-unswitch -instcombine -indvars -loop-unroll -instcombine -load-vn -gcse -sccp -instcombine -condprop -dse -dce -simplifycfg -deadtypeelim -constmerge -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -scalarrepl -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify" +all_switches="-verify -lowersetjmp -simplifycfg -mem2reg -globalopt -globaldce -ipconstprop -deadargelim -instcombine -simplifycfg -prune-eh -inline -simplify-libcalls -argpromotion -tailduplicate -simplifycfg -sroa -instcombine -predsimplify -condprop -tailcallelim -simplifycfg -reassociate -licm -loop-unswitch -instcombine -indvars -loop-unroll -instcombine -load-vn -gcse -sccp -instcombine -condprop -dse -dce -simplifycfg -deadtypeelim -constmerge -internalize -ipsccp -globalopt -constmerge -deadargelim -inline -prune-eh -globalopt -globaldce -argpromotion -instcombine -predsimplify -sroa -globalsmodref-aa -licm -load-vn -gcse -dse -instcombine -simplifycfg -verify" #counter=0 function tryit { diff --git a/utils/gdb-scripts/prettyprinters.py b/utils/gdb-scripts/prettyprinters.py new file mode 100644 index 0000000000000000000000000000000000000000..0dbc7af3e46ef1624932c9e4783dd917d429da6d --- /dev/null +++ b/utils/gdb-scripts/prettyprinters.py @@ -0,0 +1,107 @@ +import gdb.printing +class SmallStringPrinter: + """Print an llvm::SmallString object.""" + + def __init__(self, val): + self.val = val + + def to_string(self): + begin = self.val['BeginX'] + end = self.val['EndX'] + return begin.cast(gdb.lookup_type("char").pointer()).string(length = end - begin) + + def display_hint (self): + return 'string' + +class StringRefPrinter: + """Print an llvm::StringRef object.""" + + def __init__(self, val): + self.val = val + + def to_string(self): + return self.val['Data'].string(length = self.val['Length']) + + def display_hint (self): + return 'string' + +class SmallVectorPrinter: + """Print an llvm::SmallVector object.""" + + class _iterator: + def __init__(self, begin, end): + self.cur = begin + self.end = end + self.count = 0 + + def __iter__(self): + return self + + def next(self): + if self.cur == self.end: + raise StopIteration + count = self.count + self.count = self.count + 1 + cur = self.cur + self.cur = self.cur + 1 + return '[%d]' % count, cur.dereference() + + def __init__(self, val): + self.val = val + + def children(self): + t = self.val.type.template_argument(0).pointer() + begin = self.val['BeginX'].cast(t) + end = self.val['EndX'].cast(t) + return self._iterator(begin, end) + + def to_string(self): + t = self.val.type.template_argument(0).pointer() + begin = self.val['BeginX'].cast(t) + end = self.val['EndX'].cast(t) + capacity = self.val['CapacityX'].cast(t) + return 'llvm::SmallVector of length %d, capacity %d' % (end - begin, capacity - begin) + + def display_hint (self): + return 'array' + +class ArrayRefPrinter: + """Print an llvm::ArrayRef object.""" + + class _iterator: + def __init__(self, begin, end): + self.cur = begin + self.end = end + self.count = 0 + + def __iter__(self): + return self + + def next(self): + if self.cur == self.end: + raise StopIteration + count = self.count + self.count = self.count + 1 + cur = self.cur + self.cur = self.cur + 1 + return '[%d]' % count, cur.dereference() + + def __init__(self, val): + self.val = val + + def children(self): + data = self.val['Data'] + return self._iterator(data, data + self.val['Length']) + + def to_string(self): + return 'llvm::ArrayRef of length %d' % (self.val['Length']) + + def display_hint (self): + return 'array' + +pp = gdb.printing.RegexpCollectionPrettyPrinter("LLVMSupport") +pp.add_printer('llvm::SmallString', '^llvm::SmallString<.*>$', SmallStringPrinter) +pp.add_printer('llvm::StringRef', '^llvm::StringRef$', StringRefPrinter) +pp.add_printer('llvm::SmallVectorImpl', '^llvm::SmallVector(Impl)?<.*>$', SmallVectorPrinter) +pp.add_printer('llvm::ArrayRef', '^llvm::(Const)?ArrayRef<.*>$', ArrayRefPrinter) +gdb.printing.register_pretty_printer(gdb.current_objfile(), pp) diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index c7c54897f0038dd0349f5fbddf8c614bb7a4293e..9c9c47d63217a43414f81ccce0ba9cc53e2f12d2 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -102,11 +102,18 @@ class JSONMetricValue(MetricValue): def toMetricValue(value): if isinstance(value, MetricValue): return value - elif isinstance(value, int) or isinstance(value, long): + elif isinstance(value, int): return IntMetricValue(value) elif isinstance(value, float): return RealMetricValue(value) else: + # 'long' is only present in python2 + try: + if isinstance(value, long): + return IntMetricValue(value) + except NameError: + pass + # Try to create a JSONMetricValue and let the constructor throw # if value is not a valid type. return JSONMetricValue(value) diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index c791b4274f8faaa17c6ddc4141aa52b803ed6cac..24d687280c43f5e98f049680ebca8d2bc85da414 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -110,6 +110,18 @@ class TimeoutHelper(object): self._procs = [] # Python2 doesn't have list.clear() self._doneKillPass = True +class ShellCommandResult(object): + """Captures the result of an individual command.""" + + def __init__(self, command, stdout, stderr, exitCode, timeoutReached, + outputFiles = []): + self.command = command + self.stdout = stdout + self.stderr = stderr + self.exitCode = exitCode + self.timeoutReached = timeoutReached + self.outputFiles = list(outputFiles) + def executeShCmd(cmd, shenv, results, timeout=0): """ Wrapper around _executeShCmd that handles @@ -243,6 +255,7 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper): result = subprocess.PIPE else: if r[2] is None: + redir_filename = None if kAvoidDevNull and r[0] == '/dev/null': r[2] = tempfile.TemporaryFile(mode=r[1]) elif kIsWindows and r[0] == '/dev/tty': @@ -258,7 +271,7 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper): # FIXME: Actually, this is probably an instance of PR6753. if r[1] == 'a': r[2].seek(0, 2) - opened_files.append(r[2]) + opened_files.append(tuple(r) + (redir_filename,)) result = r[2] final_redirects.append(result) @@ -332,7 +345,7 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper): # need to release any handles we may have on the temporary files (important # on Win32, for example). Since we have already spawned the subprocess, our # handles have already been transferred so we do not need them anymore. - for f in opened_files: + for (name, mode, f, path) in opened_files: f.close() # FIXME: There is probably still deadlock potential here. Yawn. @@ -369,15 +382,36 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper): # Ensure the resulting output is always of string type. try: - out = to_string(out.decode('utf-8')) + if out is None: + out = '' + else: + out = to_string(out.decode('utf-8', errors='replace')) except: out = str(out) try: - err = to_string(err.decode('utf-8')) + if err is None: + err = '' + else: + err = to_string(err.decode('utf-8', errors='replace')) except: err = str(err) - results.append((cmd.commands[i], out, err, res, timeoutHelper.timeoutReached())) + # Gather the redirected output files for failed commands. + output_files = [] + if res != 0: + for (name, mode, f, path) in sorted(opened_files): + if path is not None and mode in ('w', 'a'): + try: + with open(path, 'rb') as f: + data = f.read() + except: + data = None + if data != None: + output_files.append((name, path, data)) + + results.append(ShellCommandResult( + cmd.commands[i], out, err, res, timeoutHelper.timeoutReached(), + output_files)) if cmd.pipe_err: # Python treats the exit code as a signed char. if exitCode is None: @@ -422,16 +456,49 @@ def executeScriptInternal(test, litConfig, tmpBase, commands, cwd): except InternalShellError: e = sys.exc_info()[1] exitCode = 127 - results.append((e.command, '', e.message, exitCode, False)) + results.append( + ShellCommandResult(e.command, '', e.message, exitCode, False)) out = err = '' - for i,(cmd, cmd_out, cmd_err, res, timeoutReached) in enumerate(results): - out += 'Command %d: %s\n' % (i, ' '.join('"%s"' % s for s in cmd.args)) - out += 'Command %d Result: %r\n' % (i, res) + for i,result in enumerate(results): + # Write the command line run. + out += '$ %s\n' % (' '.join('"%s"' % s + for s in result.command.args),) + + # If nothing interesting happened, move on. + if litConfig.maxIndividualTestTime == 0 and \ + result.exitCode == 0 and \ + not result.stdout.strip() and not result.stderr.strip(): + continue + + # Otherwise, something failed or was printed, show it. + + # Add the command output, if redirected. + for (name, path, data) in result.outputFiles: + if data.strip(): + out += "# redirected output from %r:\n" % (name,) + data = to_string(data.decode('utf-8', errors='replace')) + if len(data) > 1024: + out += data[:1024] + "\n...\n" + out += "note: data was truncated\n" + else: + out += data + out += "\n" + + if result.stdout.strip(): + out += '# command output:\n%s\n' % (result.stdout,) + if result.stderr.strip(): + out += '# command stderr:\n%s\n' % (result.stderr,) + if not result.stdout.strip() and not result.stderr.strip(): + out += "note: command had no output on stdout or stderr\n" + + # Show the error conditions: + if result.exitCode != 0: + out += "error: command failed with exit status: %d\n" % ( + result.exitCode,) if litConfig.maxIndividualTestTime > 0: - out += 'Command %d Reached Timeout: %s\n\n' % (i, str(timeoutReached)) - out += 'Command %d Output:\n%s\n\n' % (i, cmd_out) - out += 'Command %d Stderr:\n%s\n\n' % (i, cmd_err) + out += 'error: command reached timeout: %s\n' % ( + i, str(result.timeoutReached)) return out, err, exitCode, timeoutInfo @@ -568,6 +635,24 @@ def getDefaultSubstitutions(test, tmpDir, tmpBase, normalize_slashes=False): ('%/t', tmpBase.replace('\\', '/') + '.tmp'), ('%/T', tmpDir.replace('\\', '/')), ]) + + # "%:[STpst]" are paths without colons. + if kIsWindows: + substitutions.extend([ + ('%:s', re.sub(r'^(.):', r'\1', sourcepath)), + ('%:S', re.sub(r'^(.):', r'\1', sourcedir)), + ('%:p', re.sub(r'^(.):', r'\1', sourcedir)), + ('%:t', re.sub(r'^(.):', r'\1', tmpBase) + '.tmp'), + ('%:T', re.sub(r'^(.):', r'\1', tmpDir)), + ]) + else: + substitutions.extend([ + ('%:s', sourcepath), + ('%:S', sourcedir), + ('%:p', sourcedir), + ('%:t', tmpBase + '.tmp'), + ('%:T', tmpDir), + ]) return substitutions def applySubstitutions(script, substitutions): @@ -598,8 +683,10 @@ def parseIntegratedTestScript(test, require_script=True): sourcepath = test.getSourcePath() script = [] requires = [] + requires_any = [] unsupported = [] - keywords = ['RUN:', 'XFAIL:', 'REQUIRES:', 'UNSUPPORTED:', 'END.'] + keywords = ['RUN:', 'XFAIL:', 'REQUIRES:', 'REQUIRES-ANY:', + 'UNSUPPORTED:', 'END.'] for line_number, command_type, ln in \ parseIntegratedTestScriptCommands(sourcepath, keywords): if command_type == 'RUN': @@ -624,6 +711,8 @@ def parseIntegratedTestScript(test, require_script=True): test.xfails.extend([s.strip() for s in ln.split(',')]) elif command_type == 'REQUIRES': requires.extend([s.strip() for s in ln.split(',')]) + elif command_type == 'REQUIRES-ANY': + requires_any.extend([s.strip() for s in ln.split(',')]) elif command_type == 'UNSUPPORTED': unsupported.extend([s.strip() for s in ln.split(',')]) elif command_type == 'END': @@ -650,6 +739,12 @@ def parseIntegratedTestScript(test, require_script=True): msg = ', '.join(missing_required_features) return lit.Test.Result(Test.UNSUPPORTED, "Test requires the following features: %s" % msg) + requires_any_features = [f for f in requires_any + if f in test.config.available_features] + if requires_any and not requires_any_features: + msg = ' ,'.join(requires_any) + return lit.Test.Result(Test.UNSUPPORTED, + "Test requires any of the following features: %s" % msg) unsupported_features = [f for f in unsupported if f in test.config.available_features] if unsupported_features: diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index 7940ebd0885aea30f08ccb8bf1bdb86250de6fd7..1e39a000c90d8529aae99bd22038c53095907631 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -24,7 +24,8 @@ class TestingConfig: pass_vars = ['LIBRARY_PATH', 'LD_LIBRARY_PATH', 'SYSTEMROOT', 'TERM', 'LD_PRELOAD', 'ASAN_OPTIONS', 'UBSAN_OPTIONS', - 'LSAN_OPTIONS', 'ADB', 'ANDROID_SERIAL'] + 'LSAN_OPTIONS', 'ADB', 'ANDROID_SERIAL', + 'SANITIZER_IGNORE_CVE_2016_2143'] for var in pass_vars: val = os.environ.get(var, '') # Check for empty string as some variables such as LD_PRELOAD cannot be empty diff --git a/utils/lit/lit/formats/googletest.py b/utils/lit/lit/formats/googletest.py index 5b19d4e638f945285a97746b92b90f5457e4d84a..f0250a3f96dd1d27701cb25411b3ac10ea3e1341 100644 --- a/utils/lit/lit/formats/googletest.py +++ b/utils/lit/lit/formats/googletest.py @@ -43,6 +43,12 @@ class GoogleTest(TestFormat): if not ln.strip(): continue + if 'Running main() from gtest_main.cc' in ln: + # Upstream googletest prints this to stdout prior to running + # tests. LLVM removed that print statement in r61540, but we + # handle it here in case upstream googletest is being used. + continue + prefix = '' index = 0 while ln[index*2:index*2+2] == ' ': diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 4debf4b10b6a1dc94b439cacb084c1c6fb7b6b7d..50927e2cbf0229fd52f7e25bfda06b06f40705dd 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -336,6 +336,9 @@ def main(builtinParameters = {}): print(' %s - %d tests' %(ts.name, len(ts_tests))) print(' Source Root: %s' % ts.source_root) print(' Exec Root : %s' % ts.exec_root) + if ts.config.available_features: + print(' Available Features : %s' % ' '.join( + sorted(ts.config.available_features))) # Show the tests, if requested. if opts.showTests: diff --git a/utils/lit/tests/Inputs/googletest-upstream-format/DummySubDir/OneTest b/utils/lit/tests/Inputs/googletest-upstream-format/DummySubDir/OneTest new file mode 100755 index 0000000000000000000000000000000000000000..d7bc5968f26117c7be18ca2f5b97e117f4ac4fc4 --- /dev/null +++ b/utils/lit/tests/Inputs/googletest-upstream-format/DummySubDir/OneTest @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +import sys + +if len(sys.argv) != 2: + raise ValueError("unexpected number of args") + +if sys.argv[1] == "--gtest_list_tests": + print("""\ +Running main() from gtest_main.cc +FirstTest. + subTestA + subTestB +ParameterizedTest/0. + subTest +ParameterizedTest/1. + subTest""") + sys.exit(0) +elif not sys.argv[1].startswith("--gtest_filter="): + raise ValueError("unexpected argument: %r" % (sys.argv[1])) + +test_name = sys.argv[1].split('=',1)[1] +print('Running main() from gtest_main.cc') +if test_name == 'FirstTest.subTestA': + print('I am subTest A, I PASS') + print('[ PASSED ] 1 test.') + sys.exit(0) +elif test_name == 'FirstTest.subTestB': + print('I am subTest B, I FAIL') + print('And I have two lines of output') + sys.exit(1) +elif test_name in ('ParameterizedTest/0.subTest', + 'ParameterizedTest/1.subTest'): + print('I am a parameterized test, I also PASS') + print('[ PASSED ] 1 test.') + sys.exit(0) +else: + raise SystemExit("error: invalid test name: %r" % (test_name,)) diff --git a/utils/lit/tests/Inputs/googletest-upstream-format/lit.cfg b/utils/lit/tests/Inputs/googletest-upstream-format/lit.cfg new file mode 100644 index 0000000000000000000000000000000000000000..9fb5d2b0247be76de0371e21cd31af743a82d5b5 --- /dev/null +++ b/utils/lit/tests/Inputs/googletest-upstream-format/lit.cfg @@ -0,0 +1,3 @@ +import lit.formats +config.name = 'googletest-upstream-format' +config.test_format = lit.formats.GoogleTest('DummySubDir', 'Test') diff --git a/utils/lit/tests/Inputs/shtest-format/requires-any-missing.txt b/utils/lit/tests/Inputs/shtest-format/requires-any-missing.txt new file mode 100644 index 0000000000000000000000000000000000000000..c977ee90c9e55f153f7e1e1cc46f3ac07003bca4 --- /dev/null +++ b/utils/lit/tests/Inputs/shtest-format/requires-any-missing.txt @@ -0,0 +1,2 @@ +RUN: true +REQUIRES-ANY: a-missing-feature, a-missing-feature-2 diff --git a/utils/lit/tests/Inputs/shtest-format/requires-any-present.txt b/utils/lit/tests/Inputs/shtest-format/requires-any-present.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3be518b25827acb1d78e150cd164312babc4471 --- /dev/null +++ b/utils/lit/tests/Inputs/shtest-format/requires-any-present.txt @@ -0,0 +1,2 @@ +RUN: true +REQUIRES-ANY: a-missing-feature, a-present-feature diff --git a/utils/lit/tests/Inputs/shtest-output-printing/basic.txt b/utils/lit/tests/Inputs/shtest-output-printing/basic.txt new file mode 100644 index 0000000000000000000000000000000000000000..4899c7e63db4532102d9637c9e4720dbbc473b2a --- /dev/null +++ b/utils/lit/tests/Inputs/shtest-output-printing/basic.txt @@ -0,0 +1,3 @@ +# RUN: true +# RUN: echo hi +# RUN: wc missing-file &> %t.out diff --git a/utils/lit/tests/Inputs/shtest-output-printing/lit.cfg b/utils/lit/tests/Inputs/shtest-output-printing/lit.cfg new file mode 100644 index 0000000000000000000000000000000000000000..4fe698d73368e4a9a784bb7a2701b8aed1a2f966 --- /dev/null +++ b/utils/lit/tests/Inputs/shtest-output-printing/lit.cfg @@ -0,0 +1,4 @@ +import lit.formats +config.name = 'shtest-output-printing' +config.suffixes = ['.txt'] +config.test_format = lit.formats.ShTest(execute_external=False) diff --git a/utils/lit/tests/googletest-upstream-format.py b/utils/lit/tests/googletest-upstream-format.py new file mode 100644 index 0000000000000000000000000000000000000000..1fc7c7c4a5ad2fe0a70114de2fb6b5174ec5d02f --- /dev/null +++ b/utils/lit/tests/googletest-upstream-format.py @@ -0,0 +1,20 @@ +# Check the various features of the GoogleTest format. +# +# RUN: not %{lit} -j 1 -v %{inputs}/googletest-upstream-format > %t.out +# RUN: FileCheck < %t.out %s +# +# END. + +# CHECK: -- Testing: +# CHECK: PASS: googletest-upstream-format :: DummySubDir/OneTest/FirstTest.subTestA +# CHECK: FAIL: googletest-upstream-format :: DummySubDir/OneTest/FirstTest.subTestB +# CHECK-NEXT: *** TEST 'googletest-upstream-format :: DummySubDir/OneTest/FirstTest.subTestB' FAILED *** +# CHECK-NEXT: Running main() from gtest_main.cc +# CHECK-NEXT: I am subTest B, I FAIL +# CHECK-NEXT: And I have two lines of output +# CHECK: *** +# CHECK: PASS: googletest-upstream-format :: DummySubDir/OneTest/ParameterizedTest/0.subTest +# CHECK: PASS: googletest-upstream-format :: DummySubDir/OneTest/ParameterizedTest/1.subTest +# CHECK: Failing Tests (1) +# CHECK: Expected Passes : 3 +# CHECK: Unexpected Failures: 1 diff --git a/utils/lit/tests/shtest-format.py b/utils/lit/tests/shtest-format.py index 751f0d7080306a0176d0737197b3c10cd2741129..20884f8c4854d453f156c54b955af787b9f036a7 100644 --- a/utils/lit/tests/shtest-format.py +++ b/utils/lit/tests/shtest-format.py @@ -39,14 +39,15 @@ # # CHECK: Command Output (stdout): # CHECK-NEXT: -- -# CHECK-NEXT: Command 0: "printf" -# CHECK-NEXT: Command 0 Result: 0 -# CHECK-NEXT: Command 0 Output: +# CHECK-NEXT: $ "printf" +# CHECK-NEXT: # command output: # CHECK-NEXT: line 1: failed test output on stdout # CHECK-NEXT: line 2: failed test output on stdout # CHECK: UNRESOLVED: shtest-format :: no-test-line.txt # CHECK: PASS: shtest-format :: pass.txt +# CHECK: UNSUPPORTED: shtest-format :: requires-any-missing.txt +# CHECK: PASS: shtest-format :: requires-any-present.txt # CHECK: UNSUPPORTED: shtest-format :: requires-missing.txt # CHECK: PASS: shtest-format :: requires-present.txt # CHECK: UNSUPPORTED: shtest-format :: unsupported_dir/some-test.txt @@ -69,9 +70,9 @@ # CHECK: shtest-format :: external_shell/fail_with_bad_encoding.txt # CHECK: shtest-format :: fail.txt -# CHECK: Expected Passes : 4 +# CHECK: Expected Passes : 5 # CHECK: Expected Failures : 3 -# CHECK: Unsupported Tests : 2 +# CHECK: Unsupported Tests : 3 # CHECK: Unresolved Tests : 1 # CHECK: Unexpected Passes : 1 # CHECK: Unexpected Failures: 3 diff --git a/utils/lit/tests/shtest-output-printing.py b/utils/lit/tests/shtest-output-printing.py new file mode 100644 index 0000000000000000000000000000000000000000..24580b37f1f54a1cb99dac2cb6e6658ac1bd2d93 --- /dev/null +++ b/utils/lit/tests/shtest-output-printing.py @@ -0,0 +1,28 @@ +# Check the various features of the ShTest format. +# +# RUN: not %{lit} -j 1 -v %{inputs}/shtest-output-printing > %t.out +# RUN: FileCheck --input-file %t.out %s +# +# END. + +# CHECK: -- Testing: + +# CHECK: FAIL: shtest-output-printing :: basic.txt +# CHECK-NEXT: *** TEST 'shtest-output-printing :: basic.txt' FAILED *** +# CHECK-NEXT: Script: +# CHECK-NEXT: -- +# CHECK: -- +# CHECK-NEXT: Exit Code: 1 +# +# CHECK: Command Output +# CHECK-NEXT: -- +# CHECK-NEXT: $ "true" +# CHECK-NEXT: $ "echo" "hi" +# CHECK-NEXT: # command output: +# CHECK-NEXT: hi +# +# CHECK: $ "wc" "missing-file" +# CHECK-NEXT: # redirected output from '{{.*}}/basic.txt.tmp.out': +# CHECK-NEXT: missing-file{{.*}} No such file or directory +# CHECK: note: command had no output on stdout or stderr +# CHECK-NEXT: error: command failed with exit status: 1 diff --git a/utils/lit/tests/shtest-shell.py b/utils/lit/tests/shtest-shell.py index 32479e19a1026fe1f28c1aa8d2e940c34f61838f..18b80cd7d08775afcec1fa90d478e93c295efef9 100644 --- a/utils/lit/tests/shtest-shell.py +++ b/utils/lit/tests/shtest-shell.py @@ -1,7 +1,7 @@ # Check the internal shell handling component of the ShTest format. # # RUN: not %{lit} -j 1 -v %{inputs}/shtest-shell > %t.out -# RUN: FileCheck < %t.out %s +# RUN: FileCheck --input-file %t.out %s # # END. @@ -9,10 +9,10 @@ # CHECK: FAIL: shtest-shell :: error-0.txt # CHECK: *** TEST 'shtest-shell :: error-0.txt' FAILED *** -# CHECK: Command 0: "not-a-real-command" -# CHECK: Command 0 Result: 127 -# CHECK: Command 0 Stderr: +# CHECK: $ "not-a-real-command" +# CHECK: # command stderr: # CHECK: 'not-a-real-command': command not found +# CHECK: error: command failed with exit status: 127 # CHECK: *** # FIXME: The output here sucks. diff --git a/utils/prepare-code-coverage-artifact.py b/utils/prepare-code-coverage-artifact.py new file mode 100644 index 0000000000000000000000000000000000000000..e233c2c6efec0f0a9afe77e0b6fd91103958820b --- /dev/null +++ b/utils/prepare-code-coverage-artifact.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +'''Prepare a code coverage artifact. + +- Collate raw profiles into one indexed profile. +- Delete the raw profiles. +- Copy the coverage mappings in the binaries directory. +''' + +import argparse +import glob +import os +import subprocess +import sys + +def merge_raw_profiles(host_llvm_profdata, profile_data_dir): + print ':: Merging raw profiles...', + sys.stdout.flush() + raw_profiles = glob.glob(os.path.join(profile_data_dir, '*.profraw')) + manifest_path = os.path.join(profile_data_dir, 'profiles.manifest') + profdata_path = os.path.join(profile_data_dir, 'Coverage.profdata') + with open(manifest_path, 'w') as manifest: + manifest.write('\n'.join(raw_profiles)) + subprocess.check_call([host_llvm_profdata, 'merge', '-sparse', '-f', + manifest_path, '-o', profdata_path]) + for raw_profile in raw_profiles: + os.remove(raw_profile) + print 'Done!' + +def extract_covmappings(host_llvm_cov, profile_data_dir, llvm_bin_dir): + print ':: Extracting covmappings...', + sys.stdout.flush() + for prog in os.listdir(llvm_bin_dir): + if prog == 'llvm-lit': + continue + covmapping_path = os.path.join(profile_data_dir, + os.path.basename(prog) + '.covmapping') + subprocess.check_call([host_llvm_cov, 'convert-for-testing', + os.path.join(llvm_bin_dir, prog), '-o', + covmapping_path]) + print 'Done!' + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('host_llvm_profdata', help='Path to llvm-profdata') + parser.add_argument('host_llvm_cov', help='Path to llvm-cov') + parser.add_argument('profile_data_dir', + help='Path to the directory containing the raw profiles') + parser.add_argument('llvm_bin_dir', + help='Path to the directory containing llvm binaries') + args = parser.parse_args() + + merge_raw_profiles(args.host_llvm_profdata, args.profile_data_dir) + extract_covmappings(args.host_llvm_cov, args.profile_data_dir, + args.llvm_bin_dir) diff --git a/utils/release/build_llvm_package.bat b/utils/release/build_llvm_package.bat index 786597c3e18ad461f464b3703c66d25b93d6023e..5542ca613f310ee9c5feaa7e36cd3bfaa9a78318 100755 --- a/utils/release/build_llvm_package.bat +++ b/utils/release/build_llvm_package.bat @@ -40,9 +40,11 @@ svn.exe export -r %revision% http://llvm.org/svn/llvm-project/cfe/%branch% llvm/ svn.exe export -r %revision% http://llvm.org/svn/llvm-project/clang-tools-extra/%branch% llvm/tools/clang/tools/extra || exit /b svn.exe export -r %revision% http://llvm.org/svn/llvm-project/lld/%branch% llvm/tools/lld || exit /b svn.exe export -r %revision% http://llvm.org/svn/llvm-project/compiler-rt/%branch% llvm/projects/compiler-rt || exit /b +svn.exe export -r %revision% http://llvm.org/svn/llvm-project/openmp/%branch% llvm/projects/openmp || exit /b -set cmake_flags=-DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_TOOLCHAIN_ONLY=ON -DLLVM_USE_CRT_RELEASE=MT -DCLANG_FORMAT_VS_VERSION=%clang_format_vs_version% -DPACKAGE_VERSION=%package_version% +REM Setting CMAKE_CL_SHOWINCLUDES_PREFIX to work around PR27226. +set cmake_flags=-DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_TOOLCHAIN_ONLY=ON -DLLVM_USE_CRT_RELEASE=MT -DCLANG_FORMAT_VS_VERSION=%clang_format_vs_version% -DPACKAGE_VERSION=%package_version% -DCMAKE_CL_SHOWINCLUDES_PREFIX="Note: including file: " REM TODO: Run all tests, including lld and compiler-rt. diff --git a/utils/release/merge.sh b/utils/release/merge.sh index cc3cda9d92f61c1ebbd8b72b1af1e87fdb6be6a6..e241dcde2954ee52cec8b4c045a52bede69e952d 100755 --- a/utils/release/merge.sh +++ b/utils/release/merge.sh @@ -17,24 +17,30 @@ set -e rev="" proj="" revert="no" +srcdir="" usage() { echo "usage: `basename $0` [OPTIONS]" echo " -proj PROJECT The project to merge the result into" echo " -rev NUM The revision to merge into the project" echo " -revert Revert rather than merge the commit" + echo " -srcdir The root of the project checkout" } while [ $# -gt 0 ]; do case $1 in -rev | --rev | -r ) shift - rev=$1 + rev=${$1#r} ;; -proj | --proj | -project | --project | -p ) shift proj=$1 ;; + --srcdir | -srcdir | -s) + shift + srcdir=$1 + ;; -h | -help | --help ) usage ;; @@ -51,6 +57,10 @@ while [ $# -gt 0 ]; do shift done +if [ -z "$srcdir" ]; then + srcdir="$proj.src" +fi + if [ "x$rev" = "x" -o "x$proj" = "x" ]; then echo "error: need to specify project and revision" echo @@ -72,7 +82,7 @@ else fi svn log -c $rev http://llvm.org/svn/llvm-project/$proj/trunk >> $tempfile 2>&1 -cd $proj.src +cd "$srcdir" echo "# Updating tree" svn up diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh index fed7eeddc3e17309c8c5f07952eef0e5c6a09cd0..37af976ec0c50b494bbb96e310f51857963c9662 100755 --- a/utils/release/test-release.sh +++ b/utils/release/test-release.sh @@ -375,13 +375,13 @@ function configure_llvmCore() { echo "#" env CC="$c_compiler" CXX="$cxx_compiler" \ cmake -G "Unix Makefiles" \ -DCMAKE_BUILD_TYPE=$BuildType -DLLVM_ENABLE_ASSERTIONS=$Assertions \ - -DLLVM_ENABLE_TIMESTAMPS=OFF -DLLVM_CONFIGTIME="(timestamp not enabled)" \ + -DLLVM_CONFIGTIME="(timestamp not enabled)" \ $ExtraConfigureFlags $BuildDir/llvm.src \ 2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log env CC="$c_compiler" CXX="$cxx_compiler" \ cmake -G "Unix Makefiles" \ -DCMAKE_BUILD_TYPE=$BuildType -DLLVM_ENABLE_ASSERTIONS=$Assertions \ - -DLLVM_ENABLE_TIMESTAMPS=OFF -DLLVM_CONFIGTIME="(timestamp not enabled)" \ + -DLLVM_CONFIGTIME="(timestamp not enabled)" \ $ExtraConfigureFlags $BuildDir/llvm.src \ 2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log fi diff --git a/utils/unittest/UnitTestMain/TestMain.cpp b/utils/unittest/UnitTestMain/TestMain.cpp index fb2b0f16ee3f298fe6788dbdd9bb380cce050ec9..36cec2d474249a507b4385d49754b690a89ee132 100644 --- a/utils/unittest/UnitTestMain/TestMain.cpp +++ b/utils/unittest/UnitTestMain/TestMain.cpp @@ -22,7 +22,8 @@ const char *TestMainArgv0; int main(int argc, char **argv) { - llvm::sys::PrintStackTraceOnErrorSignal(true /* Disable crash reporting */); + llvm::sys::PrintStackTraceOnErrorSignal(argv[0], + true /* Disable crash reporting */); testing::InitGoogleTest(&argc, argv); llvm::cl::ParseCommandLineOptions(argc, argv); diff --git a/utils/update_llc_test_checks.py b/utils/update_llc_test_checks.py index 8669b32324a32dc43435721d144e547860b4363f..d2df5b6511e1565b9df401d6911f3a291742192c 100755 --- a/utils/update_llc_test_checks.py +++ b/utils/update_llc_test_checks.py @@ -32,10 +32,11 @@ SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M) SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M) SCRUB_X86_SHUFFLES_RE = ( re.compile( - r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem) = .*)$', + r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$', flags=re.M)) SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)') SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)') +SCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+') SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n') RUN_LINE_RE = re.compile('^\s*;\s*RUN:\s*(.*)$') @@ -61,6 +62,8 @@ def scrub_asm(asm): asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm) # Generically match a RIP-relative memory operand. asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm) + # Generically match a LCP symbol. + asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm) # Strip kill operands inserted into the asm. asm = SCRUB_KILL_COMMENT_RE.sub('', asm) # Strip trailing whitespace. @@ -144,7 +147,7 @@ def main(): args = parser.parse_args() autogenerated_note = ('; NOTE: Assertions have been autogenerated by ' - + os.path.basename(__file__)) + 'utils/' + os.path.basename(__file__)) for test in args.tests: if args.verbose: diff --git a/utils/update_test_checks.py b/utils/update_test_checks.py index 19b27859a56ead7dec5b57d0aaa3a1b5e81d0e4e..c084debbe9863aef59d1eef3d0fccd9110195103 100755 --- a/utils/update_test_checks.py +++ b/utils/update_test_checks.py @@ -1,10 +1,32 @@ #!/usr/bin/env python2.7 -"""A test case update script. +"""A script to generate FileCheck statements for regression tests. This script is a utility to update LLVM opt or llc test cases with new FileCheck patterns. It can either update all of the tests in the file or a single test function. + +Example usage: +$ update_test_checks.py --tool=../bin/opt test/foo.ll + +Workflow: +1. Make a compiler patch that requires updating some number of FileCheck lines + in regression test files. +2. Save the patch and revert it from your local work area. +3. Update the RUN-lines in the affected regression tests to look canonical. + Example: "; RUN: opt < %s -instcombine -S | FileCheck %s" +4. Refresh the FileCheck lines for either the entire file or select functions by + running this script. +5. Commit the fresh baseline of checks. +6. Apply your patch from step 1 and rebuild your local binaries. +7. Re-run this script on affected regression tests. +8. Check the diffs to ensure the script has done something reasonable. +9. Submit a patch including the regression test diffs for review. + +A common pattern is to have the script insert complete checking of every +instruction. Then, edit it down to only check the relevant instructions. +The script is designed to make adding checks to a test case fast, it is *not* +designed to be authoratitive about what constitutes a good test! """ import argparse @@ -16,6 +38,7 @@ import sys import tempfile import re +ADVERT = '; NOTE: Assertions have been autogenerated by ' # RegEx: this is where the magic happens. @@ -24,10 +47,11 @@ SCRUB_WHITESPACE_RE = re.compile(r'(?!^(| \w))[ \t]+', flags=re.M) SCRUB_TRAILING_WHITESPACE_RE = re.compile(r'[ \t]+$', flags=re.M) SCRUB_X86_SHUFFLES_RE = ( re.compile( - r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem) = .*)$', + r'^(\s*\w+) [^#\n]+#+ ((?:[xyz]mm\d+|mem)( \{%k\d+\}( \{z\})?)? = .*)$', flags=re.M)) SCRUB_X86_SP_RE = re.compile(r'\d+\(%(esp|rsp)\)') SCRUB_X86_RIP_RE = re.compile(r'[.\w]+\(%rip\)') +SCRUB_X86_LCP_RE = re.compile(r'\.LCPI[0-9]+_[0-9]+') SCRUB_KILL_COMMENT_RE = re.compile(r'^ *#+ +kill:.*\n') SCRUB_IR_COMMENT_RE = re.compile(r'\s*;.*') @@ -65,6 +89,8 @@ def scrub_asm(asm): asm = SCRUB_X86_SP_RE.sub(r'{{[0-9]+}}(%\1)', asm) # Generically match a RIP-relative memory operand. asm = SCRUB_X86_RIP_RE.sub(r'{{.*}}(%rip)', asm) + # Generically match a LCP symbol. + asm = SCRUB_X86_LCP_RE.sub(r'{{\.LCPI.*}}', asm) # Strip kill operands inserted into the asm. asm = SCRUB_KILL_COMMENT_RE.sub('', asm) return asm @@ -186,15 +212,25 @@ def add_checks(output_lines, prefix_list, func_dict, func_name, tool_basename): if tool_basename == "opt": func_body = genericize_check_lines(func_body) + # This could be selectively enabled with an optional invocation argument. + # Disabled for now: better to check everything. Be safe rather than sorry. + # Handle the first line of the function body as a special case because # it's often just noise (a useless asm comment or entry label). - if func_body[0].startswith("#") or func_body[0].startswith("entry:"): - is_blank_line = True - else: - output_lines.append('; %s: %s' % (checkprefix, func_body[0])) + #if func_body[0].startswith("#") or func_body[0].startswith("entry:"): + # is_blank_line = True + #else: + # output_lines.append('; %s: %s' % (checkprefix, func_body[0])) + # is_blank_line = False + + # For llc tests, there may be asm directives between the label and the + # first checked line (most likely that first checked line is "# BB#0"). + if tool_basename == "opt": is_blank_line = False + else: + is_blank_line = True; - for func_line in func_body[1:]: + for func_line in func_body: if func_line.strip() == '': is_blank_line = True continue @@ -232,7 +268,8 @@ def should_add_line_to_output(input_line, prefix_set): def main(): - parser = argparse.ArgumentParser(description=__doc__) + from argparse import RawTextHelpFormatter + parser = argparse.ArgumentParser(description=__doc__, formatter_class=RawTextHelpFormatter) parser.add_argument('-v', '--verbose', action='store_true', help='Show verbose output') parser.add_argument('--tool-binary', default='llc', @@ -242,8 +279,7 @@ def main(): parser.add_argument('tests', nargs='+') args = parser.parse_args() - autogenerated_note = ('; NOTE: Assertions have been autogenerated by ' - + os.path.basename(__file__)) + autogenerated_note = (ADVERT + 'utils/' + os.path.basename(__file__)) tool_basename = os.path.basename(args.tool_binary) if (tool_basename != "llc" and tool_basename != "opt"): @@ -333,7 +369,8 @@ def main(): is_in_function = False continue - if input_line == autogenerated_note: + # Discard any previous script advertising. + if input_line.startswith(ADVERT): continue # If it's outside a function, it just gets copied to the output. diff --git a/utils/vim/syntax/llvm.vim b/utils/vim/syntax/llvm.vim index 25a8a5cd1adeb392772c67d2822756f9c2cc9d73..0e8824e90a35d3b34be7543cd3e72e65abc4ef47 100644 --- a/utils/vim/syntax/llvm.vim +++ b/utils/vim/syntax/llvm.vim @@ -36,28 +36,122 @@ syn keyword llvmStatement umax umin une uno unreachable unwind urem va_arg syn keyword llvmStatement xchg xor zext " Keywords. -syn keyword llvmKeyword acq_rel acquire sanitize_address addrspace alias align -syn keyword llvmKeyword alignstack alwaysinline appending arm_aapcs_vfpcc -syn keyword llvmKeyword arm_aapcscc arm_apcscc asm atomic available_externally -syn keyword llvmKeyword blockaddress byval c catch cc ccc cleanup coldcc common -syn keyword llvmKeyword constant datalayout declare default define deplibs -syn keyword llvmKeyword distinct dllexport dllimport except extern_weak external -syn keyword llvmKeyword externally_initialized fastcc filter gc global hhvmcc -syn keyword llvmKeyword hhvm_ccc hidden initialexec inlinehint inreg -syn keyword llvmKeyword intel_ocl_bicc inteldialect internal linkonce -syn keyword llvmKeyword linkonce_odr localdynamic localexec minsize module -syn keyword llvmKeyword monotonic msp430_intrcc musttail naked nest -syn keyword llvmKeyword noalias nocapture noimplicitfloat noinline nonlazybind -syn keyword llvmKeyword noredzone noreturn nounwind optnone optsize personality -syn keyword llvmKeyword private protected ptx_device ptx_kernel readnone -syn keyword llvmKeyword readonly release returns_twice sanitize_thread -syn keyword llvmKeyword sanitize_memory section seq_cst sideeffect signext -syn keyword llvmKeyword singlethread spir_func spir_kernel sret ssp sspreq -syn keyword llvmKeyword sspstrong tail target thread_local to triple -syn keyword llvmKeyword unnamed_addr unordered uwtable volatile weak weak_odr -syn keyword llvmKeyword x86_fastcallcc x86_stdcallcc x86_thiscallcc -syn keyword llvmKeyword x86_64_sysvcc x86_64_win64cc zeroext uselistorder -syn keyword llvmKeyword uselistorder_bb musttail +syn keyword llvmKeyword + \ acq_rel + \ acquire + \ addrspace + \ alias + \ align + \ alignstack + \ alwaysinline + \ appending + \ arm_aapcscc + \ arm_aapcs_vfpcc + \ arm_apcscc + \ asm + \ atomic + \ available_externally + \ blockaddress + \ byval + \ c + \ catch + \ cc + \ ccc + \ cleanup + \ coldcc + \ common + \ constant + \ datalayout + \ declare + \ default + \ define + \ deplibs + \ distinct + \ dllexport + \ dllimport + \ except + \ external + \ externally_initialized + \ extern_weak + \ fastcc + \ filter + \ gc + \ global + \ hhvmcc + \ hhvm_ccc + \ hidden + \ initialexec + \ inlinehint + \ inreg + \ inteldialect + \ intel_ocl_bicc + \ internal + \ linkonce + \ linkonce_odr + \ localdynamic + \ localexec + \ local_unnamed_addr + \ minsize + \ module + \ monotonic + \ msp430_intrcc + \ musttail + \ naked + \ nest + \ noalias + \ nocapture + \ noimplicitfloat + \ noinline + \ nonlazybind + \ noredzone + \ noreturn + \ nounwind + \ optnone + \ optsize + \ personality + \ private + \ protected + \ ptx_device + \ ptx_kernel + \ readnone + \ readonly + \ release + \ returns_twice + \ sanitize_address + \ sanitize_memory + \ sanitize_thread + \ section + \ seq_cst + \ sideeffect + \ signext + \ singlethread + \ source_filename + \ spir_func + \ spir_kernel + \ sret + \ ssp + \ sspreq + \ sspstrong + \ swiftcc + \ tail + \ target + \ thread_local + \ to + \ triple + \ unnamed_addr + \ unordered + \ uselistorder + \ uselistorder_bb + \ uwtable + \ volatile + \ weak + \ weak_odr + \ x86_64_sysvcc + \ x86_64_win64cc + \ x86_fastcallcc + \ x86_stdcallcc + \ x86_thiscallcc + \ zeroext " Obsolete keywords. syn keyword llvmError getresult begin end
" << stripPathPrefix(FileName) << "