Index: vendor/llvm/dist/CMakeLists.txt =================================================================== --- vendor/llvm/dist/CMakeLists.txt (revision 309151) +++ vendor/llvm/dist/CMakeLists.txt (revision 309152) @@ -1,858 +1,858 @@ # See docs/CMake.html for instructions about how to build LLVM with CMake. 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") set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type (default Debug)") endif() if(POLICY CMP0022) cmake_policy(SET CMP0022 NEW) # automatic when 2.8.12 is required endif() if (POLICY CMP0051) # CMake 3.1 and higher include generator expressions of the form # $ in the SOURCES property. These need to be # stripped everywhere that access the SOURCES property, so we just # defer to the OLD behavior of not including generator expressions # in the output for now. cmake_policy(SET CMP0051 OLD) endif() if(NOT DEFINED LLVM_VERSION_MAJOR) set(LLVM_VERSION_MAJOR 3) endif() if(NOT DEFINED LLVM_VERSION_MINOR) set(LLVM_VERSION_MINOR 9) endif() if(NOT DEFINED LLVM_VERSION_PATCH) - set(LLVM_VERSION_PATCH 0) + set(LLVM_VERSION_PATCH 1) endif() if(NOT DEFINED LLVM_VERSION_SUFFIX) set(LLVM_VERSION_SUFFIX "") endif() if (POLICY CMP0048) cmake_policy(SET CMP0048 NEW) set(cmake_3_0_PROJ_VERSION VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}) set(cmake_3_0_LANGUAGES LANGUAGES) endif() if (NOT PACKAGE_VERSION) set(PACKAGE_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}${LLVM_VERSION_SUFFIX}") endif() project(LLVM ${cmake_3_0_PROJ_VERSION} ${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(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) endif() endif() set(LLVM_BUILD_GLOBAL_ISEL OFF CACHE BOOL "Experimental: Build GlobalISel") if(LLVM_BUILD_GLOBAL_ISEL) add_definitions(-DLLVM_BUILD_GLOBAL_ISEL) endif() set(LLVM_PARALLEL_LINK_JOBS "" CACHE STRING "Define the maximum number of concurrent link jobs.") if(LLVM_PARALLEL_LINK_JOBS) 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) endif() endif() # Add path for custom modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) # Generate a CompilationDatabase (compile_commands.json file) for our build, # for use by clang_complete, YouCompleteMe, etc. set(CMAKE_EXPORT_COMPILE_COMMANDS 1) option(LLVM_INSTALL_UTILS "Include utility binaries in the 'install' target." OFF) option(LLVM_INSTALL_TOOLCHAIN_ONLY "Only include toolchain files in the 'install' target." OFF) option(LLVM_USE_FOLDERS "Enable solution folders in Visual Studio. Disable for Express versions." ON) if ( LLVM_USE_FOLDERS ) set_property(GLOBAL PROPERTY USE_FOLDERS ON) endif() include(VersionFromVCS) option(LLVM_APPEND_VC_REV "Append the version control system revision id to LLVM version" OFF) if( LLVM_APPEND_VC_REV ) add_version_info_from_vcs(PACKAGE_VERSION) endif() set(PACKAGE_NAME LLVM) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "http://llvm.org/bugs/") set(BUG_REPORT_URL "${PACKAGE_BUGREPORT}" CACHE STRING "Default URL where bug reports are to be submitted.") # Configure CPack. set(CPACK_PACKAGE_INSTALL_DIRECTORY "LLVM") set(CPACK_PACKAGE_VENDOR "LLVM") set(CPACK_PACKAGE_VERSION_MAJOR ${LLVM_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${LLVM_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${LLVM_VERSION_PATCH}) set(CPACK_PACKAGE_VERSION ${PACKAGE_VERSION}) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.TXT") set(CPACK_NSIS_COMPRESSOR "/SOLID lzma \r\n SetCompressorDictSize 32") if(WIN32 AND NOT UNIX) set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "LLVM") set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}\\\\cmake\\\\nsis_logo.bmp") set(CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}\\\\cmake\\\\nsis_icon.ico") set(CPACK_NSIS_MUI_UNIICON "${CMAKE_CURRENT_SOURCE_DIR}\\\\cmake\\\\nsis_icon.ico") set(CPACK_NSIS_MODIFY_PATH "ON") set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL "ON") set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '$INSTDIR/tools/msbuild/install.bat'") set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "ExecWait '$INSTDIR/tools/msbuild/uninstall.bat'") if( CMAKE_CL_64 ) set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64") endif() endif() include(CPack) # Sanity check our source directory to make sure that we are not trying to # generate an in-tree build (unless on MSVC_IDE, where it is ok), and to make # sure that we don't have any stray generated files lying around in the tree # (which would end up getting picked up by header search, instead of the correct # versions). if( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE ) message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite the makefiles distributed with LLVM. Please create a directory and run cmake from there, passing the path to this source directory as the last argument. This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them.") endif() if( NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR ) file(GLOB_RECURSE tablegenned_files_on_include_dir "${CMAKE_CURRENT_SOURCE_DIR}/include/llvm/*.gen") file(GLOB_RECURSE tablegenned_files_on_lib_dir "${CMAKE_CURRENT_SOURCE_DIR}/lib/Target/*.inc") if( tablegenned_files_on_include_dir OR tablegenned_files_on_lib_dir) message(FATAL_ERROR "Apparently there is a previous in-source build, probably as the result of running `configure' and `make' on ${CMAKE_CURRENT_SOURCE_DIR}. This may cause problems. The suspicious files are: ${tablegenned_files_on_lib_dir} ${tablegenned_files_on_include_dir} Please clean the source directory.") endif() endif() string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) if (CMAKE_BUILD_TYPE AND NOT uppercase_CMAKE_BUILD_TYPE MATCHES "^(DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL)$") message(FATAL_ERROR "Invalid value for CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") 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}) if(WIN32 OR CYGWIN) # DLL platform -- put DLLs into bin. set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) else() set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) endif() # Each of them corresponds to llvm-config's. set(LLVM_TOOLS_BINARY_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) # --bindir set(LLVM_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) # --libdir set(LLVM_MAIN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR} ) # --src-root set(LLVM_MAIN_INCLUDE_DIR ${LLVM_MAIN_SRC_DIR}/include ) # --includedir set(LLVM_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} ) # --prefix set(LLVM_EXAMPLES_BINARY_DIR ${LLVM_BINARY_DIR}/examples) set(LLVM_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/include) set(LLVM_ALL_TARGETS AArch64 AMDGPU ARM BPF Hexagon Mips MSP430 NVPTX PowerPC Sparc SystemZ X86 XCore ) # List of targets with JIT support: set(LLVM_TARGETS_WITH_JIT X86 PowerPC AArch64 ARM Mips SystemZ) set(LLVM_TARGETS_TO_BUILD "all" CACHE STRING "Semicolon-separated list of targets to build, or \"all\".") set(LLVM_EXPERIMENTAL_TARGETS_TO_BUILD "" CACHE STRING "Semicolon-separated list of experimental targets to build.") option(BUILD_SHARED_LIBS "Build all libraries as shared libraries instead of static" OFF) option(LLVM_ENABLE_BACKTRACES "Enable embedding backtraces on crash." ON) if(LLVM_ENABLE_BACKTRACES) set(ENABLE_BACKTRACES 1) endif() option(LLVM_ENABLE_CRASH_OVERRIDES "Enable crash overrides." ON) if(LLVM_ENABLE_CRASH_OVERRIDES) set(ENABLE_CRASH_OVERRIDES 1) endif() option(LLVM_ENABLE_FFI "Use libffi to call external functions from the interpreter" OFF) set(FFI_LIBRARY_DIR "" CACHE PATH "Additional directory, where CMake should search for libffi.so") set(FFI_INCLUDE_DIR "" CACHE PATH "Additional directory, where CMake should search for ffi.h or ffi/ffi.h") set(LLVM_TARGET_ARCH "host" CACHE STRING "Set target to use for LLVM JIT or use \"host\" for automatic detection.") option(LLVM_ENABLE_TERMINFO "Use terminfo database if available." ON) option(LLVM_ENABLE_THREADS "Use threads if available." ON) option(LLVM_ENABLE_ZLIB "Use zlib for compression/decompression if available." ON) if( LLVM_TARGETS_TO_BUILD STREQUAL "all" ) set( LLVM_TARGETS_TO_BUILD ${LLVM_ALL_TARGETS} ) endif() set(LLVM_TARGETS_TO_BUILD ${LLVM_TARGETS_TO_BUILD} ${LLVM_EXPERIMENTAL_TARGETS_TO_BUILD}) list(REMOVE_DUPLICATES LLVM_TARGETS_TO_BUILD) 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) option(LLVM_ENABLE_LLD "Use lld as C and C++ linker." OFF) option(LLVM_ENABLE_PEDANTIC "Compile with pedantic enabled." ON) option(LLVM_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF) if( NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) option(LLVM_ENABLE_ASSERTIONS "Enable assertions" OFF) 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.") option(LLVM_FORCE_USE_OLD_HOST_TOOLCHAIN "Set to ON to force using an old, unsupported host toolchain." OFF) option(LLVM_USE_INTEL_JITEVENTS "Use Intel JIT API to inform Intel(R) VTune(TM) Amplifier XE 2011 about JIT code" OFF) if( LLVM_USE_INTEL_JITEVENTS ) # Verify we are on a supported platform if( NOT CMAKE_SYSTEM_NAME MATCHES "Windows" AND NOT CMAKE_SYSTEM_NAME MATCHES "Linux" ) message(FATAL_ERROR "Intel JIT API support is available on Linux and Windows only.") endif() endif( LLVM_USE_INTEL_JITEVENTS ) option(LLVM_USE_OPROFILE "Use opagent JIT interface to inform OProfile about JIT code" OFF) option(LLVM_EXTERNALIZE_DEBUGINFO "Generate dSYM files and strip executables and libraries (Darwin Only)" OFF) # If enabled, verify we are on a platform that supports oprofile. if( LLVM_USE_OPROFILE ) if( NOT CMAKE_SYSTEM_NAME MATCHES "Linux" ) message(FATAL_ERROR "OProfile support is available on Linux only.") endif( NOT CMAKE_SYSTEM_NAME MATCHES "Linux" ) endif( LLVM_USE_OPROFILE ) set(LLVM_USE_SANITIZER "" CACHE STRING "Define the sanitizer used to build binaries and tests.") option(LLVM_USE_SPLIT_DWARF "Use -gsplit-dwarf when compiling llvm." 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. if( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32 ) # TODO: support other platforms and toolchains. option(LLVM_BUILD_32_BITS "Build 32 bits executables and libraries." OFF) endif() # Define the default arguments to use with 'lit', and an option for the user to # override. set(LIT_ARGS_DEFAULT "-sv") if (MSVC_IDE OR XCODE) set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") endif() set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools. if( WIN32 AND NOT CYGWIN ) set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools") endif() # Define options to control the inclusion and default build behavior for # components which may not strictly be necessary (tools, examples, and tests). # # This is primarily to support building smaller or faster project files. option(LLVM_INCLUDE_TOOLS "Generate build targets for the LLVM tools." ON) 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) option(LLVM_BUILD_EXAMPLES "Build the LLVM example programs. If OFF, just generate build targets." OFF) option(LLVM_INCLUDE_EXAMPLES "Generate build targets for the LLVM examples" ON) option(LLVM_BUILD_TESTS "Build LLVM unit tests. If OFF, just generate build targets." OFF) option(LLVM_INCLUDE_TESTS "Generate build targets for the LLVM unit tests." ON) option(LLVM_INCLUDE_GO_TESTS "Include the Go bindings tests in test build targets." ON) option (LLVM_BUILD_DOCS "Build the llvm documentation." OFF) option (LLVM_INCLUDE_DOCS "Generate build targets for llvm documentation." ON) option (LLVM_ENABLE_DOXYGEN "Use doxygen to generate llvm API documentation." OFF) option (LLVM_ENABLE_SPHINX "Use Sphinx to generate llvm documentation." OFF) option (LLVM_BUILD_EXTERNAL_COMPILER_RT "Build compiler-rt as an external project." OFF) # You can configure which libraries from LLVM you want to include in the # shared library by setting LLVM_DYLIB_COMPONENTS to a semi-colon delimited # list of LLVM components. All component names handled by llvm-config are valid. if(NOT DEFINED LLVM_DYLIB_COMPONENTS) set(LLVM_DYLIB_COMPONENTS "all" CACHE STRING "Semicolon-separated list of components to include in libLLVM, or \"all\".") endif() option(LLVM_LINK_LLVM_DYLIB "Link tools against the libllvm dynamic library" OFF) option(LLVM_BUILD_LLVM_C_DYLIB "Build libllvm-c re-export library (Darwin Only)" OFF) set(LLVM_BUILD_LLVM_DYLIB_default OFF) if(LLVM_LINK_LLVM_DYLIB OR LLVM_BUILD_LLVM_C_DYLIB) set(LLVM_BUILD_LLVM_DYLIB_default ON) endif() option(LLVM_BUILD_LLVM_DYLIB "Build libllvm dynamic library" ${LLVM_BUILD_LLVM_DYLIB_default}) option(LLVM_OPTIMIZED_TABLEGEN "Force TableGen to be built with optimization" OFF) if(CMAKE_CROSSCOMPILING OR (LLVM_OPTIMIZED_TABLEGEN AND LLVM_ENABLE_ASSERTIONS)) set(LLVM_USE_HOST_TOOLS ON) endif() if (MSVC_IDE AND NOT (MSVC_VERSION LESS 1900)) option(LLVM_ADD_NATIVE_VISUALIZERS_TO_SOLUTION "Configure project to use Visual Studio native visualizers" TRUE) 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 include(config-ix) string(REPLACE "Native" ${LLVM_NATIVE_ARCH} LLVM_TARGETS_TO_BUILD "${LLVM_TARGETS_TO_BUILD}") list(REMOVE_DUPLICATES LLVM_TARGETS_TO_BUILD) # By default, we target the host, but this can be overridden at CMake # invocation time. set(LLVM_DEFAULT_TARGET_TRIPLE "${LLVM_HOST_TRIPLE}" CACHE STRING "Default target for which LLVM will generate code." ) set(TARGET_TRIPLE "${LLVM_DEFAULT_TARGET_TRIPLE}") include(HandleLLVMOptions) # Verify that we can find a Python 2 interpreter. Python 3 is unsupported. # FIXME: We should support systems with only Python 3, but that requires work # on LLDB. set(Python_ADDITIONAL_VERSIONS 2.7) include(FindPythonInterp) if( NOT PYTHONINTERP_FOUND ) message(FATAL_ERROR "Unable to find Python interpreter, required for builds and testing. Please install Python or specify the PYTHON_EXECUTABLE CMake variable.") endif() if( ${PYTHON_VERSION_STRING} VERSION_LESS 2.7 ) message(FATAL_ERROR "Python 2.7 or newer is required") endif() ###### # LLVMBuild Integration # # We use llvm-build to generate all the data required by the CMake based # build system in one swoop: # # - We generate a file (a CMake fragment) in the object root which contains # all the definitions that are required by CMake. # # - We generate the library table used by llvm-config. # # - We generate the dependencies for the CMake fragment, so that we will # automatically reconfigure outselves. set(LLVMBUILDTOOL "${LLVM_MAIN_SRC_DIR}/utils/llvm-build/llvm-build") set(LLVMCONFIGLIBRARYDEPENDENCIESINC "${LLVM_BINARY_DIR}/tools/llvm-config/LibraryDependencies.inc") set(LLVMBUILDCMAKEFRAG "${LLVM_BINARY_DIR}/LLVMBuild.cmake") # Create the list of optional components that are enabled if (LLVM_USE_INTEL_JITEVENTS) set(LLVMOPTIONALCOMPONENTS IntelJITEvents) endif (LLVM_USE_INTEL_JITEVENTS) if (LLVM_USE_OPROFILE) set(LLVMOPTIONALCOMPONENTS ${LLVMOPTIONALCOMPONENTS} OProfileJIT) endif (LLVM_USE_OPROFILE) message(STATUS "Constructing LLVMBuild project information") execute_process( COMMAND ${PYTHON_EXECUTABLE} ${LLVMBUILDTOOL} --native-target "${LLVM_NATIVE_ARCH}" --enable-targets "${LLVM_TARGETS_TO_BUILD}" --enable-optional-components "${LLVMOPTIONALCOMPONENTS}" --write-library-table ${LLVMCONFIGLIBRARYDEPENDENCIESINC} --write-cmake-fragment ${LLVMBUILDCMAKEFRAG} OUTPUT_VARIABLE LLVMBUILDOUTPUT ERROR_VARIABLE LLVMBUILDERRORS OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE LLVMBUILDRESULT) # On Win32, CMake doesn't properly handle piping the default output/error # streams into the GUI console. So, we explicitly catch and report them. if( NOT "${LLVMBUILDOUTPUT}" STREQUAL "") message(STATUS "llvm-build output: ${LLVMBUILDOUTPUT}") endif() if( NOT "${LLVMBUILDRESULT}" STREQUAL "0" ) message(FATAL_ERROR "Unexpected failure executing llvm-build: ${LLVMBUILDERRORS}") endif() # Include the generated CMake fragment. This will define properties from the # LLVMBuild files in a format which is easy to consume from CMake, and will add # the dependencies so that CMake will reconfigure properly when the LLVMBuild # files change. include(${LLVMBUILDCMAKEFRAG}) ###### # Configure all of the various header file fragments LLVM uses which depend on # configuration variables. set(LLVM_ENUM_TARGETS "") set(LLVM_ENUM_ASM_PRINTERS "") set(LLVM_ENUM_ASM_PARSERS "") set(LLVM_ENUM_DISASSEMBLERS "") foreach(t ${LLVM_TARGETS_TO_BUILD}) set( td ${LLVM_MAIN_SRC_DIR}/lib/Target/${t} ) list(FIND LLVM_ALL_TARGETS ${t} idx) list(FIND LLVM_EXPERIMENTAL_TARGETS_TO_BUILD ${t} idy) if( idx LESS 0 AND idy LESS 0 ) message(FATAL_ERROR "The target `${t}' does not exist. It should be one of\n${LLVM_ALL_TARGETS}") else() set(LLVM_ENUM_TARGETS "${LLVM_ENUM_TARGETS}LLVM_TARGET(${t})\n") endif() file(GLOB asmp_file "${td}/*AsmPrinter.cpp") if( asmp_file ) set(LLVM_ENUM_ASM_PRINTERS "${LLVM_ENUM_ASM_PRINTERS}LLVM_ASM_PRINTER(${t})\n") endif() if( EXISTS ${td}/AsmParser/CMakeLists.txt ) set(LLVM_ENUM_ASM_PARSERS "${LLVM_ENUM_ASM_PARSERS}LLVM_ASM_PARSER(${t})\n") endif() if( EXISTS ${td}/Disassembler/CMakeLists.txt ) set(LLVM_ENUM_DISASSEMBLERS "${LLVM_ENUM_DISASSEMBLERS}LLVM_DISASSEMBLER(${t})\n") endif() endforeach(t) # Produce the target definition files, which provide a way for clients to easily # include various classes of targets. configure_file( ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/AsmPrinters.def.in ${LLVM_INCLUDE_DIR}/llvm/Config/AsmPrinters.def ) configure_file( ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/AsmParsers.def.in ${LLVM_INCLUDE_DIR}/llvm/Config/AsmParsers.def ) configure_file( ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/Disassemblers.def.in ${LLVM_INCLUDE_DIR}/llvm/Config/Disassemblers.def ) configure_file( ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/Targets.def.in ${LLVM_INCLUDE_DIR}/llvm/Config/Targets.def ) # Configure the three LLVM configuration header files. configure_file( ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/config.h.cmake ${LLVM_INCLUDE_DIR}/llvm/Config/config.h) configure_file( ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/llvm-config.h.cmake ${LLVM_INCLUDE_DIR}/llvm/Config/llvm-config.h) configure_file( ${LLVM_MAIN_INCLUDE_DIR}/llvm/Support/DataTypes.h.cmake ${LLVM_INCLUDE_DIR}/llvm/Support/DataTypes.h) # They are not referenced. See set_output_directory(). set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/bin ) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX} ) set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX} ) set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) if (APPLE) set(CMAKE_INSTALL_NAME_DIR "@rpath") set(CMAKE_INSTALL_RPATH "@executable_path/../lib") else(UNIX) if(NOT DEFINED CMAKE_INSTALL_RPATH) set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib${LLVM_LIBDIR_SUFFIX}") if(${CMAKE_SYSTEM_NAME} MATCHES "(FreeBSD|DragonFly)") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,origin") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,origin") endif() endif(NOT DEFINED CMAKE_INSTALL_RPATH) endif() if(APPLE AND DARWIN_LTO_LIBRARY) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-lto_library -Wl,${DARWIN_LTO_LIBRARY}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-lto_library -Wl,${DARWIN_LTO_LIBRARY}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-lto_library -Wl,${DARWIN_LTO_LIBRARY}") endif() # Work around a broken bfd ld behavior. When linking a binary with a # foo.so library, it will try to find any library that foo.so uses and # check its symbols. This is wasteful (the check was done when foo.so # was created) and can fail since it is not the dynamic linker and # doesn't know how to handle search paths correctly. if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-allow-shlib-undefined") endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) include_directories( ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR}) # when crosscompiling import the executable targets from a file if(LLVM_USE_HOST_TOOLS) include(CrossCompile) endif(LLVM_USE_HOST_TOOLS) if(LLVM_TARGET_IS_CROSSCOMPILE_HOST) # Dummy use to avoid CMake Wraning: Manually-specified variables were not used # (this is a variable that CrossCompile sets on recursive invocations) endif() if(${CMAKE_SYSTEM_NAME} MATCHES "(FreeBSD|DragonFly)") # On FreeBSD, /usr/local/* is not used by default. In order to build LLVM # with libxml2, iconv.h, etc., we must add /usr/local paths. include_directories("/usr/local/include") link_directories("/usr/local/lib") endif(${CMAKE_SYSTEM_NAME} MATCHES "(FreeBSD|DragonFly)") if( ${CMAKE_SYSTEM_NAME} MATCHES SunOS ) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include llvm/Support/Solaris.h") endif( ${CMAKE_SYSTEM_NAME} MATCHES SunOS ) # Make sure we don't get -rdynamic in every binary. For those that need it, # use export_executable_symbols(target). set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") set(LLVM_PROFDATA_FILE "" CACHE FILEPATH "Profiling data file to use when compiling in order to improve runtime performance.") if(LLVM_PROFDATA_FILE AND EXISTS ${LLVM_PROFDATA_FILE}) if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) add_definitions("-fprofile-instr-use=${LLVM_PROFDATA_FILE}") else() message(FATAL_ERROR "LLVM_PROFDATA_FILE can only be specified when compiling with clang") endif() endif() include(AddLLVM) include(TableGen) if( MINGW ) # People report that -O3 is unreliable on MinGW. The traditional # build also uses -O2 for that reason: llvm_replace_compiler_option(CMAKE_CXX_FLAGS_RELEASE "-O3" "-O2") endif() # Put this before tblgen. Else we have a circular dependence. add_subdirectory(lib/Support) 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) if( LLVM_INCLUDE_UTILS ) add_subdirectory(utils/FileCheck) add_subdirectory(utils/PerfectShuffle) add_subdirectory(utils/count) add_subdirectory(utils/not) add_subdirectory(utils/llvm-lit) add_subdirectory(utils/yaml-bench) else() if ( LLVM_INCLUDE_TESTS ) message(FATAL_ERROR "Including tests when not building utils will not work. Either set LLVM_INCLUDE_UTILS to On, or set LLVM_INCLDE_TESTS to Off.") endif() endif() # Use LLVM_ADD_NATIVE_VISUALIZERS_TO_SOLUTION instead of LLVM_INCLUDE_UTILS because it is not really a util if (LLVM_ADD_NATIVE_VISUALIZERS_TO_SOLUTION) add_subdirectory(utils/LLVMVisualizers) endif() if(LLVM_INCLUDE_TESTS) add_subdirectory(utils/unittest) endif() foreach( binding ${LLVM_BINDINGS_LIST} ) if( EXISTS "${LLVM_MAIN_SRC_DIR}/bindings/${binding}/CMakeLists.txt" ) add_subdirectory(bindings/${binding}) endif() endforeach() add_subdirectory(projects) if( LLVM_INCLUDE_TOOLS ) add_subdirectory(tools) endif() add_subdirectory(runtimes) if( LLVM_INCLUDE_EXAMPLES ) add_subdirectory(examples) endif() if( LLVM_INCLUDE_TESTS ) if(EXISTS ${LLVM_MAIN_SRC_DIR}/projects/test-suite AND TARGET clang) include(LLVMExternalProjectUtils) llvm_ExternalProject_Add(test-suite ${LLVM_MAIN_SRC_DIR}/projects/test-suite USE_TOOLCHAIN EXCLUDE_FROM_ALL NO_INSTALL ALWAYS_CLEAN) endif() add_subdirectory(test) add_subdirectory(unittests) if (MSVC) # This utility is used to prevent crashing tests from calling Dr. Watson on # Windows. add_subdirectory(utils/KillTheDoctor) endif() # Add a global check rule now that all subdirectories have been traversed # and we know the total set of lit testsuites. get_property(LLVM_LIT_TESTSUITES GLOBAL PROPERTY LLVM_LIT_TESTSUITES) get_property(LLVM_LIT_PARAMS GLOBAL PROPERTY LLVM_LIT_PARAMS) get_property(LLVM_LIT_DEPENDS GLOBAL PROPERTY LLVM_LIT_DEPENDS) get_property(LLVM_LIT_EXTRA_ARGS GLOBAL PROPERTY LLVM_LIT_EXTRA_ARGS) add_lit_target(check-all "Running all regression tests" ${LLVM_LIT_TESTSUITES} PARAMS ${LLVM_LIT_PARAMS} DEPENDS ${LLVM_LIT_DEPENDS} 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) add_subdirectory(docs) endif() add_subdirectory(cmake/modules) if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) install(DIRECTORY include/llvm include/llvm-c DESTINATION include COMPONENT llvm-headers FILES_MATCHING PATTERN "*.def" PATTERN "*.h" PATTERN "*.td" PATTERN "*.inc" PATTERN "LICENSE.TXT" PATTERN ".svn" EXCLUDE ) install(DIRECTORY ${LLVM_INCLUDE_DIR}/llvm DESTINATION include COMPONENT llvm-headers FILES_MATCHING PATTERN "*.def" PATTERN "*.h" PATTERN "*.gen" PATTERN "*.inc" # Exclude include/llvm/CMakeFiles/intrinsics_gen.dir, matched by "*.def" PATTERN "CMakeFiles" EXCLUDE PATTERN "config.h" EXCLUDE PATTERN ".svn" EXCLUDE ) if (NOT CMAKE_CONFIGURATION_TYPES) add_custom_target(installhdrs DEPENDS ${name} COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=llvm-headers -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") endif() endif() # This must be at the end of the LLVM root CMakeLists file because it must run # after all targets are created. 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(distribution) add_custom_target(install-distribution) foreach(target ${LLVM_DISTRIBUTION_COMPONENTS}) if(TARGET ${target}) add_dependencies(distribution ${target}) else() message(FATAL_ERROR "Specified distribution component '${target}' doesn't have a target") endif() if(TARGET install-${target}) add_dependencies(install-distribution install-${target}) else() message(FATAL_ERROR "Specified distribution component '${target}' doesn't have an install target") endif() endforeach() endif() Index: vendor/llvm/dist/include/llvm/Analysis/LoopAccessAnalysis.h =================================================================== --- vendor/llvm/dist/include/llvm/Analysis/LoopAccessAnalysis.h (revision 309151) +++ vendor/llvm/dist/include/llvm/Analysis/LoopAccessAnalysis.h (revision 309152) @@ -1,804 +1,806 @@ //===- llvm/Analysis/LoopAccessAnalysis.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 interface for the loop memory dependence framework that // was originally developed for the Loop Vectorizer. // //===----------------------------------------------------------------------===// #ifndef LLVM_ANALYSIS_LOOPACCESSANALYSIS_H #define LLVM_ANALYSIS_LOOPACCESSANALYSIS_H #include "llvm/ADT/EquivalenceClasses.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SetVector.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AliasSetTracker.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" namespace llvm { class Value; class DataLayout; class ScalarEvolution; class Loop; class SCEV; class SCEVUnionPredicate; class LoopAccessInfo; /// Optimization analysis message produced during vectorization. Messages inform /// the user why vectorization did not occur. class LoopAccessReport { std::string Message; const Instruction *Instr; protected: LoopAccessReport(const Twine &Message, const Instruction *I) : Message(Message.str()), Instr(I) {} public: LoopAccessReport(const Instruction *I = nullptr) : Instr(I) {} template LoopAccessReport &operator<<(const A &Value) { raw_string_ostream Out(Message); Out << Value; return *this; } const Instruction *getInstr() const { return Instr; } std::string &str() { return Message; } const std::string &str() const { return Message; } operator Twine() { return Message; } /// \brief Emit an analysis note for \p PassName with the debug location from /// the instruction in \p Message if available. Otherwise use the location of /// \p TheLoop. static void emitAnalysis(const LoopAccessReport &Message, const Function *TheFunction, const Loop *TheLoop, const char *PassName); }; /// \brief Collection of parameters shared beetween the Loop Vectorizer and the /// Loop Access Analysis. struct VectorizerParams { /// \brief Maximum SIMD width. static const unsigned MaxVectorWidth; /// \brief VF as overridden by the user. static unsigned VectorizationFactor; /// \brief Interleave factor as overridden by the user. static unsigned VectorizationInterleave; /// \brief True if force-vector-interleave was specified by the user. static bool isInterleaveForced(); /// \\brief When performing memory disambiguation checks at runtime do not /// make more than this number of comparisons. static unsigned RuntimeMemoryCheckThreshold; }; /// \brief Checks memory dependences among accesses to the same underlying /// object to determine whether there vectorization is legal or not (and at /// which vectorization factor). /// /// Note: This class will compute a conservative dependence for access to /// different underlying pointers. Clients, such as the loop vectorizer, will /// sometimes deal these potential dependencies by emitting runtime checks. /// /// We use the ScalarEvolution framework to symbolically evalutate access /// functions pairs. Since we currently don't restructure the loop we can rely /// on the program order of memory accesses to determine their safety. /// At the moment we will only deem accesses as safe for: /// * A negative constant distance assuming program order. /// /// Safe: tmp = a[i + 1]; OR a[i + 1] = x; /// a[i] = tmp; y = a[i]; /// /// The latter case is safe because later checks guarantuee that there can't /// be a cycle through a phi node (that is, we check that "x" and "y" is not /// the same variable: a header phi can only be an induction or a reduction, a /// reduction can't have a memory sink, an induction can't have a memory /// source). This is important and must not be violated (or we have to /// resort to checking for cycles through memory). /// /// * A positive constant distance assuming program order that is bigger /// than the biggest memory access. /// /// tmp = a[i] OR b[i] = x /// a[i+2] = tmp y = b[i+2]; /// /// Safe distance: 2 x sizeof(a[0]), and 2 x sizeof(b[0]), respectively. /// /// * Zero distances and all accesses have the same size. /// class MemoryDepChecker { public: typedef PointerIntPair MemAccessInfo; typedef SmallPtrSet MemAccessInfoSet; /// \brief Set of potential dependent memory accesses. typedef EquivalenceClasses DepCandidates; /// \brief Dependece between memory access instructions. struct Dependence { /// \brief The type of the dependence. enum DepType { // No dependence. NoDep, // We couldn't determine the direction or the distance. Unknown, // Lexically forward. // // FIXME: If we only have loop-independent forward dependences (e.g. a // read and write of A[i]), LAA will locally deem the dependence "safe" // without querying the MemoryDepChecker. Therefore we can miss // enumerating loop-independent forward dependences in // getDependences. Note that as soon as there are different // indices used to access the same array, the MemoryDepChecker *is* // queried and the dependence list is complete. Forward, // Forward, but if vectorized, is likely to prevent store-to-load // forwarding. ForwardButPreventsForwarding, // Lexically backward. Backward, // Backward, but the distance allows a vectorization factor of // MaxSafeDepDistBytes. BackwardVectorizable, // Same, but may prevent store-to-load forwarding. BackwardVectorizableButPreventsForwarding }; /// \brief String version of the types. static const char *DepName[]; /// \brief Index of the source of the dependence in the InstMap vector. unsigned Source; /// \brief Index of the destination of the dependence in the InstMap vector. unsigned Destination; /// \brief The type of the dependence. DepType Type; Dependence(unsigned Source, unsigned Destination, DepType Type) : Source(Source), Destination(Destination), Type(Type) {} /// \brief Return the source instruction of the dependence. Instruction *getSource(const LoopAccessInfo &LAI) const; /// \brief Return the destination instruction of the dependence. Instruction *getDestination(const LoopAccessInfo &LAI) const; /// \brief Dependence types that don't prevent vectorization. static bool isSafeForVectorization(DepType Type); /// \brief Lexically forward dependence. bool isForward() const; /// \brief Lexically backward dependence. bool isBackward() const; /// \brief May be a lexically backward dependence type (includes Unknown). bool isPossiblyBackward() const; /// \brief Print the dependence. \p Instr is used to map the instruction /// indices to instructions. void print(raw_ostream &OS, unsigned Depth, const SmallVectorImpl &Instrs) const; }; MemoryDepChecker(PredicatedScalarEvolution &PSE, const Loop *L) : PSE(PSE), InnermostLoop(L), AccessIdx(0), ShouldRetryWithRuntimeCheck(false), SafeForVectorization(true), RecordDependences(true) {} /// \brief Register the location (instructions are given increasing numbers) /// of a write access. void addAccess(StoreInst *SI) { Value *Ptr = SI->getPointerOperand(); Accesses[MemAccessInfo(Ptr, true)].push_back(AccessIdx); InstMap.push_back(SI); ++AccessIdx; } /// \brief Register the location (instructions are given increasing numbers) /// of a write access. void addAccess(LoadInst *LI) { Value *Ptr = LI->getPointerOperand(); Accesses[MemAccessInfo(Ptr, false)].push_back(AccessIdx); InstMap.push_back(LI); ++AccessIdx; } /// \brief Check whether the dependencies between the accesses are safe. /// /// Only checks sets with elements in \p CheckDeps. bool areDepsSafe(DepCandidates &AccessSets, MemAccessInfoSet &CheckDeps, const ValueToValueMap &Strides); /// \brief No memory dependence was encountered that would inhibit /// vectorization. bool isSafeForVectorization() const { return SafeForVectorization; } /// \brief The maximum number of bytes of a vector register we can vectorize /// the accesses safely with. 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. bool shouldRetryWithRuntimeCheck() { return ShouldRetryWithRuntimeCheck; } /// \brief Returns the memory dependences. If null is returned we exceeded /// the MaxDependences threshold and this information is not /// available. const SmallVectorImpl *getDependences() const { return RecordDependences ? &Dependences : nullptr; } void clearDependences() { Dependences.clear(); } /// \brief The vector of memory access instructions. The indices are used as /// instruction identifiers in the Dependence class. const SmallVectorImpl &getMemoryInstructions() const { return InstMap; } /// \brief Generate a mapping between the memory instructions and their /// indices according to program order. DenseMap generateInstructionOrderMap() const { DenseMap OrderMap; for (unsigned I = 0; I < InstMap.size(); ++I) OrderMap[InstMap[I]] = I; return OrderMap; } /// \brief Find the set of instructions that read or write via \p Ptr. SmallVector getInstructionsForAccess(Value *Ptr, bool isWrite) const; private: /// A wrapper around ScalarEvolution, used to add runtime SCEV checks, and /// applies dynamic knowledge to simplify SCEV expressions and convert them /// to a more usable form. We need this in case assumptions about SCEV /// expressions need to be made in order to avoid unknown dependences. For /// example we might assume a unit stride for a pointer in order to prove /// that a memory access is strided and doesn't wrap. PredicatedScalarEvolution &PSE; const Loop *InnermostLoop; /// \brief Maps access locations (ptr, read/write) to program order. DenseMap > Accesses; /// \brief Memory access instructions in program order. SmallVector InstMap; /// \brief The program order index to be used for the next instruction. unsigned AccessIdx; // We can access this many bytes in parallel safely. uint64_t MaxSafeDepDistBytes; /// \brief If we see a non-constant dependence distance we can still try to /// vectorize this loop with runtime checks. bool ShouldRetryWithRuntimeCheck; /// \brief No memory dependence was encountered that would inhibit /// vectorization. bool SafeForVectorization; //// \brief True if Dependences reflects the dependences in the //// loop. If false we exceeded MaxDependences and //// Dependences is invalid. bool RecordDependences; /// \brief Memory dependences collected during the analysis. Only valid if /// RecordDependences is true. SmallVector Dependences; /// \brief Check whether there is a plausible dependence between the two /// accesses. /// /// Access \p A must happen before \p B in program order. The two indices /// identify the index into the program order map. /// /// This function checks whether there is a plausible dependence (or the /// absence of such can't be proved) between the two accesses. If there is a /// plausible dependence but the dependence distance is bigger than one /// element access it records this distance in \p MaxSafeDepDistBytes (if this /// distance is smaller than any other distance encountered so far). /// Otherwise, this function returns true signaling a possible dependence. Dependence::DepType isDependent(const MemAccessInfo &A, unsigned AIdx, const MemAccessInfo &B, unsigned BIdx, const ValueToValueMap &Strides); /// \brief Check whether the data dependence could prevent store-load /// forwarding. /// /// \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 /// that a group of pointers do not overlap. class RuntimePointerChecking { public: struct PointerInfo { /// Holds the pointer value that we need to check. TrackingVH PointerValue; - /// Holds the pointer value at the beginning of the loop. + /// Holds the smallest byte address accessed by the pointer throughout all + /// iterations of the loop. const SCEV *Start; - /// Holds the pointer value at the end of the loop. + /// Holds the largest byte address accessed by the pointer throughout all + /// iterations of the loop, plus 1. const SCEV *End; /// Holds the information if this pointer is used for writing to memory. bool IsWritePtr; /// Holds the id of the set of pointers that could be dependent because of a /// shared underlying object. unsigned DependencySetId; /// Holds the id of the disjoint alias set to which this pointer belongs. unsigned AliasSetId; /// SCEV for the access. const SCEV *Expr; PointerInfo(Value *PointerValue, const SCEV *Start, const SCEV *End, bool IsWritePtr, unsigned DependencySetId, unsigned AliasSetId, const SCEV *Expr) : PointerValue(PointerValue), Start(Start), End(End), IsWritePtr(IsWritePtr), DependencySetId(DependencySetId), AliasSetId(AliasSetId), Expr(Expr) {} }; RuntimePointerChecking(ScalarEvolution *SE) : Need(false), SE(SE) {} /// Reset the state of the pointer runtime information. void reset() { Need = false; Pointers.clear(); Checks.clear(); } /// Insert a pointer and calculate the start and end SCEVs. /// We need \p PSE in order to compute the SCEV expression of the pointer /// according to the assumptions that we've made during the analysis. /// The method might also version the pointer stride according to \p Strides, /// and add new predicates to \p PSE. void insert(Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId, unsigned ASId, const ValueToValueMap &Strides, PredicatedScalarEvolution &PSE); /// \brief No run-time memory checking is necessary. bool empty() const { return Pointers.empty(); } /// A grouping of pointers. A single memcheck is required between /// two groups. struct CheckingPtrGroup { /// \brief Create a new pointer checking group containing a single /// pointer, with index \p Index in RtCheck. CheckingPtrGroup(unsigned Index, RuntimePointerChecking &RtCheck) : RtCheck(RtCheck), High(RtCheck.Pointers[Index].End), Low(RtCheck.Pointers[Index].Start) { Members.push_back(Index); } /// \brief Tries to add the pointer recorded in RtCheck at index /// \p Index to this pointer checking group. We can only add a pointer /// to a checking group if we will still be able to get /// the upper and lower bounds of the check. Returns true in case /// of success, false otherwise. bool addPointer(unsigned Index); /// Constitutes the context of this pointer checking group. For each /// pointer that is a member of this group we will retain the index /// at which it appears in RtCheck. RuntimePointerChecking &RtCheck; /// The SCEV expression which represents the upper bound of all the /// pointers in this group. const SCEV *High; /// The SCEV expression which represents the lower bound of all the /// pointers in this group. const SCEV *Low; /// Indices of all the pointers that constitute this grouping. SmallVector Members; }; /// \brief A memcheck which made up of a pair of grouped pointers. /// /// These *have* to be const for now, since checks are generated from /// CheckingPtrGroups in LAI::addRuntimeChecks which is a const member /// function. FIXME: once check-generation is moved inside this class (after /// the PtrPartition hack is removed), we could drop const. typedef std::pair PointerCheck; /// \brief Generate the checks and store it. This also performs the grouping /// of pointers to reduce the number of memchecks necessary. void generateChecks(MemoryDepChecker::DepCandidates &DepCands, bool UseDependencies); /// \brief Returns the checks that generateChecks created. const SmallVector &getChecks() const { return Checks; } /// \brief Decide if we need to add a check between two groups of pointers, /// according to needsChecking. bool needsChecking(const CheckingPtrGroup &M, const CheckingPtrGroup &N) const; /// \brief Returns the number of run-time checks required according to /// needsChecking. unsigned getNumberOfChecks() const { return Checks.size(); } /// \brief Print the list run-time memory checks necessary. void print(raw_ostream &OS, unsigned Depth = 0) const; /// Print \p Checks. void printChecks(raw_ostream &OS, const SmallVectorImpl &Checks, unsigned Depth = 0) const; /// This flag indicates if we need to add the runtime check. bool Need; /// Information about the pointers that may require checking. SmallVector Pointers; /// Holds a partitioning of pointers into "check groups". SmallVector CheckingGroups; /// \brief Check if pointers are in the same partition /// /// \p PtrToPartition contains the partition number for pointers (-1 if the /// pointer belongs to multiple partitions). static bool arePointersInSamePartition(const SmallVectorImpl &PtrToPartition, unsigned PtrIdx1, unsigned PtrIdx2); /// \brief Decide whether we need to issue a run-time check for pointer at /// index \p I and \p J to prove their independence. bool needsChecking(unsigned I, unsigned J) const; /// \brief Return PointerInfo for pointer at index \p PtrIdx. const PointerInfo &getPointerInfo(unsigned PtrIdx) const { return Pointers[PtrIdx]; } private: /// \brief Groups pointers such that a single memcheck is required /// between two different groups. This will clear the CheckingGroups vector /// and re-compute it. We will only group dependecies if \p UseDependencies /// is true, otherwise we will create a separate group for each pointer. void groupChecks(MemoryDepChecker::DepCandidates &DepCands, bool UseDependencies); /// Generate the checks and return them. SmallVector generateChecks() const; /// Holds a pointer to the ScalarEvolution analysis. ScalarEvolution *SE; /// \brief Set of run-time checks required to establish independence of /// otherwise may-aliasing pointers in the loop. SmallVector Checks; }; /// \brief Drive the analysis of memory accesses in the loop /// /// This class is responsible for analyzing the memory accesses of a loop. It /// collects the accesses and then its main helper the AccessAnalysis class /// finds and categorizes the dependences in buildDependenceSets. /// /// For memory dependences that can be analyzed at compile time, it determines /// whether the dependence is part of cycle inhibiting vectorization. This work /// is delegated to the MemoryDepChecker class. /// /// For memory dependences that cannot be determined at compile time, it /// generates run-time checks to prove independence. This is done by /// AccessAnalysis::canCheckPtrAtRT and the checks are maintained by the /// RuntimePointerCheck class. /// /// If pointers can wrap or can't be expressed as affine AddRec expressions by /// ScalarEvolution, we will generate run-time checks by emitting a /// SCEVUnionPredicate. /// /// Checks for both memory dependences and the SCEV predicates contained in the /// PSE must be emitted in order for the results of this analysis to be valid. class LoopAccessInfo { public: 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.get(); } /// \brief Number of memchecks required to prove independence of otherwise /// may-alias pointers. unsigned getNumRuntimePointerChecks() const { return PtrRtChecking->getNumberOfChecks(); } /// Return true if the block BB needs to be predicated in order for the loop /// to be vectorized. static bool blockNeedsPredication(BasicBlock *BB, Loop *TheLoop, DominatorTree *DT); /// Returns true if the value V is uniform within the loop. bool isUniform(Value *V) const; uint64_t getMaxSafeDepDistBytes() const { return MaxSafeDepDistBytes; } unsigned getNumStores() const { return NumStores; } unsigned getNumLoads() const { return NumLoads;} /// \brief Add code that checks at runtime if the accessed arrays overlap. /// /// Returns a pair of instructions where the first element is the first /// instruction generated in possibly a sequence of instructions and the /// second value is the final comparator value or NULL if no check is needed. std::pair addRuntimeChecks(Instruction *Loc) const; /// \brief Generete the instructions for the checks in \p PointerChecks. /// /// Returns a pair of instructions where the first element is the first /// instruction generated in possibly a sequence of instructions and the /// second value is the final comparator value or NULL if no check is needed. std::pair addRuntimeChecks(Instruction *Loc, const SmallVectorImpl &PointerChecks) const; /// \brief The diagnostics report generated for the analysis. E.g. why we /// couldn't analyze the loop. const Optional &getReport() const { return Report; } /// \brief the Memory Dependence Checker which can determine the /// loop-independent and loop-carried dependences between memory accesses. 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); } /// \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 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. bool hasStoreToLoopInvariantAddress() const { return StoreToLoopInvariantAddress; } /// Used to add runtime SCEV checks. Simplifies SCEV expressions and converts /// them to a more usable form. All SCEV expressions during the analysis /// 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. const PredicatedScalarEvolution &getPSE() const { return *PSE; } private: /// \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. bool canAnalyzeLoop(); 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. 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. std::unique_ptr DepChecker; Loop *TheLoop; unsigned NumLoads; unsigned NumStores; uint64_t MaxSafeDepDistBytes; /// \brief Cache the result of analyzeLoop. bool CanVecMem; /// \brief Indicator for storing to uniform addresses. /// If a loop has write to a loop invariant address then it should be true. bool StoreToLoopInvariantAddress; /// \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); /// \brief Return the SCEV corresponding to a pointer with the symbolic stride /// replaced with constant one, assuming the SCEV predicate associated with /// \p PSE is true. /// /// If necessary this method will version the stride of the pointer according /// to \p PtrToStride and therefore add further predicates to \p PSE. /// /// If \p OrigPtr is not null, use it to look up the stride value instead of \p /// Ptr. \p PtrToStride provides the mapping between the pointer value and its /// stride as collected by LoopVectorizationLegality::collectStridedAccess. const SCEV *replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE, const ValueToValueMap &PtrToStride, Value *Ptr, Value *OrigPtr = nullptr); /// \brief If the pointer has a constant stride return it in units of its /// element size. Otherwise return zero. /// /// Ensure that it does not wrap in the address space, assuming the predicate /// associated with \p PSE is true. /// /// If necessary this method will version the stride of the pointer according /// 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. 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. bool isConsecutiveAccess(Value *A, Value *B, const DataLayout &DL, ScalarEvolution &SE, bool CheckType = true); /// \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 LAA::getInfo. getInfo return a /// LoopAccessInfo object. See this class for the specifics of what information /// is provided. class LoopAccessLegacyAnalysis : public FunctionPass { public: static char ID; LoopAccessLegacyAnalysis() : FunctionPass(ID) { initializeLoopAccessLegacyAnalysisPass(*PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override; void getAnalysisUsage(AnalysisUsage &AU) const override; /// \brief Query the result of the loop access information for the loop \p L. /// /// 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. LoopAccessInfoMap.clear(); } /// \brief Print the result of the analysis when invoked with -analyze. void print(raw_ostream &OS, const Module *M = nullptr) const override; private: /// \brief The cache. DenseMap> LoopAccessInfoMap; // The used analysis passes. ScalarEvolution *SE; const TargetLibraryInfo *TLI; AliasAnalysis *AA; DominatorTree *DT; 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]; } inline Instruction *MemoryDepChecker::Dependence::getDestination( const LoopAccessInfo &LAI) const { return LAI.getDepChecker().getMemoryInstructions()[Destination]; } } // End llvm namespace #endif Index: vendor/llvm/dist/include/llvm/ExecutionEngine/RTDyldMemoryManager.h =================================================================== --- vendor/llvm/dist/include/llvm/ExecutionEngine/RTDyldMemoryManager.h (revision 309151) +++ vendor/llvm/dist/include/llvm/ExecutionEngine/RTDyldMemoryManager.h (revision 309152) @@ -1,150 +1,150 @@ //===-- RTDyldMemoryManager.cpp - Memory manager for MC-JIT -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Interface of the runtime dynamic memory manager base class. // //===----------------------------------------------------------------------===// #ifndef LLVM_EXECUTIONENGINE_RTDYLDMEMORYMANAGER_H #define LLVM_EXECUTIONENGINE_RTDYLDMEMORYMANAGER_H #include "RuntimeDyld.h" #include "llvm-c/ExecutionEngine.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Memory.h" namespace llvm { class ExecutionEngine; namespace object { class ObjectFile; } class MCJITMemoryManager : public RuntimeDyld::MemoryManager { public: // Don't hide the notifyObjectLoaded method from RuntimeDyld::MemoryManager. using RuntimeDyld::MemoryManager::notifyObjectLoaded; /// This method is called after an object has been loaded into memory but /// before relocations are applied to the loaded sections. The object load /// may have been initiated by MCJIT to resolve an external symbol for another /// object that is being finalized. In that case, the object about which /// the memory manager is being notified will be finalized immediately after /// the memory manager returns from this call. /// /// Memory managers which are preparing code for execution in an external /// address space can use this call to remap the section addresses for the /// newly loaded object. virtual void notifyObjectLoaded(ExecutionEngine *EE, const object::ObjectFile &) {} }; // RuntimeDyld clients often want to handle the memory management of // what gets placed where. For JIT clients, this is the subset of // JITMemoryManager required for dynamic loading of binaries. // // FIXME: As the RuntimeDyld fills out, additional routines will be needed // for the varying types of objects to be allocated. class RTDyldMemoryManager : public MCJITMemoryManager, public RuntimeDyld::SymbolResolver { RTDyldMemoryManager(const RTDyldMemoryManager&) = delete; void operator=(const RTDyldMemoryManager&) = delete; public: RTDyldMemoryManager() {} ~RTDyldMemoryManager() override; /// Register EH frames in the current process. static void registerEHFramesInProcess(uint8_t *Addr, size_t Size); /// Deregister EH frames in the current proces. static void deregisterEHFramesInProcess(uint8_t *Addr, size_t Size); void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override { registerEHFramesInProcess(Addr, Size); } void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override { - registerEHFramesInProcess(Addr, Size); + deregisterEHFramesInProcess(Addr, Size); } /// This method returns the address of the specified function or variable in /// the current process. static uint64_t getSymbolAddressInProcess(const std::string &Name); /// Legacy symbol lookup - DEPRECATED! Please override findSymbol instead. /// /// This method returns the address of the specified function or variable. /// It is used to resolve symbols during module linking. virtual uint64_t getSymbolAddress(const std::string &Name) { return getSymbolAddressInProcess(Name); } /// This method returns a RuntimeDyld::SymbolInfo for the specified function /// or variable. It is used to resolve symbols during module linking. /// /// By default this falls back on the legacy lookup method: /// 'getSymbolAddress'. The address returned by getSymbolAddress is treated as /// a strong, exported symbol, consistent with historical treatment by /// RuntimeDyld. /// /// Clients writing custom RTDyldMemoryManagers are encouraged to override /// this method and return a SymbolInfo with the flags set correctly. This is /// necessary for RuntimeDyld to correctly handle weak and non-exported symbols. RuntimeDyld::SymbolInfo findSymbol(const std::string &Name) override { return RuntimeDyld::SymbolInfo(getSymbolAddress(Name), JITSymbolFlags::Exported); } /// Legacy symbol lookup -- DEPRECATED! Please override /// findSymbolInLogicalDylib instead. /// /// Default to treating all modules as separate. virtual uint64_t getSymbolAddressInLogicalDylib(const std::string &Name) { return 0; } /// Default to treating all modules as separate. /// /// By default this falls back on the legacy lookup method: /// 'getSymbolAddressInLogicalDylib'. The address returned by /// getSymbolAddressInLogicalDylib is treated as a strong, exported symbol, /// consistent with historical treatment by RuntimeDyld. /// /// Clients writing custom RTDyldMemoryManagers are encouraged to override /// this method and return a SymbolInfo with the flags set correctly. This is /// necessary for RuntimeDyld to correctly handle weak and non-exported symbols. RuntimeDyld::SymbolInfo findSymbolInLogicalDylib(const std::string &Name) override { return RuntimeDyld::SymbolInfo(getSymbolAddressInLogicalDylib(Name), JITSymbolFlags::Exported); } /// This method returns the address of the specified function. As such it is /// only useful for resolving library symbols, not code generated symbols. /// /// If \p AbortOnFailure is false and no function with the given name is /// found, this function returns a null pointer. Otherwise, it prints a /// message to stderr and aborts. /// /// This function is deprecated for memory managers to be used with /// MCJIT or RuntimeDyld. Use getSymbolAddress instead. virtual void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true); }; // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS( RTDyldMemoryManager, LLVMMCJITMemoryManagerRef) } // namespace llvm #endif Index: vendor/llvm/dist/include/llvm/IR/Intrinsics.td =================================================================== --- vendor/llvm/dist/include/llvm/IR/Intrinsics.td (revision 309151) +++ vendor/llvm/dist/include/llvm/IR/Intrinsics.td (revision 309152) @@ -1,706 +1,705 @@ //===- Intrinsics.td - Defines all LLVM intrinsics ---------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines properties of all LLVM intrinsics. // //===----------------------------------------------------------------------===// include "llvm/CodeGen/ValueTypes.td" //===----------------------------------------------------------------------===// // Properties we keep track of for intrinsics. //===----------------------------------------------------------------------===// class IntrinsicProperty; // 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). // IntrNoMem - The intrinsic does not access memory or have any other side // effects. It may be CSE'd deleted if dead, etc. def IntrNoMem : IntrinsicProperty; // 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; // 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; // Throws - This intrinsic can throw. def Throws : IntrinsicProperty; // NoCapture - The specified argument pointer is not captured by the intrinsic. 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 { int ArgNo = argNo; } def IntrNoReturn : IntrinsicProperty; // IntrNoduplicate - Calls to this intrinsic cannot be duplicated. // Parallels the noduplicate attribute on LLVM IR functions. def IntrNoDuplicate : IntrinsicProperty; // IntrConvergent - Calls to this intrinsic are convergent and may not be made // control-dependent on any additional values. // Parallels the convergent attribute on LLVM IR functions. def IntrConvergent : IntrinsicProperty; //===----------------------------------------------------------------------===// // Types used by intrinsics. //===----------------------------------------------------------------------===// class LLVMType { ValueType VT = vt; } class LLVMQualPointerType : LLVMType{ LLVMType ElTy = elty; int AddrSpace = addrspace; } class LLVMPointerType : LLVMQualPointerType; class LLVMAnyPointerType : LLVMType{ LLVMType ElTy = elty; } // Match the type of another intrinsic parameter. Number is an index into the // list of overloaded types for the intrinsic, excluding all the fixed types. // The Number value must refer to a previously listed type. For example: // Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_anyfloat_ty, LLVMMatchType<0>]> // has two overloaded types, the 2nd and 3rd arguments. LLVMMatchType<0> // refers to the first overloaded type, which is the 2nd argument. class LLVMMatchType : LLVMType{ int Number = num; } // Match the type of another intrinsic parameter that is expected to be based on // an integral type (i.e. either iN or ), but change the scalar size to // be twice as wide or half as wide as the other type. This is only useful when // the intrinsic is overloaded, so the matched type should be declared as iAny. class LLVMExtendedType : LLVMMatchType; class LLVMTruncatedType : LLVMMatchType; class LLVMVectorSameWidth : LLVMMatchType { ValueType ElTy = elty.VT; } class LLVMPointerTo : LLVMMatchType; class LLVMVectorOfPointersToElt : LLVMMatchType; // Match the type of another intrinsic parameter that is expected to be a // vector type, but change the element count to be half as many class LLVMHalfElementsVectorType : LLVMMatchType; def llvm_void_ty : LLVMType; def llvm_any_ty : LLVMType; def llvm_anyint_ty : LLVMType; def llvm_anyfloat_ty : LLVMType; def llvm_anyvector_ty : LLVMType; def llvm_i1_ty : LLVMType; def llvm_i8_ty : LLVMType; def llvm_i16_ty : LLVMType; def llvm_i32_ty : LLVMType; def llvm_i64_ty : LLVMType; def llvm_half_ty : LLVMType; def llvm_float_ty : LLVMType; def llvm_double_ty : LLVMType; def llvm_f80_ty : LLVMType; def llvm_f128_ty : LLVMType; def llvm_ppcf128_ty : LLVMType; def llvm_ptr_ty : LLVMPointerType; // i8* def llvm_ptrptr_ty : LLVMPointerType; // i8** def llvm_anyptr_ty : LLVMAnyPointerType; // (space)i8* def llvm_empty_ty : LLVMType; // { } def llvm_descriptor_ty : LLVMPointerType; // { }* def llvm_metadata_ty : LLVMType; // !{...} def llvm_token_ty : LLVMType; // token def llvm_x86mmx_ty : LLVMType; def llvm_ptrx86mmx_ty : LLVMPointerType; // <1 x i64>* def llvm_v2i1_ty : LLVMType; // 2 x i1 def llvm_v4i1_ty : LLVMType; // 4 x i1 def llvm_v8i1_ty : LLVMType; // 8 x i1 def llvm_v16i1_ty : LLVMType; // 16 x i1 def llvm_v32i1_ty : LLVMType; // 32 x i1 def llvm_v64i1_ty : LLVMType; // 64 x i1 def llvm_v512i1_ty : LLVMType; // 512 x i1 def llvm_v1024i1_ty : LLVMType; //1024 x i1 def llvm_v1i8_ty : LLVMType; // 1 x i8 def llvm_v2i8_ty : LLVMType; // 2 x i8 def llvm_v4i8_ty : LLVMType; // 4 x i8 def llvm_v8i8_ty : LLVMType; // 8 x i8 def llvm_v16i8_ty : LLVMType; // 16 x i8 def llvm_v32i8_ty : LLVMType; // 32 x i8 def llvm_v64i8_ty : LLVMType; // 64 x i8 def llvm_v128i8_ty : LLVMType; //128 x i8 def llvm_v256i8_ty : LLVMType; //256 x i8 def llvm_v1i16_ty : LLVMType; // 1 x i16 def llvm_v2i16_ty : LLVMType; // 2 x i16 def llvm_v4i16_ty : LLVMType; // 4 x i16 def llvm_v8i16_ty : LLVMType; // 8 x i16 def llvm_v16i16_ty : LLVMType; // 16 x i16 def llvm_v32i16_ty : LLVMType; // 32 x i16 def llvm_v64i16_ty : LLVMType; // 64 x i16 def llvm_v128i16_ty : LLVMType; //128 x i16 def llvm_v1i32_ty : LLVMType; // 1 x i32 def llvm_v2i32_ty : LLVMType; // 2 x i32 def llvm_v4i32_ty : LLVMType; // 4 x i32 def llvm_v8i32_ty : LLVMType; // 8 x i32 def llvm_v16i32_ty : LLVMType; // 16 x i32 def llvm_v32i32_ty : LLVMType; // 32 x i32 def llvm_v64i32_ty : LLVMType; // 64 x i32 def llvm_v1i64_ty : LLVMType; // 1 x i64 def llvm_v2i64_ty : LLVMType; // 2 x i64 def llvm_v4i64_ty : LLVMType; // 4 x i64 def llvm_v8i64_ty : LLVMType; // 8 x i64 def llvm_v16i64_ty : LLVMType; // 16 x i64 def llvm_v32i64_ty : LLVMType; // 32 x i64 def llvm_v1i128_ty : LLVMType; // 1 x i128 def llvm_v2f16_ty : LLVMType; // 2 x half (__fp16) def llvm_v4f16_ty : LLVMType; // 4 x half (__fp16) def llvm_v8f16_ty : LLVMType; // 8 x half (__fp16) def llvm_v1f32_ty : LLVMType; // 1 x float def llvm_v2f32_ty : LLVMType; // 2 x float def llvm_v4f32_ty : LLVMType; // 4 x float def llvm_v8f32_ty : LLVMType; // 8 x float def llvm_v16f32_ty : LLVMType; // 16 x float def llvm_v1f64_ty : LLVMType; // 1 x double def llvm_v2f64_ty : LLVMType; // 2 x double def llvm_v4f64_ty : LLVMType; // 4 x double def llvm_v8f64_ty : LLVMType; // 8 x double def llvm_vararg_ty : LLVMType; // this means vararg here //===----------------------------------------------------------------------===// // Intrinsic Definitions. //===----------------------------------------------------------------------===// // Intrinsic class - This is used to define one LLVM intrinsic. The name of the // intrinsic definition should start with "int_", then match the LLVM intrinsic // name with the "llvm." prefix removed, and all "."s turned into "_"s. For // example, llvm.bswap.i16 -> int_bswap_i16. // // * RetTypes is a list containing the return types expected for the // intrinsic. // * ParamTypes is a list containing the parameter types expected for the // intrinsic. // * Properties can be set to describe the behavior of the intrinsic. // class SDPatternOperator; class Intrinsic ret_types, list param_types = [], list properties = [], string name = ""> : SDPatternOperator { string LLVMName = name; string TargetPrefix = ""; // Set to a prefix for target-specific intrinsics. list RetTypes = ret_types; list ParamTypes = param_types; list IntrProperties = properties; bit isTarget = 0; } /// GCCBuiltin - If this intrinsic exactly corresponds to a GCC builtin, this /// specifies the name of the builtin. This provides automatic CBE and CFE /// support. class GCCBuiltin { string GCCBuiltinName = name; } class MSBuiltin { string MSBuiltinName = name; } //===--------------- Variable Argument Handling Intrinsics ----------------===// // def int_vastart : Intrinsic<[], [llvm_ptr_ty], [], "llvm.va_start">; def int_vacopy : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty], [], "llvm.va_copy">; def int_vaend : Intrinsic<[], [llvm_ptr_ty], [], "llvm.va_end">; //===------------------- Garbage Collection Intrinsics --------------------===// // def int_gcroot : Intrinsic<[], [llvm_ptrptr_ty, llvm_ptr_ty]>; def int_gcread : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_ptrptr_ty], [IntrReadMem, IntrArgMemOnly]>; def int_gcwrite : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_ptrptr_ty], [IntrArgMemOnly, NoCapture<1>, NoCapture<2>]>; //===--------------------- Code Generator Intrinsics ----------------------===// // def int_returnaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>; def int_frameaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>; def int_read_register : Intrinsic<[llvm_anyint_ty], [llvm_metadata_ty], [IntrReadMem], "llvm.read_register">; def int_write_register : Intrinsic<[], [llvm_metadata_ty, llvm_anyint_ty], [], "llvm.write_register">; // Gets the address of the local variable area. This is typically a copy of the // stack, frame, or base pointer depending on the type of prologue. def int_localaddress : Intrinsic<[llvm_ptr_ty], [], [IntrNoMem]>; // Escapes local variables to allow access from other functions. def int_localescape : Intrinsic<[], [llvm_vararg_ty]>; // Given a function and the localaddress of a parent frame, returns a pointer // to an escaped allocation indicated by the index. def int_localrecover : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty], [IntrNoMem]>; // Note: we treat stacksave/stackrestore as writemem because we don't otherwise // model their dependencies on allocas. def int_stacksave : Intrinsic<[llvm_ptr_ty]>, GCCBuiltin<"__builtin_stack_save">; def int_stackrestore : Intrinsic<[], [llvm_ptr_ty]>, GCCBuiltin<"__builtin_stack_restore">; def int_get_dynamic_area_offset : Intrinsic<[llvm_anyint_ty]>; 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], [IntrArgMemOnly, NoCapture<0>]>; def int_pcmarker : Intrinsic<[], [llvm_i32_ty]>; def int_readcyclecounter : Intrinsic<[llvm_i64_ty]>; // The assume intrinsic is marked as arbitrarily writing so that proper // control dependencies will be maintained. 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_stackguard : Intrinsic<[llvm_ptr_ty], [], []>; // A counter increment for instrumentation based profiling. def int_instrprof_increment : Intrinsic<[], [llvm_ptr_ty, llvm_i64_ty, llvm_i32_ty, llvm_i32_ty], []>; // A call to profile runtime for value profiling of target expressions // through instrumentation based profiling. def int_instrprof_value_profile : Intrinsic<[], [llvm_ptr_ty, llvm_i64_ty, llvm_i64_ty, llvm_i32_ty, llvm_i32_ty], []>; //===------------------- Standard C Library Intrinsics --------------------===// // def int_memcpy : Intrinsic<[], [llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty, llvm_i32_ty, llvm_i1_ty], [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], [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], [IntrArgMemOnly, NoCapture<0>, WriteOnly<0>]>; let IntrProperties = [IntrNoMem] in { def int_fma : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>]>; def int_fmuladd : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>]>; // These functions do not read memory, but are sensitive to the // rounding mode. LLVM purposely does not model changes to the FP // environment so they can be treated as readnone. def int_sqrt : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_powi : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, llvm_i32_ty]>; def int_sin : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_cos : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_pow : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>]>; def int_log : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_log10: Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_log2 : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_exp : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_exp2 : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_fabs : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_copysign : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>]>; def int_floor : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_ceil : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_trunc : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_rint : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_nearbyint : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_round : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>; def int_canonicalize : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; } def int_minnum : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, Commutative] >; def int_maxnum : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, Commutative] >; // NOTE: these are internal interfaces. def int_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>; def int_longjmp : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty], [IntrNoReturn]>; def int_sigsetjmp : Intrinsic<[llvm_i32_ty] , [llvm_ptr_ty, llvm_i32_ty]>; def int_siglongjmp : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty], [IntrNoReturn]>; // Internal interface for object size checking def int_objectsize : Intrinsic<[llvm_anyint_ty], [llvm_anyptr_ty, llvm_i1_ty], [IntrNoMem]>, GCCBuiltin<"__builtin_object_size">; //===------------------------- Expect Intrinsics --------------------------===// // def int_expect : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; //===-------------------- Bit Manipulation Intrinsics ---------------------===// // // None of these intrinsics accesses memory at all. let IntrProperties = [IntrNoMem] in { def int_bswap: Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>]>; def int_ctpop: Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>]>; def int_ctlz : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, llvm_i1_ty]>; def int_cttz : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, llvm_i1_ty]>; def int_bitreverse : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>]>; } //===------------------------ Debugger Intrinsics -------------------------===// // // None of these intrinsics accesses memory at all...but that doesn't mean the // optimizers can change them aggressively. Special handling needed in a few // places. let IntrProperties = [IntrNoMem] in { def int_dbg_declare : Intrinsic<[], [llvm_metadata_ty, llvm_metadata_ty, llvm_metadata_ty]>; def int_dbg_value : Intrinsic<[], [llvm_metadata_ty, llvm_i64_ty, llvm_metadata_ty, llvm_metadata_ty]>; } //===------------------ Exception Handling Intrinsics----------------------===// // // The result of eh.typeid.for depends on the enclosing function, but inside a // given function it is 'const' and may be CSE'd etc. def int_eh_typeid_for : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty], [IntrNoMem]>; def int_eh_return_i32 : Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty]>; def int_eh_return_i64 : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty]>; // eh.exceptionpointer returns the pointer to the exception caught by // the given `catchpad`. def int_eh_exceptionpointer : Intrinsic<[llvm_anyptr_ty], [llvm_token_ty], [IntrNoMem]>; // Gets the exception code from a catchpad token. Only used on some platforms. def int_eh_exceptioncode : Intrinsic<[llvm_i32_ty], [llvm_token_ty], [IntrNoMem]>; // __builtin_unwind_init is an undocumented GCC intrinsic that causes all // callee-saved registers to be saved and restored (regardless of whether they // are used) in the calling function. It is used by libgcc_eh. def int_eh_unwind_init: Intrinsic<[]>, GCCBuiltin<"__builtin_unwind_init">; def int_eh_dwarf_cfa : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty]>; let IntrProperties = [IntrNoMem] in { def int_eh_sjlj_lsda : Intrinsic<[llvm_ptr_ty]>; def int_eh_sjlj_callsite : Intrinsic<[], [llvm_i32_ty]>; } def int_eh_sjlj_functioncontext : Intrinsic<[], [llvm_ptr_ty]>; def int_eh_sjlj_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>; def int_eh_sjlj_longjmp : Intrinsic<[], [llvm_ptr_ty], [IntrNoReturn]>; def int_eh_sjlj_setup_dispatch : Intrinsic<[], []>; //===---------------- Generic Variable Attribute Intrinsics----------------===// // def int_var_annotation : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty], [], "llvm.var.annotation">; def int_ptr_annotation : Intrinsic<[LLVMAnyPointerType], [LLVMMatchType<0>, llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty], [], "llvm.ptr.annotation">; def int_annotation : Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty], [], "llvm.annotation">; //===------------------------ Trampoline Intrinsics -----------------------===// // def int_init_trampoline : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty], [IntrArgMemOnly, NoCapture<0>]>, GCCBuiltin<"__builtin_init_trampoline">; def int_adjust_trampoline : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], [IntrReadMem, IntrArgMemOnly]>, GCCBuiltin<"__builtin_adjust_trampoline">; //===------------------------ Overflow Intrinsics -------------------------===// // // Expose the carry flag from add operations on two integrals. def int_sadd_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; def int_uadd_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; def int_ssub_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; def int_usub_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; def int_smul_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; def int_umul_with_overflow : Intrinsic<[llvm_anyint_ty, llvm_i1_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; //===------------------------- Memory Use Markers -------------------------===// // def int_lifetime_start : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty], [IntrArgMemOnly, NoCapture<1>]>; def int_lifetime_end : Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty], [IntrArgMemOnly, NoCapture<1>]>; def int_invariant_start : Intrinsic<[llvm_descriptor_ty], [llvm_i64_ty, llvm_ptr_ty], [IntrArgMemOnly, NoCapture<1>]>; def int_invariant_end : Intrinsic<[], [llvm_descriptor_ty, llvm_i64_ty, llvm_ptr_ty], [IntrArgMemOnly, NoCapture<2>]>; def int_invariant_group_barrier : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty], [IntrNoMem]>; //===------------------------ Stackmap Intrinsics -------------------------===// // def int_experimental_stackmap : Intrinsic<[], [llvm_i64_ty, llvm_i32_ty, llvm_vararg_ty], [Throws]>; def int_experimental_patchpoint_void : Intrinsic<[], [llvm_i64_ty, llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_vararg_ty], [Throws]>; def int_experimental_patchpoint_i64 : Intrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, llvm_vararg_ty], [Throws]>; //===------------------------ Garbage Collection Intrinsics ---------------===// // These are documented in docs/Statepoint.rst def int_experimental_gc_statepoint : Intrinsic<[llvm_token_ty], [llvm_i64_ty, llvm_i32_ty, llvm_anyptr_ty, llvm_i32_ty, llvm_i32_ty, llvm_vararg_ty], [Throws]>; def int_experimental_gc_result : Intrinsic<[llvm_any_ty], [llvm_token_ty], [IntrReadMem]>; def int_experimental_gc_relocate : Intrinsic<[llvm_any_ty], [llvm_token_ty, llvm_i32_ty, llvm_i32_ty], [IntrReadMem]>; //===-------------------------- Other Intrinsics --------------------------===// // def int_flt_rounds : Intrinsic<[llvm_i32_ty]>, GCCBuiltin<"__builtin_flt_rounds">; def int_trap : Intrinsic<[], [], [IntrNoReturn]>, GCCBuiltin<"__builtin_trap">; def int_debugtrap : Intrinsic<[]>, GCCBuiltin<"__builtin_debugtrap">; // Support for dynamic deoptimization (or de-specialization) 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]>; // Intrisics to support half precision floating point format let IntrProperties = [IntrNoMem] in { def int_convert_to_fp16 : Intrinsic<[llvm_i16_ty], [llvm_anyfloat_ty]>; def int_convert_from_fp16 : Intrinsic<[llvm_anyfloat_ty], [llvm_i16_ty]>; } // These convert intrinsics are to support various conversions between // various types with rounding and saturation. NOTE: avoid using these // intrinsics as they might be removed sometime in the future and // most targets don't support them. def int_convertff : Intrinsic<[llvm_anyfloat_ty], [llvm_anyfloat_ty, llvm_i32_ty, llvm_i32_ty]>; def int_convertfsi : Intrinsic<[llvm_anyfloat_ty], [llvm_anyint_ty, llvm_i32_ty, llvm_i32_ty]>; def int_convertfui : Intrinsic<[llvm_anyfloat_ty], [llvm_anyint_ty, llvm_i32_ty, llvm_i32_ty]>; def int_convertsif : Intrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty, llvm_i32_ty, llvm_i32_ty]>; def int_convertuif : Intrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty, llvm_i32_ty, llvm_i32_ty]>; def int_convertss : Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty, llvm_i32_ty, llvm_i32_ty]>; def int_convertsu : Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty, llvm_i32_ty, llvm_i32_ty]>; def int_convertus : Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty, llvm_i32_ty, llvm_i32_ty]>; def int_convertuu : Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty, llvm_i32_ty, llvm_i32_ty]>; // Clear cache intrinsic, default to ignore (ie. emit nothing) // maps to void __clear_cache() on supporting platforms def int_clear_cache : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty], [], "llvm.clear_cache">; //===-------------------------- Masked Intrinsics -------------------------===// // def int_masked_store : Intrinsic<[], [llvm_anyvector_ty, LLVMAnyPointerType>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>], [IntrArgMemOnly]>; def int_masked_load : Intrinsic<[llvm_anyvector_ty], [LLVMAnyPointerType>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>, LLVMMatchType<0>], [IntrReadMem, IntrArgMemOnly]>; def int_masked_gather: Intrinsic<[llvm_anyvector_ty], [LLVMVectorOfPointersToElt<0>, llvm_i32_ty, LLVMVectorSameWidth<0, llvm_i1_ty>, LLVMMatchType<0>], - [IntrReadMem, IntrArgMemOnly]>; + [IntrReadMem]>; def int_masked_scatter: Intrinsic<[], [llvm_anyvector_ty, LLVMVectorOfPointersToElt<0>, llvm_i32_ty, - LLVMVectorSameWidth<0, llvm_i1_ty>], - [IntrArgMemOnly]>; + LLVMVectorSameWidth<0, llvm_i1_ty>]>; // 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]>; def int_load_relative: Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_anyint_ty], [IntrReadMem, IntrArgMemOnly]>; //===----------------------------------------------------------------------===// // Target-specific intrinsics //===----------------------------------------------------------------------===// include "llvm/IR/IntrinsicsPowerPC.td" include "llvm/IR/IntrinsicsX86.td" include "llvm/IR/IntrinsicsARM.td" include "llvm/IR/IntrinsicsAArch64.td" include "llvm/IR/IntrinsicsXCore.td" include "llvm/IR/IntrinsicsHexagon.td" include "llvm/IR/IntrinsicsNVVM.td" include "llvm/IR/IntrinsicsMips.td" include "llvm/IR/IntrinsicsAMDGPU.td" include "llvm/IR/IntrinsicsBPF.td" include "llvm/IR/IntrinsicsSystemZ.td" include "llvm/IR/IntrinsicsWebAssembly.td" Index: vendor/llvm/dist/include/llvm/IR/TypeFinder.h =================================================================== --- vendor/llvm/dist/include/llvm/IR/TypeFinder.h (revision 309151) +++ vendor/llvm/dist/include/llvm/IR/TypeFinder.h (revision 309152) @@ -1,80 +1,82 @@ //===-- llvm/IR/TypeFinder.h - Class to find used struct types --*- 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 TypeFinder class. // //===----------------------------------------------------------------------===// #ifndef LLVM_IR_TYPEFINDER_H #define LLVM_IR_TYPEFINDER_H #include "llvm/ADT/DenseSet.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Type.h" #include namespace llvm { class MDNode; class Module; class StructType; class Value; /// TypeFinder - Walk over a module, identifying all of the types that are /// used by the module. class TypeFinder { // To avoid walking constant expressions multiple times and other IR // objects, we keep several helper maps. DenseSet VisitedConstants; DenseSet VisitedMetadata; DenseSet VisitedTypes; std::vector StructTypes; bool OnlyNamed; public: TypeFinder() : OnlyNamed(false) {} void run(const Module &M, bool onlyNamed); void clear(); typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; iterator begin() { return StructTypes.begin(); } iterator end() { return StructTypes.end(); } const_iterator begin() const { return StructTypes.begin(); } const_iterator end() const { return StructTypes.end(); } bool empty() const { return StructTypes.empty(); } size_t size() const { return StructTypes.size(); } iterator erase(iterator I, iterator E) { return StructTypes.erase(I, E); } StructType *&operator[](unsigned Idx) { return StructTypes[Idx]; } + DenseSet &getVisitedMetadata() { return VisitedMetadata; } + private: /// incorporateType - This method adds the type to the list of used /// structures if it's not in there already. void incorporateType(Type *Ty); /// incorporateValue - This method is used to walk operand lists finding types /// hiding in constant expressions and other operands that won't be walked in /// other ways. GlobalValues, basic blocks, instructions, and inst operands /// are all explicitly enumerated. void incorporateValue(const Value *V); /// incorporateMDNode - This method is used to walk the operands of an MDNode /// to find types hiding within. void incorporateMDNode(const MDNode *V); }; } // end llvm namespace #endif Index: vendor/llvm/dist/lib/Analysis/LoopAccessAnalysis.cpp =================================================================== --- vendor/llvm/dist/lib/Analysis/LoopAccessAnalysis.cpp (revision 309151) +++ vendor/llvm/dist/lib/Analysis/LoopAccessAnalysis.cpp (revision 309152) @@ -1,2060 +1,2086 @@ //===- LoopAccessAnalysis.cpp - Loop Access Analysis Implementation --------==// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // The implementation for the loop memory dependence that was originally // developed for the loop vectorizer. // //===----------------------------------------------------------------------===// #include "llvm/Analysis/LoopAccessAnalysis.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopPassManager.h" #include "llvm/Analysis/ScalarEvolutionExpander.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/VectorUtils.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "loop-accesses" static cl::opt VectorizationFactor("force-vector-width", cl::Hidden, cl::desc("Sets the SIMD width. Zero is autoselect."), cl::location(VectorizerParams::VectorizationFactor)); unsigned VectorizerParams::VectorizationFactor; static cl::opt VectorizationInterleave("force-vector-interleave", cl::Hidden, cl::desc("Sets the vectorization interleave count. " "Zero is autoselect."), cl::location( VectorizerParams::VectorizationInterleave)); unsigned VectorizerParams::VectorizationInterleave; static cl::opt RuntimeMemoryCheckThreshold( "runtime-memory-check-threshold", cl::Hidden, cl::desc("When performing memory disambiguation checks at runtime do not " "generate more than this number of comparisons (default = 8)."), cl::location(VectorizerParams::RuntimeMemoryCheckThreshold), cl::init(8)); unsigned VectorizerParams::RuntimeMemoryCheckThreshold; /// \brief The maximum iterations used to merge memory checks static cl::opt MemoryCheckMergeThreshold( "memory-check-merge-threshold", cl::Hidden, cl::desc("Maximum number of comparisons done when trying to merge " "runtime memory checks. (default = 100)"), cl::init(100)); /// Maximum SIMD width. const unsigned VectorizerParams::MaxVectorWidth = 64; /// \brief We collect dependences up to this threshold. static cl::opt MaxDependences("max-dependences", cl::Hidden, cl::desc("Maximum number of dependences collected by " "loop-access analysis (default = 100)"), cl::init(100)); /// This enables versioning on the strides of symbolically striding memory /// accesses in code like the following. /// for (i = 0; i < N; ++i) /// A[i * Stride1] += B[i * Stride2] ... /// /// Will be roughly translated to /// if (Stride1 == 1 && Stride2 == 1) { /// for (i = 0; i < N; i+=4) /// A[i:i+3] += ... /// } else /// ... static cl::opt EnableMemAccessVersioning( "enable-mem-access-versioning", cl::init(true), cl::Hidden, cl::desc("Enable symbolic stride memory access versioning")); /// \brief Enable store-to-load forwarding conflict detection. This option can /// be disabled for correctness testing. static cl::opt EnableForwardingConflictDetection( "store-to-load-forwarding-conflict-detection", cl::Hidden, cl::desc("Enable conflict detection in loop-access analysis"), cl::init(true)); bool VectorizerParams::isInterleaveForced() { return ::VectorizationInterleave.getNumOccurrences() > 0; } void LoopAccessReport::emitAnalysis(const LoopAccessReport &Message, const Function *TheFunction, const Loop *TheLoop, const char *PassName) { DebugLoc DL = TheLoop->getStartLoc(); if (const Instruction *I = Message.getInstr()) DL = I->getDebugLoc(); emitOptimizationRemarkAnalysis(TheFunction->getContext(), PassName, *TheFunction, DL, Message.str()); } Value *llvm::stripIntegerCast(Value *V) { if (auto *CI = dyn_cast(V)) if (CI->getOperand(0)->getType()->isIntegerTy()) return CI->getOperand(0); return V; } const SCEV *llvm::replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE, const ValueToValueMap &PtrToStride, Value *Ptr, Value *OrigPtr) { const SCEV *OrigSCEV = PSE.getSCEV(Ptr); // If there is an entry in the map return the SCEV of the pointer with the // symbolic stride replaced by one. ValueToValueMap::const_iterator SI = PtrToStride.find(OrigPtr ? OrigPtr : Ptr); if (SI != PtrToStride.end()) { Value *StrideVal = SI->second; // Strip casts. StrideVal = stripIntegerCast(StrideVal); // Replace symbolic stride by one. Value *One = ConstantInt::get(StrideVal->getType(), 1); ValueToValueMap RewriteMap; RewriteMap[StrideVal] = One; ScalarEvolution *SE = PSE.getSE(); const auto *U = cast(SE->getSCEV(StrideVal)); const auto *CT = static_cast(SE->getOne(StrideVal->getType())); PSE.addPredicate(*SE->getEqualPredicate(U, CT)); auto *Expr = PSE.getSCEV(Ptr); DEBUG(dbgs() << "LAA: Replacing SCEV: " << *OrigSCEV << " by: " << *Expr << "\n"); return Expr; } // Otherwise, just return the SCEV of the original pointer. return OrigSCEV; } +/// Calculate Start and End points of memory access. +/// Let's assume A is the first access and B is a memory access on N-th loop +/// iteration. Then B is calculated as: +/// B = A + Step*N . +/// Step value may be positive or negative. +/// N is a calculated back-edge taken count: +/// N = (TripCount > 0) ? RoundDown(TripCount -1 , VF) : 0 +/// Start and End points are calculated in the following way: +/// Start = UMIN(A, B) ; End = UMAX(A, B) + SizeOfElt, +/// where SizeOfElt is the size of single memory access in bytes. +/// +/// There is no conflict when the intervals are disjoint: +/// NoConflict = (P2.Start >= P1.End) || (P1.Start >= P2.End) void RuntimePointerChecking::insert(Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId, unsigned ASId, const ValueToValueMap &Strides, PredicatedScalarEvolution &PSE) { // Get the stride replaced scev. const SCEV *Sc = replaceSymbolicStrideSCEV(PSE, Strides, Ptr); ScalarEvolution *SE = PSE.getSE(); const SCEV *ScStart; const SCEV *ScEnd; if (SE->isLoopInvariant(Sc, Lp)) ScStart = ScEnd = Sc; else { const SCEVAddRecExpr *AR = dyn_cast(Sc); assert(AR && "Invalid addrec expression"); const SCEV *Ex = PSE.getBackedgeTakenCount(); ScStart = AR->getStart(); ScEnd = AR->evaluateAtIteration(Ex, *SE); const SCEV *Step = AR->getStepRecurrence(*SE); // For expressions with negative step, the upper bound is ScStart and the // lower bound is ScEnd. if (const auto *CStep = dyn_cast(Step)) { if (CStep->getValue()->isNegative()) std::swap(ScStart, ScEnd); } else { - // Fallback case: the step is not constant, but the we can still + // Fallback case: the step is not constant, but we can still // get the upper and lower bounds of the interval by using min/max // expressions. ScStart = SE->getUMinExpr(ScStart, ScEnd); ScEnd = SE->getUMaxExpr(AR->getStart(), ScEnd); } + // Add the size of the pointed element to ScEnd. + unsigned EltSize = + Ptr->getType()->getPointerElementType()->getScalarSizeInBits() / 8; + const SCEV *EltSizeSCEV = SE->getConstant(ScEnd->getType(), EltSize); + ScEnd = SE->getAddExpr(ScEnd, EltSizeSCEV); } Pointers.emplace_back(Ptr, ScStart, ScEnd, WritePtr, DepSetId, ASId, Sc); } SmallVector RuntimePointerChecking::generateChecks() const { SmallVector Checks; for (unsigned I = 0; I < CheckingGroups.size(); ++I) { for (unsigned J = I + 1; J < CheckingGroups.size(); ++J) { const RuntimePointerChecking::CheckingPtrGroup &CGI = CheckingGroups[I]; const RuntimePointerChecking::CheckingPtrGroup &CGJ = CheckingGroups[J]; if (needsChecking(CGI, CGJ)) Checks.push_back(std::make_pair(&CGI, &CGJ)); } } return Checks; } void RuntimePointerChecking::generateChecks( MemoryDepChecker::DepCandidates &DepCands, bool UseDependencies) { assert(Checks.empty() && "Checks is not empty"); groupChecks(DepCands, UseDependencies); Checks = generateChecks(); } bool RuntimePointerChecking::needsChecking(const CheckingPtrGroup &M, const CheckingPtrGroup &N) const { for (unsigned I = 0, EI = M.Members.size(); EI != I; ++I) for (unsigned J = 0, EJ = N.Members.size(); EJ != J; ++J) if (needsChecking(M.Members[I], N.Members[J])) return true; return false; } /// Compare \p I and \p J and return the minimum. /// Return nullptr in case we couldn't find an answer. static const SCEV *getMinFromExprs(const SCEV *I, const SCEV *J, ScalarEvolution *SE) { const SCEV *Diff = SE->getMinusSCEV(J, I); const SCEVConstant *C = dyn_cast(Diff); if (!C) return nullptr; if (C->getValue()->isNegative()) return J; return I; } bool RuntimePointerChecking::CheckingPtrGroup::addPointer(unsigned Index) { const SCEV *Start = RtCheck.Pointers[Index].Start; const SCEV *End = RtCheck.Pointers[Index].End; // Compare the starts and ends with the known minimum and maximum // of this set. We need to know how we compare against the min/max // of the set in order to be able to emit memchecks. const SCEV *Min0 = getMinFromExprs(Start, Low, RtCheck.SE); if (!Min0) return false; const SCEV *Min1 = getMinFromExprs(End, High, RtCheck.SE); if (!Min1) return false; // Update the low bound expression if we've found a new min value. if (Min0 == Start) Low = Start; // Update the high bound expression if we've found a new max value. if (Min1 != End) High = End; Members.push_back(Index); return true; } void RuntimePointerChecking::groupChecks( MemoryDepChecker::DepCandidates &DepCands, bool UseDependencies) { // We build the groups from dependency candidates equivalence classes // because: // - We know that pointers in the same equivalence class share // the same underlying object and therefore there is a chance // that we can compare pointers // - We wouldn't be able to merge two pointers for which we need // to emit a memcheck. The classes in DepCands are already // conveniently built such that no two pointers in the same // class need checking against each other. // We use the following (greedy) algorithm to construct the groups // For every pointer in the equivalence class: // For each existing group: // - if the difference between this pointer and the min/max bounds // of the group is a constant, then make the pointer part of the // group and update the min/max bounds of that group as required. CheckingGroups.clear(); // If we need to check two pointers to the same underlying object // with a non-constant difference, we shouldn't perform any pointer // grouping with those pointers. This is because we can easily get // into cases where the resulting check would return false, even when // the accesses are safe. // // The following example shows this: // for (i = 0; i < 1000; ++i) // a[5000 + i * m] = a[i] + a[i + 9000] // // Here grouping gives a check of (5000, 5000 + 1000 * m) against // (0, 10000) which is always false. However, if m is 1, there is no // dependence. Not grouping the checks for a[i] and a[i + 9000] allows // us to perform an accurate check in this case. // // The above case requires that we have an UnknownDependence between // accesses to the same underlying object. This cannot happen unless // ShouldRetryWithRuntimeCheck is set, and therefore UseDependencies // is also false. In this case we will use the fallback path and create // separate checking groups for all pointers. // If we don't have the dependency partitions, construct a new // checking pointer group for each pointer. This is also required // for correctness, because in this case we can have checking between // pointers to the same underlying object. if (!UseDependencies) { for (unsigned I = 0; I < Pointers.size(); ++I) CheckingGroups.push_back(CheckingPtrGroup(I, *this)); return; } unsigned TotalComparisons = 0; DenseMap PositionMap; for (unsigned Index = 0; Index < Pointers.size(); ++Index) PositionMap[Pointers[Index].PointerValue] = Index; // We need to keep track of what pointers we've already seen so we // don't process them twice. SmallSet Seen; // Go through all equivalence classes, get the "pointer check groups" // and add them to the overall solution. We use the order in which accesses // appear in 'Pointers' to enforce determinism. for (unsigned I = 0; I < Pointers.size(); ++I) { // We've seen this pointer before, and therefore already processed // its equivalence class. if (Seen.count(I)) continue; MemoryDepChecker::MemAccessInfo Access(Pointers[I].PointerValue, Pointers[I].IsWritePtr); SmallVector Groups; auto LeaderI = DepCands.findValue(DepCands.getLeaderValue(Access)); // Because DepCands is constructed by visiting accesses in the order in // which they appear in alias sets (which is deterministic) and the // iteration order within an equivalence class member is only dependent on // the order in which unions and insertions are performed on the // equivalence class, the iteration order is deterministic. for (auto MI = DepCands.member_begin(LeaderI), ME = DepCands.member_end(); MI != ME; ++MI) { unsigned Pointer = PositionMap[MI->getPointer()]; bool Merged = false; // Mark this pointer as seen. Seen.insert(Pointer); // Go through all the existing sets and see if we can find one // which can include this pointer. for (CheckingPtrGroup &Group : Groups) { // Don't perform more than a certain amount of comparisons. // This should limit the cost of grouping the pointers to something // reasonable. If we do end up hitting this threshold, the algorithm // will create separate groups for all remaining pointers. if (TotalComparisons > MemoryCheckMergeThreshold) break; TotalComparisons++; if (Group.addPointer(Pointer)) { Merged = true; break; } } if (!Merged) // We couldn't add this pointer to any existing set or the threshold // for the number of comparisons has been reached. Create a new group // to hold the current pointer. Groups.push_back(CheckingPtrGroup(Pointer, *this)); } // We've computed the grouped checks for this partition. // Save the results and continue with the next one. std::copy(Groups.begin(), Groups.end(), std::back_inserter(CheckingGroups)); } } bool RuntimePointerChecking::arePointersInSamePartition( const SmallVectorImpl &PtrToPartition, unsigned PtrIdx1, unsigned PtrIdx2) { return (PtrToPartition[PtrIdx1] != -1 && PtrToPartition[PtrIdx1] == PtrToPartition[PtrIdx2]); } bool RuntimePointerChecking::needsChecking(unsigned I, unsigned J) const { const PointerInfo &PointerI = Pointers[I]; const PointerInfo &PointerJ = Pointers[J]; // No need to check if two readonly pointers intersect. if (!PointerI.IsWritePtr && !PointerJ.IsWritePtr) return false; // Only need to check pointers between two different dependency sets. if (PointerI.DependencySetId == PointerJ.DependencySetId) return false; // Only need to check pointers in the same alias set. if (PointerI.AliasSetId != PointerJ.AliasSetId) return false; return true; } void RuntimePointerChecking::printChecks( raw_ostream &OS, const SmallVectorImpl &Checks, unsigned Depth) const { unsigned N = 0; for (const auto &Check : Checks) { const auto &First = Check.first->Members, &Second = Check.second->Members; OS.indent(Depth) << "Check " << N++ << ":\n"; OS.indent(Depth + 2) << "Comparing group (" << Check.first << "):\n"; for (unsigned K = 0; K < First.size(); ++K) OS.indent(Depth + 2) << *Pointers[First[K]].PointerValue << "\n"; OS.indent(Depth + 2) << "Against group (" << Check.second << "):\n"; for (unsigned K = 0; K < Second.size(); ++K) OS.indent(Depth + 2) << *Pointers[Second[K]].PointerValue << "\n"; } } void RuntimePointerChecking::print(raw_ostream &OS, unsigned Depth) const { OS.indent(Depth) << "Run-time memory checks:\n"; printChecks(OS, Checks, Depth); OS.indent(Depth) << "Grouped accesses:\n"; for (unsigned I = 0; I < CheckingGroups.size(); ++I) { const auto &CG = CheckingGroups[I]; OS.indent(Depth + 2) << "Group " << &CG << ":\n"; OS.indent(Depth + 4) << "(Low: " << *CG.Low << " High: " << *CG.High << ")\n"; for (unsigned J = 0; J < CG.Members.size(); ++J) { OS.indent(Depth + 6) << "Member: " << *Pointers[CG.Members[J]].Expr << "\n"; } } } namespace { /// \brief Analyses memory accesses in a loop. /// /// Checks whether run time pointer checks are needed and builds sets for data /// dependence checking. class AccessAnalysis { public: /// \brief Read or write access location. typedef PointerIntPair MemAccessInfo; typedef SmallPtrSet MemAccessInfoSet; AccessAnalysis(const DataLayout &Dl, AliasAnalysis *AA, LoopInfo *LI, MemoryDepChecker::DepCandidates &DA, PredicatedScalarEvolution &PSE) : DL(Dl), AST(*AA), LI(LI), DepCands(DA), IsRTCheckAnalysisNeeded(false), PSE(PSE) {} /// \brief Register a load and whether it is only read from. void addLoad(MemoryLocation &Loc, bool IsReadOnly) { Value *Ptr = const_cast(Loc.Ptr); AST.add(Ptr, MemoryLocation::UnknownSize, Loc.AATags); Accesses.insert(MemAccessInfo(Ptr, false)); if (IsReadOnly) ReadOnlyPtr.insert(Ptr); } /// \brief Register a store. void addStore(MemoryLocation &Loc) { Value *Ptr = const_cast(Loc.Ptr); AST.add(Ptr, MemoryLocation::UnknownSize, Loc.AATags); Accesses.insert(MemAccessInfo(Ptr, true)); } /// \brief Check whether we can check the pointers at runtime for /// non-intersection. /// /// Returns true if we need no check or if we do and we can generate them /// (i.e. the pointers have computable bounds). bool canCheckPtrAtRT(RuntimePointerChecking &RtCheck, ScalarEvolution *SE, Loop *TheLoop, const ValueToValueMap &Strides, bool ShouldCheckWrap = false); /// \brief Goes over all memory accesses, checks whether a RT check is needed /// and builds sets of dependent accesses. void buildDependenceSets() { processMemAccesses(); } /// \brief Initial processing of memory accesses determined that we need to /// perform dependency checking. /// /// Note that this can later be cleared if we retry memcheck analysis without /// dependency checking (i.e. ShouldRetryWithRuntimeCheck). bool isDependencyCheckNeeded() { return !CheckDeps.empty(); } /// We decided that no dependence analysis would be used. Reset the state. void resetDepChecks(MemoryDepChecker &DepChecker) { CheckDeps.clear(); DepChecker.clearDependences(); } MemAccessInfoSet &getDependenciesToCheck() { return CheckDeps; } private: typedef SetVector PtrAccessSet; /// \brief Go over all memory access and check whether runtime pointer checks /// are needed and build sets of dependency check candidates. void processMemAccesses(); /// Set of all accesses. PtrAccessSet Accesses; const DataLayout &DL; /// Set of accesses that need a further dependence check. MemAccessInfoSet CheckDeps; /// Set of pointers that are read only. SmallPtrSet ReadOnlyPtr; /// An alias set tracker to partition the access set by underlying object and //intrinsic property (such as TBAA metadata). AliasSetTracker AST; LoopInfo *LI; /// Sets of potentially dependent accesses - members of one set share an /// underlying pointer. The set "CheckDeps" identfies which sets really need a /// dependence check. MemoryDepChecker::DepCandidates &DepCands; /// \brief Initial processing of memory accesses determined that we may need /// to add memchecks. Perform the analysis to determine the necessary checks. /// /// Note that, this is different from isDependencyCheckNeeded. When we retry /// memcheck analysis without dependency checking /// (i.e. ShouldRetryWithRuntimeCheck), isDependencyCheckNeeded is cleared /// while this remains set if we have potentially dependent accesses. bool IsRTCheckAnalysisNeeded; /// The SCEV predicate containing all the SCEV-related assumptions. PredicatedScalarEvolution &PSE; }; } // end anonymous namespace /// \brief Check whether a pointer can participate in a runtime bounds check. static bool hasComputableBounds(PredicatedScalarEvolution &PSE, const ValueToValueMap &Strides, Value *Ptr, Loop *L) { const SCEV *PtrScev = replaceSymbolicStrideSCEV(PSE, Strides, Ptr); // The bounds for loop-invariant pointer is trivial. if (PSE.getSE()->isLoopInvariant(PtrScev, L)) return true; const SCEVAddRecExpr *AR = dyn_cast(PtrScev); if (!AR) return false; return AR->isAffine(); } /// \brief Check whether a pointer address cannot wrap. static bool isNoWrap(PredicatedScalarEvolution &PSE, const ValueToValueMap &Strides, Value *Ptr, Loop *L) { const SCEV *PtrScev = PSE.getSCEV(Ptr); if (PSE.getSE()->isLoopInvariant(PtrScev, L)) return true; int64_t Stride = getPtrStride(PSE, Ptr, L, Strides); return Stride == 1; } bool AccessAnalysis::canCheckPtrAtRT(RuntimePointerChecking &RtCheck, ScalarEvolution *SE, Loop *TheLoop, const ValueToValueMap &StridesMap, bool ShouldCheckWrap) { // Find pointers with computable bounds. We are going to use this information // to place a runtime bound check. bool CanDoRT = true; bool NeedRTCheck = false; if (!IsRTCheckAnalysisNeeded) return true; bool IsDepCheckNeeded = isDependencyCheckNeeded(); // We assign a consecutive id to access from different alias sets. // Accesses between different groups doesn't need to be checked. unsigned ASId = 1; for (auto &AS : AST) { int NumReadPtrChecks = 0; int NumWritePtrChecks = 0; // We assign consecutive id to access from different dependence sets. // Accesses within the same set don't need a runtime check. unsigned RunningDepId = 1; DenseMap DepSetId; for (auto A : AS) { Value *Ptr = A.getValue(); bool IsWrite = Accesses.count(MemAccessInfo(Ptr, true)); MemAccessInfo Access(Ptr, IsWrite); if (IsWrite) ++NumWritePtrChecks; else ++NumReadPtrChecks; if (hasComputableBounds(PSE, StridesMap, Ptr, TheLoop) && // When we run after a failing dependency check we have to make sure // we don't have wrapping pointers. (!ShouldCheckWrap || isNoWrap(PSE, StridesMap, Ptr, TheLoop))) { // The id of the dependence set. unsigned DepId; if (IsDepCheckNeeded) { Value *Leader = DepCands.getLeaderValue(Access).getPointer(); unsigned &LeaderId = DepSetId[Leader]; if (!LeaderId) LeaderId = RunningDepId++; DepId = LeaderId; } else // Each access has its own dependence set. DepId = RunningDepId++; RtCheck.insert(TheLoop, Ptr, IsWrite, DepId, ASId, StridesMap, PSE); DEBUG(dbgs() << "LAA: Found a runtime check ptr:" << *Ptr << '\n'); } else { DEBUG(dbgs() << "LAA: Can't find bounds for ptr:" << *Ptr << '\n'); CanDoRT = false; } } // If we have at least two writes or one write and a read then we need to // check them. But there is no need to checks if there is only one // dependence set for this alias set. // // Note that this function computes CanDoRT and NeedRTCheck independently. // For example CanDoRT=false, NeedRTCheck=false means that we have a pointer // for which we couldn't find the bounds but we don't actually need to emit // any checks so it does not matter. if (!(IsDepCheckNeeded && CanDoRT && RunningDepId == 2)) NeedRTCheck |= (NumWritePtrChecks >= 2 || (NumReadPtrChecks >= 1 && NumWritePtrChecks >= 1)); ++ASId; } // If the pointers that we would use for the bounds comparison have different // address spaces, assume the values aren't directly comparable, so we can't // use them for the runtime check. We also have to assume they could // overlap. In the future there should be metadata for whether address spaces // are disjoint. unsigned NumPointers = RtCheck.Pointers.size(); for (unsigned i = 0; i < NumPointers; ++i) { for (unsigned j = i + 1; j < NumPointers; ++j) { // Only need to check pointers between two different dependency sets. if (RtCheck.Pointers[i].DependencySetId == RtCheck.Pointers[j].DependencySetId) continue; // Only need to check pointers in the same alias set. if (RtCheck.Pointers[i].AliasSetId != RtCheck.Pointers[j].AliasSetId) continue; Value *PtrI = RtCheck.Pointers[i].PointerValue; Value *PtrJ = RtCheck.Pointers[j].PointerValue; unsigned ASi = PtrI->getType()->getPointerAddressSpace(); unsigned ASj = PtrJ->getType()->getPointerAddressSpace(); if (ASi != ASj) { DEBUG(dbgs() << "LAA: Runtime check would require comparison between" " different address spaces\n"); return false; } } } if (NeedRTCheck && CanDoRT) RtCheck.generateChecks(DepCands, IsDepCheckNeeded); DEBUG(dbgs() << "LAA: We need to do " << RtCheck.getNumberOfChecks() << " pointer comparisons.\n"); RtCheck.Need = NeedRTCheck; bool CanDoRTIfNeeded = !NeedRTCheck || CanDoRT; if (!CanDoRTIfNeeded) RtCheck.reset(); return CanDoRTIfNeeded; } void AccessAnalysis::processMemAccesses() { // We process the set twice: first we process read-write pointers, last we // process read-only pointers. This allows us to skip dependence tests for // read-only pointers. DEBUG(dbgs() << "LAA: Processing memory accesses...\n"); DEBUG(dbgs() << " AST: "; AST.dump()); DEBUG(dbgs() << "LAA: Accesses(" << Accesses.size() << "):\n"); DEBUG({ for (auto A : Accesses) dbgs() << "\t" << *A.getPointer() << " (" << (A.getInt() ? "write" : (ReadOnlyPtr.count(A.getPointer()) ? "read-only" : "read")) << ")\n"; }); // The AliasSetTracker has nicely partitioned our pointers by metadata // compatibility and potential for underlying-object overlap. As a result, we // only need to check for potential pointer dependencies within each alias // set. for (auto &AS : AST) { // Note that both the alias-set tracker and the alias sets themselves used // linked lists internally and so the iteration order here is deterministic // (matching the original instruction order within each set). bool SetHasWrite = false; // Map of pointers to last access encountered. typedef DenseMap UnderlyingObjToAccessMap; UnderlyingObjToAccessMap ObjToLastAccess; // Set of access to check after all writes have been processed. PtrAccessSet DeferredAccesses; // Iterate over each alias set twice, once to process read/write pointers, // and then to process read-only pointers. for (int SetIteration = 0; SetIteration < 2; ++SetIteration) { bool UseDeferred = SetIteration > 0; PtrAccessSet &S = UseDeferred ? DeferredAccesses : Accesses; for (auto AV : AS) { Value *Ptr = AV.getValue(); // For a single memory access in AliasSetTracker, Accesses may contain // both read and write, and they both need to be handled for CheckDeps. for (auto AC : S) { if (AC.getPointer() != Ptr) continue; bool IsWrite = AC.getInt(); // If we're using the deferred access set, then it contains only // reads. bool IsReadOnlyPtr = ReadOnlyPtr.count(Ptr) && !IsWrite; if (UseDeferred && !IsReadOnlyPtr) continue; // Otherwise, the pointer must be in the PtrAccessSet, either as a // read or a write. assert(((IsReadOnlyPtr && UseDeferred) || IsWrite || S.count(MemAccessInfo(Ptr, false))) && "Alias-set pointer not in the access set?"); MemAccessInfo Access(Ptr, IsWrite); DepCands.insert(Access); // Memorize read-only pointers for later processing and skip them in // the first round (they need to be checked after we have seen all // write pointers). Note: we also mark pointer that are not // consecutive as "read-only" pointers (so that we check // "a[b[i]] +="). Hence, we need the second check for "!IsWrite". if (!UseDeferred && IsReadOnlyPtr) { DeferredAccesses.insert(Access); continue; } // If this is a write - check other reads and writes for conflicts. If // this is a read only check other writes for conflicts (but only if // there is no other write to the ptr - this is an optimization to // catch "a[i] = a[i] + " without having to do a dependence check). if ((IsWrite || IsReadOnlyPtr) && SetHasWrite) { CheckDeps.insert(Access); IsRTCheckAnalysisNeeded = true; } if (IsWrite) SetHasWrite = true; // Create sets of pointers connected by a shared alias set and // underlying object. typedef SmallVector ValueVector; ValueVector TempObjects; GetUnderlyingObjects(Ptr, TempObjects, DL, LI); DEBUG(dbgs() << "Underlying objects for pointer " << *Ptr << "\n"); for (Value *UnderlyingObj : TempObjects) { // nullptr never alias, don't join sets for pointer that have "null" // in their UnderlyingObjects list. if (isa(UnderlyingObj)) continue; UnderlyingObjToAccessMap::iterator Prev = ObjToLastAccess.find(UnderlyingObj); if (Prev != ObjToLastAccess.end()) DepCands.unionSets(Access, Prev->second); ObjToLastAccess[UnderlyingObj] = Access; DEBUG(dbgs() << " " << *UnderlyingObj << "\n"); } } } } } } static bool isInBoundsGep(Value *Ptr) { if (GetElementPtrInst *GEP = dyn_cast(Ptr)) return GEP->isInBounds(); return false; } /// \brief Return true if an AddRec pointer \p Ptr is unsigned non-wrapping, /// i.e. monotonically increasing/decreasing. static bool isNoWrapAddRec(Value *Ptr, const SCEVAddRecExpr *AR, PredicatedScalarEvolution &PSE, const Loop *L) { // FIXME: This should probably only return true for NUW. if (AR->getNoWrapFlags(SCEV::NoWrapMask)) return true; // Scalar evolution does not propagate the non-wrapping flags to values that // are derived from a non-wrapping induction variable because non-wrapping // could be flow-sensitive. // // Look through the potentially overflowing instruction to try to prove // non-wrapping for the *specific* value of Ptr. // The arithmetic implied by an inbounds GEP can't overflow. auto *GEP = dyn_cast(Ptr); if (!GEP || !GEP->isInBounds()) return false; // Make sure there is only one non-const index and analyze that. Value *NonConstIndex = nullptr; for (Value *Index : make_range(GEP->idx_begin(), GEP->idx_end())) if (!isa(Index)) { if (NonConstIndex) return false; NonConstIndex = Index; } if (!NonConstIndex) // The recurrence is on the pointer, ignore for now. return false; // The index in GEP is signed. It is non-wrapping if it's derived from a NSW // AddRec using a NSW operation. if (auto *OBO = dyn_cast(NonConstIndex)) if (OBO->hasNoSignedWrap() && // Assume constant for other the operand so that the AddRec can be // easily found. isa(OBO->getOperand(1))) { auto *OpScev = PSE.getSCEV(OBO->getOperand(0)); if (auto *OpAR = dyn_cast(OpScev)) return OpAR->getLoop() == L && OpAR->getNoWrapFlags(SCEV::FlagNSW); } return false; } /// \brief Check whether the access through \p Ptr has a constant stride. int64_t llvm::getPtrStride(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp, const ValueToValueMap &StridesMap, bool Assume) { Type *Ty = Ptr->getType(); assert(Ty->isPointerTy() && "Unexpected non-ptr"); // Make sure that the pointer does not point to aggregate types. auto *PtrTy = cast(Ty); if (PtrTy->getElementType()->isAggregateType()) { DEBUG(dbgs() << "LAA: Bad stride - Not a pointer to a scalar type" << *Ptr << "\n"); return 0; } const SCEV *PtrScev = replaceSymbolicStrideSCEV(PSE, StridesMap, Ptr); const SCEVAddRecExpr *AR = dyn_cast(PtrScev); if (Assume && !AR) AR = PSE.getAsAddRec(Ptr); if (!AR) { DEBUG(dbgs() << "LAA: Bad stride - Not an AddRecExpr pointer " << *Ptr << " SCEV: " << *PtrScev << "\n"); return 0; } // The accesss function must stride over the innermost loop. if (Lp != AR->getLoop()) { DEBUG(dbgs() << "LAA: Bad stride - Not striding over innermost loop " << *Ptr << " SCEV: " << *AR << "\n"); return 0; } // The address calculation must not wrap. Otherwise, a dependence could be // inverted. // An inbounds getelementptr that is a AddRec with a unit stride // cannot wrap per definition. The unit stride requirement is checked later. // An getelementptr without an inbounds attribute and unit stride would have // to access the pointer value "0" which is undefined behavior in address // space 0, therefore we can also vectorize this case. bool IsInBoundsGEP = isInBoundsGep(Ptr); bool IsNoWrapAddRec = PSE.hasNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW) || isNoWrapAddRec(Ptr, AR, PSE, Lp); bool IsInAddressSpaceZero = PtrTy->getAddressSpace() == 0; if (!IsNoWrapAddRec && !IsInBoundsGEP && !IsInAddressSpaceZero) { if (Assume) { PSE.setNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW); IsNoWrapAddRec = true; DEBUG(dbgs() << "LAA: Pointer may wrap in the address space:\n" << "LAA: Pointer: " << *Ptr << "\n" << "LAA: SCEV: " << *AR << "\n" << "LAA: Added an overflow assumption\n"); } else { DEBUG(dbgs() << "LAA: Bad stride - Pointer may wrap in the address space " << *Ptr << " SCEV: " << *AR << "\n"); return 0; } } // Check the step is constant. const SCEV *Step = AR->getStepRecurrence(*PSE.getSE()); // Calculate the pointer stride and check if it is constant. const SCEVConstant *C = dyn_cast(Step); if (!C) { DEBUG(dbgs() << "LAA: Bad stride - Not a constant strided " << *Ptr << " SCEV: " << *AR << "\n"); return 0; } auto &DL = Lp->getHeader()->getModule()->getDataLayout(); int64_t Size = DL.getTypeAllocSize(PtrTy->getElementType()); const APInt &APStepVal = C->getAPInt(); // Huge step value - give up. if (APStepVal.getBitWidth() > 64) return 0; int64_t StepVal = APStepVal.getSExtValue(); // Strided access. int64_t Stride = StepVal / Size; int64_t Rem = StepVal % Size; if (Rem) return 0; // If the SCEV could wrap but we have an inbounds gep with a unit stride we // know we can't "wrap around the address space". In case of address space // zero we know that this won't happen without triggering undefined behavior. if (!IsNoWrapAddRec && (IsInBoundsGEP || IsInAddressSpaceZero) && Stride != 1 && Stride != -1) { if (Assume) { // We can avoid this case by adding a run-time check. DEBUG(dbgs() << "LAA: Non unit strided pointer which is not either " << "inbouds or in address space 0 may wrap:\n" << "LAA: Pointer: " << *Ptr << "\n" << "LAA: SCEV: " << *AR << "\n" << "LAA: Added an overflow assumption\n"); PSE.setNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW); } else return 0; } return Stride; } /// Take the pointer operand from the Load/Store instruction. /// Returns NULL if this is not a valid Load/Store instruction. static Value *getPointerOperand(Value *I) { if (auto *LI = dyn_cast(I)) return LI->getPointerOperand(); if (auto *SI = dyn_cast(I)) return SI->getPointerOperand(); return nullptr; } /// Take the address space operand from the Load/Store instruction. /// Returns -1 if this is not a valid Load/Store instruction. static unsigned getAddressSpaceOperand(Value *I) { if (LoadInst *L = dyn_cast(I)) return L->getPointerAddressSpace(); if (StoreInst *S = dyn_cast(I)) return S->getPointerAddressSpace(); return -1; } /// Returns true if the memory operations \p A and \p B are consecutive. bool llvm::isConsecutiveAccess(Value *A, Value *B, const DataLayout &DL, ScalarEvolution &SE, bool CheckType) { Value *PtrA = getPointerOperand(A); Value *PtrB = getPointerOperand(B); unsigned ASA = getAddressSpaceOperand(A); unsigned ASB = getAddressSpaceOperand(B); // Check that the address spaces match and that the pointers are valid. if (!PtrA || !PtrB || (ASA != ASB)) return false; // Make sure that A and B are different pointers. if (PtrA == PtrB) return false; // Make sure that A and B have the same type if required. if(CheckType && PtrA->getType() != PtrB->getType()) return false; unsigned PtrBitWidth = DL.getPointerSizeInBits(ASA); Type *Ty = cast(PtrA->getType())->getElementType(); APInt Size(PtrBitWidth, DL.getTypeStoreSize(Ty)); APInt OffsetA(PtrBitWidth, 0), OffsetB(PtrBitWidth, 0); PtrA = PtrA->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetA); PtrB = PtrB->stripAndAccumulateInBoundsConstantOffsets(DL, OffsetB); // OffsetDelta = OffsetB - OffsetA; const SCEV *OffsetSCEVA = SE.getConstant(OffsetA); const SCEV *OffsetSCEVB = SE.getConstant(OffsetB); const SCEV *OffsetDeltaSCEV = SE.getMinusSCEV(OffsetSCEVB, OffsetSCEVA); const SCEVConstant *OffsetDeltaC = dyn_cast(OffsetDeltaSCEV); const APInt &OffsetDelta = OffsetDeltaC->getAPInt(); // Check if they are based on the same pointer. That makes the offsets // sufficient. if (PtrA == PtrB) return OffsetDelta == Size; // Compute the necessary base pointer delta to have the necessary final delta // equal to the size. // BaseDelta = Size - OffsetDelta; const SCEV *SizeSCEV = SE.getConstant(Size); const SCEV *BaseDelta = SE.getMinusSCEV(SizeSCEV, OffsetDeltaSCEV); // Otherwise compute the distance with SCEV between the base pointers. const SCEV *PtrSCEVA = SE.getSCEV(PtrA); const SCEV *PtrSCEVB = SE.getSCEV(PtrB); const SCEV *X = SE.getAddExpr(PtrSCEVA, BaseDelta); return X == PtrSCEVB; } bool MemoryDepChecker::Dependence::isSafeForVectorization(DepType Type) { switch (Type) { case NoDep: case Forward: case BackwardVectorizable: return true; case Unknown: case ForwardButPreventsForwarding: case Backward: case BackwardVectorizableButPreventsForwarding: return false; } llvm_unreachable("unexpected DepType!"); } bool MemoryDepChecker::Dependence::isBackward() const { switch (Type) { case NoDep: case Forward: case ForwardButPreventsForwarding: case Unknown: return false; case BackwardVectorizable: case Backward: case BackwardVectorizableButPreventsForwarding: return true; } llvm_unreachable("unexpected DepType!"); } bool MemoryDepChecker::Dependence::isPossiblyBackward() const { return isBackward() || Type == Unknown; } bool MemoryDepChecker::Dependence::isForward() const { switch (Type) { case Forward: case ForwardButPreventsForwarding: return true; case NoDep: case Unknown: case BackwardVectorizable: case Backward: case BackwardVectorizableButPreventsForwarding: return false; } llvm_unreachable("unexpected DepType!"); } bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance, uint64_t TypeByteSize) { // If loads occur at a distance that is not a multiple of a feasible vector // factor store-load forwarding does not take place. // Positive dependences might cause troubles because vectorizing them might // prevent store-load forwarding making vectorized code run a lot slower. // a[i] = a[i-3] ^ a[i-8]; // The stores to a[i:i+1] don't align with the stores to a[i-3:i-2] and // hence on your typical architecture store-load forwarding does not take // place. Vectorizing in such cases does not make sense. // Store-load forwarding distance. // After this many iterations store-to-load forwarding conflicts should not // cause any slowdowns. const uint64_t NumItersForStoreLoadThroughMemory = 8 * TypeByteSize; // Maximum vector factor. uint64_t MaxVFWithoutSLForwardIssues = std::min( VectorizerParams::MaxVectorWidth * TypeByteSize, MaxSafeDepDistBytes); // Compute the smallest VF at which the store and load would be misaligned. for (uint64_t VF = 2 * TypeByteSize; VF <= MaxVFWithoutSLForwardIssues; VF *= 2) { // If the number of vector iteration between the store and the load are // small we could incur conflicts. if (Distance % VF && Distance / VF < NumItersForStoreLoadThroughMemory) { MaxVFWithoutSLForwardIssues = (VF >>= 1); break; } } if (MaxVFWithoutSLForwardIssues < 2 * TypeByteSize) { DEBUG(dbgs() << "LAA: Distance " << Distance << " that could cause a store-load forwarding conflict\n"); return true; } if (MaxVFWithoutSLForwardIssues < MaxSafeDepDistBytes && MaxVFWithoutSLForwardIssues != VectorizerParams::MaxVectorWidth * TypeByteSize) MaxSafeDepDistBytes = MaxVFWithoutSLForwardIssues; return false; } /// \brief Check the dependence for two accesses with the same stride \p Stride. /// \p Distance is the positive distance and \p TypeByteSize is type size in /// bytes. /// /// \returns true if they are independent. static bool areStridedAccessesIndependent(uint64_t Distance, uint64_t Stride, uint64_t TypeByteSize) { assert(Stride > 1 && "The stride must be greater than 1"); assert(TypeByteSize > 0 && "The type size in byte must be non-zero"); assert(Distance > 0 && "The distance must be non-zero"); // Skip if the distance is not multiple of type byte size. if (Distance % TypeByteSize) return false; uint64_t ScaledDist = Distance / TypeByteSize; // No dependence if the scaled distance is not multiple of the stride. // E.g. // for (i = 0; i < 1024 ; i += 4) // A[i+2] = A[i] + 1; // // Two accesses in memory (scaled distance is 2, stride is 4): // | A[0] | | | | A[4] | | | | // | | | A[2] | | | | A[6] | | // // E.g. // for (i = 0; i < 1024 ; i += 3) // A[i+4] = A[i] + 1; // // Two accesses in memory (scaled distance is 4, stride is 3): // | A[0] | | | A[3] | | | A[6] | | | // | | | | | A[4] | | | A[7] | | return ScaledDist % Stride; } MemoryDepChecker::Dependence::DepType MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx, const MemAccessInfo &B, unsigned BIdx, const ValueToValueMap &Strides) { assert (AIdx < BIdx && "Must pass arguments in program order"); Value *APtr = A.getPointer(); Value *BPtr = B.getPointer(); bool AIsWrite = A.getInt(); bool BIsWrite = B.getInt(); // Two reads are independent. if (!AIsWrite && !BIsWrite) return Dependence::NoDep; // We cannot check pointers in different address spaces. if (APtr->getType()->getPointerAddressSpace() != BPtr->getType()->getPointerAddressSpace()) return Dependence::Unknown; int64_t StrideAPtr = getPtrStride(PSE, APtr, InnermostLoop, Strides, true); int64_t StrideBPtr = getPtrStride(PSE, BPtr, InnermostLoop, Strides, true); const SCEV *Src = PSE.getSCEV(APtr); const SCEV *Sink = PSE.getSCEV(BPtr); // If the induction step is negative we have to invert source and sink of the // dependence. if (StrideAPtr < 0) { std::swap(APtr, BPtr); std::swap(Src, Sink); std::swap(AIsWrite, BIsWrite); std::swap(AIdx, BIdx); std::swap(StrideAPtr, StrideBPtr); } const SCEV *Dist = PSE.getSE()->getMinusSCEV(Sink, Src); DEBUG(dbgs() << "LAA: Src Scev: " << *Src << "Sink Scev: " << *Sink << "(Induction step: " << StrideAPtr << ")\n"); DEBUG(dbgs() << "LAA: Distance for " << *InstMap[AIdx] << " to " << *InstMap[BIdx] << ": " << *Dist << "\n"); // Need accesses with constant stride. We don't want to vectorize // "A[B[i]] += ..." and similar code or pointer arithmetic that could wrap in // the address space. if (!StrideAPtr || !StrideBPtr || StrideAPtr != StrideBPtr){ DEBUG(dbgs() << "Pointer access with non-constant stride\n"); return Dependence::Unknown; } const SCEVConstant *C = dyn_cast(Dist); if (!C) { DEBUG(dbgs() << "LAA: Dependence because of non-constant distance\n"); ShouldRetryWithRuntimeCheck = true; return Dependence::Unknown; } Type *ATy = APtr->getType()->getPointerElementType(); Type *BTy = BPtr->getType()->getPointerElementType(); auto &DL = InnermostLoop->getHeader()->getModule()->getDataLayout(); uint64_t TypeByteSize = DL.getTypeAllocSize(ATy); const APInt &Val = C->getAPInt(); int64_t Distance = Val.getSExtValue(); uint64_t Stride = std::abs(StrideAPtr); // Attempt to prove strided accesses independent. if (std::abs(Distance) > 0 && Stride > 1 && ATy == BTy && areStridedAccessesIndependent(std::abs(Distance), Stride, TypeByteSize)) { DEBUG(dbgs() << "LAA: Strided accesses are independent\n"); return Dependence::NoDep; } // Negative distances are not plausible dependencies. if (Val.isNegative()) { bool IsTrueDataDependence = (AIsWrite && !BIsWrite); if (IsTrueDataDependence && EnableForwardingConflictDetection && (couldPreventStoreLoadForward(Val.abs().getZExtValue(), TypeByteSize) || ATy != BTy)) { DEBUG(dbgs() << "LAA: Forward but may prevent st->ld forwarding\n"); return Dependence::ForwardButPreventsForwarding; } DEBUG(dbgs() << "LAA: Dependence is negative\n"); return Dependence::Forward; } // Write to the same location with the same size. // Could be improved to assert type sizes are the same (i32 == float, etc). if (Val == 0) { if (ATy == BTy) return Dependence::Forward; DEBUG(dbgs() << "LAA: Zero dependence difference but different types\n"); return Dependence::Unknown; } assert(Val.isStrictlyPositive() && "Expect a positive value"); if (ATy != BTy) { DEBUG(dbgs() << "LAA: ReadWrite-Write positive dependency with different types\n"); return Dependence::Unknown; } // Bail out early if passed-in parameters make vectorization not feasible. unsigned ForcedFactor = (VectorizerParams::VectorizationFactor ? VectorizerParams::VectorizationFactor : 1); unsigned ForcedUnroll = (VectorizerParams::VectorizationInterleave ? VectorizerParams::VectorizationInterleave : 1); // The minimum number of iterations for a vectorized/unrolled version. unsigned MinNumIter = std::max(ForcedFactor * ForcedUnroll, 2U); // It's not vectorizable if the distance is smaller than the minimum distance // needed for a vectroized/unrolled version. Vectorizing one iteration in // front needs TypeByteSize * Stride. Vectorizing the last iteration needs // TypeByteSize (No need to plus the last gap distance). // // E.g. Assume one char is 1 byte in memory and one int is 4 bytes. // foo(int *A) { // int *B = (int *)((char *)A + 14); // for (i = 0 ; i < 1024 ; i += 2) // B[i] = A[i] + 1; // } // // Two accesses in memory (stride is 2): // | A[0] | | A[2] | | A[4] | | A[6] | | // | B[0] | | B[2] | | B[4] | // // Distance needs for vectorizing iterations except the last iteration: // 4 * 2 * (MinNumIter - 1). Distance needs for the last iteration: 4. // So the minimum distance needed is: 4 * 2 * (MinNumIter - 1) + 4. // // If MinNumIter is 2, it is vectorizable as the minimum distance needed is // 12, which is less than distance. // // If MinNumIter is 4 (Say if a user forces the vectorization factor to be 4), // the minimum distance needed is 28, which is greater than distance. It is // not safe to do vectorization. uint64_t MinDistanceNeeded = TypeByteSize * Stride * (MinNumIter - 1) + TypeByteSize; if (MinDistanceNeeded > static_cast(Distance)) { DEBUG(dbgs() << "LAA: Failure because of positive distance " << Distance << '\n'); return Dependence::Backward; } // Unsafe if the minimum distance needed is greater than max safe distance. if (MinDistanceNeeded > MaxSafeDepDistBytes) { DEBUG(dbgs() << "LAA: Failure because it needs at least " << MinDistanceNeeded << " size in bytes"); return Dependence::Backward; } // Positive distance bigger than max vectorization factor. // FIXME: Should use max factor instead of max distance in bytes, which could // not handle different types. // E.g. Assume one char is 1 byte in memory and one int is 4 bytes. // void foo (int *A, char *B) { // for (unsigned i = 0; i < 1024; i++) { // A[i+2] = A[i] + 1; // B[i+2] = B[i] + 1; // } // } // // This case is currently unsafe according to the max safe distance. If we // analyze the two accesses on array B, the max safe dependence distance // is 2. Then we analyze the accesses on array A, the minimum distance needed // is 8, which is less than 2 and forbidden vectorization, But actually // both A and B could be vectorized by 2 iterations. MaxSafeDepDistBytes = std::min(static_cast(Distance), MaxSafeDepDistBytes); bool IsTrueDataDependence = (!AIsWrite && BIsWrite); if (IsTrueDataDependence && EnableForwardingConflictDetection && couldPreventStoreLoadForward(Distance, TypeByteSize)) return Dependence::BackwardVectorizableButPreventsForwarding; DEBUG(dbgs() << "LAA: Positive distance " << Val.getSExtValue() << " with max VF = " << MaxSafeDepDistBytes / (TypeByteSize * Stride) << '\n'); return Dependence::BackwardVectorizable; } bool MemoryDepChecker::areDepsSafe(DepCandidates &AccessSets, MemAccessInfoSet &CheckDeps, const ValueToValueMap &Strides) { MaxSafeDepDistBytes = -1; while (!CheckDeps.empty()) { MemAccessInfo CurAccess = *CheckDeps.begin(); // Get the relevant memory access set. EquivalenceClasses::iterator I = AccessSets.findValue(AccessSets.getLeaderValue(CurAccess)); // Check accesses within this set. EquivalenceClasses::member_iterator AI = AccessSets.member_begin(I); EquivalenceClasses::member_iterator AE = AccessSets.member_end(); // Check every access pair. while (AI != AE) { CheckDeps.erase(*AI); EquivalenceClasses::member_iterator OI = std::next(AI); while (OI != AE) { // Check every accessing instruction pair in program order. for (std::vector::iterator I1 = Accesses[*AI].begin(), I1E = Accesses[*AI].end(); I1 != I1E; ++I1) for (std::vector::iterator I2 = Accesses[*OI].begin(), I2E = Accesses[*OI].end(); I2 != I2E; ++I2) { auto A = std::make_pair(&*AI, *I1); auto B = std::make_pair(&*OI, *I2); assert(*I1 != *I2); if (*I1 > *I2) std::swap(A, B); Dependence::DepType Type = isDependent(*A.first, A.second, *B.first, B.second, Strides); SafeForVectorization &= Dependence::isSafeForVectorization(Type); // Gather dependences unless we accumulated MaxDependences // dependences. In that case return as soon as we find the first // unsafe dependence. This puts a limit on this quadratic // algorithm. if (RecordDependences) { if (Type != Dependence::NoDep) Dependences.push_back(Dependence(A.second, B.second, Type)); if (Dependences.size() >= MaxDependences) { RecordDependences = false; Dependences.clear(); DEBUG(dbgs() << "Too many dependences, stopped recording\n"); } } if (!RecordDependences && !SafeForVectorization) return false; } ++OI; } AI++; } } DEBUG(dbgs() << "Total Dependences: " << Dependences.size() << "\n"); return SafeForVectorization; } SmallVector MemoryDepChecker::getInstructionsForAccess(Value *Ptr, bool isWrite) const { MemAccessInfo Access(Ptr, isWrite); auto &IndexVector = Accesses.find(Access)->second; SmallVector Insts; std::transform(IndexVector.begin(), IndexVector.end(), std::back_inserter(Insts), [&](unsigned Idx) { return this->InstMap[Idx]; }); return Insts; } const char *MemoryDepChecker::Dependence::DepName[] = { "NoDep", "Unknown", "Forward", "ForwardButPreventsForwarding", "Backward", "BackwardVectorizable", "BackwardVectorizableButPreventsForwarding"}; void MemoryDepChecker::Dependence::print( raw_ostream &OS, unsigned Depth, const SmallVectorImpl &Instrs) const { OS.indent(Depth) << DepName[Type] << ":\n"; OS.indent(Depth + 2) << *Instrs[Source] << " -> \n"; OS.indent(Depth + 2) << *Instrs[Destination] << "\n"; } bool LoopAccessInfo::canAnalyzeLoop() { // We need to have a loop header. DEBUG(dbgs() << "LAA: Found a loop in " << TheLoop->getHeader()->getParent()->getName() << ": " << TheLoop->getHeader()->getName() << '\n'); // We can only analyze innermost loops. if (!TheLoop->empty()) { DEBUG(dbgs() << "LAA: loop is not the innermost loop\n"); emitAnalysis(LoopAccessReport() << "loop is not the innermost loop"); return false; } // We must have a single backedge. if (TheLoop->getNumBackEdges() != 1) { DEBUG(dbgs() << "LAA: loop control flow is not understood by analyzer\n"); emitAnalysis( LoopAccessReport() << "loop control flow is not understood by analyzer"); return false; } // We must have a single exiting block. if (!TheLoop->getExitingBlock()) { DEBUG(dbgs() << "LAA: loop control flow is not understood by analyzer\n"); emitAnalysis( LoopAccessReport() << "loop control flow is not understood by analyzer"); return false; } // We only handle bottom-tested loops, i.e. loop in which the condition is // checked at the end of each iteration. With that we can assume that all // instructions in the loop are executed the same number of times. if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch()) { DEBUG(dbgs() << "LAA: loop control flow is not understood by analyzer\n"); emitAnalysis( LoopAccessReport() << "loop control flow is not understood by analyzer"); return false; } // ScalarEvolution needs to be able to find the exit count. const SCEV *ExitCount = PSE->getBackedgeTakenCount(); if (ExitCount == PSE->getSE()->getCouldNotCompute()) { emitAnalysis(LoopAccessReport() << "could not determine number of loop iterations"); DEBUG(dbgs() << "LAA: SCEV could not compute the loop exit count.\n"); return false; } return true; } void LoopAccessInfo::analyzeLoop(AliasAnalysis *AA, LoopInfo *LI, const TargetLibraryInfo *TLI, DominatorTree *DT) { typedef SmallPtrSet ValueSet; // Holds the Load and Store instructions. SmallVector Loads; SmallVector Stores; // Holds all the different accesses in the loop. unsigned NumReads = 0; unsigned NumReadWrites = 0; PtrRtChecking->Pointers.clear(); PtrRtChecking->Need = false; const bool IsAnnotatedParallel = TheLoop->isAnnotatedParallel(); // For each block. for (BasicBlock *BB : TheLoop->blocks()) { // Scan the BB and collect legal loads and stores. for (Instruction &I : *BB) { // If this is a load, save it. If this instruction can read from memory // but is not a load, then we quit. Notice that we don't handle function // calls that read or write. if (I.mayReadFromMemory()) { // Many math library functions read the rounding mode. We will only // vectorize a loop if it contains known function calls that don't set // the flag. Therefore, it is safe to ignore this read from memory. auto *Call = dyn_cast(&I); if (Call && getVectorIntrinsicIDForCall(Call, TLI)) continue; // If the function has an explicit vectorized counterpart, we can safely // assume that it can be vectorized. if (Call && !Call->isNoBuiltin() && Call->getCalledFunction() && TLI->isFunctionVectorizable(Call->getCalledFunction()->getName())) continue; auto *Ld = dyn_cast(&I); if (!Ld || (!Ld->isSimple() && !IsAnnotatedParallel)) { emitAnalysis(LoopAccessReport(Ld) << "read with atomic ordering or volatile read"); DEBUG(dbgs() << "LAA: Found a non-simple load.\n"); CanVecMem = false; return; } NumLoads++; Loads.push_back(Ld); DepChecker->addAccess(Ld); if (EnableMemAccessVersioning) collectStridedAccess(Ld); continue; } // Save 'store' instructions. Abort if other instructions write to memory. if (I.mayWriteToMemory()) { auto *St = dyn_cast(&I); if (!St) { emitAnalysis(LoopAccessReport(St) << "instruction cannot be vectorized"); CanVecMem = false; return; } if (!St->isSimple() && !IsAnnotatedParallel) { emitAnalysis(LoopAccessReport(St) << "write with atomic ordering or volatile write"); DEBUG(dbgs() << "LAA: Found a non-simple store.\n"); CanVecMem = false; return; } NumStores++; Stores.push_back(St); DepChecker->addAccess(St); if (EnableMemAccessVersioning) collectStridedAccess(St); } } // Next instr. } // Next block. // Now we have two lists that hold the loads and the stores. // Next, we find the pointers that they use. // Check if we see any stores. If there are no stores, then we don't // care if the pointers are *restrict*. if (!Stores.size()) { DEBUG(dbgs() << "LAA: Found a read-only loop!\n"); CanVecMem = true; return; } MemoryDepChecker::DepCandidates DependentAccesses; AccessAnalysis Accesses(TheLoop->getHeader()->getModule()->getDataLayout(), AA, LI, DependentAccesses, *PSE); // Holds the analyzed pointers. We don't want to call GetUnderlyingObjects // multiple times on the same object. If the ptr is accessed twice, once // for read and once for write, it will only appear once (on the write // list). This is okay, since we are going to check for conflicts between // writes and between reads and writes, but not between reads and reads. ValueSet Seen; for (StoreInst *ST : Stores) { Value *Ptr = ST->getPointerOperand(); // Check for store to loop invariant address. StoreToLoopInvariantAddress |= isUniform(Ptr); // If we did *not* see this pointer before, insert it to the read-write // list. At this phase it is only a 'write' list. if (Seen.insert(Ptr).second) { ++NumReadWrites; MemoryLocation Loc = MemoryLocation::get(ST); // The TBAA metadata could have a control dependency on the predication // condition, so we cannot rely on it when determining whether or not we // need runtime pointer checks. if (blockNeedsPredication(ST->getParent(), TheLoop, DT)) Loc.AATags.TBAA = nullptr; Accesses.addStore(Loc); } } if (IsAnnotatedParallel) { DEBUG(dbgs() << "LAA: A loop annotated parallel, ignore memory dependency " << "checks.\n"); CanVecMem = true; return; } for (LoadInst *LD : Loads) { Value *Ptr = LD->getPointerOperand(); // If we did *not* see this pointer before, insert it to the // read list. If we *did* see it before, then it is already in // the read-write list. This allows us to vectorize expressions // such as A[i] += x; Because the address of A[i] is a read-write // pointer. This only works if the index of A[i] is consecutive. // If the address of i is unknown (for example A[B[i]]) then we may // read a few words, modify, and write a few words, and some of the // words may be written to the same address. bool IsReadOnlyPtr = false; if (Seen.insert(Ptr).second || !getPtrStride(*PSE, Ptr, TheLoop, SymbolicStrides)) { ++NumReads; IsReadOnlyPtr = true; } MemoryLocation Loc = MemoryLocation::get(LD); // The TBAA metadata could have a control dependency on the predication // condition, so we cannot rely on it when determining whether or not we // need runtime pointer checks. if (blockNeedsPredication(LD->getParent(), TheLoop, DT)) Loc.AATags.TBAA = nullptr; Accesses.addLoad(Loc, IsReadOnlyPtr); } // If we write (or read-write) to a single destination and there are no // other reads in this loop then is it safe to vectorize. if (NumReadWrites == 1 && NumReads == 0) { DEBUG(dbgs() << "LAA: Found a write-only loop!\n"); CanVecMem = true; return; } // Build dependence sets and check whether we need a runtime pointer bounds // check. Accesses.buildDependenceSets(); // Find pointers with computable bounds. We are going to use this information // to place a runtime bound check. bool CanDoRTIfNeeded = Accesses.canCheckPtrAtRT(*PtrRtChecking, PSE->getSE(), TheLoop, SymbolicStrides); if (!CanDoRTIfNeeded) { emitAnalysis(LoopAccessReport() << "cannot identify array bounds"); DEBUG(dbgs() << "LAA: We can't vectorize because we can't find " << "the array bounds.\n"); CanVecMem = false; return; } DEBUG(dbgs() << "LAA: We can perform a memory runtime check if needed.\n"); CanVecMem = true; if (Accesses.isDependencyCheckNeeded()) { DEBUG(dbgs() << "LAA: Checking memory dependencies\n"); CanVecMem = DepChecker->areDepsSafe( DependentAccesses, Accesses.getDependenciesToCheck(), SymbolicStrides); MaxSafeDepDistBytes = DepChecker->getMaxSafeDepDistBytes(); if (!CanVecMem && DepChecker->shouldRetryWithRuntimeCheck()) { DEBUG(dbgs() << "LAA: Retrying with memory checks\n"); // Clear the dependency checks. We assume they are not needed. Accesses.resetDepChecks(*DepChecker); PtrRtChecking->reset(); PtrRtChecking->Need = true; auto *SE = PSE->getSE(); CanDoRTIfNeeded = Accesses.canCheckPtrAtRT(*PtrRtChecking, SE, TheLoop, SymbolicStrides, true); // Check that we found the bounds for the pointer. if (!CanDoRTIfNeeded) { emitAnalysis(LoopAccessReport() << "cannot check memory dependencies at runtime"); DEBUG(dbgs() << "LAA: Can't vectorize with memory checks\n"); CanVecMem = false; return; } CanVecMem = true; } } if (CanVecMem) DEBUG(dbgs() << "LAA: No unsafe dependent memory operations in loop. We" << (PtrRtChecking->Need ? "" : " don't") << " need runtime memory checks.\n"); else { emitAnalysis( LoopAccessReport() << "unsafe dependent memory operations in loop. Use " "#pragma loop distribute(enable) to allow loop distribution " "to attempt to isolate the offending operations into a separate " "loop"); DEBUG(dbgs() << "LAA: unsafe dependent memory operations in loop\n"); } } bool LoopAccessInfo::blockNeedsPredication(BasicBlock *BB, Loop *TheLoop, DominatorTree *DT) { assert(TheLoop->contains(BB) && "Unknown block used"); // Blocks that do not dominate the latch need predication. BasicBlock* Latch = TheLoop->getLoopLatch(); return !DT->dominates(BB, Latch); } void LoopAccessInfo::emitAnalysis(LoopAccessReport &Message) { assert(!Report && "Multiple reports generated"); Report = Message; } bool LoopAccessInfo::isUniform(Value *V) const { return (PSE->getSE()->isLoopInvariant(PSE->getSE()->getSCEV(V), TheLoop)); } // FIXME: this function is currently a duplicate of the one in // LoopVectorize.cpp. static Instruction *getFirstInst(Instruction *FirstInst, Value *V, Instruction *Loc) { if (FirstInst) return FirstInst; if (Instruction *I = dyn_cast(V)) return I->getParent() == Loc->getParent() ? I : nullptr; return nullptr; } namespace { /// \brief IR Values for the lower and upper bounds of a pointer evolution. We /// need to use value-handles because SCEV expansion can invalidate previously /// expanded values. Thus expansion of a pointer can invalidate the bounds for /// a previous one. struct PointerBounds { TrackingVH Start; TrackingVH End; }; } // end anonymous namespace /// \brief Expand code for the lower and upper bound of the pointer group \p CG /// in \p TheLoop. \return the values for the bounds. static PointerBounds expandBounds(const RuntimePointerChecking::CheckingPtrGroup *CG, Loop *TheLoop, Instruction *Loc, SCEVExpander &Exp, ScalarEvolution *SE, const RuntimePointerChecking &PtrRtChecking) { Value *Ptr = PtrRtChecking.Pointers[CG->Members[0]].PointerValue; const SCEV *Sc = SE->getSCEV(Ptr); if (SE->isLoopInvariant(Sc, TheLoop)) { DEBUG(dbgs() << "LAA: Adding RT check for a loop invariant ptr:" << *Ptr << "\n"); return {Ptr, Ptr}; } else { unsigned AS = Ptr->getType()->getPointerAddressSpace(); LLVMContext &Ctx = Loc->getContext(); // Use this type for pointer arithmetic. Type *PtrArithTy = Type::getInt8PtrTy(Ctx, AS); Value *Start = nullptr, *End = nullptr; DEBUG(dbgs() << "LAA: Adding RT check for range:\n"); Start = Exp.expandCodeFor(CG->Low, PtrArithTy, Loc); End = Exp.expandCodeFor(CG->High, PtrArithTy, Loc); DEBUG(dbgs() << "Start: " << *CG->Low << " End: " << *CG->High << "\n"); return {Start, End}; } } /// \brief Turns a collection of checks into a collection of expanded upper and /// lower bounds for both pointers in the check. static SmallVector, 4> expandBounds( const SmallVectorImpl &PointerChecks, Loop *L, Instruction *Loc, ScalarEvolution *SE, SCEVExpander &Exp, const RuntimePointerChecking &PtrRtChecking) { SmallVector, 4> ChecksWithBounds; // Here we're relying on the SCEV Expander's cache to only emit code for the // same bounds once. std::transform( PointerChecks.begin(), PointerChecks.end(), std::back_inserter(ChecksWithBounds), [&](const RuntimePointerChecking::PointerCheck &Check) { PointerBounds First = expandBounds(Check.first, L, Loc, Exp, SE, PtrRtChecking), Second = expandBounds(Check.second, L, Loc, Exp, SE, PtrRtChecking); return std::make_pair(First, Second); }); return ChecksWithBounds; } std::pair LoopAccessInfo::addRuntimeChecks( Instruction *Loc, const SmallVectorImpl &PointerChecks) const { const DataLayout &DL = TheLoop->getHeader()->getModule()->getDataLayout(); auto *SE = PSE->getSE(); SCEVExpander Exp(*SE, DL, "induction"); auto ExpandedChecks = expandBounds(PointerChecks, TheLoop, Loc, SE, Exp, *PtrRtChecking); LLVMContext &Ctx = Loc->getContext(); Instruction *FirstInst = nullptr; IRBuilder<> ChkBuilder(Loc); // Our instructions might fold to a constant. Value *MemoryRuntimeCheck = nullptr; for (const auto &Check : ExpandedChecks) { const PointerBounds &A = Check.first, &B = Check.second; // Check if two pointers (A and B) conflict where conflict is computed as: // start(A) <= end(B) && start(B) <= end(A) unsigned AS0 = A.Start->getType()->getPointerAddressSpace(); unsigned AS1 = B.Start->getType()->getPointerAddressSpace(); assert((AS0 == B.End->getType()->getPointerAddressSpace()) && (AS1 == A.End->getType()->getPointerAddressSpace()) && "Trying to bounds check pointers with different address spaces"); Type *PtrArithTy0 = Type::getInt8PtrTy(Ctx, AS0); Type *PtrArithTy1 = Type::getInt8PtrTy(Ctx, AS1); Value *Start0 = ChkBuilder.CreateBitCast(A.Start, PtrArithTy0, "bc"); Value *Start1 = ChkBuilder.CreateBitCast(B.Start, PtrArithTy1, "bc"); Value *End0 = ChkBuilder.CreateBitCast(A.End, PtrArithTy1, "bc"); Value *End1 = ChkBuilder.CreateBitCast(B.End, PtrArithTy0, "bc"); - Value *Cmp0 = ChkBuilder.CreateICmpULE(Start0, End1, "bound0"); + // [A|B].Start points to the first accessed byte under base [A|B]. + // [A|B].End points to the last accessed byte, plus one. + // There is no conflict when the intervals are disjoint: + // NoConflict = (B.Start >= A.End) || (A.Start >= B.End) + // + // bound0 = (B.Start < A.End) + // bound1 = (A.Start < B.End) + // IsConflict = bound0 & bound1 + Value *Cmp0 = ChkBuilder.CreateICmpULT(Start0, End1, "bound0"); FirstInst = getFirstInst(FirstInst, Cmp0, Loc); - Value *Cmp1 = ChkBuilder.CreateICmpULE(Start1, End0, "bound1"); + Value *Cmp1 = ChkBuilder.CreateICmpULT(Start1, End0, "bound1"); FirstInst = getFirstInst(FirstInst, Cmp1, Loc); Value *IsConflict = ChkBuilder.CreateAnd(Cmp0, Cmp1, "found.conflict"); FirstInst = getFirstInst(FirstInst, IsConflict, Loc); if (MemoryRuntimeCheck) { IsConflict = ChkBuilder.CreateOr(MemoryRuntimeCheck, IsConflict, "conflict.rdx"); FirstInst = getFirstInst(FirstInst, IsConflict, Loc); } MemoryRuntimeCheck = IsConflict; } if (!MemoryRuntimeCheck) return std::make_pair(nullptr, nullptr); // We have to do this trickery because the IRBuilder might fold the check to a // constant expression in which case there is no Instruction anchored in a // the block. Instruction *Check = BinaryOperator::CreateAnd(MemoryRuntimeCheck, ConstantInt::getTrue(Ctx)); ChkBuilder.Insert(Check, "memcheck.conflict"); FirstInst = getFirstInst(FirstInst, Check, Loc); return std::make_pair(FirstInst, Check); } std::pair LoopAccessInfo::addRuntimeChecks(Instruction *Loc) const { if (!PtrRtChecking->Need) return std::make_pair(nullptr, nullptr); return addRuntimeChecks(Loc, PtrRtChecking->getChecks()); } void LoopAccessInfo::collectStridedAccess(Value *MemAccess) { Value *Ptr = nullptr; if (LoadInst *LI = dyn_cast(MemAccess)) Ptr = LI->getPointerOperand(); else if (StoreInst *SI = dyn_cast(MemAccess)) Ptr = SI->getPointerOperand(); else return; Value *Stride = getStrideFromPointer(Ptr, PSE->getSE(), TheLoop); if (!Stride) return; DEBUG(dbgs() << "LAA: Found a strided access that we can version"); DEBUG(dbgs() << " Ptr: " << *Ptr << " Stride: " << *Stride << "\n"); SymbolicStrides[Ptr] = Stride; StrideSet.insert(Stride); } LoopAccessInfo::LoopAccessInfo(Loop *L, ScalarEvolution *SE, const TargetLibraryInfo *TLI, AliasAnalysis *AA, DominatorTree *DT, LoopInfo *LI) : PSE(llvm::make_unique(*SE, *L)), PtrRtChecking(llvm::make_unique(SE)), DepChecker(llvm::make_unique(*PSE, L)), TheLoop(L), NumLoads(0), NumStores(0), MaxSafeDepDistBytes(-1), CanVecMem(false), StoreToLoopInvariantAddress(false) { if (canAnalyzeLoop()) analyzeLoop(AA, LI, TLI, DT); } void LoopAccessInfo::print(raw_ostream &OS, unsigned Depth) const { if (CanVecMem) { OS.indent(Depth) << "Memory dependences are safe"; if (MaxSafeDepDistBytes != -1ULL) OS << " with a maximum dependence distance of " << MaxSafeDepDistBytes << " bytes"; if (PtrRtChecking->Need) OS << " with run-time checks"; OS << "\n"; } if (Report) OS.indent(Depth) << "Report: " << Report->str() << "\n"; if (auto *Dependences = DepChecker->getDependences()) { OS.indent(Depth) << "Dependences:\n"; for (auto &Dep : *Dependences) { Dep.print(OS, Depth + 2, DepChecker->getMemoryInstructions()); OS << "\n"; } } else OS.indent(Depth) << "Too many dependences, not recorded\n"; // List the pair of accesses need run-time checks to prove independence. PtrRtChecking->print(OS, Depth); OS << "\n"; OS.indent(Depth) << "Store to invariant address was " << (StoreToLoopInvariantAddress ? "" : "not ") << "found in loop.\n"; OS.indent(Depth) << "SCEV assumptions:\n"; PSE->getUnionPredicate().print(OS, Depth); OS << "\n"; OS.indent(Depth) << "Expressions re-written:\n"; PSE->print(OS, Depth); } const LoopAccessInfo &LoopAccessLegacyAnalysis::getInfo(Loop *L) { auto &LAI = LoopAccessInfoMap[L]; if (!LAI) LAI = llvm::make_unique(L, SE, TLI, AA, DT, LI); return *LAI.get(); } void LoopAccessLegacyAnalysis::print(raw_ostream &OS, const Module *M) const { LoopAccessLegacyAnalysis &LAA = *const_cast(this); for (Loop *TopLevelLoop : *LI) for (Loop *L : depth_first(TopLevelLoop)) { OS.indent(2) << L->getHeader()->getName() << ":\n"; auto &LAI = LAA.getInfo(L); LAI.print(OS, 4); } } bool LoopAccessLegacyAnalysis::runOnFunction(Function &F) { SE = &getAnalysis().getSE(); auto *TLIP = getAnalysisIfAvailable(); TLI = TLIP ? &TLIP->getTLI() : nullptr; AA = &getAnalysis().getAAResults(); DT = &getAnalysis().getDomTree(); LI = &getAnalysis().getLoopInfo(); return false; } void LoopAccessLegacyAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.setPreservesAll(); } char LoopAccessLegacyAnalysis::ID = 0; static const char laa_name[] = "Loop Access Analysis"; #define LAA_NAME "loop-accesses" INITIALIZE_PASS_BEGIN(LoopAccessLegacyAnalysis, LAA_NAME, laa_name, false, true) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_END(LoopAccessLegacyAnalysis, LAA_NAME, laa_name, false, true) char LoopAccessAnalysis::PassID; LoopAccessInfo LoopAccessAnalysis::run(Loop &L, AnalysisManager &AM) { const AnalysisManager &FAM = AM.getResult(L).getManager(); Function &F = *L.getHeader()->getParent(); auto *SE = FAM.getCachedResult(F); auto *TLI = FAM.getCachedResult(F); auto *AA = FAM.getCachedResult(F); auto *DT = FAM.getCachedResult(F); auto *LI = FAM.getCachedResult(F); if (!SE) report_fatal_error( "ScalarEvolution must have been cached at a higher level"); if (!AA) report_fatal_error("AliasAnalysis must have been cached at a higher level"); if (!DT) report_fatal_error("DominatorTree must have been cached at a higher level"); if (!LI) report_fatal_error("LoopInfo must have been cached at a higher level"); return LoopAccessInfo(&L, SE, TLI, AA, DT, LI); } PreservedAnalyses LoopAccessInfoPrinterPass::run(Loop &L, AnalysisManager &AM) { Function &F = *L.getHeader()->getParent(); auto &LAI = AM.getResult(L); OS << "Loop access info in function '" << F.getName() << "':\n"; OS.indent(2) << L.getHeader()->getName() << ":\n"; LAI.print(OS, 4); return PreservedAnalyses::all(); } namespace llvm { Pass *createLAAPass() { return new LoopAccessLegacyAnalysis(); } } Index: vendor/llvm/dist/lib/CodeGen/BranchFolding.cpp =================================================================== --- vendor/llvm/dist/lib/CodeGen/BranchFolding.cpp (revision 309151) +++ vendor/llvm/dist/lib/CodeGen/BranchFolding.cpp (revision 309152) @@ -1,1933 +1,1942 @@ //===-- BranchFolding.cpp - Fold machine code branch instructions ---------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This pass forwards branches to unconditional branches to make them branch // directly to the target block. This pass often results in dead MBB's, which // it then removes. // // Note that this pass must be run after register allocation, it cannot handle // SSA form. It also must handle virtual registers for targets that emit virtual // ISA (e.g. NVPTX). // //===----------------------------------------------------------------------===// #include "BranchFolding.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineBranchProbabilityInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/Function.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" #include using namespace llvm; #define DEBUG_TYPE "branchfolding" STATISTIC(NumDeadBlocks, "Number of dead blocks removed"); STATISTIC(NumBranchOpts, "Number of branches optimized"); STATISTIC(NumTailMerge , "Number of block tails merged"); STATISTIC(NumHoist , "Number of times common instructions are hoisted"); static cl::opt FlagEnableTailMerge("enable-tail-merge", cl::init(cl::BOU_UNSET), cl::Hidden); // Throttle for huge numbers of predecessors (compile speed problems) static cl::opt TailMergeThreshold("tail-merge-threshold", cl::desc("Max number of predecessors to consider tail merging"), cl::init(150), cl::Hidden); // Heuristic for tail merging (and, inversely, tail duplication). // TODO: This should be replaced with a target query. static cl::opt TailMergeSize("tail-merge-size", cl::desc("Min number of instructions to consider tail merging"), cl::init(3), cl::Hidden); namespace { /// BranchFolderPass - Wrap branch folder in a machine function pass. class BranchFolderPass : public MachineFunctionPass { public: static char ID; explicit BranchFolderPass(): MachineFunctionPass(ID) {} bool runOnMachineFunction(MachineFunction &MF) override; void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); AU.addRequired(); AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } }; } char BranchFolderPass::ID = 0; char &llvm::BranchFolderPassID = BranchFolderPass::ID; INITIALIZE_PASS(BranchFolderPass, "branch-folder", "Control Flow Optimizer", false, false) bool BranchFolderPass::runOnMachineFunction(MachineFunction &MF) { if (skipFunction(*MF.getFunction())) return false; TargetPassConfig *PassConfig = &getAnalysis(); // TailMerge can create jump into if branches that make CFG irreducible for // HW that requires structurized CFG. bool EnableTailMerge = !MF.getTarget().requiresStructuredCFG() && PassConfig->getEnableTailMerge(); BranchFolder::MBFIWrapper MBBFreqInfo( getAnalysis()); BranchFolder Folder(EnableTailMerge, /*CommonHoist=*/true, MBBFreqInfo, getAnalysis()); return Folder.OptimizeFunction(MF, MF.getSubtarget().getInstrInfo(), MF.getSubtarget().getRegisterInfo(), getAnalysisIfAvailable()); } BranchFolder::BranchFolder(bool defaultEnableTailMerge, bool CommonHoist, MBFIWrapper &FreqInfo, const MachineBranchProbabilityInfo &ProbInfo) : EnableHoistCommonCode(CommonHoist), MBBFreqInfo(FreqInfo), MBPI(ProbInfo) { switch (FlagEnableTailMerge) { case cl::BOU_UNSET: EnableTailMerge = defaultEnableTailMerge; break; case cl::BOU_TRUE: EnableTailMerge = true; break; case cl::BOU_FALSE: EnableTailMerge = false; break; } } /// RemoveDeadBlock - Remove the specified dead machine basic block from the /// function, updating the CFG. void BranchFolder::RemoveDeadBlock(MachineBasicBlock *MBB) { assert(MBB->pred_empty() && "MBB must be dead!"); DEBUG(dbgs() << "\nRemoving MBB: " << *MBB); MachineFunction *MF = MBB->getParent(); // drop all successors. while (!MBB->succ_empty()) MBB->removeSuccessor(MBB->succ_end()-1); // Avoid matching if this pointer gets reused. TriedMerging.erase(MBB); // Remove the block. MF->erase(MBB); FuncletMembership.erase(MBB); if (MLI) MLI->removeBlock(MBB); } /// OptimizeImpDefsBlock - If a basic block is just a bunch of implicit_def /// followed by terminators, and if the implicitly defined registers are not /// used by the terminators, remove those implicit_def's. e.g. /// BB1: /// r0 = implicit_def /// r1 = implicit_def /// br /// This block can be optimized away later if the implicit instructions are /// removed. bool BranchFolder::OptimizeImpDefsBlock(MachineBasicBlock *MBB) { SmallSet ImpDefRegs; MachineBasicBlock::iterator I = MBB->begin(); while (I != MBB->end()) { if (!I->isImplicitDef()) break; unsigned Reg = I->getOperand(0).getReg(); if (TargetRegisterInfo::isPhysicalRegister(Reg)) { for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/true); SubRegs.isValid(); ++SubRegs) ImpDefRegs.insert(*SubRegs); } else { ImpDefRegs.insert(Reg); } ++I; } if (ImpDefRegs.empty()) return false; MachineBasicBlock::iterator FirstTerm = I; while (I != MBB->end()) { if (!TII->isUnpredicatedTerminator(*I)) return false; // See if it uses any of the implicitly defined registers. for (const MachineOperand &MO : I->operands()) { if (!MO.isReg() || !MO.isUse()) continue; unsigned Reg = MO.getReg(); if (ImpDefRegs.count(Reg)) return false; } ++I; } I = MBB->begin(); while (I != FirstTerm) { MachineInstr *ImpDefMI = &*I; ++I; MBB->erase(ImpDefMI); } return true; } /// OptimizeFunction - Perhaps branch folding, tail merging and other /// CFG optimizations on the given function. Block placement changes the layout /// and may create new tail merging opportunities. bool BranchFolder::OptimizeFunction(MachineFunction &MF, const TargetInstrInfo *tii, const TargetRegisterInfo *tri, MachineModuleInfo *mmi, MachineLoopInfo *mli, bool AfterPlacement) { if (!tii) return false; TriedMerging.clear(); AfterBlockPlacement = AfterPlacement; TII = tii; TRI = tri; MMI = mmi; MLI = mli; MachineRegisterInfo &MRI = MF.getRegInfo(); UpdateLiveIns = MRI.tracksLiveness() && TRI->trackLivenessAfterRegAlloc(MF); if (!UpdateLiveIns) MRI.invalidateLiveness(); // Fix CFG. The later algorithms expect it to be right. bool MadeChange = false; for (MachineBasicBlock &MBB : MF) { MachineBasicBlock *TBB = nullptr, *FBB = nullptr; SmallVector Cond; if (!TII->analyzeBranch(MBB, TBB, FBB, Cond, true)) MadeChange |= MBB.CorrectExtraCFGEdges(TBB, FBB, !Cond.empty()); MadeChange |= OptimizeImpDefsBlock(&MBB); } // Recalculate funclet membership. FuncletMembership = getFuncletMembership(MF); bool MadeChangeThisIteration = true; while (MadeChangeThisIteration) { MadeChangeThisIteration = TailMergeBlocks(MF); // No need to clean up if tail merging does not change anything after the // block placement. if (!AfterBlockPlacement || MadeChangeThisIteration) MadeChangeThisIteration |= OptimizeBranches(MF); if (EnableHoistCommonCode) MadeChangeThisIteration |= HoistCommonCode(MF); MadeChange |= MadeChangeThisIteration; } // See if any jump tables have become dead as the code generator // did its thing. MachineJumpTableInfo *JTI = MF.getJumpTableInfo(); if (!JTI) return MadeChange; // Walk the function to find jump tables that are live. BitVector JTIsLive(JTI->getJumpTables().size()); for (const MachineBasicBlock &BB : MF) { for (const MachineInstr &I : BB) for (const MachineOperand &Op : I.operands()) { if (!Op.isJTI()) continue; // Remember that this JT is live. JTIsLive.set(Op.getIndex()); } } // Finally, remove dead jump tables. This happens when the // indirect jump was unreachable (and thus deleted). for (unsigned i = 0, e = JTIsLive.size(); i != e; ++i) if (!JTIsLive.test(i)) { JTI->RemoveJumpTable(i); MadeChange = true; } return MadeChange; } //===----------------------------------------------------------------------===// // Tail Merging of Blocks //===----------------------------------------------------------------------===// /// HashMachineInstr - Compute a hash value for MI and its operands. static unsigned HashMachineInstr(const MachineInstr &MI) { unsigned Hash = MI.getOpcode(); for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { const MachineOperand &Op = MI.getOperand(i); // Merge in bits from the operand if easy. We can't use MachineOperand's // hash_code here because it's not deterministic and we sort by hash value // later. unsigned OperandHash = 0; switch (Op.getType()) { case MachineOperand::MO_Register: OperandHash = Op.getReg(); break; case MachineOperand::MO_Immediate: OperandHash = Op.getImm(); break; case MachineOperand::MO_MachineBasicBlock: OperandHash = Op.getMBB()->getNumber(); break; case MachineOperand::MO_FrameIndex: case MachineOperand::MO_ConstantPoolIndex: case MachineOperand::MO_JumpTableIndex: OperandHash = Op.getIndex(); break; case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_ExternalSymbol: // Global address / external symbol are too hard, don't bother, but do // pull in the offset. OperandHash = Op.getOffset(); break; default: break; } Hash += ((OperandHash << 3) | Op.getType()) << (i & 31); } return Hash; } /// HashEndOfMBB - Hash the last instruction in the MBB. static unsigned HashEndOfMBB(const MachineBasicBlock &MBB) { MachineBasicBlock::const_iterator I = MBB.getLastNonDebugInstr(); if (I == MBB.end()) return 0; return HashMachineInstr(*I); } /// ComputeCommonTailLength - Given two machine basic blocks, compute the number /// of instructions they actually have in common together at their end. Return /// iterators for the first shared instruction in each block. static unsigned ComputeCommonTailLength(MachineBasicBlock *MBB1, MachineBasicBlock *MBB2, MachineBasicBlock::iterator &I1, MachineBasicBlock::iterator &I2) { I1 = MBB1->end(); I2 = MBB2->end(); unsigned TailLen = 0; while (I1 != MBB1->begin() && I2 != MBB2->begin()) { --I1; --I2; // Skip debugging pseudos; necessary to avoid changing the code. while (I1->isDebugValue()) { if (I1==MBB1->begin()) { while (I2->isDebugValue()) { if (I2==MBB2->begin()) // I1==DBG at begin; I2==DBG at begin return TailLen; --I2; } ++I2; // I1==DBG at begin; I2==non-DBG, or first of DBGs not at begin return TailLen; } --I1; } // I1==first (untested) non-DBG preceding known match while (I2->isDebugValue()) { if (I2==MBB2->begin()) { ++I1; // I1==non-DBG, or first of DBGs not at begin; I2==DBG at begin return TailLen; } --I2; } // I1, I2==first (untested) non-DBGs preceding known match if (!I1->isIdenticalTo(*I2) || // FIXME: This check is dubious. It's used to get around a problem where // people incorrectly expect inline asm directives to remain in the same // relative order. This is untenable because normal compiler // optimizations (like this one) may reorder and/or merge these // directives. I1->isInlineAsm()) { ++I1; ++I2; break; } ++TailLen; } // Back past possible debugging pseudos at beginning of block. This matters // when one block differs from the other only by whether debugging pseudos // are present at the beginning. (This way, the various checks later for // I1==MBB1->begin() work as expected.) if (I1 == MBB1->begin() && I2 != MBB2->begin()) { --I2; while (I2->isDebugValue()) { if (I2 == MBB2->begin()) return TailLen; --I2; } ++I2; } if (I2 == MBB2->begin() && I1 != MBB1->begin()) { --I1; while (I1->isDebugValue()) { if (I1 == MBB1->begin()) return TailLen; --I1; } ++I1; } return TailLen; } void BranchFolder::computeLiveIns(MachineBasicBlock &MBB) { if (!UpdateLiveIns) return; LiveRegs.init(TRI); LiveRegs.addLiveOutsNoPristines(MBB); for (MachineInstr &MI : make_range(MBB.rbegin(), MBB.rend())) LiveRegs.stepBackward(MI); for (unsigned Reg : LiveRegs) { // Skip the register if we are about to add one of its super registers. bool ContainsSuperReg = false; for (MCSuperRegIterator SReg(Reg, TRI); SReg.isValid(); ++SReg) { if (LiveRegs.contains(*SReg)) { ContainsSuperReg = true; break; } } if (ContainsSuperReg) continue; MBB.addLiveIn(Reg); } } /// ReplaceTailWithBranchTo - Delete the instruction OldInst and everything /// after it, replacing it with an unconditional branch to NewDest. void BranchFolder::ReplaceTailWithBranchTo(MachineBasicBlock::iterator OldInst, MachineBasicBlock *NewDest) { TII->ReplaceTailWithBranchTo(OldInst, NewDest); computeLiveIns(*NewDest); ++NumTailMerge; } /// SplitMBBAt - Given a machine basic block and an iterator into it, split the /// MBB so that the part before the iterator falls into the part starting at the /// iterator. This returns the new MBB. MachineBasicBlock *BranchFolder::SplitMBBAt(MachineBasicBlock &CurMBB, MachineBasicBlock::iterator BBI1, const BasicBlock *BB) { if (!TII->isLegalToSplitMBBAt(CurMBB, BBI1)) return nullptr; MachineFunction &MF = *CurMBB.getParent(); // Create the fall-through block. MachineFunction::iterator MBBI = CurMBB.getIterator(); MachineBasicBlock *NewMBB =MF.CreateMachineBasicBlock(BB); CurMBB.getParent()->insert(++MBBI, NewMBB); // Move all the successors of this block to the specified block. NewMBB->transferSuccessors(&CurMBB); // Add an edge from CurMBB to NewMBB for the fall-through. CurMBB.addSuccessor(NewMBB); // Splice the code over. NewMBB->splice(NewMBB->end(), &CurMBB, BBI1, CurMBB.end()); // NewMBB belongs to the same loop as CurMBB. if (MLI) if (MachineLoop *ML = MLI->getLoopFor(&CurMBB)) ML->addBasicBlockToLoop(NewMBB, MLI->getBase()); // NewMBB inherits CurMBB's block frequency. MBBFreqInfo.setBlockFreq(NewMBB, MBBFreqInfo.getBlockFreq(&CurMBB)); computeLiveIns(*NewMBB); // Add the new block to the funclet. const auto &FuncletI = FuncletMembership.find(&CurMBB); if (FuncletI != FuncletMembership.end()) { auto n = FuncletI->second; FuncletMembership[NewMBB] = n; } return NewMBB; } /// EstimateRuntime - Make a rough estimate for how long it will take to run /// the specified code. static unsigned EstimateRuntime(MachineBasicBlock::iterator I, MachineBasicBlock::iterator E) { unsigned Time = 0; for (; I != E; ++I) { if (I->isDebugValue()) continue; if (I->isCall()) Time += 10; else if (I->mayLoad() || I->mayStore()) Time += 2; else ++Time; } return Time; } // CurMBB needs to add an unconditional branch to SuccMBB (we removed these // branches temporarily for tail merging). In the case where CurMBB ends // with a conditional branch to the next block, optimize by reversing the // test and conditionally branching to SuccMBB instead. static void FixTail(MachineBasicBlock *CurMBB, MachineBasicBlock *SuccBB, const TargetInstrInfo *TII) { MachineFunction *MF = CurMBB->getParent(); MachineFunction::iterator I = std::next(MachineFunction::iterator(CurMBB)); MachineBasicBlock *TBB = nullptr, *FBB = nullptr; SmallVector Cond; DebugLoc dl; // FIXME: this is nowhere if (I != MF->end() && !TII->analyzeBranch(*CurMBB, TBB, FBB, Cond, true)) { MachineBasicBlock *NextBB = &*I; if (TBB == NextBB && !Cond.empty() && !FBB) { if (!TII->ReverseBranchCondition(Cond)) { TII->RemoveBranch(*CurMBB); TII->InsertBranch(*CurMBB, SuccBB, nullptr, Cond, dl); return; } } } TII->InsertBranch(*CurMBB, SuccBB, nullptr, SmallVector(), dl); } bool BranchFolder::MergePotentialsElt::operator<(const MergePotentialsElt &o) const { if (getHash() < o.getHash()) return true; if (getHash() > o.getHash()) return false; if (getBlock()->getNumber() < o.getBlock()->getNumber()) return true; if (getBlock()->getNumber() > o.getBlock()->getNumber()) return false; // _GLIBCXX_DEBUG checks strict weak ordering, which involves comparing // an object with itself. #ifndef _GLIBCXX_DEBUG llvm_unreachable("Predecessor appears twice"); #else return false; #endif } BlockFrequency BranchFolder::MBFIWrapper::getBlockFreq(const MachineBasicBlock *MBB) const { auto I = MergedBBFreq.find(MBB); if (I != MergedBBFreq.end()) return I->second; return MBFI.getBlockFreq(MBB); } void BranchFolder::MBFIWrapper::setBlockFreq(const MachineBasicBlock *MBB, BlockFrequency F) { MergedBBFreq[MBB] = F; } raw_ostream & BranchFolder::MBFIWrapper::printBlockFreq(raw_ostream &OS, const MachineBasicBlock *MBB) const { return MBFI.printBlockFreq(OS, getBlockFreq(MBB)); } raw_ostream & BranchFolder::MBFIWrapper::printBlockFreq(raw_ostream &OS, const BlockFrequency Freq) const { return MBFI.printBlockFreq(OS, Freq); } /// CountTerminators - Count the number of terminators in the given /// block and set I to the position of the first non-terminator, if there /// is one, or MBB->end() otherwise. static unsigned CountTerminators(MachineBasicBlock *MBB, MachineBasicBlock::iterator &I) { I = MBB->end(); unsigned NumTerms = 0; for (;;) { if (I == MBB->begin()) { I = MBB->end(); break; } --I; if (!I->isTerminator()) break; ++NumTerms; } return NumTerms; } /// ProfitableToMerge - Check if two machine basic blocks have a common tail /// and decide if it would be profitable to merge those tails. Return the /// length of the common tail and iterators to the first common instruction /// in each block. static bool ProfitableToMerge(MachineBasicBlock *MBB1, MachineBasicBlock *MBB2, unsigned minCommonTailLength, unsigned &CommonTailLen, MachineBasicBlock::iterator &I1, MachineBasicBlock::iterator &I2, MachineBasicBlock *SuccBB, MachineBasicBlock *PredBB, DenseMap &FuncletMembership) { // It is never profitable to tail-merge blocks from two different funclets. if (!FuncletMembership.empty()) { auto Funclet1 = FuncletMembership.find(MBB1); assert(Funclet1 != FuncletMembership.end()); auto Funclet2 = FuncletMembership.find(MBB2); assert(Funclet2 != FuncletMembership.end()); if (Funclet1->second != Funclet2->second) return false; } CommonTailLen = ComputeCommonTailLength(MBB1, MBB2, I1, I2); if (CommonTailLen == 0) return false; DEBUG(dbgs() << "Common tail length of BB#" << MBB1->getNumber() << " and BB#" << MBB2->getNumber() << " is " << CommonTailLen << '\n'); // It's almost always profitable to merge any number of non-terminator // instructions with the block that falls through into the common successor. if (MBB1 == PredBB || MBB2 == PredBB) { MachineBasicBlock::iterator I; unsigned NumTerms = CountTerminators(MBB1 == PredBB ? MBB2 : MBB1, I); if (CommonTailLen > NumTerms) return true; } // If one of the blocks can be completely merged and happens to be in // a position where the other could fall through into it, merge any number // of instructions, because it can be done without a branch. // TODO: If the blocks are not adjacent, move one of them so that they are? if (MBB1->isLayoutSuccessor(MBB2) && I2 == MBB2->begin()) return true; if (MBB2->isLayoutSuccessor(MBB1) && I1 == MBB1->begin()) return true; // If both blocks have an unconditional branch temporarily stripped out, // count that as an additional common instruction for the following // heuristics. unsigned EffectiveTailLen = CommonTailLen; if (SuccBB && MBB1 != PredBB && MBB2 != PredBB && !MBB1->back().isBarrier() && !MBB2->back().isBarrier()) ++EffectiveTailLen; // Check if the common tail is long enough to be worthwhile. if (EffectiveTailLen >= minCommonTailLength) return true; // If we are optimizing for code size, 2 instructions in common is enough if // we don't have to split a block. At worst we will be introducing 1 new // branch instruction, which is likely to be smaller than the 2 // instructions that would be deleted in the merge. MachineFunction *MF = MBB1->getParent(); return EffectiveTailLen >= 2 && MF->getFunction()->optForSize() && (I1 == MBB1->begin() || I2 == MBB2->begin()); } /// ComputeSameTails - Look through all the blocks in MergePotentials that have /// hash CurHash (guaranteed to match the last element). Build the vector /// SameTails of all those that have the (same) largest number of instructions /// in common of any pair of these blocks. SameTails entries contain an /// iterator into MergePotentials (from which the MachineBasicBlock can be /// found) and a MachineBasicBlock::iterator into that MBB indicating the /// instruction where the matching code sequence begins. /// Order of elements in SameTails is the reverse of the order in which /// those blocks appear in MergePotentials (where they are not necessarily /// consecutive). unsigned BranchFolder::ComputeSameTails(unsigned CurHash, unsigned minCommonTailLength, MachineBasicBlock *SuccBB, MachineBasicBlock *PredBB) { unsigned maxCommonTailLength = 0U; SameTails.clear(); MachineBasicBlock::iterator TrialBBI1, TrialBBI2; MPIterator HighestMPIter = std::prev(MergePotentials.end()); for (MPIterator CurMPIter = std::prev(MergePotentials.end()), B = MergePotentials.begin(); CurMPIter != B && CurMPIter->getHash() == CurHash; --CurMPIter) { for (MPIterator I = std::prev(CurMPIter); I->getHash() == CurHash; --I) { unsigned CommonTailLen; if (ProfitableToMerge(CurMPIter->getBlock(), I->getBlock(), minCommonTailLength, CommonTailLen, TrialBBI1, TrialBBI2, SuccBB, PredBB, FuncletMembership)) { if (CommonTailLen > maxCommonTailLength) { SameTails.clear(); maxCommonTailLength = CommonTailLen; HighestMPIter = CurMPIter; SameTails.push_back(SameTailElt(CurMPIter, TrialBBI1)); } if (HighestMPIter == CurMPIter && CommonTailLen == maxCommonTailLength) SameTails.push_back(SameTailElt(I, TrialBBI2)); } if (I == B) break; } } return maxCommonTailLength; } /// RemoveBlocksWithHash - Remove all blocks with hash CurHash from /// MergePotentials, restoring branches at ends of blocks as appropriate. void BranchFolder::RemoveBlocksWithHash(unsigned CurHash, MachineBasicBlock *SuccBB, MachineBasicBlock *PredBB) { MPIterator CurMPIter, B; for (CurMPIter = std::prev(MergePotentials.end()), B = MergePotentials.begin(); CurMPIter->getHash() == CurHash; --CurMPIter) { // Put the unconditional branch back, if we need one. MachineBasicBlock *CurMBB = CurMPIter->getBlock(); if (SuccBB && CurMBB != PredBB) FixTail(CurMBB, SuccBB, TII); if (CurMPIter == B) break; } if (CurMPIter->getHash() != CurHash) CurMPIter++; MergePotentials.erase(CurMPIter, MergePotentials.end()); } /// CreateCommonTailOnlyBlock - None of the blocks to be tail-merged consist /// only of the common tail. Create a block that does by splitting one. bool BranchFolder::CreateCommonTailOnlyBlock(MachineBasicBlock *&PredBB, MachineBasicBlock *SuccBB, unsigned maxCommonTailLength, unsigned &commonTailIndex) { commonTailIndex = 0; unsigned TimeEstimate = ~0U; for (unsigned i = 0, e = SameTails.size(); i != e; ++i) { // Use PredBB if possible; that doesn't require a new branch. if (SameTails[i].getBlock() == PredBB) { commonTailIndex = i; break; } // Otherwise, make a (fairly bogus) choice based on estimate of // how long it will take the various blocks to execute. unsigned t = EstimateRuntime(SameTails[i].getBlock()->begin(), SameTails[i].getTailStartPos()); if (t <= TimeEstimate) { TimeEstimate = t; commonTailIndex = i; } } MachineBasicBlock::iterator BBI = SameTails[commonTailIndex].getTailStartPos(); MachineBasicBlock *MBB = SameTails[commonTailIndex].getBlock(); // If the common tail includes any debug info we will take it pretty // randomly from one of the inputs. Might be better to remove it? DEBUG(dbgs() << "\nSplitting BB#" << MBB->getNumber() << ", size " << maxCommonTailLength); // If the split block unconditionally falls-thru to SuccBB, it will be // merged. In control flow terms it should then take SuccBB's name. e.g. If // SuccBB is an inner loop, the common tail is still part of the inner loop. const BasicBlock *BB = (SuccBB && MBB->succ_size() == 1) ? SuccBB->getBasicBlock() : MBB->getBasicBlock(); MachineBasicBlock *newMBB = SplitMBBAt(*MBB, BBI, BB); if (!newMBB) { DEBUG(dbgs() << "... failed!"); return false; } SameTails[commonTailIndex].setBlock(newMBB); SameTails[commonTailIndex].setTailStartPos(newMBB->begin()); // If we split PredBB, newMBB is the new predecessor. if (PredBB == MBB) PredBB = newMBB; return true; } static void -mergeMMOsFromMemoryOperations(MachineBasicBlock::iterator MBBIStartPos, - MachineBasicBlock &MBBCommon) { - // Merge MMOs from memory operations in the common block. +mergeOperations(MachineBasicBlock::iterator MBBIStartPos, + MachineBasicBlock &MBBCommon) { MachineBasicBlock *MBB = MBBIStartPos->getParent(); // Note CommonTailLen does not necessarily matches the size of // the common BB nor all its instructions because of debug // instructions differences. unsigned CommonTailLen = 0; for (auto E = MBB->end(); MBBIStartPos != E; ++MBBIStartPos) ++CommonTailLen; MachineBasicBlock::reverse_iterator MBBI = MBB->rbegin(); MachineBasicBlock::reverse_iterator MBBIE = MBB->rend(); MachineBasicBlock::reverse_iterator MBBICommon = MBBCommon.rbegin(); MachineBasicBlock::reverse_iterator MBBIECommon = MBBCommon.rend(); while (CommonTailLen--) { assert(MBBI != MBBIE && "Reached BB end within common tail length!"); (void)MBBIE; if (MBBI->isDebugValue()) { ++MBBI; continue; } while ((MBBICommon != MBBIECommon) && MBBICommon->isDebugValue()) ++MBBICommon; assert(MBBICommon != MBBIECommon && "Reached BB end within common tail length!"); assert(MBBICommon->isIdenticalTo(*MBBI) && "Expected matching MIIs!"); + // Merge MMOs from memory operations in the common block. if (MBBICommon->mayLoad() || MBBICommon->mayStore()) MBBICommon->setMemRefs(MBBICommon->mergeMemRefsWith(*MBBI)); + // Drop undef flags if they aren't present in all merged instructions. + for (unsigned I = 0, E = MBBICommon->getNumOperands(); I != E; ++I) { + MachineOperand &MO = MBBICommon->getOperand(I); + if (MO.isReg() && MO.isUndef()) { + const MachineOperand &OtherMO = MBBI->getOperand(I); + if (!OtherMO.isUndef()) + MO.setIsUndef(false); + } + } ++MBBI; ++MBBICommon; } } // See if any of the blocks in MergePotentials (which all have SuccBB as a // successor, or all have no successor if it is null) can be tail-merged. // If there is a successor, any blocks in MergePotentials that are not // tail-merged and are not immediately before Succ must have an unconditional // branch to Succ added (but the predecessor/successor lists need no // adjustment). The lone predecessor of Succ that falls through into Succ, // if any, is given in PredBB. bool BranchFolder::TryTailMergeBlocks(MachineBasicBlock *SuccBB, MachineBasicBlock *PredBB) { bool MadeChange = false; // Except for the special cases below, tail-merge if there are at least // this many instructions in common. unsigned minCommonTailLength = TailMergeSize; DEBUG(dbgs() << "\nTryTailMergeBlocks: "; for (unsigned i = 0, e = MergePotentials.size(); i != e; ++i) dbgs() << "BB#" << MergePotentials[i].getBlock()->getNumber() << (i == e-1 ? "" : ", "); dbgs() << "\n"; if (SuccBB) { dbgs() << " with successor BB#" << SuccBB->getNumber() << '\n'; if (PredBB) dbgs() << " which has fall-through from BB#" << PredBB->getNumber() << "\n"; } dbgs() << "Looking for common tails of at least " << minCommonTailLength << " instruction" << (minCommonTailLength == 1 ? "" : "s") << '\n'; ); // Sort by hash value so that blocks with identical end sequences sort // together. array_pod_sort(MergePotentials.begin(), MergePotentials.end()); // Walk through equivalence sets looking for actual exact matches. while (MergePotentials.size() > 1) { unsigned CurHash = MergePotentials.back().getHash(); // Build SameTails, identifying the set of blocks with this hash code // and with the maximum number of instructions in common. unsigned maxCommonTailLength = ComputeSameTails(CurHash, minCommonTailLength, SuccBB, PredBB); // If we didn't find any pair that has at least minCommonTailLength // instructions in common, remove all blocks with this hash code and retry. if (SameTails.empty()) { RemoveBlocksWithHash(CurHash, SuccBB, PredBB); continue; } // If one of the blocks is the entire common tail (and not the entry // block, which we can't jump to), we can treat all blocks with this same // tail at once. Use PredBB if that is one of the possibilities, as that // will not introduce any extra branches. MachineBasicBlock *EntryBB = &MergePotentials.front().getBlock()->getParent()->front(); unsigned commonTailIndex = SameTails.size(); // If there are two blocks, check to see if one can be made to fall through // into the other. if (SameTails.size() == 2 && SameTails[0].getBlock()->isLayoutSuccessor(SameTails[1].getBlock()) && SameTails[1].tailIsWholeBlock()) commonTailIndex = 1; else if (SameTails.size() == 2 && SameTails[1].getBlock()->isLayoutSuccessor( SameTails[0].getBlock()) && SameTails[0].tailIsWholeBlock()) commonTailIndex = 0; else { // Otherwise just pick one, favoring the fall-through predecessor if // there is one. for (unsigned i = 0, e = SameTails.size(); i != e; ++i) { MachineBasicBlock *MBB = SameTails[i].getBlock(); if (MBB == EntryBB && SameTails[i].tailIsWholeBlock()) continue; if (MBB == PredBB) { commonTailIndex = i; break; } if (SameTails[i].tailIsWholeBlock()) commonTailIndex = i; } } if (commonTailIndex == SameTails.size() || (SameTails[commonTailIndex].getBlock() == PredBB && !SameTails[commonTailIndex].tailIsWholeBlock())) { // None of the blocks consist entirely of the common tail. // Split a block so that one does. if (!CreateCommonTailOnlyBlock(PredBB, SuccBB, maxCommonTailLength, commonTailIndex)) { RemoveBlocksWithHash(CurHash, SuccBB, PredBB); continue; } } MachineBasicBlock *MBB = SameTails[commonTailIndex].getBlock(); // Recompute common tail MBB's edge weights and block frequency. setCommonTailEdgeWeights(*MBB); // MBB is common tail. Adjust all other BB's to jump to this one. // Traversal must be forwards so erases work. DEBUG(dbgs() << "\nUsing common tail in BB#" << MBB->getNumber() << " for "); for (unsigned int i=0, e = SameTails.size(); i != e; ++i) { if (commonTailIndex == i) continue; DEBUG(dbgs() << "BB#" << SameTails[i].getBlock()->getNumber() << (i == e-1 ? "" : ", ")); - // Merge MMOs from memory operations as needed. - mergeMMOsFromMemoryOperations(SameTails[i].getTailStartPos(), *MBB); + // Merge operations (MMOs, undef flags) + mergeOperations(SameTails[i].getTailStartPos(), *MBB); // Hack the end off BB i, making it jump to BB commonTailIndex instead. ReplaceTailWithBranchTo(SameTails[i].getTailStartPos(), MBB); // BB i is no longer a predecessor of SuccBB; remove it from the worklist. MergePotentials.erase(SameTails[i].getMPIter()); } DEBUG(dbgs() << "\n"); // We leave commonTailIndex in the worklist in case there are other blocks // that match it with a smaller number of instructions. MadeChange = true; } return MadeChange; } bool BranchFolder::TailMergeBlocks(MachineFunction &MF) { bool MadeChange = false; if (!EnableTailMerge) return MadeChange; // First find blocks with no successors. // Block placement does not create new tail merging opportunities for these // blocks. if (!AfterBlockPlacement) { MergePotentials.clear(); for (MachineBasicBlock &MBB : MF) { if (MergePotentials.size() == TailMergeThreshold) break; if (!TriedMerging.count(&MBB) && MBB.succ_empty()) MergePotentials.push_back(MergePotentialsElt(HashEndOfMBB(MBB), &MBB)); } // If this is a large problem, avoid visiting the same basic blocks // multiple times. if (MergePotentials.size() == TailMergeThreshold) for (unsigned i = 0, e = MergePotentials.size(); i != e; ++i) TriedMerging.insert(MergePotentials[i].getBlock()); // See if we can do any tail merging on those. if (MergePotentials.size() >= 2) MadeChange |= TryTailMergeBlocks(nullptr, nullptr); } // Look at blocks (IBB) with multiple predecessors (PBB). // We change each predecessor to a canonical form, by // (1) temporarily removing any unconditional branch from the predecessor // to IBB, and // (2) alter conditional branches so they branch to the other block // not IBB; this may require adding back an unconditional branch to IBB // later, where there wasn't one coming in. E.g. // Bcc IBB // fallthrough to QBB // here becomes // Bncc QBB // with a conceptual B to IBB after that, which never actually exists. // With those changes, we see whether the predecessors' tails match, // and merge them if so. We change things out of canonical form and // back to the way they were later in the process. (OptimizeBranches // would undo some of this, but we can't use it, because we'd get into // a compile-time infinite loop repeatedly doing and undoing the same // transformations.) for (MachineFunction::iterator I = std::next(MF.begin()), E = MF.end(); I != E; ++I) { if (I->pred_size() < 2) continue; SmallPtrSet UniquePreds; MachineBasicBlock *IBB = &*I; MachineBasicBlock *PredBB = &*std::prev(I); MergePotentials.clear(); MachineLoop *ML; // Bail if merging after placement and IBB is the loop header because // -- If merging predecessors that belong to the same loop as IBB, the // common tail of merged predecessors may become the loop top if block // placement is called again and the predecessors may branch to this common // tail and require more branches. This can be relaxed if // MachineBlockPlacement::findBestLoopTop is more flexible. // --If merging predecessors that do not belong to the same loop as IBB, the // loop info of IBB's loop and the other loops may be affected. Calling the // block placement again may make big change to the layout and eliminate the // reason to do tail merging here. if (AfterBlockPlacement && MLI) { ML = MLI->getLoopFor(IBB); if (ML && IBB == ML->getHeader()) continue; } for (MachineBasicBlock *PBB : I->predecessors()) { if (MergePotentials.size() == TailMergeThreshold) break; if (TriedMerging.count(PBB)) continue; // Skip blocks that loop to themselves, can't tail merge these. if (PBB == IBB) continue; // Visit each predecessor only once. if (!UniquePreds.insert(PBB).second) continue; // Skip blocks which may jump to a landing pad. Can't tail merge these. if (PBB->hasEHPadSuccessor()) continue; // After block placement, only consider predecessors that belong to the // same loop as IBB. The reason is the same as above when skipping loop // header. if (AfterBlockPlacement && MLI) if (ML != MLI->getLoopFor(PBB)) continue; MachineBasicBlock *TBB = nullptr, *FBB = nullptr; SmallVector Cond; if (!TII->analyzeBranch(*PBB, TBB, FBB, Cond, true)) { // Failing case: IBB is the target of a cbr, and we cannot reverse the // branch. SmallVector NewCond(Cond); if (!Cond.empty() && TBB == IBB) { if (TII->ReverseBranchCondition(NewCond)) continue; // This is the QBB case described above if (!FBB) { auto Next = ++PBB->getIterator(); if (Next != MF.end()) FBB = &*Next; } } // Failing case: the only way IBB can be reached from PBB is via // exception handling. Happens for landing pads. Would be nice to have // a bit in the edge so we didn't have to do all this. if (IBB->isEHPad()) { MachineFunction::iterator IP = ++PBB->getIterator(); MachineBasicBlock *PredNextBB = nullptr; if (IP != MF.end()) PredNextBB = &*IP; if (!TBB) { if (IBB != PredNextBB) // fallthrough continue; } else if (FBB) { if (TBB != IBB && FBB != IBB) // cbr then ubr continue; } else if (Cond.empty()) { if (TBB != IBB) // ubr continue; } else { if (TBB != IBB && IBB != PredNextBB) // cbr continue; } } // Remove the unconditional branch at the end, if any. if (TBB && (Cond.empty() || FBB)) { DebugLoc dl; // FIXME: this is nowhere TII->RemoveBranch(*PBB); if (!Cond.empty()) // reinsert conditional branch only, for now TII->InsertBranch(*PBB, (TBB == IBB) ? FBB : TBB, nullptr, NewCond, dl); } MergePotentials.push_back(MergePotentialsElt(HashEndOfMBB(*PBB), PBB)); } } // If this is a large problem, avoid visiting the same basic blocks multiple // times. if (MergePotentials.size() == TailMergeThreshold) for (unsigned i = 0, e = MergePotentials.size(); i != e; ++i) TriedMerging.insert(MergePotentials[i].getBlock()); if (MergePotentials.size() >= 2) MadeChange |= TryTailMergeBlocks(IBB, PredBB); // Reinsert an unconditional branch if needed. The 1 below can occur as a // result of removing blocks in TryTailMergeBlocks. PredBB = &*std::prev(I); // this may have been changed in TryTailMergeBlocks if (MergePotentials.size() == 1 && MergePotentials.begin()->getBlock() != PredBB) FixTail(MergePotentials.begin()->getBlock(), IBB, TII); } return MadeChange; } void BranchFolder::setCommonTailEdgeWeights(MachineBasicBlock &TailMBB) { SmallVector EdgeFreqLs(TailMBB.succ_size()); BlockFrequency AccumulatedMBBFreq; // Aggregate edge frequency of successor edge j: // edgeFreq(j) = sum (freq(bb) * edgeProb(bb, j)), // where bb is a basic block that is in SameTails. for (const auto &Src : SameTails) { const MachineBasicBlock *SrcMBB = Src.getBlock(); BlockFrequency BlockFreq = MBBFreqInfo.getBlockFreq(SrcMBB); AccumulatedMBBFreq += BlockFreq; // It is not necessary to recompute edge weights if TailBB has less than two // successors. if (TailMBB.succ_size() <= 1) continue; auto EdgeFreq = EdgeFreqLs.begin(); for (auto SuccI = TailMBB.succ_begin(), SuccE = TailMBB.succ_end(); SuccI != SuccE; ++SuccI, ++EdgeFreq) *EdgeFreq += BlockFreq * MBPI.getEdgeProbability(SrcMBB, *SuccI); } MBBFreqInfo.setBlockFreq(&TailMBB, AccumulatedMBBFreq); if (TailMBB.succ_size() <= 1) return; auto SumEdgeFreq = std::accumulate(EdgeFreqLs.begin(), EdgeFreqLs.end(), BlockFrequency(0)) .getFrequency(); auto EdgeFreq = EdgeFreqLs.begin(); if (SumEdgeFreq > 0) { for (auto SuccI = TailMBB.succ_begin(), SuccE = TailMBB.succ_end(); SuccI != SuccE; ++SuccI, ++EdgeFreq) { auto Prob = BranchProbability::getBranchProbability( EdgeFreq->getFrequency(), SumEdgeFreq); TailMBB.setSuccProbability(SuccI, Prob); } } } //===----------------------------------------------------------------------===// // Branch Optimization //===----------------------------------------------------------------------===// bool BranchFolder::OptimizeBranches(MachineFunction &MF) { bool MadeChange = false; // Make sure blocks are numbered in order MF.RenumberBlocks(); // Renumbering blocks alters funclet membership, recalculate it. FuncletMembership = getFuncletMembership(MF); for (MachineFunction::iterator I = std::next(MF.begin()), E = MF.end(); I != E; ) { MachineBasicBlock *MBB = &*I++; MadeChange |= OptimizeBlock(MBB); // If it is dead, remove it. if (MBB->pred_empty()) { RemoveDeadBlock(MBB); MadeChange = true; ++NumDeadBlocks; } } return MadeChange; } // Blocks should be considered empty if they contain only debug info; // else the debug info would affect codegen. static bool IsEmptyBlock(MachineBasicBlock *MBB) { return MBB->getFirstNonDebugInstr() == MBB->end(); } // Blocks with only debug info and branches should be considered the same // as blocks with only branches. static bool IsBranchOnlyBlock(MachineBasicBlock *MBB) { MachineBasicBlock::iterator I = MBB->getFirstNonDebugInstr(); assert(I != MBB->end() && "empty block!"); return I->isBranch(); } /// IsBetterFallthrough - Return true if it would be clearly better to /// fall-through to MBB1 than to fall through into MBB2. This has to return /// a strict ordering, returning true for both (MBB1,MBB2) and (MBB2,MBB1) will /// result in infinite loops. static bool IsBetterFallthrough(MachineBasicBlock *MBB1, MachineBasicBlock *MBB2) { // Right now, we use a simple heuristic. If MBB2 ends with a call, and // MBB1 doesn't, we prefer to fall through into MBB1. This allows us to // optimize branches that branch to either a return block or an assert block // into a fallthrough to the return. MachineBasicBlock::iterator MBB1I = MBB1->getLastNonDebugInstr(); MachineBasicBlock::iterator MBB2I = MBB2->getLastNonDebugInstr(); if (MBB1I == MBB1->end() || MBB2I == MBB2->end()) return false; // If there is a clear successor ordering we make sure that one block // will fall through to the next if (MBB1->isSuccessor(MBB2)) return true; if (MBB2->isSuccessor(MBB1)) return false; return MBB2I->isCall() && !MBB1I->isCall(); } /// getBranchDebugLoc - Find and return, if any, the DebugLoc of the branch /// instructions on the block. static DebugLoc getBranchDebugLoc(MachineBasicBlock &MBB) { MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); if (I != MBB.end() && I->isBranch()) return I->getDebugLoc(); return DebugLoc(); } /// OptimizeBlock - Analyze and optimize control flow related to the specified /// block. This is never called on the entry block. bool BranchFolder::OptimizeBlock(MachineBasicBlock *MBB) { bool MadeChange = false; MachineFunction &MF = *MBB->getParent(); ReoptimizeBlock: MachineFunction::iterator FallThrough = MBB->getIterator(); ++FallThrough; // Make sure MBB and FallThrough belong to the same funclet. bool SameFunclet = true; if (!FuncletMembership.empty() && FallThrough != MF.end()) { auto MBBFunclet = FuncletMembership.find(MBB); assert(MBBFunclet != FuncletMembership.end()); auto FallThroughFunclet = FuncletMembership.find(&*FallThrough); assert(FallThroughFunclet != FuncletMembership.end()); SameFunclet = MBBFunclet->second == FallThroughFunclet->second; } // If this block is empty, make everyone use its fall-through, not the block // explicitly. Landing pads should not do this since the landing-pad table // points to this block. Blocks with their addresses taken shouldn't be // optimized away. if (IsEmptyBlock(MBB) && !MBB->isEHPad() && !MBB->hasAddressTaken() && SameFunclet) { // Dead block? Leave for cleanup later. if (MBB->pred_empty()) return MadeChange; if (FallThrough == MF.end()) { // TODO: Simplify preds to not branch here if possible! } else if (FallThrough->isEHPad()) { // Don't rewrite to a landing pad fallthough. That could lead to the case // where a BB jumps to more than one landing pad. // TODO: Is it ever worth rewriting predecessors which don't already // jump to a landing pad, and so can safely jump to the fallthrough? } else if (MBB->isSuccessor(&*FallThrough)) { // Rewrite all predecessors of the old block to go to the fallthrough // instead. while (!MBB->pred_empty()) { MachineBasicBlock *Pred = *(MBB->pred_end()-1); Pred->ReplaceUsesOfBlockWith(MBB, &*FallThrough); } // If MBB was the target of a jump table, update jump tables to go to the // fallthrough instead. if (MachineJumpTableInfo *MJTI = MF.getJumpTableInfo()) MJTI->ReplaceMBBInJumpTables(MBB, &*FallThrough); MadeChange = true; } return MadeChange; } // Check to see if we can simplify the terminator of the block before this // one. MachineBasicBlock &PrevBB = *std::prev(MachineFunction::iterator(MBB)); MachineBasicBlock *PriorTBB = nullptr, *PriorFBB = nullptr; SmallVector PriorCond; bool PriorUnAnalyzable = TII->analyzeBranch(PrevBB, PriorTBB, PriorFBB, PriorCond, true); if (!PriorUnAnalyzable) { // If the CFG for the prior block has extra edges, remove them. MadeChange |= PrevBB.CorrectExtraCFGEdges(PriorTBB, PriorFBB, !PriorCond.empty()); // If the previous branch is conditional and both conditions go to the same // destination, remove the branch, replacing it with an unconditional one or // a fall-through. if (PriorTBB && PriorTBB == PriorFBB) { DebugLoc dl = getBranchDebugLoc(PrevBB); TII->RemoveBranch(PrevBB); PriorCond.clear(); if (PriorTBB != MBB) TII->InsertBranch(PrevBB, PriorTBB, nullptr, PriorCond, dl); MadeChange = true; ++NumBranchOpts; goto ReoptimizeBlock; } // If the previous block unconditionally falls through to this block and // this block has no other predecessors, move the contents of this block // into the prior block. This doesn't usually happen when SimplifyCFG // has been used, but it can happen if tail merging splits a fall-through // predecessor of a block. // This has to check PrevBB->succ_size() because EH edges are ignored by // AnalyzeBranch. if (PriorCond.empty() && !PriorTBB && MBB->pred_size() == 1 && PrevBB.succ_size() == 1 && !MBB->hasAddressTaken() && !MBB->isEHPad()) { DEBUG(dbgs() << "\nMerging into block: " << PrevBB << "From MBB: " << *MBB); // Remove redundant DBG_VALUEs first. if (PrevBB.begin() != PrevBB.end()) { MachineBasicBlock::iterator PrevBBIter = PrevBB.end(); --PrevBBIter; MachineBasicBlock::iterator MBBIter = MBB->begin(); // Check if DBG_VALUE at the end of PrevBB is identical to the // DBG_VALUE at the beginning of MBB. while (PrevBBIter != PrevBB.begin() && MBBIter != MBB->end() && PrevBBIter->isDebugValue() && MBBIter->isDebugValue()) { if (!MBBIter->isIdenticalTo(*PrevBBIter)) break; MachineInstr &DuplicateDbg = *MBBIter; ++MBBIter; -- PrevBBIter; DuplicateDbg.eraseFromParent(); } } PrevBB.splice(PrevBB.end(), MBB, MBB->begin(), MBB->end()); PrevBB.removeSuccessor(PrevBB.succ_begin()); assert(PrevBB.succ_empty()); PrevBB.transferSuccessors(MBB); MadeChange = true; return MadeChange; } // If the previous branch *only* branches to *this* block (conditional or // not) remove the branch. if (PriorTBB == MBB && !PriorFBB) { TII->RemoveBranch(PrevBB); MadeChange = true; ++NumBranchOpts; goto ReoptimizeBlock; } // If the prior block branches somewhere else on the condition and here if // the condition is false, remove the uncond second branch. if (PriorFBB == MBB) { DebugLoc dl = getBranchDebugLoc(PrevBB); TII->RemoveBranch(PrevBB); TII->InsertBranch(PrevBB, PriorTBB, nullptr, PriorCond, dl); MadeChange = true; ++NumBranchOpts; goto ReoptimizeBlock; } // If the prior block branches here on true and somewhere else on false, and // if the branch condition is reversible, reverse the branch to create a // fall-through. if (PriorTBB == MBB) { SmallVector NewPriorCond(PriorCond); if (!TII->ReverseBranchCondition(NewPriorCond)) { DebugLoc dl = getBranchDebugLoc(PrevBB); TII->RemoveBranch(PrevBB); TII->InsertBranch(PrevBB, PriorFBB, nullptr, NewPriorCond, dl); MadeChange = true; ++NumBranchOpts; goto ReoptimizeBlock; } } // If this block has no successors (e.g. it is a return block or ends with // a call to a no-return function like abort or __cxa_throw) and if the pred // falls through into this block, and if it would otherwise fall through // into the block after this, move this block to the end of the function. // // We consider it more likely that execution will stay in the function (e.g. // due to loops) than it is to exit it. This asserts in loops etc, moving // the assert condition out of the loop body. if (MBB->succ_empty() && !PriorCond.empty() && !PriorFBB && MachineFunction::iterator(PriorTBB) == FallThrough && !MBB->canFallThrough()) { bool DoTransform = true; // We have to be careful that the succs of PredBB aren't both no-successor // blocks. If neither have successors and if PredBB is the second from // last block in the function, we'd just keep swapping the two blocks for // last. Only do the swap if one is clearly better to fall through than // the other. if (FallThrough == --MF.end() && !IsBetterFallthrough(PriorTBB, MBB)) DoTransform = false; if (DoTransform) { // Reverse the branch so we will fall through on the previous true cond. SmallVector NewPriorCond(PriorCond); if (!TII->ReverseBranchCondition(NewPriorCond)) { DEBUG(dbgs() << "\nMoving MBB: " << *MBB << "To make fallthrough to: " << *PriorTBB << "\n"); DebugLoc dl = getBranchDebugLoc(PrevBB); TII->RemoveBranch(PrevBB); TII->InsertBranch(PrevBB, MBB, nullptr, NewPriorCond, dl); // Move this block to the end of the function. MBB->moveAfter(&MF.back()); MadeChange = true; ++NumBranchOpts; return MadeChange; } } } } // Analyze the branch in the current block. MachineBasicBlock *CurTBB = nullptr, *CurFBB = nullptr; SmallVector CurCond; bool CurUnAnalyzable = TII->analyzeBranch(*MBB, CurTBB, CurFBB, CurCond, true); if (!CurUnAnalyzable) { // If the CFG for the prior block has extra edges, remove them. MadeChange |= MBB->CorrectExtraCFGEdges(CurTBB, CurFBB, !CurCond.empty()); // If this is a two-way branch, and the FBB branches to this block, reverse // the condition so the single-basic-block loop is faster. Instead of: // Loop: xxx; jcc Out; jmp Loop // we want: // Loop: xxx; jncc Loop; jmp Out if (CurTBB && CurFBB && CurFBB == MBB && CurTBB != MBB) { SmallVector NewCond(CurCond); if (!TII->ReverseBranchCondition(NewCond)) { DebugLoc dl = getBranchDebugLoc(*MBB); TII->RemoveBranch(*MBB); TII->InsertBranch(*MBB, CurFBB, CurTBB, NewCond, dl); MadeChange = true; ++NumBranchOpts; goto ReoptimizeBlock; } } // If this branch is the only thing in its block, see if we can forward // other blocks across it. if (CurTBB && CurCond.empty() && !CurFBB && IsBranchOnlyBlock(MBB) && CurTBB != MBB && !MBB->hasAddressTaken() && !MBB->isEHPad()) { DebugLoc dl = getBranchDebugLoc(*MBB); // This block may contain just an unconditional branch. Because there can // be 'non-branch terminators' in the block, try removing the branch and // then seeing if the block is empty. TII->RemoveBranch(*MBB); // If the only things remaining in the block are debug info, remove these // as well, so this will behave the same as an empty block in non-debug // mode. if (IsEmptyBlock(MBB)) { // Make the block empty, losing the debug info (we could probably // improve this in some cases.) MBB->erase(MBB->begin(), MBB->end()); } // If this block is just an unconditional branch to CurTBB, we can // usually completely eliminate the block. The only case we cannot // completely eliminate the block is when the block before this one // falls through into MBB and we can't understand the prior block's branch // condition. if (MBB->empty()) { bool PredHasNoFallThrough = !PrevBB.canFallThrough(); if (PredHasNoFallThrough || !PriorUnAnalyzable || !PrevBB.isSuccessor(MBB)) { // If the prior block falls through into us, turn it into an // explicit branch to us to make updates simpler. if (!PredHasNoFallThrough && PrevBB.isSuccessor(MBB) && PriorTBB != MBB && PriorFBB != MBB) { if (!PriorTBB) { assert(PriorCond.empty() && !PriorFBB && "Bad branch analysis"); PriorTBB = MBB; } else { assert(!PriorFBB && "Machine CFG out of date!"); PriorFBB = MBB; } DebugLoc pdl = getBranchDebugLoc(PrevBB); TII->RemoveBranch(PrevBB); TII->InsertBranch(PrevBB, PriorTBB, PriorFBB, PriorCond, pdl); } // Iterate through all the predecessors, revectoring each in-turn. size_t PI = 0; bool DidChange = false; bool HasBranchToSelf = false; while(PI != MBB->pred_size()) { MachineBasicBlock *PMBB = *(MBB->pred_begin() + PI); if (PMBB == MBB) { // If this block has an uncond branch to itself, leave it. ++PI; HasBranchToSelf = true; } else { DidChange = true; PMBB->ReplaceUsesOfBlockWith(MBB, CurTBB); // If this change resulted in PMBB ending in a conditional // branch where both conditions go to the same destination, // change this to an unconditional branch (and fix the CFG). MachineBasicBlock *NewCurTBB = nullptr, *NewCurFBB = nullptr; SmallVector NewCurCond; bool NewCurUnAnalyzable = TII->analyzeBranch( *PMBB, NewCurTBB, NewCurFBB, NewCurCond, true); if (!NewCurUnAnalyzable && NewCurTBB && NewCurTBB == NewCurFBB) { DebugLoc pdl = getBranchDebugLoc(*PMBB); TII->RemoveBranch(*PMBB); NewCurCond.clear(); TII->InsertBranch(*PMBB, NewCurTBB, nullptr, NewCurCond, pdl); MadeChange = true; ++NumBranchOpts; PMBB->CorrectExtraCFGEdges(NewCurTBB, nullptr, false); } } } // Change any jumptables to go to the new MBB. if (MachineJumpTableInfo *MJTI = MF.getJumpTableInfo()) MJTI->ReplaceMBBInJumpTables(MBB, CurTBB); if (DidChange) { ++NumBranchOpts; MadeChange = true; if (!HasBranchToSelf) return MadeChange; } } } // Add the branch back if the block is more than just an uncond branch. TII->InsertBranch(*MBB, CurTBB, nullptr, CurCond, dl); } } // If the prior block doesn't fall through into this block, and if this // block doesn't fall through into some other block, see if we can find a // place to move this block where a fall-through will happen. if (!PrevBB.canFallThrough()) { // Now we know that there was no fall-through into this block, check to // see if it has a fall-through into its successor. bool CurFallsThru = MBB->canFallThrough(); if (!MBB->isEHPad()) { // Check all the predecessors of this block. If one of them has no fall // throughs, move this block right after it. for (MachineBasicBlock *PredBB : MBB->predecessors()) { // Analyze the branch at the end of the pred. MachineBasicBlock *PredTBB = nullptr, *PredFBB = nullptr; SmallVector PredCond; if (PredBB != MBB && !PredBB->canFallThrough() && !TII->analyzeBranch(*PredBB, PredTBB, PredFBB, PredCond, true) && (!CurFallsThru || !CurTBB || !CurFBB) && (!CurFallsThru || MBB->getNumber() >= PredBB->getNumber())) { // If the current block doesn't fall through, just move it. // If the current block can fall through and does not end with a // conditional branch, we need to append an unconditional jump to // the (current) next block. To avoid a possible compile-time // infinite loop, move blocks only backward in this case. // Also, if there are already 2 branches here, we cannot add a third; // this means we have the case // Bcc next // B elsewhere // next: if (CurFallsThru) { MachineBasicBlock *NextBB = &*std::next(MBB->getIterator()); CurCond.clear(); TII->InsertBranch(*MBB, NextBB, nullptr, CurCond, DebugLoc()); } MBB->moveAfter(PredBB); MadeChange = true; goto ReoptimizeBlock; } } } if (!CurFallsThru) { // Check all successors to see if we can move this block before it. for (MachineBasicBlock *SuccBB : MBB->successors()) { // Analyze the branch at the end of the block before the succ. MachineFunction::iterator SuccPrev = --SuccBB->getIterator(); // If this block doesn't already fall-through to that successor, and if // the succ doesn't already have a block that can fall through into it, // and if the successor isn't an EH destination, we can arrange for the // fallthrough to happen. if (SuccBB != MBB && &*SuccPrev != MBB && !SuccPrev->canFallThrough() && !CurUnAnalyzable && !SuccBB->isEHPad()) { MBB->moveBefore(SuccBB); MadeChange = true; goto ReoptimizeBlock; } } // Okay, there is no really great place to put this block. If, however, // the block before this one would be a fall-through if this block were // removed, move this block to the end of the function. MachineBasicBlock *PrevTBB = nullptr, *PrevFBB = nullptr; SmallVector PrevCond; // We're looking for cases where PrevBB could possibly fall through to // FallThrough, but if FallThrough is an EH pad that wouldn't be useful // so here we skip over any EH pads so we might have a chance to find // a branch target from PrevBB. while (FallThrough != MF.end() && FallThrough->isEHPad()) ++FallThrough; // Now check to see if the current block is sitting between PrevBB and // a block to which it could fall through. if (FallThrough != MF.end() && !TII->analyzeBranch(PrevBB, PrevTBB, PrevFBB, PrevCond, true) && PrevBB.isSuccessor(&*FallThrough)) { MBB->moveAfter(&MF.back()); MadeChange = true; return MadeChange; } } } return MadeChange; } //===----------------------------------------------------------------------===// // Hoist Common Code //===----------------------------------------------------------------------===// /// HoistCommonCode - Hoist common instruction sequences at the start of basic /// blocks to their common predecessor. bool BranchFolder::HoistCommonCode(MachineFunction &MF) { bool MadeChange = false; for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ) { MachineBasicBlock *MBB = &*I++; MadeChange |= HoistCommonCodeInSuccs(MBB); } return MadeChange; } /// findFalseBlock - BB has a fallthrough. Find its 'false' successor given /// its 'true' successor. static MachineBasicBlock *findFalseBlock(MachineBasicBlock *BB, MachineBasicBlock *TrueBB) { for (MachineBasicBlock *SuccBB : BB->successors()) if (SuccBB != TrueBB) return SuccBB; return nullptr; } template static void addRegAndItsAliases(unsigned Reg, const TargetRegisterInfo *TRI, Container &Set) { if (TargetRegisterInfo::isPhysicalRegister(Reg)) { for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) Set.insert(*AI); } else { Set.insert(Reg); } } /// findHoistingInsertPosAndDeps - Find the location to move common instructions /// in successors to. The location is usually just before the terminator, /// however if the terminator is a conditional branch and its previous /// instruction is the flag setting instruction, the previous instruction is /// the preferred location. This function also gathers uses and defs of the /// instructions from the insertion point to the end of the block. The data is /// used by HoistCommonCodeInSuccs to ensure safety. static MachineBasicBlock::iterator findHoistingInsertPosAndDeps(MachineBasicBlock *MBB, const TargetInstrInfo *TII, const TargetRegisterInfo *TRI, SmallSet &Uses, SmallSet &Defs) { MachineBasicBlock::iterator Loc = MBB->getFirstTerminator(); if (!TII->isUnpredicatedTerminator(*Loc)) return MBB->end(); for (const MachineOperand &MO : Loc->operands()) { if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); if (!Reg) continue; if (MO.isUse()) { addRegAndItsAliases(Reg, TRI, Uses); } else { if (!MO.isDead()) // Don't try to hoist code in the rare case the terminator defines a // register that is later used. return MBB->end(); // If the terminator defines a register, make sure we don't hoist // the instruction whose def might be clobbered by the terminator. addRegAndItsAliases(Reg, TRI, Defs); } } if (Uses.empty()) return Loc; if (Loc == MBB->begin()) return MBB->end(); // The terminator is probably a conditional branch, try not to separate the // branch from condition setting instruction. MachineBasicBlock::iterator PI = Loc; --PI; while (PI != MBB->begin() && PI->isDebugValue()) --PI; bool IsDef = false; for (const MachineOperand &MO : PI->operands()) { // If PI has a regmask operand, it is probably a call. Separate away. if (MO.isRegMask()) return Loc; if (!MO.isReg() || MO.isUse()) continue; unsigned Reg = MO.getReg(); if (!Reg) continue; if (Uses.count(Reg)) { IsDef = true; break; } } if (!IsDef) // The condition setting instruction is not just before the conditional // branch. return Loc; // Be conservative, don't insert instruction above something that may have // side-effects. And since it's potentially bad to separate flag setting // instruction from the conditional branch, just abort the optimization // completely. // Also avoid moving code above predicated instruction since it's hard to // reason about register liveness with predicated instruction. bool DontMoveAcrossStore = true; if (!PI->isSafeToMove(nullptr, DontMoveAcrossStore) || TII->isPredicated(*PI)) return MBB->end(); // Find out what registers are live. Note this routine is ignoring other live // registers which are only used by instructions in successor blocks. for (const MachineOperand &MO : PI->operands()) { if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); if (!Reg) continue; if (MO.isUse()) { addRegAndItsAliases(Reg, TRI, Uses); } else { if (Uses.erase(Reg)) { if (TargetRegisterInfo::isPhysicalRegister(Reg)) { for (MCSubRegIterator SubRegs(Reg, TRI); SubRegs.isValid(); ++SubRegs) Uses.erase(*SubRegs); // Use sub-registers to be conservative } } addRegAndItsAliases(Reg, TRI, Defs); } } return PI; } /// HoistCommonCodeInSuccs - If the successors of MBB has common instruction /// sequence at the start of the function, move the instructions before MBB /// terminator if it's legal. bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) { MachineBasicBlock *TBB = nullptr, *FBB = nullptr; SmallVector Cond; if (TII->analyzeBranch(*MBB, TBB, FBB, Cond, true) || !TBB || Cond.empty()) return false; if (!FBB) FBB = findFalseBlock(MBB, TBB); if (!FBB) // Malformed bcc? True and false blocks are the same? return false; // Restrict the optimization to cases where MBB is the only predecessor, // it is an obvious win. if (TBB->pred_size() > 1 || FBB->pred_size() > 1) return false; // Find a suitable position to hoist the common instructions to. Also figure // out which registers are used or defined by instructions from the insertion // point to the end of the block. SmallSet Uses, Defs; MachineBasicBlock::iterator Loc = findHoistingInsertPosAndDeps(MBB, TII, TRI, Uses, Defs); if (Loc == MBB->end()) return false; bool HasDups = false; SmallVector LocalDefs; SmallSet LocalDefsSet; MachineBasicBlock::iterator TIB = TBB->begin(); MachineBasicBlock::iterator FIB = FBB->begin(); MachineBasicBlock::iterator TIE = TBB->end(); MachineBasicBlock::iterator FIE = FBB->end(); while (TIB != TIE && FIB != FIE) { // Skip dbg_value instructions. These do not count. if (TIB->isDebugValue()) { while (TIB != TIE && TIB->isDebugValue()) ++TIB; if (TIB == TIE) break; } if (FIB->isDebugValue()) { while (FIB != FIE && FIB->isDebugValue()) ++FIB; if (FIB == FIE) break; } if (!TIB->isIdenticalTo(*FIB, MachineInstr::CheckKillDead)) break; if (TII->isPredicated(*TIB)) // Hard to reason about register liveness with predicated instruction. break; bool IsSafe = true; for (MachineOperand &MO : TIB->operands()) { // Don't attempt to hoist instructions with register masks. if (MO.isRegMask()) { IsSafe = false; break; } if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); if (!Reg) continue; if (MO.isDef()) { if (Uses.count(Reg)) { // Avoid clobbering a register that's used by the instruction at // the point of insertion. IsSafe = false; break; } if (Defs.count(Reg) && !MO.isDead()) { // Don't hoist the instruction if the def would be clobber by the // instruction at the point insertion. FIXME: This is overly // conservative. It should be possible to hoist the instructions // in BB2 in the following example: // BB1: // r1, eflag = op1 r2, r3 // brcc eflag // // BB2: // r1 = op2, ... // = op3, r1 IsSafe = false; break; } } else if (!LocalDefsSet.count(Reg)) { if (Defs.count(Reg)) { // Use is defined by the instruction at the point of insertion. IsSafe = false; break; } if (MO.isKill() && Uses.count(Reg)) // Kills a register that's read by the instruction at the point of // insertion. Remove the kill marker. MO.setIsKill(false); } } if (!IsSafe) break; bool DontMoveAcrossStore = true; if (!TIB->isSafeToMove(nullptr, DontMoveAcrossStore)) break; // Remove kills from LocalDefsSet, these registers had short live ranges. for (const MachineOperand &MO : TIB->operands()) { if (!MO.isReg() || !MO.isUse() || !MO.isKill()) continue; unsigned Reg = MO.getReg(); if (!Reg || !LocalDefsSet.count(Reg)) continue; if (TargetRegisterInfo::isPhysicalRegister(Reg)) { for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) LocalDefsSet.erase(*AI); } else { LocalDefsSet.erase(Reg); } } // Track local defs so we can update liveins. for (const MachineOperand &MO : TIB->operands()) { if (!MO.isReg() || !MO.isDef() || MO.isDead()) continue; unsigned Reg = MO.getReg(); if (!Reg || TargetRegisterInfo::isVirtualRegister(Reg)) continue; LocalDefs.push_back(Reg); addRegAndItsAliases(Reg, TRI, LocalDefsSet); } HasDups = true; ++TIB; ++FIB; } if (!HasDups) return false; MBB->splice(Loc, TBB, TBB->begin(), TIB); FBB->erase(FBB->begin(), FIB); // Update livein's. for (unsigned i = 0, e = LocalDefs.size(); i != e; ++i) { unsigned Def = LocalDefs[i]; if (LocalDefsSet.count(Def)) { TBB->addLiveIn(Def); FBB->addLiveIn(Def); } } ++NumHoist; return true; } Index: vendor/llvm/dist/lib/Linker/IRMover.cpp =================================================================== --- vendor/llvm/dist/lib/Linker/IRMover.cpp (revision 309151) +++ vendor/llvm/dist/lib/Linker/IRMover.cpp (revision 309152) @@ -1,1356 +1,1370 @@ //===- lib/Linker/IRMover.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/Linker/IRMover.h" #include "LinkDiagnosticInfo.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/TypeFinder.h" #include "llvm/Support/Error.h" #include "llvm/Transforms/Utils/Cloning.h" #include using namespace llvm; //===----------------------------------------------------------------------===// // TypeMap implementation. //===----------------------------------------------------------------------===// namespace { class TypeMapTy : public ValueMapTypeRemapper { /// This is a mapping from a source type to a destination type to use. DenseMap MappedTypes; /// When checking to see if two subgraphs are isomorphic, we speculatively /// add types to MappedTypes, but keep track of them here in case we need to /// roll back. SmallVector SpeculativeTypes; SmallVector SpeculativeDstOpaqueTypes; /// This is a list of non-opaque structs in the source module that are mapped /// to an opaque struct in the destination module. SmallVector SrcDefinitionsToResolve; /// This is the set of opaque types in the destination modules who are /// getting a body from the source module. SmallPtrSet DstResolvedOpaqueTypes; public: TypeMapTy(IRMover::IdentifiedStructTypeSet &DstStructTypesSet) : DstStructTypesSet(DstStructTypesSet) {} IRMover::IdentifiedStructTypeSet &DstStructTypesSet; /// Indicate that the specified type in the destination module is conceptually /// equivalent to the specified type in the source module. void addTypeMapping(Type *DstTy, Type *SrcTy); /// Produce a body for an opaque type in the dest module from a type /// definition in the source module. void linkDefinedTypeBodies(); /// Return the mapped type to use for the specified input type from the /// source module. Type *get(Type *SrcTy); Type *get(Type *SrcTy, SmallPtrSet &Visited); void finishType(StructType *DTy, StructType *STy, ArrayRef ETypes); FunctionType *get(FunctionType *T) { return cast(get((Type *)T)); } private: Type *remapType(Type *SrcTy) override { return get(SrcTy); } bool areTypesIsomorphic(Type *DstTy, Type *SrcTy); }; } void TypeMapTy::addTypeMapping(Type *DstTy, Type *SrcTy) { assert(SpeculativeTypes.empty()); assert(SpeculativeDstOpaqueTypes.empty()); // Check to see if these types are recursively isomorphic and establish a // mapping between them if so. if (!areTypesIsomorphic(DstTy, SrcTy)) { // Oops, they aren't isomorphic. Just discard this request by rolling out // any speculative mappings we've established. for (Type *Ty : SpeculativeTypes) MappedTypes.erase(Ty); SrcDefinitionsToResolve.resize(SrcDefinitionsToResolve.size() - SpeculativeDstOpaqueTypes.size()); for (StructType *Ty : SpeculativeDstOpaqueTypes) DstResolvedOpaqueTypes.erase(Ty); } else { for (Type *Ty : SpeculativeTypes) if (auto *STy = dyn_cast(Ty)) if (STy->hasName()) STy->setName(""); } SpeculativeTypes.clear(); SpeculativeDstOpaqueTypes.clear(); } /// Recursively walk this pair of types, returning true if they are isomorphic, /// false if they are not. bool TypeMapTy::areTypesIsomorphic(Type *DstTy, Type *SrcTy) { // Two types with differing kinds are clearly not isomorphic. if (DstTy->getTypeID() != SrcTy->getTypeID()) return false; // If we have an entry in the MappedTypes table, then we have our answer. Type *&Entry = MappedTypes[SrcTy]; if (Entry) return Entry == DstTy; // Two identical types are clearly isomorphic. Remember this // non-speculatively. if (DstTy == SrcTy) { Entry = DstTy; return true; } // Okay, we have two types with identical kinds that we haven't seen before. // If this is an opaque struct type, special case it. if (StructType *SSTy = dyn_cast(SrcTy)) { // Mapping an opaque type to any struct, just keep the dest struct. if (SSTy->isOpaque()) { Entry = DstTy; SpeculativeTypes.push_back(SrcTy); return true; } // Mapping a non-opaque source type to an opaque dest. If this is the first // type that we're mapping onto this destination type then we succeed. Keep // the dest, but fill it in later. If this is the second (different) type // that we're trying to map onto the same opaque type then we fail. if (cast(DstTy)->isOpaque()) { // We can only map one source type onto the opaque destination type. if (!DstResolvedOpaqueTypes.insert(cast(DstTy)).second) return false; SrcDefinitionsToResolve.push_back(SSTy); SpeculativeTypes.push_back(SrcTy); SpeculativeDstOpaqueTypes.push_back(cast(DstTy)); Entry = DstTy; return true; } } // If the number of subtypes disagree between the two types, then we fail. if (SrcTy->getNumContainedTypes() != DstTy->getNumContainedTypes()) return false; // Fail if any of the extra properties (e.g. array size) of the type disagree. if (isa(DstTy)) return false; // bitwidth disagrees. if (PointerType *PT = dyn_cast(DstTy)) { if (PT->getAddressSpace() != cast(SrcTy)->getAddressSpace()) return false; } else if (FunctionType *FT = dyn_cast(DstTy)) { if (FT->isVarArg() != cast(SrcTy)->isVarArg()) return false; } else if (StructType *DSTy = dyn_cast(DstTy)) { StructType *SSTy = cast(SrcTy); if (DSTy->isLiteral() != SSTy->isLiteral() || DSTy->isPacked() != SSTy->isPacked()) return false; } else if (ArrayType *DATy = dyn_cast(DstTy)) { if (DATy->getNumElements() != cast(SrcTy)->getNumElements()) return false; } else if (VectorType *DVTy = dyn_cast(DstTy)) { if (DVTy->getNumElements() != cast(SrcTy)->getNumElements()) return false; } // Otherwise, we speculate that these two types will line up and recursively // check the subelements. Entry = DstTy; SpeculativeTypes.push_back(SrcTy); for (unsigned I = 0, E = SrcTy->getNumContainedTypes(); I != E; ++I) if (!areTypesIsomorphic(DstTy->getContainedType(I), SrcTy->getContainedType(I))) return false; // If everything seems to have lined up, then everything is great. return true; } void TypeMapTy::linkDefinedTypeBodies() { SmallVector Elements; for (StructType *SrcSTy : SrcDefinitionsToResolve) { StructType *DstSTy = cast(MappedTypes[SrcSTy]); assert(DstSTy->isOpaque()); // Map the body of the source type over to a new body for the dest type. Elements.resize(SrcSTy->getNumElements()); for (unsigned I = 0, E = Elements.size(); I != E; ++I) Elements[I] = get(SrcSTy->getElementType(I)); DstSTy->setBody(Elements, SrcSTy->isPacked()); DstStructTypesSet.switchToNonOpaque(DstSTy); } SrcDefinitionsToResolve.clear(); DstResolvedOpaqueTypes.clear(); } void TypeMapTy::finishType(StructType *DTy, StructType *STy, ArrayRef ETypes) { DTy->setBody(ETypes, STy->isPacked()); // Steal STy's name. if (STy->hasName()) { SmallString<16> TmpName = STy->getName(); STy->setName(""); DTy->setName(TmpName); } DstStructTypesSet.addNonOpaque(DTy); } Type *TypeMapTy::get(Type *Ty) { SmallPtrSet Visited; return get(Ty, Visited); } Type *TypeMapTy::get(Type *Ty, SmallPtrSet &Visited) { // If we already have an entry for this type, return it. Type **Entry = &MappedTypes[Ty]; if (*Entry) return *Entry; // These are types that LLVM itself will unique. bool IsUniqued = !isa(Ty) || cast(Ty)->isLiteral(); #ifndef NDEBUG if (!IsUniqued) { for (auto &Pair : MappedTypes) { assert(!(Pair.first != Ty && Pair.second == Ty) && "mapping to a source type"); } } #endif if (!IsUniqued && !Visited.insert(cast(Ty)).second) { StructType *DTy = StructType::create(Ty->getContext()); return *Entry = DTy; } // If this is not a recursive type, then just map all of the elements and // then rebuild the type from inside out. SmallVector ElementTypes; // If there are no element types to map, then the type is itself. This is // true for the anonymous {} struct, things like 'float', integers, etc. if (Ty->getNumContainedTypes() == 0 && IsUniqued) return *Entry = Ty; // Remap all of the elements, keeping track of whether any of them change. bool AnyChange = false; ElementTypes.resize(Ty->getNumContainedTypes()); for (unsigned I = 0, E = Ty->getNumContainedTypes(); I != E; ++I) { ElementTypes[I] = get(Ty->getContainedType(I), Visited); AnyChange |= ElementTypes[I] != Ty->getContainedType(I); } // If we found our type while recursively processing stuff, just use it. Entry = &MappedTypes[Ty]; if (*Entry) { if (auto *DTy = dyn_cast(*Entry)) { if (DTy->isOpaque()) { auto *STy = cast(Ty); finishType(DTy, STy, ElementTypes); } } return *Entry; } // If all of the element types mapped directly over and the type is not // a nomed struct, then the type is usable as-is. if (!AnyChange && IsUniqued) return *Entry = Ty; // Otherwise, rebuild a modified type. switch (Ty->getTypeID()) { default: llvm_unreachable("unknown derived type to remap"); case Type::ArrayTyID: return *Entry = ArrayType::get(ElementTypes[0], cast(Ty)->getNumElements()); case Type::VectorTyID: return *Entry = VectorType::get(ElementTypes[0], cast(Ty)->getNumElements()); case Type::PointerTyID: return *Entry = PointerType::get(ElementTypes[0], cast(Ty)->getAddressSpace()); case Type::FunctionTyID: return *Entry = FunctionType::get(ElementTypes[0], makeArrayRef(ElementTypes).slice(1), cast(Ty)->isVarArg()); case Type::StructTyID: { auto *STy = cast(Ty); bool IsPacked = STy->isPacked(); if (IsUniqued) return *Entry = StructType::get(Ty->getContext(), ElementTypes, IsPacked); // If the type is opaque, we can just use it directly. if (STy->isOpaque()) { DstStructTypesSet.addOpaque(STy); return *Entry = Ty; } if (StructType *OldT = DstStructTypesSet.findNonOpaque(ElementTypes, IsPacked)) { STy->setName(""); return *Entry = OldT; } if (!AnyChange) { DstStructTypesSet.addNonOpaque(STy); return *Entry = Ty; } StructType *DTy = StructType::create(Ty->getContext()); finishType(DTy, STy, ElementTypes); return *Entry = DTy; } } } LinkDiagnosticInfo::LinkDiagnosticInfo(DiagnosticSeverity Severity, const Twine &Msg) : DiagnosticInfo(DK_Linker, Severity), Msg(Msg) {} void LinkDiagnosticInfo::print(DiagnosticPrinter &DP) const { DP << Msg; } //===----------------------------------------------------------------------===// // IRLinker implementation. //===----------------------------------------------------------------------===// namespace { class IRLinker; /// Creates prototypes for functions that are lazily linked on the fly. This /// speeds up linking for modules with many/ lazily linked functions of which /// few get used. class GlobalValueMaterializer final : public ValueMaterializer { IRLinker &TheIRLinker; public: GlobalValueMaterializer(IRLinker &TheIRLinker) : TheIRLinker(TheIRLinker) {} Value *materialize(Value *V) override; }; class LocalValueMaterializer final : public ValueMaterializer { IRLinker &TheIRLinker; public: LocalValueMaterializer(IRLinker &TheIRLinker) : TheIRLinker(TheIRLinker) {} Value *materialize(Value *V) override; }; /// Type of the Metadata map in \a ValueToValueMapTy. typedef DenseMap MDMapT; /// This is responsible for keeping track of the state used for moving data /// from SrcM to DstM. class IRLinker { Module &DstM; std::unique_ptr SrcM; /// See IRMover::move(). std::function AddLazyFor; TypeMapTy TypeMap; GlobalValueMaterializer GValMaterializer; LocalValueMaterializer LValMaterializer; /// A metadata map that's shared between IRLinker instances. MDMapT &SharedMDs; /// Mapping of values from what they used to be in Src, to what they are now /// in DstM. ValueToValueMapTy is a ValueMap, which involves some overhead /// due to the use of Value handles which the Linker doesn't actually need, /// but this allows us to reuse the ValueMapper code. ValueToValueMapTy ValueMap; ValueToValueMapTy AliasValueMap; DenseSet ValuesToLink; std::vector Worklist; void maybeAdd(GlobalValue *GV) { if (ValuesToLink.insert(GV).second) Worklist.push_back(GV); } /// Set to true when all global value body linking is complete (including /// lazy linking). Used to prevent metadata linking from creating new /// references. bool DoneLinkingBodies = false; /// The Error encountered during materialization. We use an Optional here to /// avoid needing to manage an unconsumed success value. Optional FoundError; void setError(Error E) { if (E) FoundError = std::move(E); } /// Most of the errors produced by this module are inconvertible StringErrors. /// This convenience function lets us return one of those more easily. Error stringErr(const Twine &T) { return make_error(T, inconvertibleErrorCode()); } /// Entry point for mapping values and alternate context for mapping aliases. ValueMapper Mapper; unsigned AliasMCID; /// Handles cloning of a global values from the source module into /// the destination module, including setting the attributes and visibility. GlobalValue *copyGlobalValueProto(const GlobalValue *SGV, bool ForDefinition); void emitWarning(const Twine &Message) { SrcM->getContext().diagnose(LinkDiagnosticInfo(DS_Warning, Message)); } /// Given a global in the source module, return the global in the /// destination module that is being linked to, if any. GlobalValue *getLinkedToGlobal(const GlobalValue *SrcGV) { // If the source has no name it can't link. If it has local linkage, // there is no name match-up going on. if (!SrcGV->hasName() || SrcGV->hasLocalLinkage()) return nullptr; // Otherwise see if we have a match in the destination module's symtab. GlobalValue *DGV = DstM.getNamedValue(SrcGV->getName()); if (!DGV) return nullptr; // If we found a global with the same name in the dest module, but it has // internal linkage, we are really not doing any linkage here. if (DGV->hasLocalLinkage()) return nullptr; // Otherwise, we do in fact link to the destination global. return DGV; } void computeTypeMapping(); Expected linkAppendingVarProto(GlobalVariable *DstGV, const GlobalVariable *SrcGV); /// Given the GlobaValue \p SGV in the source module, and the matching /// GlobalValue \p DGV (if any), return true if the linker will pull \p SGV /// into the destination module. /// /// Note this code may call the client-provided \p AddLazyFor. bool shouldLink(GlobalValue *DGV, GlobalValue &SGV); Expected linkGlobalValueProto(GlobalValue *GV, bool ForAlias); Error linkModuleFlagsMetadata(); void linkGlobalInit(GlobalVariable &Dst, GlobalVariable &Src); Error linkFunctionBody(Function &Dst, Function &Src); void linkAliasBody(GlobalAlias &Dst, GlobalAlias &Src); Error linkGlobalValueBody(GlobalValue &Dst, GlobalValue &Src); /// Functions that take care of cloning a specific global value type /// into the destination module. GlobalVariable *copyGlobalVariableProto(const GlobalVariable *SGVar); Function *copyFunctionProto(const Function *SF); GlobalValue *copyGlobalAliasProto(const GlobalAlias *SGA); void linkNamedMDNodes(); public: IRLinker(Module &DstM, MDMapT &SharedMDs, IRMover::IdentifiedStructTypeSet &Set, std::unique_ptr SrcM, ArrayRef ValuesToLink, std::function AddLazyFor) : DstM(DstM), SrcM(std::move(SrcM)), AddLazyFor(std::move(AddLazyFor)), TypeMap(Set), GValMaterializer(*this), LValMaterializer(*this), SharedMDs(SharedMDs), Mapper(ValueMap, RF_MoveDistinctMDs | RF_IgnoreMissingLocals, &TypeMap, &GValMaterializer), AliasMCID(Mapper.registerAlternateMappingContext(AliasValueMap, &LValMaterializer)) { ValueMap.getMDMap() = std::move(SharedMDs); for (GlobalValue *GV : ValuesToLink) maybeAdd(GV); } ~IRLinker() { SharedMDs = std::move(*ValueMap.getMDMap()); } Error run(); Value *materialize(Value *V, bool ForAlias); }; } /// The LLVM SymbolTable class autorenames globals that conflict in the symbol /// table. This is good for all clients except for us. Go through the trouble /// to force this back. static void forceRenaming(GlobalValue *GV, StringRef Name) { // If the global doesn't force its name or if it already has the right name, // there is nothing for us to do. if (GV->hasLocalLinkage() || GV->getName() == Name) return; Module *M = GV->getParent(); // If there is a conflict, rename the conflict. if (GlobalValue *ConflictGV = M->getNamedValue(Name)) { GV->takeName(ConflictGV); ConflictGV->setName(Name); // This will cause ConflictGV to get renamed assert(ConflictGV->getName() != Name && "forceRenaming didn't work"); } else { GV->setName(Name); // Force the name back } } Value *GlobalValueMaterializer::materialize(Value *SGV) { return TheIRLinker.materialize(SGV, false); } Value *LocalValueMaterializer::materialize(Value *SGV) { return TheIRLinker.materialize(SGV, true); } Value *IRLinker::materialize(Value *V, bool ForAlias) { auto *SGV = dyn_cast(V); if (!SGV) return nullptr; Expected NewProto = linkGlobalValueProto(SGV, ForAlias); if (!NewProto) { setError(NewProto.takeError()); return nullptr; } if (!*NewProto) return nullptr; GlobalValue *New = dyn_cast(*NewProto); if (!New) return *NewProto; // If we already created the body, just return. if (auto *F = dyn_cast(New)) { if (!F->isDeclaration()) return New; } else if (auto *V = dyn_cast(New)) { if (V->hasInitializer() || V->hasAppendingLinkage()) return New; } else { auto *A = cast(New); if (A->getAliasee()) return New; } // When linking a global for an alias, it will always be linked. However we // need to check if it was not already scheduled to satify a reference from a // regular global value initializer. We know if it has been schedule if the // "New" GlobalValue that is mapped here for the alias is the same as the one // already mapped. If there is an entry in the ValueMap but the value is // different, it means that the value already had a definition in the // destination module (linkonce for instance), but we need a new definition // for the alias ("New" will be different. if (ForAlias && ValueMap.lookup(SGV) == New) return New; if (ForAlias || shouldLink(New, *SGV)) setError(linkGlobalValueBody(*New, *SGV)); return New; } /// Loop through the global variables in the src module and merge them into the /// dest module. GlobalVariable *IRLinker::copyGlobalVariableProto(const GlobalVariable *SGVar) { // No linking to be performed or linking from the source: simply create an // identical version of the symbol over in the dest module... the // initializer will be filled in later by LinkGlobalInits. GlobalVariable *NewDGV = new GlobalVariable(DstM, TypeMap.get(SGVar->getValueType()), SGVar->isConstant(), GlobalValue::ExternalLinkage, /*init*/ nullptr, SGVar->getName(), /*insertbefore*/ nullptr, SGVar->getThreadLocalMode(), SGVar->getType()->getAddressSpace()); NewDGV->setAlignment(SGVar->getAlignment()); return NewDGV; } /// Link the function in the source module into the destination module if /// needed, setting up mapping information. Function *IRLinker::copyFunctionProto(const Function *SF) { // If there is no linkage to be performed or we are linking from the source, // bring SF over. return Function::Create(TypeMap.get(SF->getFunctionType()), GlobalValue::ExternalLinkage, SF->getName(), &DstM); } /// Set up prototypes for any aliases that come over from the source module. GlobalValue *IRLinker::copyGlobalAliasProto(const GlobalAlias *SGA) { // If there is no linkage to be performed or we're linking from the source, // bring over SGA. auto *Ty = TypeMap.get(SGA->getValueType()); return GlobalAlias::create(Ty, SGA->getType()->getPointerAddressSpace(), GlobalValue::ExternalLinkage, SGA->getName(), &DstM); } GlobalValue *IRLinker::copyGlobalValueProto(const GlobalValue *SGV, bool ForDefinition) { GlobalValue *NewGV; if (auto *SGVar = dyn_cast(SGV)) { NewGV = copyGlobalVariableProto(SGVar); } else if (auto *SF = dyn_cast(SGV)) { NewGV = copyFunctionProto(SF); } else { if (ForDefinition) NewGV = copyGlobalAliasProto(cast(SGV)); else NewGV = new GlobalVariable( DstM, TypeMap.get(SGV->getValueType()), /*isConstant*/ false, GlobalValue::ExternalLinkage, /*init*/ nullptr, SGV->getName(), /*insertbefore*/ nullptr, SGV->getThreadLocalMode(), SGV->getType()->getAddressSpace()); } if (ForDefinition) NewGV->setLinkage(SGV->getLinkage()); else if (SGV->hasExternalWeakLinkage()) NewGV->setLinkage(GlobalValue::ExternalWeakLinkage); NewGV->copyAttributesFrom(SGV); if (auto *NewGO = dyn_cast(NewGV)) { // Metadata for global variables and function declarations is copied eagerly. if (isa(SGV) || SGV->isDeclaration()) NewGO->copyMetadata(cast(SGV), 0); } // Remove these copied constants in case this stays a declaration, since // they point to the source module. If the def is linked the values will // be mapped in during linkFunctionBody. if (auto *NewF = dyn_cast(NewGV)) { NewF->setPersonalityFn(nullptr); NewF->setPrefixData(nullptr); NewF->setPrologueData(nullptr); } return NewGV; } /// Loop over all of the linked values to compute type mappings. For example, /// if we link "extern Foo *x" and "Foo *x = NULL", then we have two struct /// types 'Foo' but one got renamed when the module was loaded into the same /// LLVMContext. void IRLinker::computeTypeMapping() { for (GlobalValue &SGV : SrcM->globals()) { GlobalValue *DGV = getLinkedToGlobal(&SGV); if (!DGV) continue; if (!DGV->hasAppendingLinkage() || !SGV.hasAppendingLinkage()) { TypeMap.addTypeMapping(DGV->getType(), SGV.getType()); continue; } // Unify the element type of appending arrays. ArrayType *DAT = cast(DGV->getValueType()); ArrayType *SAT = cast(SGV.getValueType()); TypeMap.addTypeMapping(DAT->getElementType(), SAT->getElementType()); } for (GlobalValue &SGV : *SrcM) if (GlobalValue *DGV = getLinkedToGlobal(&SGV)) TypeMap.addTypeMapping(DGV->getType(), SGV.getType()); for (GlobalValue &SGV : SrcM->aliases()) if (GlobalValue *DGV = getLinkedToGlobal(&SGV)) TypeMap.addTypeMapping(DGV->getType(), SGV.getType()); // Incorporate types by name, scanning all the types in the source module. // At this point, the destination module may have a type "%foo = { i32 }" for // example. When the source module got loaded into the same LLVMContext, if // it had the same type, it would have been renamed to "%foo.42 = { i32 }". std::vector Types = SrcM->getIdentifiedStructTypes(); for (StructType *ST : Types) { if (!ST->hasName()) continue; + if (TypeMap.DstStructTypesSet.hasType(ST)) { + // This is actually a type from the destination module. + // getIdentifiedStructTypes() can have found it by walking debug info + // metadata nodes, some of which get linked by name when ODR Type Uniquing + // is enabled on the Context, from the source to the destination module. + continue; + } + // Check to see if there is a dot in the name followed by a digit. size_t DotPos = ST->getName().rfind('.'); if (DotPos == 0 || DotPos == StringRef::npos || ST->getName().back() == '.' || !isdigit(static_cast(ST->getName()[DotPos + 1]))) continue; // Check to see if the destination module has a struct with the prefix name. StructType *DST = DstM.getTypeByName(ST->getName().substr(0, DotPos)); if (!DST) continue; // Don't use it if this actually came from the source module. They're in // the same LLVMContext after all. Also don't use it unless the type is // actually used in the destination module. This can happen in situations // like this: // // Module A Module B // -------- -------- // %Z = type { %A } %B = type { %C.1 } // %A = type { %B.1, [7 x i8] } %C.1 = type { i8* } // %B.1 = type { %C } %A.2 = type { %B.3, [5 x i8] } // %C = type { i8* } %B.3 = type { %C.1 } // // When we link Module B with Module A, the '%B' in Module B is // used. However, that would then use '%C.1'. But when we process '%C.1', // we prefer to take the '%C' version. So we are then left with both // '%C.1' and '%C' being used for the same types. This leads to some // variables using one type and some using the other. if (TypeMap.DstStructTypesSet.hasType(DST)) TypeMap.addTypeMapping(DST, ST); } // Now that we have discovered all of the type equivalences, get a body for // any 'opaque' types in the dest module that are now resolved. TypeMap.linkDefinedTypeBodies(); } static void getArrayElements(const Constant *C, SmallVectorImpl &Dest) { unsigned NumElements = cast(C->getType())->getNumElements(); for (unsigned i = 0; i != NumElements; ++i) Dest.push_back(C->getAggregateElement(i)); } /// If there were any appending global variables, link them together now. Expected IRLinker::linkAppendingVarProto(GlobalVariable *DstGV, const GlobalVariable *SrcGV) { Type *EltTy = cast(TypeMap.get(SrcGV->getValueType())) ->getElementType(); // FIXME: This upgrade is done during linking to support the C API. Once the // old form is deprecated, we should move this upgrade to // llvm::UpgradeGlobalVariable() and simplify the logic here and in // Mapper::mapAppendingVariable() in ValueMapper.cpp. StringRef Name = SrcGV->getName(); bool IsNewStructor = false; bool IsOldStructor = false; if (Name == "llvm.global_ctors" || Name == "llvm.global_dtors") { if (cast(EltTy)->getNumElements() == 3) IsNewStructor = true; else IsOldStructor = true; } PointerType *VoidPtrTy = Type::getInt8Ty(SrcGV->getContext())->getPointerTo(); if (IsOldStructor) { auto &ST = *cast(EltTy); Type *Tys[3] = {ST.getElementType(0), ST.getElementType(1), VoidPtrTy}; EltTy = StructType::get(SrcGV->getContext(), Tys, false); } uint64_t DstNumElements = 0; if (DstGV) { ArrayType *DstTy = cast(DstGV->getValueType()); DstNumElements = DstTy->getNumElements(); if (!SrcGV->hasAppendingLinkage() || !DstGV->hasAppendingLinkage()) return stringErr( "Linking globals named '" + SrcGV->getName() + "': can only link appending global with another appending " "global!"); // Check to see that they two arrays agree on type. if (EltTy != DstTy->getElementType()) return stringErr("Appending variables with different element types!"); if (DstGV->isConstant() != SrcGV->isConstant()) return stringErr("Appending variables linked with different const'ness!"); if (DstGV->getAlignment() != SrcGV->getAlignment()) return stringErr( "Appending variables with different alignment need to be linked!"); if (DstGV->getVisibility() != SrcGV->getVisibility()) return stringErr( "Appending variables with different visibility need to be linked!"); if (DstGV->hasGlobalUnnamedAddr() != SrcGV->hasGlobalUnnamedAddr()) return stringErr( "Appending variables with different unnamed_addr need to be linked!"); if (DstGV->getSection() != SrcGV->getSection()) return stringErr( "Appending variables with different section name need to be linked!"); } SmallVector SrcElements; getArrayElements(SrcGV->getInitializer(), SrcElements); if (IsNewStructor) SrcElements.erase( std::remove_if(SrcElements.begin(), SrcElements.end(), [this](Constant *E) { auto *Key = dyn_cast( E->getAggregateElement(2)->stripPointerCasts()); if (!Key) return false; GlobalValue *DGV = getLinkedToGlobal(Key); return !shouldLink(DGV, *Key); }), SrcElements.end()); uint64_t NewSize = DstNumElements + SrcElements.size(); ArrayType *NewType = ArrayType::get(EltTy, NewSize); // Create the new global variable. GlobalVariable *NG = new GlobalVariable( DstM, NewType, SrcGV->isConstant(), SrcGV->getLinkage(), /*init*/ nullptr, /*name*/ "", DstGV, SrcGV->getThreadLocalMode(), SrcGV->getType()->getAddressSpace()); NG->copyAttributesFrom(SrcGV); forceRenaming(NG, SrcGV->getName()); Constant *Ret = ConstantExpr::getBitCast(NG, TypeMap.get(SrcGV->getType())); Mapper.scheduleMapAppendingVariable(*NG, DstGV ? DstGV->getInitializer() : nullptr, IsOldStructor, SrcElements); // Replace any uses of the two global variables with uses of the new // global. if (DstGV) { DstGV->replaceAllUsesWith(ConstantExpr::getBitCast(NG, DstGV->getType())); DstGV->eraseFromParent(); } return Ret; } bool IRLinker::shouldLink(GlobalValue *DGV, GlobalValue &SGV) { if (ValuesToLink.count(&SGV) || SGV.hasLocalLinkage()) return true; if (DGV && !DGV->isDeclarationForLinker()) return false; if (SGV.hasAvailableExternallyLinkage()) return true; if (SGV.isDeclaration() || DoneLinkingBodies) return false; // Callback to the client to give a chance to lazily add the Global to the // list of value to link. bool LazilyAdded = false; AddLazyFor(SGV, [this, &LazilyAdded](GlobalValue &GV) { maybeAdd(&GV); LazilyAdded = true; }); return LazilyAdded; } Expected IRLinker::linkGlobalValueProto(GlobalValue *SGV, bool ForAlias) { GlobalValue *DGV = getLinkedToGlobal(SGV); bool ShouldLink = shouldLink(DGV, *SGV); // just missing from map if (ShouldLink) { auto I = ValueMap.find(SGV); if (I != ValueMap.end()) return cast(I->second); I = AliasValueMap.find(SGV); if (I != AliasValueMap.end()) return cast(I->second); } if (!ShouldLink && ForAlias) DGV = nullptr; // Handle the ultra special appending linkage case first. assert(!DGV || SGV->hasAppendingLinkage() == DGV->hasAppendingLinkage()); if (SGV->hasAppendingLinkage()) return linkAppendingVarProto(cast_or_null(DGV), cast(SGV)); GlobalValue *NewGV; if (DGV && !ShouldLink) { NewGV = DGV; } else { // If we are done linking global value bodies (i.e. we are performing // metadata linking), don't link in the global value due to this // reference, simply map it to null. if (DoneLinkingBodies) return nullptr; NewGV = copyGlobalValueProto(SGV, ShouldLink); if (ShouldLink || !ForAlias) forceRenaming(NewGV, SGV->getName()); } // Overloaded intrinsics have overloaded types names as part of their // names. If we renamed overloaded types we should rename the intrinsic // as well. if (Function *F = dyn_cast(NewGV)) if (auto Remangled = Intrinsic::remangleIntrinsicFunction(F)) NewGV = Remangled.getValue(); if (ShouldLink || ForAlias) { if (const Comdat *SC = SGV->getComdat()) { if (auto *GO = dyn_cast(NewGV)) { Comdat *DC = DstM.getOrInsertComdat(SC->getName()); DC->setSelectionKind(SC->getSelectionKind()); GO->setComdat(DC); } } } if (!ShouldLink && ForAlias) NewGV->setLinkage(GlobalValue::InternalLinkage); Constant *C = NewGV; if (DGV) C = ConstantExpr::getBitCast(NewGV, TypeMap.get(SGV->getType())); if (DGV && NewGV != DGV) { DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewGV, DGV->getType())); DGV->eraseFromParent(); } return C; } /// Update the initializers in the Dest module now that all globals that may be /// referenced are in Dest. void IRLinker::linkGlobalInit(GlobalVariable &Dst, GlobalVariable &Src) { // Figure out what the initializer looks like in the dest module. Mapper.scheduleMapGlobalInitializer(Dst, *Src.getInitializer()); } /// Copy the source function over into the dest function and fix up references /// to values. At this point we know that Dest is an external function, and /// that Src is not. Error IRLinker::linkFunctionBody(Function &Dst, Function &Src) { assert(Dst.isDeclaration() && !Src.isDeclaration()); // Materialize if needed. if (std::error_code EC = Src.materialize()) return errorCodeToError(EC); // Link in the operands without remapping. if (Src.hasPrefixData()) Dst.setPrefixData(Src.getPrefixData()); if (Src.hasPrologueData()) Dst.setPrologueData(Src.getPrologueData()); if (Src.hasPersonalityFn()) Dst.setPersonalityFn(Src.getPersonalityFn()); // Copy over the metadata attachments without remapping. Dst.copyMetadata(&Src, 0); // Steal arguments and splice the body of Src into Dst. Dst.stealArgumentListFrom(Src); Dst.getBasicBlockList().splice(Dst.end(), Src.getBasicBlockList()); // Everything has been moved over. Remap it. Mapper.scheduleRemapFunction(Dst); return Error::success(); } void IRLinker::linkAliasBody(GlobalAlias &Dst, GlobalAlias &Src) { Mapper.scheduleMapGlobalAliasee(Dst, *Src.getAliasee(), AliasMCID); } Error IRLinker::linkGlobalValueBody(GlobalValue &Dst, GlobalValue &Src) { if (auto *F = dyn_cast(&Src)) return linkFunctionBody(cast(Dst), *F); if (auto *GVar = dyn_cast(&Src)) { linkGlobalInit(cast(Dst), *GVar); return Error::success(); } linkAliasBody(cast(Dst), cast(Src)); return Error::success(); } /// Insert all of the named MDNodes in Src into the Dest module. void IRLinker::linkNamedMDNodes() { const NamedMDNode *SrcModFlags = SrcM->getModuleFlagsMetadata(); for (const NamedMDNode &NMD : SrcM->named_metadata()) { // Don't link module flags here. Do them separately. if (&NMD == SrcModFlags) continue; NamedMDNode *DestNMD = DstM.getOrInsertNamedMetadata(NMD.getName()); // Add Src elements into Dest node. for (const MDNode *Op : NMD.operands()) DestNMD->addOperand(Mapper.mapMDNode(*Op)); } } /// Merge the linker flags in Src into the Dest module. Error IRLinker::linkModuleFlagsMetadata() { // If the source module has no module flags, we are done. const NamedMDNode *SrcModFlags = SrcM->getModuleFlagsMetadata(); if (!SrcModFlags) return Error::success(); // If the destination module doesn't have module flags yet, then just copy // over the source module's flags. NamedMDNode *DstModFlags = DstM.getOrInsertModuleFlagsMetadata(); if (DstModFlags->getNumOperands() == 0) { for (unsigned I = 0, E = SrcModFlags->getNumOperands(); I != E; ++I) DstModFlags->addOperand(SrcModFlags->getOperand(I)); return Error::success(); } // First build a map of the existing module flags and requirements. DenseMap> Flags; SmallSetVector Requirements; for (unsigned I = 0, E = DstModFlags->getNumOperands(); I != E; ++I) { MDNode *Op = DstModFlags->getOperand(I); ConstantInt *Behavior = mdconst::extract(Op->getOperand(0)); MDString *ID = cast(Op->getOperand(1)); if (Behavior->getZExtValue() == Module::Require) { Requirements.insert(cast(Op->getOperand(2))); } else { Flags[ID] = std::make_pair(Op, I); } } // Merge in the flags from the source module, and also collect its set of // requirements. for (unsigned I = 0, E = SrcModFlags->getNumOperands(); I != E; ++I) { MDNode *SrcOp = SrcModFlags->getOperand(I); ConstantInt *SrcBehavior = mdconst::extract(SrcOp->getOperand(0)); MDString *ID = cast(SrcOp->getOperand(1)); MDNode *DstOp; unsigned DstIndex; std::tie(DstOp, DstIndex) = Flags.lookup(ID); unsigned SrcBehaviorValue = SrcBehavior->getZExtValue(); // If this is a requirement, add it and continue. if (SrcBehaviorValue == Module::Require) { // If the destination module does not already have this requirement, add // it. if (Requirements.insert(cast(SrcOp->getOperand(2)))) { DstModFlags->addOperand(SrcOp); } continue; } // If there is no existing flag with this ID, just add it. if (!DstOp) { Flags[ID] = std::make_pair(SrcOp, DstModFlags->getNumOperands()); DstModFlags->addOperand(SrcOp); continue; } // Otherwise, perform a merge. ConstantInt *DstBehavior = mdconst::extract(DstOp->getOperand(0)); unsigned DstBehaviorValue = DstBehavior->getZExtValue(); // If either flag has override behavior, handle it first. if (DstBehaviorValue == Module::Override) { // Diagnose inconsistent flags which both have override behavior. if (SrcBehaviorValue == Module::Override && SrcOp->getOperand(2) != DstOp->getOperand(2)) return stringErr("linking module flags '" + ID->getString() + "': IDs have conflicting override values"); continue; } else if (SrcBehaviorValue == Module::Override) { // Update the destination flag to that of the source. DstModFlags->setOperand(DstIndex, SrcOp); Flags[ID].first = SrcOp; continue; } // Diagnose inconsistent merge behavior types. if (SrcBehaviorValue != DstBehaviorValue) return stringErr("linking module flags '" + ID->getString() + "': IDs have conflicting behaviors"); auto replaceDstValue = [&](MDNode *New) { Metadata *FlagOps[] = {DstOp->getOperand(0), ID, New}; MDNode *Flag = MDNode::get(DstM.getContext(), FlagOps); DstModFlags->setOperand(DstIndex, Flag); Flags[ID].first = Flag; }; // Perform the merge for standard behavior types. switch (SrcBehaviorValue) { case Module::Require: case Module::Override: llvm_unreachable("not possible"); case Module::Error: { // Emit an error if the values differ. if (SrcOp->getOperand(2) != DstOp->getOperand(2)) return stringErr("linking module flags '" + ID->getString() + "': IDs have conflicting values"); continue; } case Module::Warning: { // Emit a warning if the values differ. if (SrcOp->getOperand(2) != DstOp->getOperand(2)) { emitWarning("linking module flags '" + ID->getString() + "': IDs have conflicting values"); } continue; } case Module::Append: { MDNode *DstValue = cast(DstOp->getOperand(2)); MDNode *SrcValue = cast(SrcOp->getOperand(2)); SmallVector MDs; MDs.reserve(DstValue->getNumOperands() + SrcValue->getNumOperands()); MDs.append(DstValue->op_begin(), DstValue->op_end()); MDs.append(SrcValue->op_begin(), SrcValue->op_end()); replaceDstValue(MDNode::get(DstM.getContext(), MDs)); break; } case Module::AppendUnique: { SmallSetVector Elts; MDNode *DstValue = cast(DstOp->getOperand(2)); MDNode *SrcValue = cast(SrcOp->getOperand(2)); Elts.insert(DstValue->op_begin(), DstValue->op_end()); Elts.insert(SrcValue->op_begin(), SrcValue->op_end()); replaceDstValue(MDNode::get(DstM.getContext(), makeArrayRef(Elts.begin(), Elts.end()))); break; } } } // Check all of the requirements. for (unsigned I = 0, E = Requirements.size(); I != E; ++I) { MDNode *Requirement = Requirements[I]; MDString *Flag = cast(Requirement->getOperand(0)); Metadata *ReqValue = Requirement->getOperand(1); MDNode *Op = Flags[Flag].first; if (!Op || Op->getOperand(2) != ReqValue) return stringErr("linking module flags '" + Flag->getString() + "': does not have the required value"); } return Error::success(); } // This function returns true if the triples match. static bool triplesMatch(const Triple &T0, const Triple &T1) { // If vendor is apple, ignore the version number. if (T0.getVendor() == Triple::Apple) return T0.getArch() == T1.getArch() && T0.getSubArch() == T1.getSubArch() && T0.getVendor() == T1.getVendor() && T0.getOS() == T1.getOS(); return T0 == T1; } // This function returns the merged triple. static std::string mergeTriples(const Triple &SrcTriple, const Triple &DstTriple) { // If vendor is apple, pick the triple with the larger version number. if (SrcTriple.getVendor() == Triple::Apple) if (DstTriple.isOSVersionLT(SrcTriple)) return SrcTriple.str(); return DstTriple.str(); } Error IRLinker::run() { // Ensure metadata materialized before value mapping. if (SrcM->getMaterializer()) if (std::error_code EC = SrcM->getMaterializer()->materializeMetadata()) return errorCodeToError(EC); // Inherit the target data from the source module if the destination module // doesn't have one already. if (DstM.getDataLayout().isDefault()) DstM.setDataLayout(SrcM->getDataLayout()); if (SrcM->getDataLayout() != DstM.getDataLayout()) { emitWarning("Linking two modules of different data layouts: '" + SrcM->getModuleIdentifier() + "' is '" + SrcM->getDataLayoutStr() + "' whereas '" + DstM.getModuleIdentifier() + "' is '" + DstM.getDataLayoutStr() + "'\n"); } // Copy the target triple from the source to dest if the dest's is empty. if (DstM.getTargetTriple().empty() && !SrcM->getTargetTriple().empty()) DstM.setTargetTriple(SrcM->getTargetTriple()); Triple SrcTriple(SrcM->getTargetTriple()), DstTriple(DstM.getTargetTriple()); if (!SrcM->getTargetTriple().empty() && !triplesMatch(SrcTriple, DstTriple)) emitWarning("Linking two modules of different target triples: " + SrcM->getModuleIdentifier() + "' is '" + SrcM->getTargetTriple() + "' whereas '" + DstM.getModuleIdentifier() + "' is '" + DstM.getTargetTriple() + "'\n"); DstM.setTargetTriple(mergeTriples(SrcTriple, DstTriple)); // Append the module inline asm string. if (!SrcM->getModuleInlineAsm().empty()) { if (DstM.getModuleInlineAsm().empty()) DstM.setModuleInlineAsm(SrcM->getModuleInlineAsm()); else DstM.setModuleInlineAsm(DstM.getModuleInlineAsm() + "\n" + SrcM->getModuleInlineAsm()); } // Loop over all of the linked values to compute type mappings. computeTypeMapping(); std::reverse(Worklist.begin(), Worklist.end()); while (!Worklist.empty()) { GlobalValue *GV = Worklist.back(); Worklist.pop_back(); // Already mapped. if (ValueMap.find(GV) != ValueMap.end() || AliasValueMap.find(GV) != AliasValueMap.end()) continue; assert(!GV->isDeclaration()); Mapper.mapValue(*GV); if (FoundError) return std::move(*FoundError); } // Note that we are done linking global value bodies. This prevents // metadata linking from creating new references. DoneLinkingBodies = true; Mapper.addFlags(RF_NullMapMissingGlobalValues); // Remap all of the named MDNodes in Src into the DstM module. We do this // after linking GlobalValues so that MDNodes that reference GlobalValues // are properly remapped. linkNamedMDNodes(); // Merge the module flags into the DstM module. return linkModuleFlagsMetadata(); } IRMover::StructTypeKeyInfo::KeyTy::KeyTy(ArrayRef E, bool P) : ETypes(E), IsPacked(P) {} IRMover::StructTypeKeyInfo::KeyTy::KeyTy(const StructType *ST) : ETypes(ST->elements()), IsPacked(ST->isPacked()) {} bool IRMover::StructTypeKeyInfo::KeyTy::operator==(const KeyTy &That) const { return IsPacked == That.IsPacked && ETypes == That.ETypes; } bool IRMover::StructTypeKeyInfo::KeyTy::operator!=(const KeyTy &That) const { return !this->operator==(That); } StructType *IRMover::StructTypeKeyInfo::getEmptyKey() { return DenseMapInfo::getEmptyKey(); } StructType *IRMover::StructTypeKeyInfo::getTombstoneKey() { return DenseMapInfo::getTombstoneKey(); } unsigned IRMover::StructTypeKeyInfo::getHashValue(const KeyTy &Key) { return hash_combine(hash_combine_range(Key.ETypes.begin(), Key.ETypes.end()), Key.IsPacked); } unsigned IRMover::StructTypeKeyInfo::getHashValue(const StructType *ST) { return getHashValue(KeyTy(ST)); } bool IRMover::StructTypeKeyInfo::isEqual(const KeyTy &LHS, const StructType *RHS) { if (RHS == getEmptyKey() || RHS == getTombstoneKey()) return false; return LHS == KeyTy(RHS); } bool IRMover::StructTypeKeyInfo::isEqual(const StructType *LHS, const StructType *RHS) { if (RHS == getEmptyKey() || RHS == getTombstoneKey()) return LHS == RHS; return KeyTy(LHS) == KeyTy(RHS); } void IRMover::IdentifiedStructTypeSet::addNonOpaque(StructType *Ty) { assert(!Ty->isOpaque()); NonOpaqueStructTypes.insert(Ty); } void IRMover::IdentifiedStructTypeSet::switchToNonOpaque(StructType *Ty) { assert(!Ty->isOpaque()); NonOpaqueStructTypes.insert(Ty); bool Removed = OpaqueStructTypes.erase(Ty); (void)Removed; assert(Removed); } void IRMover::IdentifiedStructTypeSet::addOpaque(StructType *Ty) { assert(Ty->isOpaque()); OpaqueStructTypes.insert(Ty); } StructType * IRMover::IdentifiedStructTypeSet::findNonOpaque(ArrayRef ETypes, bool IsPacked) { IRMover::StructTypeKeyInfo::KeyTy Key(ETypes, IsPacked); auto I = NonOpaqueStructTypes.find_as(Key); return I == NonOpaqueStructTypes.end() ? nullptr : *I; } bool IRMover::IdentifiedStructTypeSet::hasType(StructType *Ty) { if (Ty->isOpaque()) return OpaqueStructTypes.count(Ty); auto I = NonOpaqueStructTypes.find(Ty); return I == NonOpaqueStructTypes.end() ? false : *I == Ty; } IRMover::IRMover(Module &M) : Composite(M) { TypeFinder StructTypes; - StructTypes.run(M, true); + StructTypes.run(M, /* OnlyNamed */ false); for (StructType *Ty : StructTypes) { if (Ty->isOpaque()) IdentifiedStructTypes.addOpaque(Ty); else IdentifiedStructTypes.addNonOpaque(Ty); + } + // Self-map metadatas in the destination module. This is needed when + // DebugTypeODRUniquing is enabled on the LLVMContext, since metadata in the + // destination module may be reached from the source module. + for (auto *MD : StructTypes.getVisitedMetadata()) { + SharedMDs[MD].reset(const_cast(MD)); } } Error IRMover::move( std::unique_ptr Src, ArrayRef ValuesToLink, std::function AddLazyFor) { IRLinker TheIRLinker(Composite, SharedMDs, IdentifiedStructTypes, std::move(Src), ValuesToLink, std::move(AddLazyFor)); Error E = TheIRLinker.run(); Composite.dropTriviallyDeadConstantArrays(); return E; } Index: vendor/llvm/dist/lib/Support/Unix/Signals.inc =================================================================== --- vendor/llvm/dist/lib/Support/Unix/Signals.inc (revision 309151) +++ vendor/llvm/dist/lib/Support/Unix/Signals.inc (revision 309152) @@ -1,497 +1,497 @@ //===- Signals.cpp - Generic Unix Signals Implementation -----*- 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 some helpful functions for dealing with the possibility of // Unix signals occurring while your program is running. // //===----------------------------------------------------------------------===// #include "Unix.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Format.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Program.h" #include "llvm/Support/UniqueLock.h" #include "llvm/Support/raw_ostream.h" #include #include #if HAVE_EXECINFO_H # include // For backtrace(). #endif #if HAVE_SIGNAL_H #include #endif #if HAVE_SYS_STAT_H #include #endif #if HAVE_CXXABI_H #include #endif #if HAVE_DLFCN_H #include #endif #if HAVE_MACH_MACH_H #include #endif #if HAVE_LINK_H #include #endif #if HAVE_UNWIND_BACKTRACE // FIXME: We should be able to use for any target that has an // _Unwind_Backtrace function, but on FreeBSD the configure test passes // despite the function not existing, and on Android, conflicts // with . #ifdef __GLIBC__ #include #else #undef HAVE_UNWIND_BACKTRACE #endif #endif using namespace llvm; static RETSIGTYPE SignalHandler(int Sig); // defined below. static ManagedStatic > SignalsMutex; /// InterruptFunction - The function to call if ctrl-c is pressed. static void (*InterruptFunction)() = nullptr; static ManagedStatic> FilesToRemove; static StringRef Argv0; // IntSigs - Signals that represent requested termination. There's no bug // or failure, or if there is, it's not our direct responsibility. For whatever // reason, our continued execution is no longer desirable. static const int IntSigs[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 }; // KillSigs - Signals that represent that we have a bug, and our prompt // termination has been ordered. static const int KillSigs[] = { SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGQUIT #ifdef SIGSYS , SIGSYS #endif #ifdef SIGXCPU , SIGXCPU #endif #ifdef SIGXFSZ , SIGXFSZ #endif #ifdef SIGEMT , SIGEMT #endif }; static unsigned NumRegisteredSignals = 0; static struct { struct sigaction SA; int SigNo; } RegisteredSignalInfo[array_lengthof(IntSigs) + array_lengthof(KillSigs)]; static void RegisterHandler(int Signal) { assert(NumRegisteredSignals < array_lengthof(RegisteredSignalInfo) && "Out of space for signal handlers!"); struct sigaction NewHandler; NewHandler.sa_handler = SignalHandler; NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK; sigemptyset(&NewHandler.sa_mask); // Install the new handler, save the old one in RegisteredSignalInfo. sigaction(Signal, &NewHandler, &RegisteredSignalInfo[NumRegisteredSignals].SA); RegisteredSignalInfo[NumRegisteredSignals].SigNo = Signal; ++NumRegisteredSignals; } #if defined(HAVE_SIGALTSTACK) // Hold onto the old alternate signal stack so that it's not reported as a leak. // We don't make any attempt to remove our alt signal stack if we remove our // signal handlers; that can't be done reliably if someone else is also trying // to do the same thing. static stack_t OldAltStack; static void CreateSigAltStack() { const size_t AltStackSize = MINSIGSTKSZ + 8192; // If we're executing on the alternate stack, or we already have an alternate // signal stack that we're happy with, there's nothing for us to do. Don't // reduce the size, some other part of the process might need a larger stack // than we do. if (sigaltstack(nullptr, &OldAltStack) != 0 || OldAltStack.ss_flags & SS_ONSTACK || (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize)) return; stack_t AltStack = {}; AltStack.ss_sp = reinterpret_cast(malloc(AltStackSize)); AltStack.ss_size = AltStackSize; if (sigaltstack(&AltStack, &OldAltStack) != 0) free(AltStack.ss_sp); } #else static void CreateSigAltStack() {} #endif static void RegisterHandlers() { // We need to dereference the signals mutex during handler registration so // that we force its construction. This is to prevent the first use being // during handling an actual signal because you can't safely call new in a // signal handler. *SignalsMutex; // If the handlers are already registered, we're done. if (NumRegisteredSignals != 0) return; // Create an alternate stack for signal handling. This is necessary for us to // be able to reliably handle signals due to stack overflow. CreateSigAltStack(); for (auto S : IntSigs) RegisterHandler(S); for (auto S : KillSigs) RegisterHandler(S); } static void UnregisterHandlers() { // Restore all of the signal handlers to how they were before we showed up. for (unsigned i = 0, e = NumRegisteredSignals; i != e; ++i) sigaction(RegisteredSignalInfo[i].SigNo, &RegisteredSignalInfo[i].SA, nullptr); NumRegisteredSignals = 0; } /// RemoveFilesToRemove - Process the FilesToRemove list. This function /// should be called with the SignalsMutex lock held. /// NB: This must be an async signal safe function. It cannot allocate or free /// memory, even in debug builds. static void RemoveFilesToRemove() { // Avoid constructing ManagedStatic in the signal handler. // If FilesToRemove is not constructed, there are no files to remove. if (!FilesToRemove.isConstructed()) return; // We avoid iterators in case of debug iterators that allocate or release // memory. std::vector& FilesToRemoveRef = *FilesToRemove; for (unsigned i = 0, e = FilesToRemoveRef.size(); i != e; ++i) { const char *path = FilesToRemoveRef[i].c_str(); // Get the status so we can determine if it's a file or directory. If we // can't stat the file, ignore it. struct stat buf; if (stat(path, &buf) != 0) continue; // If this is not a regular file, ignore it. We want to prevent removal of // special files like /dev/null, even if the compiler is being run with the // super-user permissions. if (!S_ISREG(buf.st_mode)) continue; // Otherwise, remove the file. We ignore any errors here as there is nothing // else we can do. unlink(path); } } // SignalHandler - The signal handler that runs. static RETSIGTYPE SignalHandler(int Sig) { // Restore the signal behavior to default, so that the program actually // crashes when we return and the signal reissues. This also ensures that if // we crash in our signal handler that the program will terminate immediately // instead of recursing in the signal handler. UnregisterHandlers(); // Unmask all potentially blocked kill signals. sigset_t SigMask; sigfillset(&SigMask); sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); { unique_lock> Guard(*SignalsMutex); RemoveFilesToRemove(); if (std::find(std::begin(IntSigs), std::end(IntSigs), Sig) != std::end(IntSigs)) { if (InterruptFunction) { void (*IF)() = InterruptFunction; Guard.unlock(); InterruptFunction = nullptr; IF(); // run the interrupt function. return; } Guard.unlock(); raise(Sig); // Execute the default handler. return; } } // Otherwise if it is a fault (like SEGV) run any handler. llvm::sys::RunSignalHandlers(); #ifdef __s390__ // On S/390, certain signals are delivered with PSW Address pointing to // *after* the faulting instruction. Simply returning from the signal // handler would continue execution after that point, instead of // re-raising the signal. Raise the signal manually in those cases. if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP) raise(Sig); #endif } void llvm::sys::RunInterruptHandlers() { sys::SmartScopedLock Guard(*SignalsMutex); RemoveFilesToRemove(); } void llvm::sys::SetInterruptFunction(void (*IF)()) { { sys::SmartScopedLock Guard(*SignalsMutex); InterruptFunction = IF; } RegisterHandlers(); } // RemoveFileOnSignal - The public API bool llvm::sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { { sys::SmartScopedLock Guard(*SignalsMutex); FilesToRemove->push_back(Filename); } RegisterHandlers(); return false; } // DontRemoveFileOnSignal - The public API void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) { sys::SmartScopedLock Guard(*SignalsMutex); std::vector::reverse_iterator RI = std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); std::vector::iterator I = FilesToRemove->end(); if (RI != FilesToRemove->rend()) I = FilesToRemove->erase(RI.base()-1); } /// AddSignalHandler - Add a function to be called when a signal is delivered /// to the process. The handler can have a cookie passed to it to identify /// what instance of the handler it is. void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); RegisterHandlers(); } #if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) && HAVE_LINK_H && \ (defined(__linux__) || defined(__FreeBSD__) || \ defined(__FreeBSD_kernel__) || defined(__NetBSD__)) struct DlIteratePhdrData { void **StackTrace; int depth; bool first; const char **modules; intptr_t *offsets; const char *main_exec_name; }; static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { DlIteratePhdrData *data = (DlIteratePhdrData*)arg; const char *name = data->first ? data->main_exec_name : info->dlpi_name; data->first = false; for (int i = 0; i < info->dlpi_phnum; i++) { const auto *phdr = &info->dlpi_phdr[i]; if (phdr->p_type != PT_LOAD) continue; intptr_t beg = info->dlpi_addr + phdr->p_vaddr; intptr_t end = beg + phdr->p_memsz; for (int j = 0; j < data->depth; j++) { if (data->modules[j]) continue; intptr_t addr = (intptr_t)data->StackTrace[j]; if (beg <= addr && addr < end) { data->modules[j] = name; data->offsets[j] = addr - info->dlpi_addr; } } } return 0; } /// If this is an ELF platform, we can find all loaded modules and their virtual /// addresses with dl_iterate_phdr. static bool findModulesAndOffsets(void **StackTrace, int Depth, const char **Modules, intptr_t *Offsets, const char *MainExecutableName, StringSaver &StrPool) { DlIteratePhdrData data = {StackTrace, Depth, true, Modules, Offsets, MainExecutableName}; dl_iterate_phdr(dl_iterate_phdr_cb, &data); return true; } #else /// This platform does not have dl_iterate_phdr, so we do not yet know how to /// find all loaded DSOs. static bool findModulesAndOffsets(void **StackTrace, int Depth, const char **Modules, intptr_t *Offsets, const char *MainExecutableName, StringSaver &StrPool) { return false; } #endif // defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) && ... #if defined(ENABLE_BACKTRACES) && defined(HAVE_UNWIND_BACKTRACE) static int unwindBacktrace(void **StackTrace, int MaxEntries) { if (MaxEntries < 0) return 0; // Skip the first frame ('unwindBacktrace' itself). int Entries = -1; auto HandleFrame = [&](_Unwind_Context *Context) -> _Unwind_Reason_Code { // Apparently we need to detect reaching the end of the stack ourselves. void *IP = (void *)_Unwind_GetIP(Context); if (!IP) return _URC_END_OF_STACK; assert(Entries < MaxEntries && "recursively called after END_OF_STACK?"); if (Entries >= 0) StackTrace[Entries] = IP; if (++Entries == MaxEntries) return _URC_END_OF_STACK; return _URC_NO_REASON; }; _Unwind_Backtrace( [](_Unwind_Context *Context, void *Handler) { return (*static_cast(Handler))(Context); }, static_cast(&HandleFrame)); return std::max(Entries, 0); } #endif // PrintStackTrace - In the case of a program crash or fault, print out a stack // trace so that the user has an indication of why and where we died. // // On glibc systems we have the 'backtrace' function, which works nicely, but // doesn't demangle symbols. void llvm::sys::PrintStackTrace(raw_ostream &OS) { #if defined(ENABLE_BACKTRACES) static void *StackTrace[256]; int depth = 0; #if defined(HAVE_BACKTRACE) // Use backtrace() to output a backtrace on Linux systems with glibc. if (!depth) depth = backtrace(StackTrace, static_cast(array_lengthof(StackTrace))); #endif #if defined(HAVE_UNWIND_BACKTRACE) // Try _Unwind_Backtrace() if backtrace() failed. if (!depth) depth = unwindBacktrace(StackTrace, static_cast(array_lengthof(StackTrace))); #endif if (!depth) return; if (printSymbolizedStackTrace(Argv0, StackTrace, depth, OS)) return; -#if HAVE_DLFCN_H && __GNUG__ +#if HAVE_DLFCN_H && __GNUG__ && !defined(__CYGWIN__) int width = 0; for (int i = 0; i < depth; ++i) { Dl_info dlinfo; dladdr(StackTrace[i], &dlinfo); const char* name = strrchr(dlinfo.dli_fname, '/'); int nwidth; if (!name) nwidth = strlen(dlinfo.dli_fname); else nwidth = strlen(name) - 1; if (nwidth > width) width = nwidth; } for (int i = 0; i < depth; ++i) { Dl_info dlinfo; dladdr(StackTrace[i], &dlinfo); OS << format("%-2d", i); const char* name = strrchr(dlinfo.dli_fname, '/'); if (!name) OS << format(" %-*s", width, dlinfo.dli_fname); else OS << format(" %-*s", width, name+1); OS << format(" %#0*lx", (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]); if (dlinfo.dli_sname != nullptr) { OS << ' '; # if HAVE_CXXABI_H int res; char* d = abi::__cxa_demangle(dlinfo.dli_sname, nullptr, nullptr, &res); # else char* d = NULL; # endif if (!d) OS << dlinfo.dli_sname; else OS << d; free(d); // FIXME: When we move to C++11, use %t length modifier. It's not in // C++03 and causes gcc to issue warnings. Losing the upper 32 bits of // the stack offset for a stack dump isn't likely to cause any problems. OS << format(" + %u",(unsigned)((char*)StackTrace[i]- (char*)dlinfo.dli_saddr)); } OS << '\n'; } #elif defined(HAVE_BACKTRACE) backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); #endif #endif } static void PrintStackTraceSignalHandler(void *) { PrintStackTrace(llvm::errs()); } void llvm::sys::DisableSystemDialogsOnCrash() {} /// PrintStackTraceOnErrorSignal - When an error signal (such as SIGABRT or /// SIGSEGV) is delivered to the process, print a stack trace and then exit. void llvm::sys::PrintStackTraceOnErrorSignal(StringRef Argv0, bool DisableCrashReporting) { ::Argv0 = Argv0; AddSignalHandler(PrintStackTraceSignalHandler, nullptr); #if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES) // Environment variable to disable any kind of crash dialog. if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) { mach_port_t self = mach_task_self(); exception_mask_t mask = EXC_MASK_CRASH; kern_return_t ret = task_set_exception_ports(self, mask, MACH_PORT_NULL, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, THREAD_STATE_NONE); (void)ret; } #endif } Index: vendor/llvm/dist/lib/Target/ARM/ARMInstrThumb2.td =================================================================== --- vendor/llvm/dist/lib/Target/ARM/ARMInstrThumb2.td (revision 309151) +++ vendor/llvm/dist/lib/Target/ARM/ARMInstrThumb2.td (revision 309152) @@ -1,4828 +1,4832 @@ //===-- ARMInstrThumb2.td - Thumb2 support for ARM ---------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file describes the Thumb2 instruction set. // //===----------------------------------------------------------------------===// // IT block predicate field def it_pred_asmoperand : AsmOperandClass { let Name = "ITCondCode"; let ParserMethod = "parseITCondCode"; } def it_pred : Operand { let PrintMethod = "printMandatoryPredicateOperand"; let ParserMatchClass = it_pred_asmoperand; } // IT block condition mask def it_mask_asmoperand : AsmOperandClass { let Name = "ITMask"; } def it_mask : Operand { let PrintMethod = "printThumbITMask"; let ParserMatchClass = it_mask_asmoperand; } // t2_shift_imm: An integer that encodes a shift amount and the type of shift // (asr or lsl). The 6-bit immediate encodes as: // {5} 0 ==> lsl // 1 asr // {4-0} imm5 shift amount. // asr #32 not allowed def t2_shift_imm : Operand { let PrintMethod = "printShiftImmOperand"; let ParserMatchClass = ShifterImmAsmOperand; let DecoderMethod = "DecodeT2ShifterImmOperand"; } // Shifted operands. No register controlled shifts for Thumb2. // Note: We do not support rrx shifted operands yet. def t2_so_reg : Operand, // reg imm ComplexPattern { let EncoderMethod = "getT2SORegOpValue"; let PrintMethod = "printT2SOOperand"; let DecoderMethod = "DecodeSORegImmOperand"; let ParserMatchClass = ShiftedImmAsmOperand; let MIOperandInfo = (ops rGPR, i32imm); } // t2_so_imm_not_XFORM - Return the complement of a t2_so_imm value def t2_so_imm_not_XFORM : SDNodeXFormgetTargetConstant(~((uint32_t)N->getZExtValue()), SDLoc(N), MVT::i32); }]>; // t2_so_imm_neg_XFORM - Return the negation of a t2_so_imm value def t2_so_imm_neg_XFORM : SDNodeXFormgetTargetConstant(-((int)N->getZExtValue()), SDLoc(N), MVT::i32); }]>; // so_imm_notSext_XFORM - Return a so_imm value packed into the format // described for so_imm_notSext def below, with sign extension from 16 // bits. def t2_so_imm_notSext16_XFORM : SDNodeXFormgetAPIntValue(); unsigned N16bitSignExt = apIntN.trunc(16).sext(32).getZExtValue(); return CurDAG->getTargetConstant(~N16bitSignExt, SDLoc(N), MVT::i32); }]>; // t2_so_imm - Match a 32-bit immediate operand, which is an // 8-bit immediate rotated by an arbitrary number of bits, or an 8-bit // immediate splatted into multiple bytes of the word. def t2_so_imm_asmoperand : ImmAsmOperand { let Name = "T2SOImm"; } def t2_so_imm : Operand, ImmLeaf { let ParserMatchClass = t2_so_imm_asmoperand; let EncoderMethod = "getT2SOImmOpValue"; let DecoderMethod = "DecodeT2SOImm"; } // t2_so_imm_not - Match an immediate that is a complement // of a t2_so_imm. // Note: this pattern doesn't require an encoder method and such, as it's // only used on aliases (Pat<> and InstAlias<>). The actual encoding // is handled by the destination instructions, which use t2_so_imm. def t2_so_imm_not_asmoperand : AsmOperandClass { let Name = "T2SOImmNot"; } def t2_so_imm_not : Operand, PatLeaf<(imm), [{ return ARM_AM::getT2SOImmVal(~((uint32_t)N->getZExtValue())) != -1; }], t2_so_imm_not_XFORM> { let ParserMatchClass = t2_so_imm_not_asmoperand; } // t2_so_imm_notSext - match an immediate that is a complement of a t2_so_imm // if the upper 16 bits are zero. def t2_so_imm_notSext : Operand, PatLeaf<(imm), [{ APInt apIntN = N->getAPIntValue(); if (!apIntN.isIntN(16)) return false; unsigned N16bitSignExt = apIntN.trunc(16).sext(32).getZExtValue(); return ARM_AM::getT2SOImmVal(~N16bitSignExt) != -1; }], t2_so_imm_notSext16_XFORM> { let ParserMatchClass = t2_so_imm_not_asmoperand; } // t2_so_imm_neg - Match an immediate that is a negation of a t2_so_imm. def t2_so_imm_neg_asmoperand : AsmOperandClass { let Name = "T2SOImmNeg"; } def t2_so_imm_neg : Operand, PatLeaf<(imm), [{ int64_t Value = -(int)N->getZExtValue(); return Value && ARM_AM::getT2SOImmVal(Value) != -1; }], t2_so_imm_neg_XFORM> { let ParserMatchClass = t2_so_imm_neg_asmoperand; } /// imm0_4095 predicate - True if the 32-bit immediate is in the range [0.4095]. def imm0_4095_asmoperand: ImmAsmOperand { let Name = "Imm0_4095"; } def imm0_4095 : Operand, ImmLeaf= 0 && Imm < 4096; }]> { let ParserMatchClass = imm0_4095_asmoperand; } def imm0_4095_neg_asmoperand: AsmOperandClass { let Name = "Imm0_4095Neg"; } def imm0_4095_neg : Operand, PatLeaf<(i32 imm), [{ return (uint32_t)(-N->getZExtValue()) < 4096; }], imm_neg_XFORM> { let ParserMatchClass = imm0_4095_neg_asmoperand; } def imm1_255_neg : PatLeaf<(i32 imm), [{ uint32_t Val = -N->getZExtValue(); return (Val > 0 && Val < 255); }], imm_neg_XFORM>; def imm0_255_not : PatLeaf<(i32 imm), [{ return (uint32_t)(~N->getZExtValue()) < 255; }], imm_comp_XFORM>; def lo5AllOne : PatLeaf<(i32 imm), [{ // Returns true if all low 5-bits are 1. return (((uint32_t)N->getZExtValue()) & 0x1FUL) == 0x1FUL; }]>; // Define Thumb2 specific addressing modes. // t2addrmode_imm12 := reg + imm12 def t2addrmode_imm12_asmoperand : AsmOperandClass {let Name="MemUImm12Offset";} def t2addrmode_imm12 : MemOperand, ComplexPattern { let PrintMethod = "printAddrModeImm12Operand"; let EncoderMethod = "getAddrModeImm12OpValue"; let DecoderMethod = "DecodeT2AddrModeImm12"; let ParserMatchClass = t2addrmode_imm12_asmoperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } // t2ldrlabel := imm12 def t2ldrlabel : Operand { let EncoderMethod = "getAddrModeImm12OpValue"; let PrintMethod = "printThumbLdrLabelOperand"; } def t2ldr_pcrel_imm12_asmoperand : AsmOperandClass {let Name = "MemPCRelImm12";} def t2ldr_pcrel_imm12 : Operand { let ParserMatchClass = t2ldr_pcrel_imm12_asmoperand; // used for assembler pseudo instruction and maps to t2ldrlabel, so // doesn't need encoder or print methods of its own. } // ADR instruction labels. def t2adrlabel : Operand { let EncoderMethod = "getT2AdrLabelOpValue"; let PrintMethod = "printAdrLabelOperand<0>"; } // t2addrmode_posimm8 := reg + imm8 def MemPosImm8OffsetAsmOperand : AsmOperandClass {let Name="MemPosImm8Offset";} def t2addrmode_posimm8 : MemOperand { let PrintMethod = "printT2AddrModeImm8Operand"; let EncoderMethod = "getT2AddrModeImm8OpValue"; let DecoderMethod = "DecodeT2AddrModeImm8"; let ParserMatchClass = MemPosImm8OffsetAsmOperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } // t2addrmode_negimm8 := reg - imm8 def MemNegImm8OffsetAsmOperand : AsmOperandClass {let Name="MemNegImm8Offset";} def t2addrmode_negimm8 : MemOperand, ComplexPattern { let PrintMethod = "printT2AddrModeImm8Operand"; let EncoderMethod = "getT2AddrModeImm8OpValue"; let DecoderMethod = "DecodeT2AddrModeImm8"; let ParserMatchClass = MemNegImm8OffsetAsmOperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } // t2addrmode_imm8 := reg +/- imm8 def MemImm8OffsetAsmOperand : AsmOperandClass { let Name = "MemImm8Offset"; } class T2AddrMode_Imm8 : MemOperand, ComplexPattern { let EncoderMethod = "getT2AddrModeImm8OpValue"; let DecoderMethod = "DecodeT2AddrModeImm8"; let ParserMatchClass = MemImm8OffsetAsmOperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } def t2addrmode_imm8 : T2AddrMode_Imm8 { let PrintMethod = "printT2AddrModeImm8Operand"; } def t2addrmode_imm8_pre : T2AddrMode_Imm8 { let PrintMethod = "printT2AddrModeImm8Operand"; } def t2am_imm8_offset : MemOperand, ComplexPattern { let PrintMethod = "printT2AddrModeImm8OffsetOperand"; let EncoderMethod = "getT2AddrModeImm8OffsetOpValue"; let DecoderMethod = "DecodeT2Imm8"; } // t2addrmode_imm8s4 := reg +/- (imm8 << 2) def MemImm8s4OffsetAsmOperand : AsmOperandClass {let Name = "MemImm8s4Offset";} class T2AddrMode_Imm8s4 : MemOperand { let EncoderMethod = "getT2AddrModeImm8s4OpValue"; let DecoderMethod = "DecodeT2AddrModeImm8s4"; let ParserMatchClass = MemImm8s4OffsetAsmOperand; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } def t2addrmode_imm8s4 : T2AddrMode_Imm8s4 { let PrintMethod = "printT2AddrModeImm8s4Operand"; } def t2addrmode_imm8s4_pre : T2AddrMode_Imm8s4 { let PrintMethod = "printT2AddrModeImm8s4Operand"; } def t2am_imm8s4_offset_asmoperand : AsmOperandClass { let Name = "Imm8s4"; } def t2am_imm8s4_offset : MemOperand { let PrintMethod = "printT2AddrModeImm8s4OffsetOperand"; let EncoderMethod = "getT2Imm8s4OpValue"; let DecoderMethod = "DecodeT2Imm8S4"; } // t2addrmode_imm0_1020s4 := reg + (imm8 << 2) def MemImm0_1020s4OffsetAsmOperand : AsmOperandClass { let Name = "MemImm0_1020s4Offset"; } def t2addrmode_imm0_1020s4 : MemOperand, ComplexPattern { let PrintMethod = "printT2AddrModeImm0_1020s4Operand"; let EncoderMethod = "getT2AddrModeImm0_1020s4OpValue"; let DecoderMethod = "DecodeT2AddrModeImm0_1020s4"; let ParserMatchClass = MemImm0_1020s4OffsetAsmOperand; let MIOperandInfo = (ops GPRnopc:$base, i32imm:$offsimm); } // t2addrmode_so_reg := reg + (reg << imm2) def t2addrmode_so_reg_asmoperand : AsmOperandClass {let Name="T2MemRegOffset";} def t2addrmode_so_reg : MemOperand, ComplexPattern { let PrintMethod = "printT2AddrModeSoRegOperand"; let EncoderMethod = "getT2AddrModeSORegOpValue"; let DecoderMethod = "DecodeT2AddrModeSOReg"; let ParserMatchClass = t2addrmode_so_reg_asmoperand; let MIOperandInfo = (ops GPRnopc:$base, rGPR:$offsreg, i32imm:$offsimm); } // Addresses for the TBB/TBH instructions. def addrmode_tbb_asmoperand : AsmOperandClass { let Name = "MemTBB"; } def addrmode_tbb : MemOperand { let PrintMethod = "printAddrModeTBB"; let ParserMatchClass = addrmode_tbb_asmoperand; let MIOperandInfo = (ops GPR:$Rn, rGPR:$Rm); } def addrmode_tbh_asmoperand : AsmOperandClass { let Name = "MemTBH"; } def addrmode_tbh : MemOperand { let PrintMethod = "printAddrModeTBH"; let ParserMatchClass = addrmode_tbh_asmoperand; let MIOperandInfo = (ops GPR:$Rn, rGPR:$Rm); } //===----------------------------------------------------------------------===// // Multiclass helpers... // class T2OneRegImm pattern> : T2I { bits<4> Rd; bits<12> imm; let Inst{11-8} = Rd; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } class T2sOneRegImm pattern> : T2sI { bits<4> Rd; bits<4> Rn; bits<12> imm; let Inst{11-8} = Rd; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } class T2OneRegCmpImm pattern> : T2I { bits<4> Rn; bits<12> imm; let Inst{19-16} = Rn; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } class T2OneRegShiftedReg pattern> : T2I { bits<4> Rd; bits<12> ShiftedRm; let Inst{11-8} = Rd; let Inst{3-0} = ShiftedRm{3-0}; let Inst{5-4} = ShiftedRm{6-5}; let Inst{14-12} = ShiftedRm{11-9}; let Inst{7-6} = ShiftedRm{8-7}; } class T2sOneRegShiftedReg pattern> : T2sI { bits<4> Rd; bits<12> ShiftedRm; let Inst{11-8} = Rd; let Inst{3-0} = ShiftedRm{3-0}; let Inst{5-4} = ShiftedRm{6-5}; let Inst{14-12} = ShiftedRm{11-9}; let Inst{7-6} = ShiftedRm{8-7}; } class T2OneRegCmpShiftedReg pattern> : T2I { bits<4> Rn; bits<12> ShiftedRm; let Inst{19-16} = Rn; let Inst{3-0} = ShiftedRm{3-0}; let Inst{5-4} = ShiftedRm{6-5}; let Inst{14-12} = ShiftedRm{11-9}; let Inst{7-6} = ShiftedRm{8-7}; } class T2TwoReg pattern> : T2I { bits<4> Rd; bits<4> Rm; let Inst{11-8} = Rd; let Inst{3-0} = Rm; } class T2sTwoReg pattern> : T2sI { bits<4> Rd; bits<4> Rm; let Inst{11-8} = Rd; let Inst{3-0} = Rm; } class T2TwoRegCmp pattern> : T2I { bits<4> Rn; bits<4> Rm; let Inst{19-16} = Rn; let Inst{3-0} = Rm; } class T2TwoRegImm pattern> : T2I { bits<4> Rd; bits<4> Rn; bits<12> imm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } class T2sTwoRegImm pattern> : T2sI { bits<4> Rd; bits<4> Rn; bits<12> imm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; } class T2TwoRegShiftImm pattern> : T2I { bits<4> Rd; bits<4> Rm; bits<5> imm; let Inst{11-8} = Rd; let Inst{3-0} = Rm; let Inst{14-12} = imm{4-2}; let Inst{7-6} = imm{1-0}; } class T2sTwoRegShiftImm pattern> : T2sI { bits<4> Rd; bits<4> Rm; bits<5> imm; let Inst{11-8} = Rd; let Inst{3-0} = Rm; let Inst{14-12} = imm{4-2}; let Inst{7-6} = imm{1-0}; } class T2ThreeReg pattern> : T2I { bits<4> Rd; bits<4> Rn; bits<4> Rm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = Rm; } class T2ThreeRegNoP pattern> : T2XI { bits<4> Rd; bits<4> Rn; bits<4> Rm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = Rm; } class T2sThreeReg pattern> : T2sI { bits<4> Rd; bits<4> Rn; bits<4> Rm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = Rm; } class T2TwoRegShiftedReg pattern> : T2I { bits<4> Rd; bits<4> Rn; bits<12> ShiftedRm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = ShiftedRm{3-0}; let Inst{5-4} = ShiftedRm{6-5}; let Inst{14-12} = ShiftedRm{11-9}; let Inst{7-6} = ShiftedRm{8-7}; } class T2sTwoRegShiftedReg pattern> : T2sI { bits<4> Rd; bits<4> Rn; bits<12> ShiftedRm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = ShiftedRm{3-0}; let Inst{5-4} = ShiftedRm{6-5}; let Inst{14-12} = ShiftedRm{11-9}; let Inst{7-6} = ShiftedRm{8-7}; } class T2FourReg pattern> : T2I { bits<4> Rd; bits<4> Rn; bits<4> Rm; bits<4> Ra; let Inst{19-16} = Rn; let Inst{15-12} = Ra; let Inst{11-8} = Rd; let Inst{3-0} = Rm; } class T2MulLong opc22_20, bits<4> opc7_4, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2I { bits<4> RdLo; bits<4> RdHi; bits<4> Rn; bits<4> Rm; let Inst{31-23} = 0b111110111; let Inst{22-20} = opc22_20; let Inst{19-16} = Rn; let Inst{15-12} = RdLo; let Inst{11-8} = RdHi; let Inst{7-4} = opc7_4; let Inst{3-0} = Rm; } class T2MlaLong opc22_20, bits<4> opc7_4, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2I { bits<4> RdLo; bits<4> RdHi; bits<4> Rn; bits<4> Rm; let Inst{31-23} = 0b111110111; let Inst{22-20} = opc22_20; let Inst{19-16} = Rn; let Inst{15-12} = RdLo; let Inst{11-8} = RdHi; let Inst{7-4} = opc7_4; let Inst{3-0} = Rm; } /// T2I_bin_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a /// binary operation that produces a value. These are predicable and can be /// changed to modify CPSR. multiclass T2I_bin_irs opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, SDPatternOperator opnode, bit Commutable = 0, string wide = ""> { // shifted imm def ri : T2sTwoRegImm< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm), iii, opc, "\t$Rd, $Rn, $imm", [(set rGPR:$Rd, (opnode rGPR:$Rn, t2_so_imm:$imm))]>, Sched<[WriteALU, ReadALU]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{15} = 0; } // register def rr : T2sThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), iir, opc, !strconcat(wide, "\t$Rd, $Rn, $Rm"), [(set rGPR:$Rd, (opnode rGPR:$Rn, rGPR:$Rm))]>, Sched<[WriteALU, ReadALU, ReadALU]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{14-12} = 0b000; // imm3 let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def rs : T2sTwoRegShiftedReg< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm), iis, opc, !strconcat(wide, "\t$Rd, $Rn, $ShiftedRm"), [(set rGPR:$Rd, (opnode rGPR:$Rn, t2_so_reg:$ShiftedRm))]>, Sched<[WriteALUsi, ReadALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; } // Assembly aliases for optional destination operand when it's the same // as the source operand. def : t2InstAlias(NAME#"ri") rGPR:$Rdn, rGPR:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias(NAME#"rr") rGPR:$Rdn, rGPR:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias(NAME#"rs") rGPR:$Rdn, rGPR:$Rdn, t2_so_reg:$shift, pred:$p, cc_out:$s)>; } /// T2I_bin_w_irs - Same as T2I_bin_irs except these operations need // the ".w" suffix to indicate that they are wide. multiclass T2I_bin_w_irs opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, SDPatternOperator opnode, bit Commutable = 0> : T2I_bin_irs { // Assembler aliases w/ the ".w" suffix. def : t2InstAlias(NAME#"ri") rGPR:$Rd, rGPR:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; // Assembler aliases w/o the ".w" suffix. def : t2InstAlias(NAME#"rr") rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias(NAME#"rs") rGPR:$Rd, rGPR:$Rn, t2_so_reg:$shift, pred:$p, cc_out:$s)>; // and with the optional destination operand, too. def : t2InstAlias(NAME#"ri") rGPR:$Rdn, rGPR:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias(NAME#"rr") rGPR:$Rdn, rGPR:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias(NAME#"rs") rGPR:$Rdn, rGPR:$Rdn, t2_so_reg:$shift, pred:$p, cc_out:$s)>; } /// T2I_rbin_is - Same as T2I_bin_irs except the order of operands are /// reversed. The 'rr' form is only defined for the disassembler; for codegen /// it is equivalent to the T2I_bin_irs counterpart. multiclass T2I_rbin_irs opcod, string opc, SDNode opnode> { // shifted imm def ri : T2sTwoRegImm< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm), IIC_iALUi, opc, ".w\t$Rd, $Rn, $imm", [(set rGPR:$Rd, (opnode t2_so_imm:$imm, rGPR:$Rn))]>, Sched<[WriteALU, ReadALU]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{15} = 0; } // register def rr : T2sThreeReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iALUr, opc, "\t$Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, Sched<[WriteALU, ReadALU, ReadALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{14-12} = 0b000; // imm3 let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def rs : T2sTwoRegShiftedReg< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm), IIC_iALUsir, opc, "\t$Rd, $Rn, $ShiftedRm", [(set rGPR:$Rd, (opnode t2_so_reg:$ShiftedRm, rGPR:$Rn))]>, Sched<[WriteALUsi, ReadALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; } } /// T2I_bin_s_irs - Similar to T2I_bin_irs except it sets the 's' bit so the /// instruction modifies the CPSR register. /// /// These opcodes will be converted to the real non-S opcodes by /// AdjustInstrPostInstrSelection after giving then an optional CPSR operand. let hasPostISelHook = 1, Defs = [CPSR] in { multiclass T2I_bin_s_irs { // shifted imm def ri : t2PseudoInst<(outs rGPR:$Rd), (ins GPRnopc:$Rn, t2_so_imm:$imm, pred:$p), 4, iii, [(set rGPR:$Rd, CPSR, (opnode GPRnopc:$Rn, t2_so_imm:$imm))]>, Sched<[WriteALU, ReadALU]>; // register def rr : t2PseudoInst<(outs rGPR:$Rd), (ins GPRnopc:$Rn, rGPR:$Rm, pred:$p), 4, iir, [(set rGPR:$Rd, CPSR, (opnode GPRnopc:$Rn, rGPR:$Rm))]>, Sched<[WriteALU, ReadALU, ReadALU]> { let isCommutable = Commutable; } // shifted register def rs : t2PseudoInst<(outs rGPR:$Rd), (ins GPRnopc:$Rn, t2_so_reg:$ShiftedRm, pred:$p), 4, iis, [(set rGPR:$Rd, CPSR, (opnode GPRnopc:$Rn, t2_so_reg:$ShiftedRm))]>, Sched<[WriteALUsi, ReadALUsr]>; } } /// T2I_rbin_s_is - Same as T2I_bin_s_irs, except selection DAG /// operands are reversed. let hasPostISelHook = 1, Defs = [CPSR] in { multiclass T2I_rbin_s_is { // shifted imm def ri : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm, pred:$p), 4, IIC_iALUi, [(set rGPR:$Rd, CPSR, (opnode t2_so_imm:$imm, rGPR:$Rn))]>, Sched<[WriteALU, ReadALU]>; // shifted register def rs : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm, pred:$p), 4, IIC_iALUsi, [(set rGPR:$Rd, CPSR, (opnode t2_so_reg:$ShiftedRm, rGPR:$Rn))]>, Sched<[WriteALUsi, ReadALU]>; } } /// T2I_bin_ii12rs - Defines a set of (op reg, {so_imm|imm0_4095|r|so_reg}) /// patterns for a binary operation that produces a value. multiclass T2I_bin_ii12rs op23_21, string opc, SDNode opnode, bit Commutable = 0> { // shifted imm // The register-immediate version is re-materializable. This is useful // in particular for taking the address of a local. let isReMaterializable = 1 in { def ri : T2sTwoRegImm< (outs GPRnopc:$Rd), (ins GPRnopc:$Rn, t2_so_imm:$imm), IIC_iALUi, opc, ".w\t$Rd, $Rn, $imm", [(set GPRnopc:$Rd, (opnode GPRnopc:$Rn, t2_so_imm:$imm))]>, Sched<[WriteALU, ReadALU]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24} = 1; let Inst{23-21} = op23_21; let Inst{15} = 0; } } // 12-bit imm def ri12 : T2I< (outs GPRnopc:$Rd), (ins GPR:$Rn, imm0_4095:$imm), IIC_iALUi, !strconcat(opc, "w"), "\t$Rd, $Rn, $imm", [(set GPRnopc:$Rd, (opnode GPR:$Rn, imm0_4095:$imm))]>, Sched<[WriteALU, ReadALU]> { bits<4> Rd; bits<4> Rn; bits<12> imm; let Inst{31-27} = 0b11110; let Inst{26} = imm{11}; let Inst{25-24} = 0b10; let Inst{23-21} = op23_21; let Inst{20} = 0; // The S bit. let Inst{19-16} = Rn; let Inst{15} = 0; let Inst{14-12} = imm{10-8}; let Inst{11-8} = Rd; let Inst{7-0} = imm{7-0}; } // register def rr : T2sThreeReg<(outs GPRnopc:$Rd), (ins GPRnopc:$Rn, rGPR:$Rm), IIC_iALUr, opc, ".w\t$Rd, $Rn, $Rm", [(set GPRnopc:$Rd, (opnode GPRnopc:$Rn, rGPR:$Rm))]>, Sched<[WriteALU, ReadALU, ReadALU]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24} = 1; let Inst{23-21} = op23_21; let Inst{14-12} = 0b000; // imm3 let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def rs : T2sTwoRegShiftedReg< (outs GPRnopc:$Rd), (ins GPRnopc:$Rn, t2_so_reg:$ShiftedRm), IIC_iALUsi, opc, ".w\t$Rd, $Rn, $ShiftedRm", [(set GPRnopc:$Rd, (opnode GPRnopc:$Rn, t2_so_reg:$ShiftedRm))]>, Sched<[WriteALUsi, ReadALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24} = 1; let Inst{23-21} = op23_21; } } /// T2I_adde_sube_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns /// for a binary operation that produces a value and use the carry /// bit. It's not predicable. let Defs = [CPSR], Uses = [CPSR] in { multiclass T2I_adde_sube_irs opcod, string opc, SDNode opnode, bit Commutable = 0> { // shifted imm def ri : T2sTwoRegImm<(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm), IIC_iALUi, opc, "\t$Rd, $Rn, $imm", [(set rGPR:$Rd, CPSR, (opnode rGPR:$Rn, t2_so_imm:$imm, CPSR))]>, Requires<[IsThumb2]>, Sched<[WriteALU, ReadALU]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{15} = 0; } // register def rr : T2sThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iALUr, opc, ".w\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, CPSR, (opnode rGPR:$Rn, rGPR:$Rm, CPSR))]>, Requires<[IsThumb2]>, Sched<[WriteALU, ReadALU, ReadALU]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{14-12} = 0b000; // imm3 let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def rs : T2sTwoRegShiftedReg< (outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm), IIC_iALUsi, opc, ".w\t$Rd, $Rn, $ShiftedRm", [(set rGPR:$Rd, CPSR, (opnode rGPR:$Rn, t2_so_reg:$ShiftedRm, CPSR))]>, Requires<[IsThumb2]>, Sched<[WriteALUsi, ReadALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; } } } /// T2I_sh_ir - Defines a set of (op reg, {so_imm|r}) patterns for a shift / // rotate operation that produces a value. multiclass T2I_sh_ir opcod, string opc, Operand ty, SDNode opnode> { // 5-bit imm def ri : T2sTwoRegShiftImm< (outs rGPR:$Rd), (ins rGPR:$Rm, ty:$imm), IIC_iMOVsi, opc, ".w\t$Rd, $Rm, $imm", [(set rGPR:$Rd, (opnode rGPR:$Rm, (i32 ty:$imm)))]>, Sched<[WriteALU]> { let Inst{31-27} = 0b11101; let Inst{26-21} = 0b010010; let Inst{19-16} = 0b1111; // Rn let Inst{5-4} = opcod; } // register def rr : T2sThreeReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMOVsr, opc, ".w\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (opnode rGPR:$Rn, rGPR:$Rm))]>, Sched<[WriteALU]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-21} = opcod; let Inst{15-12} = 0b1111; let Inst{7-4} = 0b0000; } // Optional destination register def : t2InstAlias(NAME#"ri") rGPR:$Rdn, rGPR:$Rdn, ty:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias(NAME#"rr") rGPR:$Rdn, rGPR:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; // Assembler aliases w/o the ".w" suffix. def : t2InstAlias(NAME#"ri") rGPR:$Rd, rGPR:$Rn, ty:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias(NAME#"rr") rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; // and with the optional destination operand, too. def : t2InstAlias(NAME#"ri") rGPR:$Rdn, rGPR:$Rdn, ty:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias(NAME#"rr") rGPR:$Rdn, rGPR:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; } /// T2I_cmp_irs - Defines a set of (op r, {so_imm|r|so_reg}) cmp / test /// patterns. Similar to T2I_bin_irs except the instruction does not produce /// a explicit result, only implicitly set CPSR. multiclass T2I_cmp_irs opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, SDPatternOperator opnode> { let isCompare = 1, Defs = [CPSR] in { // shifted imm def ri : T2OneRegCmpImm< (outs), (ins GPRnopc:$Rn, t2_so_imm:$imm), iii, opc, ".w\t$Rn, $imm", [(opnode GPRnopc:$Rn, t2_so_imm:$imm)]>, Sched<[WriteCMP]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{20} = 1; // The S bit. let Inst{15} = 0; let Inst{11-8} = 0b1111; // Rd } // register def rr : T2TwoRegCmp< (outs), (ins GPRnopc:$Rn, rGPR:$Rm), iir, opc, ".w\t$Rn, $Rm", [(opnode GPRnopc:$Rn, rGPR:$Rm)]>, Sched<[WriteCMP]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{20} = 1; // The S bit. let Inst{14-12} = 0b000; // imm3 let Inst{11-8} = 0b1111; // Rd let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def rs : T2OneRegCmpShiftedReg< (outs), (ins GPRnopc:$Rn, t2_so_reg:$ShiftedRm), iis, opc, ".w\t$Rn, $ShiftedRm", [(opnode GPRnopc:$Rn, t2_so_reg:$ShiftedRm)]>, Sched<[WriteCMPsi]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{20} = 1; // The S bit. let Inst{11-8} = 0b1111; // Rd } } // Assembler aliases w/o the ".w" suffix. // No alias here for 'rr' version as not all instantiations of this // multiclass want one (CMP in particular, does not). def : t2InstAlias(NAME#"ri") GPRnopc:$Rn, t2_so_imm:$imm, pred:$p)>; def : t2InstAlias(NAME#"rs") GPRnopc:$Rn, t2_so_reg:$shift, pred:$p)>; } /// T2I_ld - Defines a set of (op r, {imm12|imm8|so_reg}) load patterns. multiclass T2I_ld opcod, string opc, InstrItinClass iii, InstrItinClass iis, RegisterClass target, PatFrag opnode> { def i12 : T2Ii12<(outs target:$Rt), (ins t2addrmode_imm12:$addr), iii, opc, ".w\t$Rt, $addr", [(set target:$Rt, (opnode t2addrmode_imm12:$addr))]> { bits<4> Rt; bits<17> addr; let Inst{31-25} = 0b1111100; let Inst{24} = signed; let Inst{23} = 1; let Inst{22-21} = opcod; let Inst{20} = 1; // load let Inst{19-16} = addr{16-13}; // Rn let Inst{15-12} = Rt; let Inst{11-0} = addr{11-0}; // imm let DecoderMethod = "DecodeT2LoadImm12"; } def i8 : T2Ii8 <(outs target:$Rt), (ins t2addrmode_negimm8:$addr), iii, opc, "\t$Rt, $addr", [(set target:$Rt, (opnode t2addrmode_negimm8:$addr))]> { bits<4> Rt; bits<13> addr; let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = signed; let Inst{23} = 0; let Inst{22-21} = opcod; let Inst{20} = 1; // load let Inst{19-16} = addr{12-9}; // Rn let Inst{15-12} = Rt; let Inst{11} = 1; // Offset: index==TRUE, wback==FALSE let Inst{10} = 1; // The P bit. let Inst{9} = addr{8}; // U let Inst{8} = 0; // The W bit. let Inst{7-0} = addr{7-0}; // imm let DecoderMethod = "DecodeT2LoadImm8"; } def s : T2Iso <(outs target:$Rt), (ins t2addrmode_so_reg:$addr), iis, opc, ".w\t$Rt, $addr", [(set target:$Rt, (opnode t2addrmode_so_reg:$addr))]> { let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = signed; let Inst{23} = 0; let Inst{22-21} = opcod; let Inst{20} = 1; // load let Inst{11-6} = 0b000000; bits<4> Rt; let Inst{15-12} = Rt; bits<10> addr; let Inst{19-16} = addr{9-6}; // Rn let Inst{3-0} = addr{5-2}; // Rm let Inst{5-4} = addr{1-0}; // imm let DecoderMethod = "DecodeT2LoadShift"; } // pci variant is very similar to i12, but supports negative offsets // from the PC. def pci : T2Ipc <(outs target:$Rt), (ins t2ldrlabel:$addr), iii, opc, ".w\t$Rt, $addr", [(set target:$Rt, (opnode (ARMWrapper tconstpool:$addr)))]> { let isReMaterializable = 1; let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = signed; let Inst{22-21} = opcod; let Inst{20} = 1; // load let Inst{19-16} = 0b1111; // Rn bits<4> Rt; let Inst{15-12} = Rt{3-0}; bits<13> addr; let Inst{23} = addr{12}; // add = (U == '1') let Inst{11-0} = addr{11-0}; let DecoderMethod = "DecodeT2LoadLabel"; } } /// T2I_st - Defines a set of (op r, {imm12|imm8|so_reg}) store patterns. multiclass T2I_st opcod, string opc, InstrItinClass iii, InstrItinClass iis, RegisterClass target, PatFrag opnode> { def i12 : T2Ii12<(outs), (ins target:$Rt, t2addrmode_imm12:$addr), iii, opc, ".w\t$Rt, $addr", [(opnode target:$Rt, t2addrmode_imm12:$addr)]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0001; let Inst{22-21} = opcod; let Inst{20} = 0; // !load bits<4> Rt; let Inst{15-12} = Rt; bits<17> addr; let addr{12} = 1; // add = TRUE let Inst{19-16} = addr{16-13}; // Rn let Inst{23} = addr{12}; // U let Inst{11-0} = addr{11-0}; // imm } def i8 : T2Ii8 <(outs), (ins target:$Rt, t2addrmode_negimm8:$addr), iii, opc, "\t$Rt, $addr", [(opnode target:$Rt, t2addrmode_negimm8:$addr)]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0000; let Inst{22-21} = opcod; let Inst{20} = 0; // !load let Inst{11} = 1; // Offset: index==TRUE, wback==FALSE let Inst{10} = 1; // The P bit. let Inst{8} = 0; // The W bit. bits<4> Rt; let Inst{15-12} = Rt; bits<13> addr; let Inst{19-16} = addr{12-9}; // Rn let Inst{9} = addr{8}; // U let Inst{7-0} = addr{7-0}; // imm } def s : T2Iso <(outs), (ins target:$Rt, t2addrmode_so_reg:$addr), iis, opc, ".w\t$Rt, $addr", [(opnode target:$Rt, t2addrmode_so_reg:$addr)]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0000; let Inst{22-21} = opcod; let Inst{20} = 0; // !load let Inst{11-6} = 0b000000; bits<4> Rt; let Inst{15-12} = Rt; bits<10> addr; let Inst{19-16} = addr{9-6}; // Rn let Inst{3-0} = addr{5-2}; // Rm let Inst{5-4} = addr{1-0}; // imm } } /// T2I_ext_rrot - A unary operation with two forms: one whose operand is a /// register and one whose operand is a register rotated by 8/16/24. class T2I_ext_rrot opcod, string opc, PatFrag opnode> : T2TwoReg<(outs rGPR:$Rd), (ins rGPR:$Rm, rot_imm:$rot), IIC_iEXTr, opc, ".w\t$Rd, $Rm$rot", [(set rGPR:$Rd, (opnode (rotr rGPR:$Rm, rot_imm:$rot)))]>, Requires<[IsThumb2]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; let Inst{19-16} = 0b1111; // Rn let Inst{15-12} = 0b1111; let Inst{7} = 1; bits<2> rot; let Inst{5-4} = rot{1-0}; // rotate } // UXTB16 - Requres T2ExtractPack, does not need the .w qualifier. class T2I_ext_rrot_uxtb16 opcod, string opc, PatFrag opnode> : T2TwoReg<(outs rGPR:$Rd), (ins rGPR:$Rm, rot_imm:$rot), IIC_iEXTr, opc, "\t$Rd, $Rm$rot", [(set rGPR:$Rd, (opnode (rotr rGPR:$Rm, rot_imm:$rot)))]>, Requires<[HasT2ExtractPack, IsThumb2]> { bits<2> rot; let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; let Inst{19-16} = 0b1111; // Rn let Inst{15-12} = 0b1111; let Inst{7} = 1; let Inst{5-4} = rot; } // SXTB16 - Requres T2ExtractPack, does not need the .w qualifier, no pattern // supported yet. class T2I_ext_rrot_sxtb16 opcod, string opc> : T2TwoReg<(outs rGPR:$Rd), (ins rGPR:$Rm, rot_imm:$rot), IIC_iEXTr, opc, "\t$Rd, $Rm$rot", []>, Requires<[IsThumb2, HasT2ExtractPack]> { bits<2> rot; let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; let Inst{19-16} = 0b1111; // Rn let Inst{15-12} = 0b1111; let Inst{7} = 1; let Inst{5-4} = rot; } /// T2I_exta_rrot - A binary operation with two forms: one whose operand is a /// register and one whose operand is a register rotated by 8/16/24. class T2I_exta_rrot opcod, string opc, PatFrag opnode> : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rot_imm:$rot), IIC_iEXTAsr, opc, "\t$Rd, $Rn, $Rm$rot", [(set rGPR:$Rd, (opnode rGPR:$Rn, (rotr rGPR:$Rm,rot_imm:$rot)))]>, Requires<[HasT2ExtractPack, IsThumb2]> { bits<2> rot; let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; let Inst{15-12} = 0b1111; let Inst{7} = 1; let Inst{5-4} = rot; } class T2I_exta_rrot_np opcod, string opc> : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm,rot_imm:$rot), IIC_iEXTAsr, opc, "\t$Rd, $Rn, $Rm$rot", []>, Requires<[HasT2ExtractPack, IsThumb2]> { bits<2> rot; let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; let Inst{15-12} = 0b1111; let Inst{7} = 1; let Inst{5-4} = rot; } //===----------------------------------------------------------------------===// // Instructions //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Miscellaneous Instructions. // class T2PCOneRegImm pattern> : T2XI { bits<4> Rd; bits<12> label; let Inst{11-8} = Rd; let Inst{26} = label{11}; let Inst{14-12} = label{10-8}; let Inst{7-0} = label{7-0}; } // LEApcrel - Load a pc-relative address into a register without offending the // assembler. def t2ADR : T2PCOneRegImm<(outs rGPR:$Rd), (ins t2adrlabel:$addr, pred:$p), IIC_iALUi, "adr{$p}.w\t$Rd, $addr", []>, Sched<[WriteALU, ReadALU]> { let Inst{31-27} = 0b11110; let Inst{25-24} = 0b10; // Inst{23:21} = '11' (add = FALSE) or '00' (add = TRUE) let Inst{22} = 0; let Inst{20} = 0; let Inst{19-16} = 0b1111; // Rn let Inst{15} = 0; bits<4> Rd; bits<13> addr; let Inst{11-8} = Rd; let Inst{23} = addr{12}; let Inst{21} = addr{12}; let Inst{26} = addr{11}; let Inst{14-12} = addr{10-8}; let Inst{7-0} = addr{7-0}; let DecoderMethod = "DecodeT2Adr"; } let hasSideEffects = 0, isReMaterializable = 1 in def t2LEApcrel : t2PseudoInst<(outs rGPR:$Rd), (ins i32imm:$label, pred:$p), 4, IIC_iALUi, []>, Sched<[WriteALU, ReadALU]>; let hasSideEffects = 1 in def t2LEApcrelJT : t2PseudoInst<(outs rGPR:$Rd), (ins i32imm:$label, pred:$p), 4, IIC_iALUi, []>, Sched<[WriteALU, ReadALU]>; //===----------------------------------------------------------------------===// // Load / store Instructions. // // Load let canFoldAsLoad = 1, isReMaterializable = 1 in defm t2LDR : T2I_ld<0, 0b10, "ldr", IIC_iLoad_i, IIC_iLoad_si, GPR, load>; // Loads with zero extension defm t2LDRH : T2I_ld<0, 0b01, "ldrh", IIC_iLoad_bh_i, IIC_iLoad_bh_si, GPRnopc, zextloadi16>; defm t2LDRB : T2I_ld<0, 0b00, "ldrb", IIC_iLoad_bh_i, IIC_iLoad_bh_si, GPRnopc, zextloadi8>; // Loads with sign extension defm t2LDRSH : T2I_ld<1, 0b01, "ldrsh", IIC_iLoad_bh_i, IIC_iLoad_bh_si, GPRnopc, sextloadi16>; defm t2LDRSB : T2I_ld<1, 0b00, "ldrsb", IIC_iLoad_bh_i, IIC_iLoad_bh_si, GPRnopc, sextloadi8>; let mayLoad = 1, hasSideEffects = 0, hasExtraDefRegAllocReq = 1 in { // Load doubleword def t2LDRDi8 : T2Ii8s4<1, 0, 1, (outs rGPR:$Rt, rGPR:$Rt2), (ins t2addrmode_imm8s4:$addr), IIC_iLoad_d_i, "ldrd", "\t$Rt, $Rt2, $addr", "", []>; } // mayLoad = 1, hasSideEffects = 0, hasExtraDefRegAllocReq = 1 // zextload i1 -> zextload i8 def : T2Pat<(zextloadi1 t2addrmode_imm12:$addr), (t2LDRBi12 t2addrmode_imm12:$addr)>; def : T2Pat<(zextloadi1 t2addrmode_negimm8:$addr), (t2LDRBi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(zextloadi1 t2addrmode_so_reg:$addr), (t2LDRBs t2addrmode_so_reg:$addr)>; def : T2Pat<(zextloadi1 (ARMWrapper tconstpool:$addr)), (t2LDRBpci tconstpool:$addr)>; // extload -> zextload // FIXME: Reduce the number of patterns by legalizing extload to zextload // earlier? def : T2Pat<(extloadi1 t2addrmode_imm12:$addr), (t2LDRBi12 t2addrmode_imm12:$addr)>; def : T2Pat<(extloadi1 t2addrmode_negimm8:$addr), (t2LDRBi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(extloadi1 t2addrmode_so_reg:$addr), (t2LDRBs t2addrmode_so_reg:$addr)>; def : T2Pat<(extloadi1 (ARMWrapper tconstpool:$addr)), (t2LDRBpci tconstpool:$addr)>; def : T2Pat<(extloadi8 t2addrmode_imm12:$addr), (t2LDRBi12 t2addrmode_imm12:$addr)>; def : T2Pat<(extloadi8 t2addrmode_negimm8:$addr), (t2LDRBi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(extloadi8 t2addrmode_so_reg:$addr), (t2LDRBs t2addrmode_so_reg:$addr)>; def : T2Pat<(extloadi8 (ARMWrapper tconstpool:$addr)), (t2LDRBpci tconstpool:$addr)>; def : T2Pat<(extloadi16 t2addrmode_imm12:$addr), (t2LDRHi12 t2addrmode_imm12:$addr)>; def : T2Pat<(extloadi16 t2addrmode_negimm8:$addr), (t2LDRHi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(extloadi16 t2addrmode_so_reg:$addr), (t2LDRHs t2addrmode_so_reg:$addr)>; def : T2Pat<(extloadi16 (ARMWrapper tconstpool:$addr)), (t2LDRHpci tconstpool:$addr)>; // FIXME: The destination register of the loads and stores can't be PC, but // can be SP. We need another regclass (similar to rGPR) to represent // that. Not a pressing issue since these are selected manually, // not via pattern. // Indexed loads let mayLoad = 1, hasSideEffects = 0 in { def t2LDR_PRE : T2Ipreldst<0, 0b10, 1, 1, (outs GPR:$Rt, GPR:$Rn_wb), (ins t2addrmode_imm8_pre:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_iu, "ldr", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []>; def t2LDR_POST : T2Ipostldst<0, 0b10, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), (ins addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_iu, "ldr", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb", []>; def t2LDRB_PRE : T2Ipreldst<0, 0b00, 1, 1, (outs GPR:$Rt, GPR:$Rn_wb), (ins t2addrmode_imm8_pre:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, "ldrb", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []>; def t2LDRB_POST : T2Ipostldst<0, 0b00, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), (ins addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, "ldrb", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb", []>; def t2LDRH_PRE : T2Ipreldst<0, 0b01, 1, 1, (outs GPR:$Rt, GPR:$Rn_wb), (ins t2addrmode_imm8_pre:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, "ldrh", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []>; def t2LDRH_POST : T2Ipostldst<0, 0b01, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), (ins addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, "ldrh", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb", []>; def t2LDRSB_PRE : T2Ipreldst<1, 0b00, 1, 1, (outs GPR:$Rt, GPR:$Rn_wb), (ins t2addrmode_imm8_pre:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, "ldrsb", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []>; def t2LDRSB_POST : T2Ipostldst<1, 0b00, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), (ins addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, "ldrsb", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb", []>; def t2LDRSH_PRE : T2Ipreldst<1, 0b01, 1, 1, (outs GPR:$Rt, GPR:$Rn_wb), (ins t2addrmode_imm8_pre:$addr), AddrModeT2_i8, IndexModePre, IIC_iLoad_bh_iu, "ldrsh", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []>; def t2LDRSH_POST : T2Ipostldst<1, 0b01, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb), (ins addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iLoad_bh_iu, "ldrsh", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb", []>; } // mayLoad = 1, hasSideEffects = 0 // LDRT, LDRBT, LDRHT, LDRSBT, LDRSHT all have offset mode (PUW=0b110). // Ref: A8.6.57 LDR (immediate, Thumb) Encoding T4 class T2IldT type, string opc, InstrItinClass ii> : T2Ii8<(outs rGPR:$Rt), (ins t2addrmode_posimm8:$addr), ii, opc, "\t$Rt, $addr", []> { bits<4> Rt; bits<13> addr; let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = signed; let Inst{23} = 0; let Inst{22-21} = type; let Inst{20} = 1; // load let Inst{19-16} = addr{12-9}; let Inst{15-12} = Rt; let Inst{11} = 1; let Inst{10-8} = 0b110; // PUW. let Inst{7-0} = addr{7-0}; let DecoderMethod = "DecodeT2LoadT"; } def t2LDRT : T2IldT<0, 0b10, "ldrt", IIC_iLoad_i>; def t2LDRBT : T2IldT<0, 0b00, "ldrbt", IIC_iLoad_bh_i>; def t2LDRHT : T2IldT<0, 0b01, "ldrht", IIC_iLoad_bh_i>; def t2LDRSBT : T2IldT<1, 0b00, "ldrsbt", IIC_iLoad_bh_i>; def t2LDRSHT : T2IldT<1, 0b01, "ldrsht", IIC_iLoad_bh_i>; class T2Ildacq bits23_20, bits<2> bit54, dag oops, dag iops, string opc, string asm, list pattern> : Thumb2I, Requires<[IsThumb, HasAcquireRelease]> { bits<4> Rt; bits<4> addr; let Inst{31-27} = 0b11101; let Inst{26-24} = 0b000; let Inst{23-20} = bits23_20; let Inst{11-6} = 0b111110; let Inst{5-4} = bit54; let Inst{3-0} = 0b1111; // Encode instruction operands let Inst{19-16} = addr; let Inst{15-12} = Rt; } def t2LDA : T2Ildacq<0b1101, 0b10, (outs rGPR:$Rt), (ins addr_offset_none:$addr), "lda", "\t$Rt, $addr", []>; def t2LDAB : T2Ildacq<0b1101, 0b00, (outs rGPR:$Rt), (ins addr_offset_none:$addr), "ldab", "\t$Rt, $addr", []>; def t2LDAH : T2Ildacq<0b1101, 0b01, (outs rGPR:$Rt), (ins addr_offset_none:$addr), "ldah", "\t$Rt, $addr", []>; // Store defm t2STR :T2I_st<0b10,"str", IIC_iStore_i, IIC_iStore_si, GPR, store>; defm t2STRB:T2I_st<0b00,"strb", IIC_iStore_bh_i, IIC_iStore_bh_si, rGPR, truncstorei8>; defm t2STRH:T2I_st<0b01,"strh", IIC_iStore_bh_i, IIC_iStore_bh_si, rGPR, truncstorei16>; // Store doubleword let mayStore = 1, hasSideEffects = 0, hasExtraSrcRegAllocReq = 1 in def t2STRDi8 : T2Ii8s4<1, 0, 0, (outs), (ins rGPR:$Rt, rGPR:$Rt2, t2addrmode_imm8s4:$addr), IIC_iStore_d_r, "strd", "\t$Rt, $Rt2, $addr", "", []>; // Indexed stores let mayStore = 1, hasSideEffects = 0 in { def t2STR_PRE : T2Ipreldst<0, 0b10, 0, 1, (outs GPRnopc:$Rn_wb), (ins GPRnopc:$Rt, t2addrmode_imm8_pre:$addr), AddrModeT2_i8, IndexModePre, IIC_iStore_iu, "str", "\t$Rt, $addr!", "$addr.base = $Rn_wb,@earlyclobber $Rn_wb", []>; def t2STRH_PRE : T2Ipreldst<0, 0b01, 0, 1, (outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, t2addrmode_imm8_pre:$addr), AddrModeT2_i8, IndexModePre, IIC_iStore_iu, "strh", "\t$Rt, $addr!", "$addr.base = $Rn_wb,@earlyclobber $Rn_wb", []>; def t2STRB_PRE : T2Ipreldst<0, 0b00, 0, 1, (outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, t2addrmode_imm8_pre:$addr), AddrModeT2_i8, IndexModePre, IIC_iStore_bh_iu, "strb", "\t$Rt, $addr!", "$addr.base = $Rn_wb,@earlyclobber $Rn_wb", []>; } // mayStore = 1, hasSideEffects = 0 def t2STR_POST : T2Ipostldst<0, 0b10, 0, 0, (outs GPRnopc:$Rn_wb), (ins GPRnopc:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iStore_iu, "str", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb,@earlyclobber $Rn_wb", [(set GPRnopc:$Rn_wb, (post_store GPRnopc:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset))]>; def t2STRH_POST : T2Ipostldst<0, 0b01, 0, 0, (outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iStore_bh_iu, "strh", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb,@earlyclobber $Rn_wb", [(set GPRnopc:$Rn_wb, (post_truncsti16 rGPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset))]>; def t2STRB_POST : T2Ipostldst<0, 0b00, 0, 0, (outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset), AddrModeT2_i8, IndexModePost, IIC_iStore_bh_iu, "strb", "\t$Rt, $Rn$offset", "$Rn = $Rn_wb,@earlyclobber $Rn_wb", [(set GPRnopc:$Rn_wb, (post_truncsti8 rGPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$offset))]>; // Pseudo-instructions for pattern matching the pre-indexed stores. We can't // put the patterns on the instruction definitions directly as ISel wants // the address base and offset to be separate operands, not a single // complex operand like we represent the instructions themselves. The // pseudos map between the two. let usesCustomInserter = 1, Constraints = "$Rn = $Rn_wb,@earlyclobber $Rn_wb" in { def t2STR_preidx: t2PseudoInst<(outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset, pred:$p), 4, IIC_iStore_ru, [(set GPRnopc:$Rn_wb, (pre_store rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset))]>; def t2STRB_preidx: t2PseudoInst<(outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset, pred:$p), 4, IIC_iStore_ru, [(set GPRnopc:$Rn_wb, (pre_truncsti8 rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset))]>; def t2STRH_preidx: t2PseudoInst<(outs GPRnopc:$Rn_wb), (ins rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset, pred:$p), 4, IIC_iStore_ru, [(set GPRnopc:$Rn_wb, (pre_truncsti16 rGPR:$Rt, GPRnopc:$Rn, t2am_imm8_offset:$offset))]>; } // STRT, STRBT, STRHT all have offset mode (PUW=0b110) and are for disassembly // only. // Ref: A8.6.193 STR (immediate, Thumb) Encoding T4 class T2IstT type, string opc, InstrItinClass ii> : T2Ii8<(outs rGPR:$Rt), (ins t2addrmode_imm8:$addr), ii, opc, "\t$Rt, $addr", []> { let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; let Inst{24} = 0; // not signed let Inst{23} = 0; let Inst{22-21} = type; let Inst{20} = 0; // store let Inst{11} = 1; let Inst{10-8} = 0b110; // PUW bits<4> Rt; bits<13> addr; let Inst{15-12} = Rt; let Inst{19-16} = addr{12-9}; let Inst{7-0} = addr{7-0}; } def t2STRT : T2IstT<0b10, "strt", IIC_iStore_i>; def t2STRBT : T2IstT<0b00, "strbt", IIC_iStore_bh_i>; def t2STRHT : T2IstT<0b01, "strht", IIC_iStore_bh_i>; // ldrd / strd pre / post variants let mayLoad = 1 in def t2LDRD_PRE : T2Ii8s4<1, 1, 1, (outs rGPR:$Rt, rGPR:$Rt2, GPR:$wb), (ins t2addrmode_imm8s4_pre:$addr), IIC_iLoad_d_ru, "ldrd", "\t$Rt, $Rt2, $addr!", "$addr.base = $wb", []> { let DecoderMethod = "DecodeT2LDRDPreInstruction"; } let mayLoad = 1 in def t2LDRD_POST : T2Ii8s4post<0, 1, 1, (outs rGPR:$Rt, rGPR:$Rt2, GPR:$wb), (ins addr_offset_none:$addr, t2am_imm8s4_offset:$imm), IIC_iLoad_d_ru, "ldrd", "\t$Rt, $Rt2, $addr$imm", "$addr.base = $wb", []>; let mayStore = 1 in def t2STRD_PRE : T2Ii8s4<1, 1, 0, (outs GPR:$wb), (ins rGPR:$Rt, rGPR:$Rt2, t2addrmode_imm8s4_pre:$addr), IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, $addr!", "$addr.base = $wb", []> { let DecoderMethod = "DecodeT2STRDPreInstruction"; } let mayStore = 1 in def t2STRD_POST : T2Ii8s4post<0, 1, 0, (outs GPR:$wb), (ins rGPR:$Rt, rGPR:$Rt2, addr_offset_none:$addr, t2am_imm8s4_offset:$imm), IIC_iStore_d_ru, "strd", "\t$Rt, $Rt2, $addr$imm", "$addr.base = $wb", []>; class T2Istrrel bit54, dag oops, dag iops, string opc, string asm, list pattern> : Thumb2I, Requires<[IsThumb, HasAcquireRelease]> { bits<4> Rt; bits<4> addr; let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0001100; let Inst{11-6} = 0b111110; let Inst{5-4} = bit54; let Inst{3-0} = 0b1111; // Encode instruction operands let Inst{19-16} = addr; let Inst{15-12} = Rt; } def t2STL : T2Istrrel<0b10, (outs), (ins rGPR:$Rt, addr_offset_none:$addr), "stl", "\t$Rt, $addr", []>; def t2STLB : T2Istrrel<0b00, (outs), (ins rGPR:$Rt, addr_offset_none:$addr), "stlb", "\t$Rt, $addr", []>; def t2STLH : T2Istrrel<0b01, (outs), (ins rGPR:$Rt, addr_offset_none:$addr), "stlh", "\t$Rt, $addr", []>; // T2Ipl (Preload Data/Instruction) signals the memory system of possible future // data/instruction access. // instr_write is inverted for Thumb mode: (prefetch 3) -> (preload 0), // (prefetch 1) -> (preload 2), (prefetch 2) -> (preload 1). multiclass T2Ipl write, bits<1> instr, string opc> { def i12 : T2Ii12<(outs), (ins t2addrmode_imm12:$addr), IIC_Preload, opc, "\t$addr", [(ARMPreload t2addrmode_imm12:$addr, (i32 write), (i32 instr))]>, Sched<[WritePreLd]> { let Inst{31-25} = 0b1111100; let Inst{24} = instr; let Inst{23} = 1; let Inst{22} = 0; let Inst{21} = write; let Inst{20} = 1; let Inst{15-12} = 0b1111; bits<17> addr; let Inst{19-16} = addr{16-13}; // Rn let Inst{11-0} = addr{11-0}; // imm12 let DecoderMethod = "DecodeT2LoadImm12"; } def i8 : T2Ii8<(outs), (ins t2addrmode_negimm8:$addr), IIC_Preload, opc, "\t$addr", [(ARMPreload t2addrmode_negimm8:$addr, (i32 write), (i32 instr))]>, Sched<[WritePreLd]> { let Inst{31-25} = 0b1111100; let Inst{24} = instr; let Inst{23} = 0; // U = 0 let Inst{22} = 0; let Inst{21} = write; let Inst{20} = 1; let Inst{15-12} = 0b1111; let Inst{11-8} = 0b1100; bits<13> addr; let Inst{19-16} = addr{12-9}; // Rn let Inst{7-0} = addr{7-0}; // imm8 let DecoderMethod = "DecodeT2LoadImm8"; } def s : T2Iso<(outs), (ins t2addrmode_so_reg:$addr), IIC_Preload, opc, "\t$addr", [(ARMPreload t2addrmode_so_reg:$addr, (i32 write), (i32 instr))]>, Sched<[WritePreLd]> { let Inst{31-25} = 0b1111100; let Inst{24} = instr; let Inst{23} = 0; // add = TRUE for T1 let Inst{22} = 0; let Inst{21} = write; let Inst{20} = 1; let Inst{15-12} = 0b1111; let Inst{11-6} = 0b000000; bits<10> addr; let Inst{19-16} = addr{9-6}; // Rn let Inst{3-0} = addr{5-2}; // Rm let Inst{5-4} = addr{1-0}; // imm2 let DecoderMethod = "DecodeT2LoadShift"; } } defm t2PLD : T2Ipl<0, 0, "pld">, Requires<[IsThumb2]>; defm t2PLDW : T2Ipl<1, 0, "pldw">, Requires<[IsThumb2,HasV7,HasMP]>; defm t2PLI : T2Ipl<0, 1, "pli">, Requires<[IsThumb2,HasV7]>; // pci variant is very similar to i12, but supports negative offsets // from the PC. Only PLD and PLI have pci variants (not PLDW) class T2Iplpci inst, string opc> : T2Iso<(outs), (ins t2ldrlabel:$addr), IIC_Preload, opc, "\t$addr", [(ARMPreload (ARMWrapper tconstpool:$addr), (i32 0), (i32 inst))]>, Sched<[WritePreLd]> { let Inst{31-25} = 0b1111100; let Inst{24} = inst; let Inst{22-20} = 0b001; let Inst{19-16} = 0b1111; let Inst{15-12} = 0b1111; bits<13> addr; let Inst{23} = addr{12}; // add = (U == '1') let Inst{11-0} = addr{11-0}; // imm12 let DecoderMethod = "DecodeT2LoadLabel"; } def t2PLDpci : T2Iplpci<0, "pld">, Requires<[IsThumb2]>; def t2PLIpci : T2Iplpci<1, "pli">, Requires<[IsThumb2,HasV7]>; //===----------------------------------------------------------------------===// // Load / store multiple Instructions. // multiclass thumb2_ld_mult { def IA : T2XI<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin, !strconcat(asm, "${p}.w\t$Rn, $regs"), []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b01; // Increment After let Inst{22} = 0; let Inst{21} = 0; // No writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15-0} = regs; } def IA_UPD : T2XIt<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin_upd, !strconcat(asm, "${p}.w\t$Rn!, $regs"), "$Rn = $wb", []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b01; // Increment After let Inst{22} = 0; let Inst{21} = 1; // Writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15-0} = regs; } def DB : T2XI<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin, !strconcat(asm, "db${p}\t$Rn, $regs"), []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b10; // Decrement Before let Inst{22} = 0; let Inst{21} = 0; // No writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15-0} = regs; } def DB_UPD : T2XIt<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin_upd, !strconcat(asm, "db${p}\t$Rn!, $regs"), "$Rn = $wb", []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b10; // Decrement Before let Inst{22} = 0; let Inst{21} = 1; // Writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15-0} = regs; } } let hasSideEffects = 0 in { let mayLoad = 1, hasExtraDefRegAllocReq = 1 in defm t2LDM : thumb2_ld_mult<"ldm", IIC_iLoad_m, IIC_iLoad_mu, 1>; multiclass thumb2_st_mult { def IA : T2XI<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin, !strconcat(asm, "${p}.w\t$Rn, $regs"), []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b01; // Increment After let Inst{22} = 0; let Inst{21} = 0; // No writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15} = 0; let Inst{14} = regs{14}; let Inst{13} = 0; let Inst{12-0} = regs{12-0}; } def IA_UPD : T2XIt<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin_upd, !strconcat(asm, "${p}.w\t$Rn!, $regs"), "$Rn = $wb", []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b01; // Increment After let Inst{22} = 0; let Inst{21} = 1; // Writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15} = 0; let Inst{14} = regs{14}; let Inst{13} = 0; let Inst{12-0} = regs{12-0}; } def DB : T2XI<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin, !strconcat(asm, "db${p}\t$Rn, $regs"), []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b10; // Decrement Before let Inst{22} = 0; let Inst{21} = 0; // No writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15} = 0; let Inst{14} = regs{14}; let Inst{13} = 0; let Inst{12-0} = regs{12-0}; } def DB_UPD : T2XIt<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), itin_upd, !strconcat(asm, "db${p}\t$Rn!, $regs"), "$Rn = $wb", []> { bits<4> Rn; bits<16> regs; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = 0b10; // Decrement Before let Inst{22} = 0; let Inst{21} = 1; // Writeback let Inst{20} = L_bit; let Inst{19-16} = Rn; let Inst{15} = 0; let Inst{14} = regs{14}; let Inst{13} = 0; let Inst{12-0} = regs{12-0}; } } let mayStore = 1, hasExtraSrcRegAllocReq = 1 in defm t2STM : thumb2_st_mult<"stm", IIC_iStore_m, IIC_iStore_mu, 0>; } // hasSideEffects //===----------------------------------------------------------------------===// // Move Instructions. // let hasSideEffects = 0 in def t2MOVr : T2sTwoReg<(outs GPRnopc:$Rd), (ins GPR:$Rm), IIC_iMOVr, "mov", ".w\t$Rd, $Rm", []>, Sched<[WriteALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; let Inst{19-16} = 0b1111; // Rn let Inst{14-12} = 0b000; let Inst{7-4} = 0b0000; } def : t2InstAlias<"mov${p}.w $Rd, $Rm", (t2MOVr GPRnopc:$Rd, GPR:$Rm, pred:$p, zero_reg)>; def : t2InstAlias<"movs${p}.w $Rd, $Rm", (t2MOVr GPRnopc:$Rd, GPR:$Rm, pred:$p, CPSR)>; def : t2InstAlias<"movs${p} $Rd, $Rm", (t2MOVr GPRnopc:$Rd, GPR:$Rm, pred:$p, CPSR)>; // AddedComplexity to ensure isel tries t2MOVi before t2MOVi16. let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1, AddedComplexity = 1 in def t2MOVi : T2sOneRegImm<(outs rGPR:$Rd), (ins t2_so_imm:$imm), IIC_iMOVi, "mov", ".w\t$Rd, $imm", [(set rGPR:$Rd, t2_so_imm:$imm)]>, Sched<[WriteALU]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = 0b0010; let Inst{19-16} = 0b1111; // Rn let Inst{15} = 0; } // cc_out is handled as part of the explicit mnemonic in the parser for 'mov'. // Use aliases to get that to play nice here. def : t2InstAlias<"movs${p}.w $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm, pred:$p, CPSR)>; def : t2InstAlias<"movs${p} $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm, pred:$p, CPSR)>; def : t2InstAlias<"mov${p}.w $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm, pred:$p, zero_reg)>; def : t2InstAlias<"mov${p} $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm:$imm, pred:$p, zero_reg)>; let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in def t2MOVi16 : T2I<(outs rGPR:$Rd), (ins imm0_65535_expr:$imm), IIC_iMOVi, "movw", "\t$Rd, $imm", [(set rGPR:$Rd, imm0_65535:$imm)]>, Sched<[WriteALU]>, Requires<[IsThumb, HasV8MBaseline]> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-21} = 0b0010; let Inst{20} = 0; // The S bit. let Inst{15} = 0; bits<4> Rd; bits<16> imm; let Inst{11-8} = Rd; let Inst{19-16} = imm{15-12}; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; let DecoderMethod = "DecodeT2MOVTWInstruction"; } def : InstAlias<"mov${p} $Rd, $imm", (t2MOVi16 rGPR:$Rd, imm256_65535_expr:$imm, pred:$p), 0>, Requires<[IsThumb, HasV8MBaseline]>; def t2MOVi16_ga_pcrel : PseudoInst<(outs rGPR:$Rd), (ins i32imm:$addr, pclabel:$id), IIC_iMOVi, []>; let Constraints = "$src = $Rd" in { def t2MOVTi16 : T2I<(outs rGPR:$Rd), (ins rGPR:$src, imm0_65535_expr:$imm), IIC_iMOVi, "movt", "\t$Rd, $imm", [(set rGPR:$Rd, (or (and rGPR:$src, 0xffff), lo16AllZero:$imm))]>, Sched<[WriteALU]>, Requires<[IsThumb, HasV8MBaseline]> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-21} = 0b0110; let Inst{20} = 0; // The S bit. let Inst{15} = 0; bits<4> Rd; bits<16> imm; let Inst{11-8} = Rd; let Inst{19-16} = imm{15-12}; let Inst{26} = imm{11}; let Inst{14-12} = imm{10-8}; let Inst{7-0} = imm{7-0}; let DecoderMethod = "DecodeT2MOVTWInstruction"; } def t2MOVTi16_ga_pcrel : PseudoInst<(outs rGPR:$Rd), (ins rGPR:$src, i32imm:$addr, pclabel:$id), IIC_iMOVi, []>, Sched<[WriteALU]>, Requires<[IsThumb, HasV8MBaseline]>; } // Constraints def : T2Pat<(or rGPR:$src, 0xffff0000), (t2MOVTi16 rGPR:$src, 0xffff)>; //===----------------------------------------------------------------------===// // Extend Instructions. // // Sign extenders def t2SXTB : T2I_ext_rrot<0b100, "sxtb", UnOpFrag<(sext_inreg node:$Src, i8)>>; def t2SXTH : T2I_ext_rrot<0b000, "sxth", UnOpFrag<(sext_inreg node:$Src, i16)>>; def t2SXTB16 : T2I_ext_rrot_sxtb16<0b010, "sxtb16">; def t2SXTAB : T2I_exta_rrot<0b100, "sxtab", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS, i8))>>; def t2SXTAH : T2I_exta_rrot<0b000, "sxtah", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS,i16))>>; def t2SXTAB16 : T2I_exta_rrot_np<0b010, "sxtab16">; // A simple right-shift can also be used in most cases (the exception is the // SXTH operations with a rotate of 24: there the non-contiguous bits are // relevant). def : Pat<(add rGPR:$Rn, (sext_inreg (srl rGPR:$Rm, rot_imm:$rot), i8)), (t2SXTAB rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : Pat<(add rGPR:$Rn, (sext_inreg (srl rGPR:$Rm, imm8_or_16:$rot), i16)), (t2SXTAH rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>, Requires<[HasT2ExtractPack, IsThumb2]>; // Zero extenders let AddedComplexity = 16 in { def t2UXTB : T2I_ext_rrot<0b101, "uxtb", UnOpFrag<(and node:$Src, 0x000000FF)>>; def t2UXTH : T2I_ext_rrot<0b001, "uxth", UnOpFrag<(and node:$Src, 0x0000FFFF)>>; def t2UXTB16 : T2I_ext_rrot_uxtb16<0b011, "uxtb16", UnOpFrag<(and node:$Src, 0x00FF00FF)>>; // FIXME: This pattern incorrectly assumes the shl operator is a rotate. // The transformation should probably be done as a combiner action // instead so we can include a check for masking back in the upper // eight bits of the source into the lower eight bits of the result. //def : T2Pat<(and (shl rGPR:$Src, (i32 8)), 0xFF00FF), // (t2UXTB16 rGPR:$Src, 3)>, // Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(and (srl rGPR:$Src, (i32 8)), 0xFF00FF), (t2UXTB16 rGPR:$Src, 1)>, Requires<[HasT2ExtractPack, IsThumb2]>; def t2UXTAB : T2I_exta_rrot<0b101, "uxtab", BinOpFrag<(add node:$LHS, (and node:$RHS, 0x00FF))>>; def t2UXTAH : T2I_exta_rrot<0b001, "uxtah", BinOpFrag<(add node:$LHS, (and node:$RHS, 0xFFFF))>>; def t2UXTAB16 : T2I_exta_rrot_np<0b011, "uxtab16">; def : Pat<(add rGPR:$Rn, (and (srl rGPR:$Rm, rot_imm:$rot), 0xFF)), (t2UXTAB rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : Pat<(add rGPR:$Rn, (and (srl rGPR:$Rm, imm8_or_16:$rot), 0xFFFF)), (t2UXTAH rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>, Requires<[HasT2ExtractPack, IsThumb2]>; } //===----------------------------------------------------------------------===// // Arithmetic Instructions. // defm t2ADD : T2I_bin_ii12rs<0b000, "add", add, 1>; defm t2SUB : T2I_bin_ii12rs<0b101, "sub", sub>; // ADD and SUB with 's' bit set. No 12-bit immediate (T4) variants. // // Currently, t2ADDS/t2SUBS are pseudo opcodes that exist only in the // selection DAG. They are "lowered" to real t2ADD/t2SUB opcodes by // AdjustInstrPostInstrSelection where we determine whether or not to // set the "s" bit based on CPSR liveness. // // FIXME: Eliminate t2ADDS/t2SUBS pseudo opcodes after adding tablegen // support for an optional CPSR definition that corresponds to the DAG // node's second value. We can then eliminate the implicit def of CPSR. defm t2ADDS : T2I_bin_s_irs ; defm t2SUBS : T2I_bin_s_irs ; let hasPostISelHook = 1 in { defm t2ADC : T2I_adde_sube_irs<0b1010, "adc", ARMadde, 1>; defm t2SBC : T2I_adde_sube_irs<0b1011, "sbc", ARMsube>; } // RSB defm t2RSB : T2I_rbin_irs <0b1110, "rsb", sub>; // FIXME: Eliminate them if we can write def : Pat patterns which defines // CPSR and the implicit def of CPSR is not needed. defm t2RSBS : T2I_rbin_s_is ; // (sub X, imm) gets canonicalized to (add X, -imm). Match this form. // The assume-no-carry-in form uses the negation of the input since add/sub // assume opposite meanings of the carry flag (i.e., carry == !borrow). // See the definition of AddWithCarry() in the ARM ARM A2.2.1 for the gory // details. // The AddedComplexity preferences the first variant over the others since // it can be shrunk to a 16-bit wide encoding, while the others cannot. let AddedComplexity = 1 in def : T2Pat<(add GPR:$src, imm1_255_neg:$imm), (t2SUBri GPR:$src, imm1_255_neg:$imm)>; def : T2Pat<(add GPR:$src, t2_so_imm_neg:$imm), (t2SUBri GPR:$src, t2_so_imm_neg:$imm)>; def : T2Pat<(add GPR:$src, imm0_4095_neg:$imm), (t2SUBri12 GPR:$src, imm0_4095_neg:$imm)>; def : T2Pat<(add GPR:$src, imm0_65535_neg:$imm), (t2SUBrr GPR:$src, (t2MOVi16 (imm_neg_XFORM imm:$imm)))>; let AddedComplexity = 1 in def : T2Pat<(ARMaddc rGPR:$src, imm1_255_neg:$imm), (t2SUBSri rGPR:$src, imm1_255_neg:$imm)>; def : T2Pat<(ARMaddc rGPR:$src, t2_so_imm_neg:$imm), (t2SUBSri rGPR:$src, t2_so_imm_neg:$imm)>; def : T2Pat<(ARMaddc rGPR:$src, imm0_65535_neg:$imm), (t2SUBSrr rGPR:$src, (t2MOVi16 (imm_neg_XFORM imm:$imm)))>; // The with-carry-in form matches bitwise not instead of the negation. // Effectively, the inverse interpretation of the carry flag already accounts // for part of the negation. let AddedComplexity = 1 in def : T2Pat<(ARMadde rGPR:$src, imm0_255_not:$imm, CPSR), (t2SBCri rGPR:$src, imm0_255_not:$imm)>; def : T2Pat<(ARMadde rGPR:$src, t2_so_imm_not:$imm, CPSR), (t2SBCri rGPR:$src, t2_so_imm_not:$imm)>; def : T2Pat<(ARMadde rGPR:$src, imm0_65535_neg:$imm, CPSR), (t2SBCrr rGPR:$src, (t2MOVi16 (imm_not_XFORM imm:$imm)))>; // Select Bytes -- for disassembly only def t2SEL : T2ThreeReg<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), NoItinerary, "sel", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-24} = 0b010; let Inst{23} = 0b1; let Inst{22-20} = 0b010; let Inst{15-12} = 0b1111; let Inst{7} = 0b1; let Inst{6-4} = 0b000; } // A6.3.13, A6.3.14, A6.3.15 Parallel addition and subtraction (signed/unsigned) // And Miscellaneous operations -- for disassembly only class T2I_pam op22_20, bits<4> op7_4, string opc, list pat = [/* For disassembly only; pattern left blank */], dag iops = (ins rGPR:$Rn, rGPR:$Rm), string asm = "\t$Rd, $Rn, $Rm"> : T2I<(outs rGPR:$Rd), iops, NoItinerary, opc, asm, pat>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0101; let Inst{22-20} = op22_20; let Inst{15-12} = 0b1111; let Inst{7-4} = op7_4; bits<4> Rd; bits<4> Rn; bits<4> Rm; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{3-0} = Rm; } // Saturating add/subtract -- for disassembly only def t2QADD : T2I_pam<0b000, 0b1000, "qadd", [(set rGPR:$Rd, (int_arm_qadd rGPR:$Rn, rGPR:$Rm))], (ins rGPR:$Rm, rGPR:$Rn), "\t$Rd, $Rm, $Rn">; def t2QADD16 : T2I_pam<0b001, 0b0001, "qadd16">; def t2QADD8 : T2I_pam<0b000, 0b0001, "qadd8">; def t2QASX : T2I_pam<0b010, 0b0001, "qasx">; def t2QDADD : T2I_pam<0b000, 0b1001, "qdadd", [], (ins rGPR:$Rm, rGPR:$Rn), "\t$Rd, $Rm, $Rn">; def t2QDSUB : T2I_pam<0b000, 0b1011, "qdsub", [], (ins rGPR:$Rm, rGPR:$Rn), "\t$Rd, $Rm, $Rn">; def t2QSAX : T2I_pam<0b110, 0b0001, "qsax">; def t2QSUB : T2I_pam<0b000, 0b1010, "qsub", [(set rGPR:$Rd, (int_arm_qsub rGPR:$Rn, rGPR:$Rm))], (ins rGPR:$Rm, rGPR:$Rn), "\t$Rd, $Rm, $Rn">; def t2QSUB16 : T2I_pam<0b101, 0b0001, "qsub16">; def t2QSUB8 : T2I_pam<0b100, 0b0001, "qsub8">; def t2UQADD16 : T2I_pam<0b001, 0b0101, "uqadd16">; def t2UQADD8 : T2I_pam<0b000, 0b0101, "uqadd8">; def t2UQASX : T2I_pam<0b010, 0b0101, "uqasx">; def t2UQSAX : T2I_pam<0b110, 0b0101, "uqsax">; def t2UQSUB16 : T2I_pam<0b101, 0b0101, "uqsub16">; def t2UQSUB8 : T2I_pam<0b100, 0b0101, "uqsub8">; // Signed/Unsigned add/subtract -- for disassembly only def t2SASX : T2I_pam<0b010, 0b0000, "sasx">; def t2SADD16 : T2I_pam<0b001, 0b0000, "sadd16">; def t2SADD8 : T2I_pam<0b000, 0b0000, "sadd8">; def t2SSAX : T2I_pam<0b110, 0b0000, "ssax">; def t2SSUB16 : T2I_pam<0b101, 0b0000, "ssub16">; def t2SSUB8 : T2I_pam<0b100, 0b0000, "ssub8">; def t2UASX : T2I_pam<0b010, 0b0100, "uasx">; def t2UADD16 : T2I_pam<0b001, 0b0100, "uadd16">; def t2UADD8 : T2I_pam<0b000, 0b0100, "uadd8">; def t2USAX : T2I_pam<0b110, 0b0100, "usax">; def t2USUB16 : T2I_pam<0b101, 0b0100, "usub16">; def t2USUB8 : T2I_pam<0b100, 0b0100, "usub8">; // Signed/Unsigned halving add/subtract -- for disassembly only def t2SHASX : T2I_pam<0b010, 0b0010, "shasx">; def t2SHADD16 : T2I_pam<0b001, 0b0010, "shadd16">; def t2SHADD8 : T2I_pam<0b000, 0b0010, "shadd8">; def t2SHSAX : T2I_pam<0b110, 0b0010, "shsax">; def t2SHSUB16 : T2I_pam<0b101, 0b0010, "shsub16">; def t2SHSUB8 : T2I_pam<0b100, 0b0010, "shsub8">; def t2UHASX : T2I_pam<0b010, 0b0110, "uhasx">; def t2UHADD16 : T2I_pam<0b001, 0b0110, "uhadd16">; def t2UHADD8 : T2I_pam<0b000, 0b0110, "uhadd8">; def t2UHSAX : T2I_pam<0b110, 0b0110, "uhsax">; def t2UHSUB16 : T2I_pam<0b101, 0b0110, "uhsub16">; def t2UHSUB8 : T2I_pam<0b100, 0b0110, "uhsub8">; // Helper class for disassembly only // A6.3.16 & A6.3.17 // T2Imac - Thumb2 multiply [accumulate, and absolute difference] instructions. class T2ThreeReg_mac op22_20, bits<4> op7_4, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2ThreeReg { let Inst{31-27} = 0b11111; let Inst{26-24} = 0b011; let Inst{23} = long; let Inst{22-20} = op22_20; let Inst{7-4} = op7_4; } class T2FourReg_mac op22_20, bits<4> op7_4, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2FourReg { let Inst{31-27} = 0b11111; let Inst{26-24} = 0b011; let Inst{23} = long; let Inst{22-20} = op22_20; let Inst{7-4} = op7_4; } // Unsigned Sum of Absolute Differences [and Accumulate]. def t2USAD8 : T2ThreeReg_mac<0, 0b111, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), NoItinerary, "usad8", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]> { let Inst{15-12} = 0b1111; } def t2USADA8 : T2FourReg_mac<0, 0b111, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), NoItinerary, "usada8", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasDSP]>; // Signed/Unsigned saturate. class T2SatI pattern> : T2I { bits<4> Rd; bits<4> Rn; bits<5> sat_imm; bits<7> sh; let Inst{11-8} = Rd; let Inst{19-16} = Rn; let Inst{4-0} = sat_imm; let Inst{21} = sh{5}; let Inst{14-12} = sh{4-2}; let Inst{7-6} = sh{1-0}; } def t2SSAT: T2SatI< (outs rGPR:$Rd), (ins imm1_32:$sat_imm, rGPR:$Rn, t2_shift_imm:$sh), NoItinerary, "ssat", "\t$Rd, $sat_imm, $Rn$sh", []>, Requires<[IsThumb2]> { let Inst{31-27} = 0b11110; let Inst{25-22} = 0b1100; let Inst{20} = 0; let Inst{15} = 0; let Inst{5} = 0; } def t2SSAT16: T2SatI< (outs rGPR:$Rd), (ins imm1_16:$sat_imm, rGPR:$Rn), NoItinerary, "ssat16", "\t$Rd, $sat_imm, $Rn", []>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11110; let Inst{25-22} = 0b1100; let Inst{20} = 0; let Inst{15} = 0; let Inst{21} = 1; // sh = '1' let Inst{14-12} = 0b000; // imm3 = '000' let Inst{7-6} = 0b00; // imm2 = '00' let Inst{5-4} = 0b00; } def t2USAT: T2SatI< (outs rGPR:$Rd), (ins imm0_31:$sat_imm, rGPR:$Rn, t2_shift_imm:$sh), NoItinerary, "usat", "\t$Rd, $sat_imm, $Rn$sh", []>, Requires<[IsThumb2]> { let Inst{31-27} = 0b11110; let Inst{25-22} = 0b1110; let Inst{20} = 0; let Inst{15} = 0; } def t2USAT16: T2SatI<(outs rGPR:$Rd), (ins imm0_15:$sat_imm, rGPR:$Rn), NoItinerary, "usat16", "\t$Rd, $sat_imm, $Rn", []>, Requires<[IsThumb2, HasDSP]> { let Inst{31-22} = 0b1111001110; let Inst{20} = 0; let Inst{15} = 0; let Inst{21} = 1; // sh = '1' let Inst{14-12} = 0b000; // imm3 = '000' let Inst{7-6} = 0b00; // imm2 = '00' let Inst{5-4} = 0b00; } def : T2Pat<(int_arm_ssat GPR:$a, imm1_32:$pos), (t2SSAT imm1_32:$pos, GPR:$a, 0)>; def : T2Pat<(int_arm_usat GPR:$a, imm0_31:$pos), (t2USAT imm0_31:$pos, GPR:$a, 0)>; def : T2Pat<(ARMssatnoshift GPRnopc:$Rn, imm0_31:$imm), (t2SSAT imm0_31:$imm, GPRnopc:$Rn, 0)>; //===----------------------------------------------------------------------===// // Shift and rotate Instructions. // defm t2LSL : T2I_sh_ir<0b00, "lsl", imm0_31, shl>; defm t2LSR : T2I_sh_ir<0b01, "lsr", imm_sr, srl>; defm t2ASR : T2I_sh_ir<0b10, "asr", imm_sr, sra>; defm t2ROR : T2I_sh_ir<0b11, "ror", imm0_31, rotr>; // (rotr x, (and y, 0x...1f)) ==> (ROR x, y) def : T2Pat<(rotr rGPR:$lhs, (and rGPR:$rhs, lo5AllOne)), (t2RORrr rGPR:$lhs, rGPR:$rhs)>; let Uses = [CPSR] in { def t2RRX : T2sTwoReg<(outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iMOVsi, "rrx", "\t$Rd, $Rm", [(set rGPR:$Rd, (ARMrrx rGPR:$Rm))]>, Sched<[WriteALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; let Inst{19-16} = 0b1111; // Rn let Inst{14-12} = 0b000; let Inst{7-4} = 0b0011; } } let isCodeGenOnly = 1, Defs = [CPSR] in { def t2MOVsrl_flag : T2TwoRegShiftImm< (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iMOVsi, "lsrs", ".w\t$Rd, $Rm, #1", [(set rGPR:$Rd, (ARMsrl_flag rGPR:$Rm))]>, Sched<[WriteALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; let Inst{20} = 1; // The S bit. let Inst{19-16} = 0b1111; // Rn let Inst{5-4} = 0b01; // Shift type. // Shift amount = Inst{14-12:7-6} = 1. let Inst{14-12} = 0b000; let Inst{7-6} = 0b01; } def t2MOVsra_flag : T2TwoRegShiftImm< (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iMOVsi, "asrs", ".w\t$Rd, $Rm, #1", [(set rGPR:$Rd, (ARMsra_flag rGPR:$Rm))]>, Sched<[WriteALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; let Inst{20} = 1; // The S bit. let Inst{19-16} = 0b1111; // Rn let Inst{5-4} = 0b10; // Shift type. // Shift amount = Inst{14-12:7-6} = 1. let Inst{14-12} = 0b000; let Inst{7-6} = 0b01; } } //===----------------------------------------------------------------------===// // Bitwise Instructions. // defm t2AND : T2I_bin_w_irs<0b0000, "and", IIC_iBITi, IIC_iBITr, IIC_iBITsi, and, 1>; defm t2ORR : T2I_bin_w_irs<0b0010, "orr", IIC_iBITi, IIC_iBITr, IIC_iBITsi, or, 1>; defm t2EOR : T2I_bin_w_irs<0b0100, "eor", IIC_iBITi, IIC_iBITr, IIC_iBITsi, xor, 1>; defm t2BIC : T2I_bin_w_irs<0b0001, "bic", IIC_iBITi, IIC_iBITr, IIC_iBITsi, BinOpFrag<(and node:$LHS, (not node:$RHS))>>; class T2BitFI pattern> : T2I { bits<4> Rd; bits<5> msb; bits<5> lsb; let Inst{11-8} = Rd; let Inst{4-0} = msb{4-0}; let Inst{14-12} = lsb{4-2}; let Inst{7-6} = lsb{1-0}; } class T2TwoRegBitFI pattern> : T2BitFI { bits<4> Rn; let Inst{19-16} = Rn; } let Constraints = "$src = $Rd" in def t2BFC : T2BitFI<(outs rGPR:$Rd), (ins rGPR:$src, bf_inv_mask_imm:$imm), IIC_iUNAsi, "bfc", "\t$Rd, $imm", [(set rGPR:$Rd, (and rGPR:$src, bf_inv_mask_imm:$imm))]> { let Inst{31-27} = 0b11110; let Inst{26} = 0; // should be 0. let Inst{25} = 1; let Inst{24-20} = 0b10110; let Inst{19-16} = 0b1111; // Rn let Inst{15} = 0; let Inst{5} = 0; // should be 0. bits<10> imm; let msb{4-0} = imm{9-5}; let lsb{4-0} = imm{4-0}; } def t2SBFX: T2TwoRegBitFI< (outs rGPR:$Rd), (ins rGPR:$Rn, imm0_31:$lsb, imm1_32:$msb), IIC_iUNAsi, "sbfx", "\t$Rd, $Rn, $lsb, $msb", []> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-20} = 0b10100; let Inst{15} = 0; } def t2UBFX: T2TwoRegBitFI< (outs rGPR:$Rd), (ins rGPR:$Rn, imm0_31:$lsb, imm1_32:$msb), IIC_iUNAsi, "ubfx", "\t$Rd, $Rn, $lsb, $msb", []> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-20} = 0b11100; let Inst{15} = 0; } // A8.8.247 UDF - Undefined (Encoding T2) def t2UDF : T2XI<(outs), (ins imm0_65535:$imm16), IIC_Br, "udf.w\t$imm16", [(int_arm_undefined imm0_65535:$imm16)]> { bits<16> imm16; let Inst{31-29} = 0b111; let Inst{28-27} = 0b10; let Inst{26-20} = 0b1111111; let Inst{19-16} = imm16{15-12}; let Inst{15} = 0b1; let Inst{14-12} = 0b010; let Inst{11-0} = imm16{11-0}; } // A8.6.18 BFI - Bitfield insert (Encoding T1) let Constraints = "$src = $Rd" in { def t2BFI : T2TwoRegBitFI<(outs rGPR:$Rd), (ins rGPR:$src, rGPR:$Rn, bf_inv_mask_imm:$imm), IIC_iBITi, "bfi", "\t$Rd, $Rn, $imm", [(set rGPR:$Rd, (ARMbfi rGPR:$src, rGPR:$Rn, bf_inv_mask_imm:$imm))]> { let Inst{31-27} = 0b11110; let Inst{26} = 0; // should be 0. let Inst{25} = 1; let Inst{24-20} = 0b10110; let Inst{15} = 0; let Inst{5} = 0; // should be 0. bits<10> imm; let msb{4-0} = imm{9-5}; let lsb{4-0} = imm{4-0}; } } defm t2ORN : T2I_bin_irs<0b0011, "orn", IIC_iBITi, IIC_iBITr, IIC_iBITsi, BinOpFrag<(or node:$LHS, (not node:$RHS))>, 0, "">; /// T2I_un_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a /// unary operation that produces a value. These are predicable and can be /// changed to modify CPSR. multiclass T2I_un_irs opcod, string opc, InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, PatFrag opnode, bit Cheap = 0, bit ReMat = 0, bit MoveImm = 0> { // shifted imm def i : T2sOneRegImm<(outs rGPR:$Rd), (ins t2_so_imm:$imm), iii, opc, "\t$Rd, $imm", [(set rGPR:$Rd, (opnode t2_so_imm:$imm))]>, Sched<[WriteALU]> { let isAsCheapAsAMove = Cheap; let isReMaterializable = ReMat; let isMoveImm = MoveImm; let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{19-16} = 0b1111; // Rn let Inst{15} = 0; } // register def r : T2sTwoReg<(outs rGPR:$Rd), (ins rGPR:$Rm), iir, opc, ".w\t$Rd, $Rm", [(set rGPR:$Rd, (opnode rGPR:$Rm))]>, Sched<[WriteALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{19-16} = 0b1111; // Rn let Inst{14-12} = 0b000; // imm3 let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def s : T2sOneRegShiftedReg<(outs rGPR:$Rd), (ins t2_so_reg:$ShiftedRm), iis, opc, ".w\t$Rd, $ShiftedRm", [(set rGPR:$Rd, (opnode t2_so_reg:$ShiftedRm))]>, Sched<[WriteALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; let Inst{19-16} = 0b1111; // Rn } } // Prefer over of t2EORri ra, rb, -1 because mvn has 16-bit version let AddedComplexity = 1 in defm t2MVN : T2I_un_irs <0b0011, "mvn", IIC_iMVNi, IIC_iMVNr, IIC_iMVNsi, not, 1, 1, 1>; let AddedComplexity = 1 in def : T2Pat<(and rGPR:$src, t2_so_imm_not:$imm), (t2BICri rGPR:$src, t2_so_imm_not:$imm)>; // top16Zero - answer true if the upper 16 bits of $src are 0, false otherwise def top16Zero: PatLeaf<(i32 rGPR:$src), [{ return CurDAG->MaskedValueIsZero(SDValue(N,0), APInt::getHighBitsSet(32, 16)); }]>; // so_imm_notSext is needed instead of so_imm_not, as the value of imm // will match the extended, not the original bitWidth for $src. def : T2Pat<(and top16Zero:$src, t2_so_imm_notSext:$imm), (t2BICri rGPR:$src, t2_so_imm_notSext:$imm)>; // FIXME: Disable this pattern on Darwin to workaround an assembler bug. def : T2Pat<(or rGPR:$src, t2_so_imm_not:$imm), (t2ORNri rGPR:$src, t2_so_imm_not:$imm)>, Requires<[IsThumb2]>; def : T2Pat<(t2_so_imm_not:$src), (t2MVNi t2_so_imm_not:$src)>; //===----------------------------------------------------------------------===// // Multiply Instructions. // let isCommutable = 1 in def t2MUL: T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL32, "mul", "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (mul rGPR:$Rn, rGPR:$Rm))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b000; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-4} = 0b0000; // Multiply } def t2MLA: T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "mla", "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add (mul rGPR:$Rn, rGPR:$Rm), rGPR:$Ra))]>, Requires<[IsThumb2, UseMulOps]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b000; let Inst{7-4} = 0b0000; // Multiply } def t2MLS: T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "mls", "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (sub rGPR:$Ra, (mul rGPR:$Rn, rGPR:$Rm)))]>, Requires<[IsThumb2, UseMulOps]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b000; let Inst{7-4} = 0b0001; // Multiply and Subtract } // Extra precision multiplies with low / high results let hasSideEffects = 0 in { let isCommutable = 1 in { def t2SMULL : T2MulLong<0b000, 0b0000, (outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL64, "smull", "\t$RdLo, $RdHi, $Rn, $Rm", []>; def t2UMULL : T2MulLong<0b010, 0b0000, (outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL64, "umull", "\t$RdLo, $RdHi, $Rn, $Rm", []>; } // isCommutable // Multiply + accumulate def t2SMLAL : T2MlaLong<0b100, 0b0000, (outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$RLo, rGPR:$RHi), IIC_iMAC64, "smlal", "\t$RdLo, $RdHi, $Rn, $Rm", []>, RegConstraint<"$RLo = $RdLo, $RHi = $RdHi">; def t2UMLAL : T2MlaLong<0b110, 0b0000, (outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$RLo, rGPR:$RHi), IIC_iMAC64, "umlal", "\t$RdLo, $RdHi, $Rn, $Rm", []>, RegConstraint<"$RLo = $RdLo, $RHi = $RdHi">; def t2UMAAL : T2MulLong<0b110, 0b0110, (outs rGPR:$RdLo, rGPR:$RdHi), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$RLo, rGPR:$RHi), IIC_iMAC64, "umaal", "\t$RdLo, $RdHi, $Rn, $Rm", []>, RegConstraint<"$RLo = $RdLo, $RHi = $RdHi">, Requires<[IsThumb2, HasDSP]>; } // hasSideEffects // Rounding variants of the below included for disassembly only // Most significant word multiply def t2SMMUL : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL32, "smmul", "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (mulhs rGPR:$Rn, rGPR:$Rm))]>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b101; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0) } def t2SMMULR : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL32, "smmulr", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b101; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1) } def t2SMMLA : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smmla", "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add (mulhs rGPR:$Rm, rGPR:$Rn), rGPR:$Ra))]>, Requires<[IsThumb2, HasDSP, UseMulOps]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b101; let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0) } def t2SMMLAR: T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smmlar", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b101; let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1) } def t2SMMLS: T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smmls", "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (sub rGPR:$Ra, (mulhs rGPR:$Rn, rGPR:$Rm)))]>, Requires<[IsThumb2, HasDSP, UseMulOps]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b110; let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0) } def t2SMMLSR:T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smmlsr", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b110; let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1) } multiclass T2I_smul { def BB : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "bb"), "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (opnode (sext_inreg rGPR:$Rn, i16), (sext_inreg rGPR:$Rm, i16)))]>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b00; } def BT : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "bt"), "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (opnode (sext_inreg rGPR:$Rn, i16), (sra rGPR:$Rm, (i32 16))))]>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b01; } def TB : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "tb"), "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (opnode (sra rGPR:$Rn, (i32 16)), (sext_inreg rGPR:$Rm, i16)))]>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b10; } def TT : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "tt"), "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (opnode (sra rGPR:$Rn, (i32 16)), (sra rGPR:$Rm, (i32 16))))]>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b11; } def WB : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "wb"), "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b00; } def WT : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMUL16, !strconcat(opc, "wt"), "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate) let Inst{7-6} = 0b00; let Inst{5-4} = 0b01; } } multiclass T2I_smla { def BB : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "bb"), "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sext_inreg rGPR:$Rn, i16), (sext_inreg rGPR:$Rm, i16))))]>, Requires<[IsThumb2, HasDSP, UseMulOps]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{7-6} = 0b00; let Inst{5-4} = 0b00; } def BT : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "bt"), "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sext_inreg rGPR:$Rn, i16), (sra rGPR:$Rm, (i32 16)))))]>, Requires<[IsThumb2, HasDSP, UseMulOps]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{7-6} = 0b00; let Inst{5-4} = 0b01; } def TB : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "tb"), "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sra rGPR:$Rn, (i32 16)), (sext_inreg rGPR:$Rm, i16))))]>, Requires<[IsThumb2, HasDSP, UseMulOps]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{7-6} = 0b00; let Inst{5-4} = 0b10; } def TT : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "tt"), "\t$Rd, $Rn, $Rm, $Ra", [(set rGPR:$Rd, (add rGPR:$Ra, (opnode (sra rGPR:$Rn, (i32 16)), (sra rGPR:$Rm, (i32 16)))))]>, Requires<[IsThumb2, HasDSP, UseMulOps]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; let Inst{7-6} = 0b00; let Inst{5-4} = 0b11; } def WB : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "wb"), "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasDSP, UseMulOps]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; let Inst{7-6} = 0b00; let Inst{5-4} = 0b00; } def WT : T2FourReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC16, !strconcat(opc, "wt"), "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasDSP, UseMulOps]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; let Inst{7-6} = 0b00; let Inst{5-4} = 0b01; } } defm t2SMUL : T2I_smul<"smul", mul>; defm t2SMLA : T2I_smla<"smla", mul>; // Halfword multiple accumulate long: SMLAL def t2SMLALBB : T2FourReg_mac<1, 0b100, 0b1000, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlalbb", "\t$Ra, $Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, Requires<[IsThumb2, HasDSP]>; def t2SMLALBT : T2FourReg_mac<1, 0b100, 0b1001, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlalbt", "\t$Ra, $Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, Requires<[IsThumb2, HasDSP]>; def t2SMLALTB : T2FourReg_mac<1, 0b100, 0b1010, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlaltb", "\t$Ra, $Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, Requires<[IsThumb2, HasDSP]>; def t2SMLALTT : T2FourReg_mac<1, 0b100, 0b1011, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlaltt", "\t$Ra, $Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, Requires<[IsThumb2, HasDSP]>; // Dual halfword multiple: SMUAD, SMUSD, SMLAD, SMLSD, SMLALD, SMLSLD def t2SMUAD: T2ThreeReg_mac< 0, 0b010, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC32, "smuad", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]> { let Inst{15-12} = 0b1111; } def t2SMUADX:T2ThreeReg_mac< 0, 0b010, 0b0001, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC32, "smuadx", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]> { let Inst{15-12} = 0b1111; } def t2SMUSD: T2ThreeReg_mac< 0, 0b100, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC32, "smusd", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]> { let Inst{15-12} = 0b1111; } def t2SMUSDX:T2ThreeReg_mac< 0, 0b100, 0b0001, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC32, "smusdx", "\t$Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]> { let Inst{15-12} = 0b1111; } def t2SMLAD : T2FourReg_mac< 0, 0b010, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smlad", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasDSP]>; def t2SMLADX : T2FourReg_mac< 0, 0b010, 0b0001, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smladx", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasDSP]>; def t2SMLSD : T2FourReg_mac<0, 0b100, 0b0000, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smlsd", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasDSP]>; def t2SMLSDX : T2FourReg_mac<0, 0b100, 0b0001, (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, rGPR:$Ra), IIC_iMAC32, "smlsdx", "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsThumb2, HasDSP]>; def t2SMLALD : T2FourReg_mac<1, 0b100, 0b1100, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iMAC64, "smlald", "\t$Ra, $Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]>; def t2SMLALDX : T2FourReg_mac<1, 0b100, 0b1101, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlaldx", "\t$Ra, $Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]>; def t2SMLSLD : T2FourReg_mac<1, 0b101, 0b1100, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rn,rGPR:$Rm), IIC_iMAC64, "smlsld", "\t$Ra, $Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]>; def t2SMLSLDX : T2FourReg_mac<1, 0b101, 0b1101, (outs rGPR:$Ra,rGPR:$Rd), (ins rGPR:$Rm,rGPR:$Rn), IIC_iMAC64, "smlsldx", "\t$Ra, $Rd, $Rn, $Rm", []>, Requires<[IsThumb2, HasDSP]>; //===----------------------------------------------------------------------===// // Division Instructions. // Signed and unsigned division on v7-M // def t2SDIV : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iDIV, "sdiv", "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (sdiv rGPR:$Rn, rGPR:$Rm))]>, Requires<[HasDivide, IsThumb, HasV8MBaseline]> { let Inst{31-27} = 0b11111; let Inst{26-21} = 0b011100; let Inst{20} = 0b1; let Inst{15-12} = 0b1111; let Inst{7-4} = 0b1111; } def t2UDIV : T2ThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iDIV, "udiv", "\t$Rd, $Rn, $Rm", [(set rGPR:$Rd, (udiv rGPR:$Rn, rGPR:$Rm))]>, Requires<[HasDivide, IsThumb, HasV8MBaseline]> { let Inst{31-27} = 0b11111; let Inst{26-21} = 0b011101; let Inst{20} = 0b1; let Inst{15-12} = 0b1111; let Inst{7-4} = 0b1111; } //===----------------------------------------------------------------------===// // Misc. Arithmetic Instructions. // class T2I_misc op1, bits<2> op2, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2ThreeReg { let Inst{31-27} = 0b11111; let Inst{26-22} = 0b01010; let Inst{21-20} = op1; let Inst{15-12} = 0b1111; let Inst{7-6} = 0b10; let Inst{5-4} = op2; let Rn{3-0} = Rm; } def t2CLZ : T2I_misc<0b11, 0b00, (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iUNAr, "clz", "\t$Rd, $Rm", [(set rGPR:$Rd, (ctlz rGPR:$Rm))]>, Sched<[WriteALU]>; def t2RBIT : T2I_misc<0b01, 0b10, (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iUNAr, "rbit", "\t$Rd, $Rm", [(set rGPR:$Rd, (bitreverse rGPR:$Rm))]>, Sched<[WriteALU]>; def t2REV : T2I_misc<0b01, 0b00, (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iUNAr, "rev", ".w\t$Rd, $Rm", [(set rGPR:$Rd, (bswap rGPR:$Rm))]>, Sched<[WriteALU]>; def t2REV16 : T2I_misc<0b01, 0b01, (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iUNAr, "rev16", ".w\t$Rd, $Rm", [(set rGPR:$Rd, (rotr (bswap rGPR:$Rm), (i32 16)))]>, Sched<[WriteALU]>; def t2REVSH : T2I_misc<0b01, 0b11, (outs rGPR:$Rd), (ins rGPR:$Rm), IIC_iUNAr, "revsh", ".w\t$Rd, $Rm", [(set rGPR:$Rd, (sra (bswap rGPR:$Rm), (i32 16)))]>, Sched<[WriteALU]>; def : T2Pat<(or (sra (shl rGPR:$Rm, (i32 24)), (i32 16)), (and (srl rGPR:$Rm, (i32 8)), 0xFF)), (t2REVSH rGPR:$Rm)>; def t2PKHBT : T2ThreeReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, pkh_lsl_amt:$sh), IIC_iBITsi, "pkhbt", "\t$Rd, $Rn, $Rm$sh", [(set rGPR:$Rd, (or (and rGPR:$Rn, 0xFFFF), (and (shl rGPR:$Rm, pkh_lsl_amt:$sh), 0xFFFF0000)))]>, Requires<[HasT2ExtractPack, IsThumb2]>, Sched<[WriteALUsi, ReadALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-20} = 0b01100; let Inst{5} = 0; // BT form let Inst{4} = 0; bits<5> sh; let Inst{14-12} = sh{4-2}; let Inst{7-6} = sh{1-0}; } // Alternate cases for PKHBT where identities eliminate some nodes. def : T2Pat<(or (and rGPR:$src1, 0xFFFF), (and rGPR:$src2, 0xFFFF0000)), (t2PKHBT rGPR:$src1, rGPR:$src2, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(or (and rGPR:$src1, 0xFFFF), (shl rGPR:$src2, imm16_31:$sh)), (t2PKHBT rGPR:$src1, rGPR:$src2, imm16_31:$sh)>, Requires<[HasT2ExtractPack, IsThumb2]>; // Note: Shifts of 1-15 bits will be transformed to srl instead of sra and // will match the pattern below. def t2PKHTB : T2ThreeReg< (outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm, pkh_asr_amt:$sh), IIC_iBITsi, "pkhtb", "\t$Rd, $Rn, $Rm$sh", [(set rGPR:$Rd, (or (and rGPR:$Rn, 0xFFFF0000), (and (sra rGPR:$Rm, pkh_asr_amt:$sh), 0xFFFF)))]>, Requires<[HasT2ExtractPack, IsThumb2]>, Sched<[WriteALUsi, ReadALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-20} = 0b01100; let Inst{5} = 1; // TB form let Inst{4} = 0; bits<5> sh; let Inst{14-12} = sh{4-2}; let Inst{7-6} = sh{1-0}; } // Alternate cases for PKHTB where identities eliminate some nodes. Note that // a shift amount of 0 is *not legal* here, it is PKHBT instead. // We also can not replace a srl (17..31) by an arithmetic shift we would use in // pkhtb src1, src2, asr (17..31). def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000), (srl rGPR:$src2, imm16:$sh)), (t2PKHTB rGPR:$src1, rGPR:$src2, imm16:$sh)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000), (sra rGPR:$src2, imm16_31:$sh)), (t2PKHTB rGPR:$src1, rGPR:$src2, imm16_31:$sh)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000), (and (srl rGPR:$src2, imm1_15:$sh), 0xFFFF)), (t2PKHTB rGPR:$src1, rGPR:$src2, imm1_15:$sh)>, Requires<[HasT2ExtractPack, IsThumb2]>; //===----------------------------------------------------------------------===// // CRC32 Instructions // // Polynomials: // + CRC32{B,H,W} 0x04C11DB7 // + CRC32C{B,H,W} 0x1EDC6F41 // class T2I_crc32 sz, string suffix, SDPatternOperator builtin> : T2ThreeRegNoP<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), NoItinerary, !strconcat("crc32", suffix, "\t$Rd, $Rn, $Rm"), [(set rGPR:$Rd, (builtin rGPR:$Rn, rGPR:$Rm))]>, Requires<[IsThumb2, HasV8, HasCRC]> { let Inst{31-27} = 0b11111; let Inst{26-21} = 0b010110; let Inst{20} = C; let Inst{15-12} = 0b1111; let Inst{7-6} = 0b10; let Inst{5-4} = sz; } def t2CRC32B : T2I_crc32<0, 0b00, "b", int_arm_crc32b>; def t2CRC32CB : T2I_crc32<1, 0b00, "cb", int_arm_crc32cb>; def t2CRC32H : T2I_crc32<0, 0b01, "h", int_arm_crc32h>; def t2CRC32CH : T2I_crc32<1, 0b01, "ch", int_arm_crc32ch>; def t2CRC32W : T2I_crc32<0, 0b10, "w", int_arm_crc32w>; def t2CRC32CW : T2I_crc32<1, 0b10, "cw", int_arm_crc32cw>; //===----------------------------------------------------------------------===// // Comparison Instructions... // defm t2CMP : T2I_cmp_irs<0b1101, "cmp", IIC_iCMPi, IIC_iCMPr, IIC_iCMPsi, ARMcmp>; def : T2Pat<(ARMcmpZ GPRnopc:$lhs, t2_so_imm:$imm), (t2CMPri GPRnopc:$lhs, t2_so_imm:$imm)>; def : T2Pat<(ARMcmpZ GPRnopc:$lhs, rGPR:$rhs), (t2CMPrr GPRnopc:$lhs, rGPR:$rhs)>; def : T2Pat<(ARMcmpZ GPRnopc:$lhs, t2_so_reg:$rhs), (t2CMPrs GPRnopc:$lhs, t2_so_reg:$rhs)>; let isCompare = 1, Defs = [CPSR] in { // shifted imm def t2CMNri : T2OneRegCmpImm< (outs), (ins GPRnopc:$Rn, t2_so_imm:$imm), IIC_iCMPi, "cmn", ".w\t$Rn, $imm", [(ARMcmn GPRnopc:$Rn, (ineg t2_so_imm:$imm))]>, Sched<[WriteCMP, ReadALU]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = 0b1000; let Inst{20} = 1; // The S bit. let Inst{15} = 0; let Inst{11-8} = 0b1111; // Rd } // register def t2CMNzrr : T2TwoRegCmp< (outs), (ins GPRnopc:$Rn, rGPR:$Rm), IIC_iCMPr, "cmn", ".w\t$Rn, $Rm", [(BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))> GPRnopc:$Rn, rGPR:$Rm)]>, Sched<[WriteCMP, ReadALU, ReadALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b1000; let Inst{20} = 1; // The S bit. let Inst{14-12} = 0b000; // imm3 let Inst{11-8} = 0b1111; // Rd let Inst{7-6} = 0b00; // imm2 let Inst{5-4} = 0b00; // type } // shifted register def t2CMNzrs : T2OneRegCmpShiftedReg< (outs), (ins GPRnopc:$Rn, t2_so_reg:$ShiftedRm), IIC_iCMPsi, "cmn", ".w\t$Rn, $ShiftedRm", [(BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))> GPRnopc:$Rn, t2_so_reg:$ShiftedRm)]>, Sched<[WriteCMPsi, ReadALU, ReadALU]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b1000; let Inst{20} = 1; // The S bit. let Inst{11-8} = 0b1111; // Rd } } // Assembler aliases w/o the ".w" suffix. // No alias here for 'rr' version as not all instantiations of this multiclass // want one (CMP in particular, does not). def : t2InstAlias<"cmn${p} $Rn, $imm", (t2CMNri GPRnopc:$Rn, t2_so_imm:$imm, pred:$p)>; def : t2InstAlias<"cmn${p} $Rn, $shift", (t2CMNzrs GPRnopc:$Rn, t2_so_reg:$shift, pred:$p)>; def : T2Pat<(ARMcmp GPR:$src, t2_so_imm_neg:$imm), (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>; def : T2Pat<(ARMcmpZ GPRnopc:$src, t2_so_imm_neg:$imm), (t2CMNri GPRnopc:$src, t2_so_imm_neg:$imm)>; defm t2TST : T2I_cmp_irs<0b0000, "tst", IIC_iTSTi, IIC_iTSTr, IIC_iTSTsi, BinOpFrag<(ARMcmpZ (and_su node:$LHS, node:$RHS), 0)>>; defm t2TEQ : T2I_cmp_irs<0b0100, "teq", IIC_iTSTi, IIC_iTSTr, IIC_iTSTsi, BinOpFrag<(ARMcmpZ (xor_su node:$LHS, node:$RHS), 0)>>; // Conditional moves let hasSideEffects = 0 in { let isCommutable = 1, isSelect = 1 in def t2MOVCCr : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$false, rGPR:$Rm, cmovpred:$p), 4, IIC_iCMOVr, [(set rGPR:$Rd, (ARMcmov rGPR:$false, rGPR:$Rm, cmovpred:$p))]>, RegConstraint<"$false = $Rd">, Sched<[WriteALU]>; let isMoveImm = 1 in def t2MOVCCi : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$false, t2_so_imm:$imm, cmovpred:$p), 4, IIC_iCMOVi, [(set rGPR:$Rd, (ARMcmov rGPR:$false,t2_so_imm:$imm, cmovpred:$p))]>, RegConstraint<"$false = $Rd">, Sched<[WriteALU]>; let isCodeGenOnly = 1 in { let isMoveImm = 1 in def t2MOVCCi16 : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$false, imm0_65535_expr:$imm, cmovpred:$p), 4, IIC_iCMOVi, [(set rGPR:$Rd, (ARMcmov rGPR:$false, imm0_65535:$imm, cmovpred:$p))]>, RegConstraint<"$false = $Rd">, Sched<[WriteALU]>; let isMoveImm = 1 in def t2MVNCCi : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$false, t2_so_imm:$imm, cmovpred:$p), 4, IIC_iCMOVi, [(set rGPR:$Rd, (ARMcmov rGPR:$false, t2_so_imm_not:$imm, cmovpred:$p))]>, RegConstraint<"$false = $Rd">, Sched<[WriteALU]>; class MOVCCShPseudo : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$false, rGPR:$Rm, i32imm:$imm, cmovpred:$p), 4, IIC_iCMOVsi, [(set rGPR:$Rd, (ARMcmov rGPR:$false, (opnode rGPR:$Rm, (i32 ty:$imm)), cmovpred:$p))]>, RegConstraint<"$false = $Rd">, Sched<[WriteALU]>; def t2MOVCClsl : MOVCCShPseudo; def t2MOVCClsr : MOVCCShPseudo; def t2MOVCCasr : MOVCCShPseudo; def t2MOVCCror : MOVCCShPseudo; let isMoveImm = 1 in def t2MOVCCi32imm : t2PseudoInst<(outs rGPR:$dst), (ins rGPR:$false, i32imm:$src, cmovpred:$p), 8, IIC_iCMOVix2, [(set rGPR:$dst, (ARMcmov rGPR:$false, imm:$src, cmovpred:$p))]>, RegConstraint<"$false = $dst">; } // isCodeGenOnly = 1 } // hasSideEffects //===----------------------------------------------------------------------===// // Atomic operations intrinsics // // memory barriers protect the atomic sequences let hasSideEffects = 1 in { def t2DMB : T2I<(outs), (ins memb_opt:$opt), NoItinerary, "dmb", "\t$opt", [(int_arm_dmb (i32 imm0_15:$opt))]>, Requires<[IsThumb, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f5; let Inst{3-0} = opt; } def t2DSB : T2I<(outs), (ins memb_opt:$opt), NoItinerary, "dsb", "\t$opt", [(int_arm_dsb (i32 imm0_15:$opt))]>, Requires<[IsThumb, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f4; let Inst{3-0} = opt; } def t2ISB : T2I<(outs), (ins instsyncb_opt:$opt), NoItinerary, "isb", "\t$opt", [(int_arm_isb (i32 imm0_15:$opt))]>, Requires<[IsThumb, HasDB]> { bits<4> opt; let Inst{31-4} = 0xf3bf8f6; let Inst{3-0} = opt; } } class T2I_ldrex opcod, dag oops, dag iops, AddrMode am, int sz, InstrItinClass itin, string opc, string asm, string cstr, list pattern, bits<4> rt2 = 0b1111> : Thumb2I { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0001101; let Inst{11-8} = rt2; let Inst{7-4} = opcod; let Inst{3-0} = 0b1111; bits<4> addr; bits<4> Rt; let Inst{19-16} = addr; let Inst{15-12} = Rt; } class T2I_strex opcod, dag oops, dag iops, AddrMode am, int sz, InstrItinClass itin, string opc, string asm, string cstr, list pattern, bits<4> rt2 = 0b1111> : Thumb2I { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0001100; let Inst{11-8} = rt2; let Inst{7-4} = opcod; bits<4> Rd; bits<4> addr; bits<4> Rt; let Inst{3-0} = Rd; let Inst{19-16} = addr; let Inst{15-12} = Rt; } let mayLoad = 1 in { def t2LDREXB : T2I_ldrex<0b0100, (outs rGPR:$Rt), (ins addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "ldrexb", "\t$Rt, $addr", "", [(set rGPR:$Rt, (ldrex_1 addr_offset_none:$addr))]>, Requires<[IsThumb, HasV8MBaseline]>; def t2LDREXH : T2I_ldrex<0b0101, (outs rGPR:$Rt), (ins addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "ldrexh", "\t$Rt, $addr", "", [(set rGPR:$Rt, (ldrex_2 addr_offset_none:$addr))]>, Requires<[IsThumb, HasV8MBaseline]>; def t2LDREX : Thumb2I<(outs rGPR:$Rt), (ins t2addrmode_imm0_1020s4:$addr), AddrModeNone, 4, NoItinerary, "ldrex", "\t$Rt, $addr", "", [(set rGPR:$Rt, (ldrex_4 t2addrmode_imm0_1020s4:$addr))]>, Requires<[IsThumb, HasV8MBaseline]> { bits<4> Rt; bits<12> addr; let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0000101; let Inst{19-16} = addr{11-8}; let Inst{15-12} = Rt; let Inst{11-8} = 0b1111; let Inst{7-0} = addr{7-0}; } let hasExtraDefRegAllocReq = 1 in def t2LDREXD : T2I_ldrex<0b0111, (outs rGPR:$Rt, rGPR:$Rt2), (ins addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "ldrexd", "\t$Rt, $Rt2, $addr", "", [], {?, ?, ?, ?}>, Requires<[IsThumb2, IsNotMClass]> { bits<4> Rt2; let Inst{11-8} = Rt2; } def t2LDAEXB : T2I_ldrex<0b1100, (outs rGPR:$Rt), (ins addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "ldaexb", "\t$Rt, $addr", "", [(set rGPR:$Rt, (ldaex_1 addr_offset_none:$addr))]>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex]>; def t2LDAEXH : T2I_ldrex<0b1101, (outs rGPR:$Rt), (ins addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "ldaexh", "\t$Rt, $addr", "", [(set rGPR:$Rt, (ldaex_2 addr_offset_none:$addr))]>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex]>; def t2LDAEX : Thumb2I<(outs rGPR:$Rt), (ins addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "ldaex", "\t$Rt, $addr", "", [(set rGPR:$Rt, (ldaex_4 addr_offset_none:$addr))]>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex]> { bits<4> Rt; bits<4> addr; let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0001101; let Inst{19-16} = addr; let Inst{15-12} = Rt; let Inst{11-8} = 0b1111; let Inst{7-0} = 0b11101111; } let hasExtraDefRegAllocReq = 1 in def t2LDAEXD : T2I_ldrex<0b1111, (outs rGPR:$Rt, rGPR:$Rt2), (ins addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "ldaexd", "\t$Rt, $Rt2, $addr", "", [], {?, ?, ?, ?}>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex, IsNotMClass]> { bits<4> Rt2; let Inst{11-8} = Rt2; let Inst{7} = 1; } } let mayStore = 1, Constraints = "@earlyclobber $Rd" in { def t2STREXB : T2I_strex<0b0100, (outs rGPR:$Rd), (ins rGPR:$Rt, addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "strexb", "\t$Rd, $Rt, $addr", "", [(set rGPR:$Rd, (strex_1 rGPR:$Rt, addr_offset_none:$addr))]>, Requires<[IsThumb, HasV8MBaseline]>; def t2STREXH : T2I_strex<0b0101, (outs rGPR:$Rd), (ins rGPR:$Rt, addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "strexh", "\t$Rd, $Rt, $addr", "", [(set rGPR:$Rd, (strex_2 rGPR:$Rt, addr_offset_none:$addr))]>, Requires<[IsThumb, HasV8MBaseline]>; def t2STREX : Thumb2I<(outs rGPR:$Rd), (ins rGPR:$Rt, t2addrmode_imm0_1020s4:$addr), AddrModeNone, 4, NoItinerary, "strex", "\t$Rd, $Rt, $addr", "", [(set rGPR:$Rd, (strex_4 rGPR:$Rt, t2addrmode_imm0_1020s4:$addr))]>, Requires<[IsThumb, HasV8MBaseline]> { bits<4> Rd; bits<4> Rt; bits<12> addr; let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0000100; let Inst{19-16} = addr{11-8}; let Inst{15-12} = Rt; let Inst{11-8} = Rd; let Inst{7-0} = addr{7-0}; } let hasExtraSrcRegAllocReq = 1 in def t2STREXD : T2I_strex<0b0111, (outs rGPR:$Rd), (ins rGPR:$Rt, rGPR:$Rt2, addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "strexd", "\t$Rd, $Rt, $Rt2, $addr", "", [], {?, ?, ?, ?}>, Requires<[IsThumb2, IsNotMClass]> { bits<4> Rt2; let Inst{11-8} = Rt2; } def t2STLEXB : T2I_strex<0b1100, (outs rGPR:$Rd), (ins rGPR:$Rt, addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "stlexb", "\t$Rd, $Rt, $addr", "", [(set rGPR:$Rd, (stlex_1 rGPR:$Rt, addr_offset_none:$addr))]>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex]>; def t2STLEXH : T2I_strex<0b1101, (outs rGPR:$Rd), (ins rGPR:$Rt, addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "stlexh", "\t$Rd, $Rt, $addr", "", [(set rGPR:$Rd, (stlex_2 rGPR:$Rt, addr_offset_none:$addr))]>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex]>; def t2STLEX : Thumb2I<(outs rGPR:$Rd), (ins rGPR:$Rt, addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "stlex", "\t$Rd, $Rt, $addr", "", [(set rGPR:$Rd, (stlex_4 rGPR:$Rt, addr_offset_none:$addr))]>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex]> { bits<4> Rd; bits<4> Rt; bits<4> addr; let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0001100; let Inst{19-16} = addr; let Inst{15-12} = Rt; let Inst{11-4} = 0b11111110; let Inst{3-0} = Rd; } let hasExtraSrcRegAllocReq = 1 in def t2STLEXD : T2I_strex<0b1111, (outs rGPR:$Rd), (ins rGPR:$Rt, rGPR:$Rt2, addr_offset_none:$addr), AddrModeNone, 4, NoItinerary, "stlexd", "\t$Rd, $Rt, $Rt2, $addr", "", [], {?, ?, ?, ?}>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex, IsNotMClass]> { bits<4> Rt2; let Inst{11-8} = Rt2; } } def t2CLREX : T2I<(outs), (ins), NoItinerary, "clrex", "", [(int_arm_clrex)]>, Requires<[IsThumb, HasV7Clrex]> { let Inst{31-16} = 0xf3bf; let Inst{15-14} = 0b10; let Inst{13} = 0; let Inst{12} = 0; let Inst{11-8} = 0b1111; let Inst{7-4} = 0b0010; let Inst{3-0} = 0b1111; } def : T2Pat<(and (ldrex_1 addr_offset_none:$addr), 0xff), (t2LDREXB addr_offset_none:$addr)>, Requires<[IsThumb, HasV8MBaseline]>; def : T2Pat<(and (ldrex_2 addr_offset_none:$addr), 0xffff), (t2LDREXH addr_offset_none:$addr)>, Requires<[IsThumb, HasV8MBaseline]>; def : T2Pat<(strex_1 (and GPR:$Rt, 0xff), addr_offset_none:$addr), (t2STREXB GPR:$Rt, addr_offset_none:$addr)>, Requires<[IsThumb, HasV8MBaseline]>; def : T2Pat<(strex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr), (t2STREXH GPR:$Rt, addr_offset_none:$addr)>, Requires<[IsThumb, HasV8MBaseline]>; def : T2Pat<(and (ldaex_1 addr_offset_none:$addr), 0xff), (t2LDAEXB addr_offset_none:$addr)>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex]>; def : T2Pat<(and (ldaex_2 addr_offset_none:$addr), 0xffff), (t2LDAEXH addr_offset_none:$addr)>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex]>; def : T2Pat<(stlex_1 (and GPR:$Rt, 0xff), addr_offset_none:$addr), (t2STLEXB GPR:$Rt, addr_offset_none:$addr)>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex]>; def : T2Pat<(stlex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr), (t2STLEXH GPR:$Rt, addr_offset_none:$addr)>, Requires<[IsThumb, HasAcquireRelease, HasV7Clrex]>; //===----------------------------------------------------------------------===// // SJLJ Exception handling intrinsics // eh_sjlj_setjmp() is an instruction sequence to store the return // address and save #0 in R0 for the non-longjmp case. // Since by its nature we may be coming from some other function to get // here, and we're using the stack frame for the containing function to // save/restore registers, we can't keep anything live in regs across // the eh_sjlj_setjmp(), else it will almost certainly have been tromped upon // when we get here from a longjmp(). We force everything out of registers // except for our own input by listing the relevant registers in Defs. By // doing so, we also cause the prologue/epilogue code to actively preserve // all of the callee-saved resgisters, which is exactly what we want. // $val is a scratch register for our use. let Defs = [ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, CPSR, Q0, Q1, Q2, Q3, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15], hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1, usesCustomInserter = 1 in { def t2Int_eh_sjlj_setjmp : Thumb2XI<(outs), (ins tGPR:$src, tGPR:$val), AddrModeNone, 0, NoItinerary, "", "", [(set R0, (ARMeh_sjlj_setjmp tGPR:$src, tGPR:$val))]>, Requires<[IsThumb2, HasVFP2]>; } let Defs = [ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, CPSR ], hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1, usesCustomInserter = 1 in { def t2Int_eh_sjlj_setjmp_nofp : Thumb2XI<(outs), (ins tGPR:$src, tGPR:$val), AddrModeNone, 0, NoItinerary, "", "", [(set R0, (ARMeh_sjlj_setjmp tGPR:$src, tGPR:$val))]>, Requires<[IsThumb2, NoVFP]>; } //===----------------------------------------------------------------------===// // Control-Flow Instructions // // FIXME: remove when we have a way to marking a MI with these properties. // FIXME: Should pc be an implicit operand like PICADD, etc? let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1, hasExtraDefRegAllocReq = 1, isCodeGenOnly = 1 in def t2LDMIA_RET: t2PseudoExpand<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), 4, IIC_iLoad_mBr, [], (t2LDMIA_UPD GPR:$wb, GPR:$Rn, pred:$p, reglist:$regs)>, RegConstraint<"$Rn = $wb">; let isBranch = 1, isTerminator = 1, isBarrier = 1 in { let isPredicable = 1 in def t2B : T2I<(outs), (ins thumb_br_target:$target), IIC_Br, "b", ".w\t$target", [(br bb:$target)]>, Sched<[WriteBr]>, Requires<[IsThumb, HasV8MBaseline]> { let Inst{31-27} = 0b11110; let Inst{15-14} = 0b10; let Inst{12} = 1; bits<24> target; let Inst{26} = target{23}; let Inst{13} = target{22}; let Inst{11} = target{21}; let Inst{25-16} = target{20-11}; let Inst{10-0} = target{10-0}; let DecoderMethod = "DecodeT2BInstruction"; let AsmMatchConverter = "cvtThumbBranches"; } let Size = 4, isNotDuplicable = 1, isIndirectBranch = 1 in { def t2BR_JT : t2PseudoInst<(outs), (ins GPR:$target, GPR:$index, i32imm:$jt), 0, IIC_Br, [(ARMbr2jt GPR:$target, GPR:$index, tjumptable:$jt)]>, Sched<[WriteBr]>; // FIXME: Add a case that can be predicated. def t2TBB_JT : t2PseudoInst<(outs), (ins GPR:$base, GPR:$index, i32imm:$jt, i32imm:$pclbl), 0, IIC_Br, []>, Sched<[WriteBr]>; def t2TBH_JT : t2PseudoInst<(outs), (ins GPR:$base, GPR:$index, i32imm:$jt, i32imm:$pclbl), 0, IIC_Br, []>, Sched<[WriteBr]>; def t2TBB : T2I<(outs), (ins addrmode_tbb:$addr), IIC_Br, "tbb", "\t$addr", []>, Sched<[WriteBrTbl]> { bits<4> Rn; bits<4> Rm; let Inst{31-20} = 0b111010001101; let Inst{19-16} = Rn; let Inst{15-5} = 0b11110000000; let Inst{4} = 0; // B form let Inst{3-0} = Rm; let DecoderMethod = "DecodeThumbTableBranch"; } def t2TBH : T2I<(outs), (ins addrmode_tbh:$addr), IIC_Br, "tbh", "\t$addr", []>, Sched<[WriteBrTbl]> { bits<4> Rn; bits<4> Rm; let Inst{31-20} = 0b111010001101; let Inst{19-16} = Rn; let Inst{15-5} = 0b11110000000; let Inst{4} = 1; // H form let Inst{3-0} = Rm; let DecoderMethod = "DecodeThumbTableBranch"; } } // isNotDuplicable, isIndirectBranch } // isBranch, isTerminator, isBarrier // FIXME: should be able to write a pattern for ARMBrcond, but can't use // a two-value operand where a dag node expects ", "two operands. :( let isBranch = 1, isTerminator = 1 in def t2Bcc : T2I<(outs), (ins brtarget:$target), IIC_Br, "b", ".w\t$target", [/*(ARMbrcond bb:$target, imm:$cc)*/]>, Sched<[WriteBr]> { let Inst{31-27} = 0b11110; let Inst{15-14} = 0b10; let Inst{12} = 0; bits<4> p; let Inst{25-22} = p; bits<21> target; let Inst{26} = target{20}; let Inst{11} = target{19}; let Inst{13} = target{18}; let Inst{21-16} = target{17-12}; let Inst{10-0} = target{11-1}; let DecoderMethod = "DecodeThumb2BCCInstruction"; let AsmMatchConverter = "cvtThumbBranches"; } // Tail calls. The MachO version of thumb tail calls uses a t2 branch, so // it goes here. let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in { // IOS version. let Uses = [SP] in def tTAILJMPd: tPseudoExpand<(outs), (ins thumb_br_target:$dst, pred:$p), 4, IIC_Br, [], (t2B thumb_br_target:$dst, pred:$p)>, Requires<[IsThumb2, IsMachO]>, Sched<[WriteBr]>; } // IT block let Defs = [ITSTATE] in def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask), AddrModeNone, 2, IIC_iALUx, "it$mask\t$cc", "", []>, ComplexDeprecationPredicate<"IT"> { // 16-bit instruction. let Inst{31-16} = 0x0000; let Inst{15-8} = 0b10111111; bits<4> cc; bits<4> mask; let Inst{7-4} = cc; let Inst{3-0} = mask; let DecoderMethod = "DecodeIT"; } // Branch and Exchange Jazelle -- for disassembly only // Rm = Inst{19-16} def t2BXJ : T2I<(outs), (ins GPRnopc:$func), NoItinerary, "bxj", "\t$func", []>, Sched<[WriteBr]>, Requires<[IsThumb2, IsNotMClass]> { bits<4> func; let Inst{31-27} = 0b11110; let Inst{26} = 0; let Inst{25-20} = 0b111100; let Inst{19-16} = func; let Inst{15-0} = 0b1000111100000000; } // Compare and branch on zero / non-zero let isBranch = 1, isTerminator = 1 in { def tCBZ : T1I<(outs), (ins tGPR:$Rn, thumb_cb_target:$target), IIC_Br, "cbz\t$Rn, $target", []>, T1Misc<{0,0,?,1,?,?,?}>, Requires<[IsThumb, HasV8MBaseline]>, Sched<[WriteBr]> { // A8.6.27 bits<6> target; bits<3> Rn; let Inst{9} = target{5}; let Inst{7-3} = target{4-0}; let Inst{2-0} = Rn; } def tCBNZ : T1I<(outs), (ins tGPR:$Rn, thumb_cb_target:$target), IIC_Br, "cbnz\t$Rn, $target", []>, T1Misc<{1,0,?,1,?,?,?}>, Requires<[IsThumb, HasV8MBaseline]>, Sched<[WriteBr]> { // A8.6.27 bits<6> target; bits<3> Rn; let Inst{9} = target{5}; let Inst{7-3} = target{4-0}; let Inst{2-0} = Rn; } } // Change Processor State is a system instruction. // FIXME: Since the asm parser has currently no clean way to handle optional // operands, create 3 versions of the same instruction. Once there's a clean // framework to represent optional operands, change this behavior. class t2CPS : T2XI<(outs), iops, NoItinerary, !strconcat("cps", asm_op), []>, Requires<[IsThumb2, IsNotMClass]> { bits<2> imod; bits<3> iflags; bits<5> mode; bit M; let Inst{31-11} = 0b111100111010111110000; let Inst{10-9} = imod; let Inst{8} = M; let Inst{7-5} = iflags; let Inst{4-0} = mode; let DecoderMethod = "DecodeT2CPSInstruction"; } let M = 1 in def t2CPS3p : t2CPS<(ins imod_op:$imod, iflags_op:$iflags, i32imm:$mode), "$imod\t$iflags, $mode">; let mode = 0, M = 0 in def t2CPS2p : t2CPS<(ins imod_op:$imod, iflags_op:$iflags), "$imod.w\t$iflags">; let imod = 0, iflags = 0, M = 1 in def t2CPS1p : t2CPS<(ins imm0_31:$mode), "\t$mode">; def : t2InstAlias<"cps$imod.w $iflags, $mode", (t2CPS3p imod_op:$imod, iflags_op:$iflags, i32imm:$mode), 0>; def : t2InstAlias<"cps.w $mode", (t2CPS1p imm0_31:$mode), 0>; // A6.3.4 Branches and miscellaneous control // Table A6-14 Change Processor State, and hint instructions def t2HINT : T2I<(outs), (ins imm0_239:$imm), NoItinerary, "hint", ".w\t$imm", [(int_arm_hint imm0_239:$imm)]> { bits<8> imm; let Inst{31-3} = 0b11110011101011111000000000000; let Inst{7-0} = imm; } def : t2InstAlias<"hint$p $imm", (t2HINT imm0_239:$imm, pred:$p), 0>; def : t2InstAlias<"nop$p.w", (t2HINT 0, pred:$p), 1>; def : t2InstAlias<"yield$p.w", (t2HINT 1, pred:$p), 1>; def : t2InstAlias<"wfe$p.w", (t2HINT 2, pred:$p), 1>; def : t2InstAlias<"wfi$p.w", (t2HINT 3, pred:$p), 1>; def : t2InstAlias<"sev$p.w", (t2HINT 4, pred:$p), 1>; def : t2InstAlias<"sevl$p.w", (t2HINT 5, pred:$p), 1> { let Predicates = [IsThumb2, HasV8]; } def : t2InstAlias<"esb$p.w", (t2HINT 16, pred:$p), 1> { let Predicates = [IsThumb2, HasRAS]; } def : t2InstAlias<"esb$p", (t2HINT 16, pred:$p), 0> { let Predicates = [IsThumb2, HasRAS]; } def t2DBG : T2I<(outs), (ins imm0_15:$opt), NoItinerary, "dbg", "\t$opt", [(int_arm_dbg imm0_15:$opt)]> { bits<4> opt; let Inst{31-20} = 0b111100111010; let Inst{19-16} = 0b1111; let Inst{15-8} = 0b10000000; let Inst{7-4} = 0b1111; let Inst{3-0} = opt; } // Secure Monitor Call is a system instruction. // Option = Inst{19-16} def t2SMC : T2I<(outs), (ins imm0_15:$opt), NoItinerary, "smc", "\t$opt", []>, Requires<[IsThumb2, HasTrustZone]> { let Inst{31-27} = 0b11110; let Inst{26-20} = 0b1111111; let Inst{15-12} = 0b1000; bits<4> opt; let Inst{19-16} = opt; } class T2DCPS opt, string opc> : T2I<(outs), (ins), NoItinerary, opc, "", []>, Requires<[IsThumb2, HasV8]> { let Inst{31-27} = 0b11110; let Inst{26-20} = 0b1111000; let Inst{19-16} = 0b1111; let Inst{15-12} = 0b1000; let Inst{11-2} = 0b0000000000; let Inst{1-0} = opt; } def t2DCPS1 : T2DCPS<0b01, "dcps1">; def t2DCPS2 : T2DCPS<0b10, "dcps2">; def t2DCPS3 : T2DCPS<0b11, "dcps3">; class T2SRS Op, bit W, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2I, Requires<[IsThumb2,IsNotMClass]> { bits<5> mode; let Inst{31-25} = 0b1110100; let Inst{24-23} = Op; let Inst{22} = 0; let Inst{21} = W; let Inst{20-16} = 0b01101; let Inst{15-5} = 0b11000000000; let Inst{4-0} = mode{4-0}; } // Store Return State is a system instruction. def t2SRSDB_UPD : T2SRS<0b00, 1, (outs), (ins imm0_31:$mode), NoItinerary, "srsdb", "\tsp!, $mode", []>; def t2SRSDB : T2SRS<0b00, 0, (outs), (ins imm0_31:$mode), NoItinerary, "srsdb","\tsp, $mode", []>; def t2SRSIA_UPD : T2SRS<0b11, 1, (outs), (ins imm0_31:$mode), NoItinerary, "srsia","\tsp!, $mode", []>; def t2SRSIA : T2SRS<0b11, 0, (outs), (ins imm0_31:$mode), NoItinerary, "srsia","\tsp, $mode", []>; def : t2InstAlias<"srsdb${p} $mode", (t2SRSDB imm0_31:$mode, pred:$p)>; def : t2InstAlias<"srsdb${p} $mode!", (t2SRSDB_UPD imm0_31:$mode, pred:$p)>; def : t2InstAlias<"srsia${p} $mode", (t2SRSIA imm0_31:$mode, pred:$p)>; def : t2InstAlias<"srsia${p} $mode!", (t2SRSIA_UPD imm0_31:$mode, pred:$p)>; // Return From Exception is a system instruction. class T2RFE op31_20, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : T2I, Requires<[IsThumb2,IsNotMClass]> { let Inst{31-20} = op31_20{11-0}; bits<4> Rn; let Inst{19-16} = Rn; let Inst{15-0} = 0xc000; } def t2RFEDBW : T2RFE<0b111010000011, (outs), (ins GPR:$Rn), NoItinerary, "rfedb", "\t$Rn!", [/* For disassembly only; pattern left blank */]>; def t2RFEDB : T2RFE<0b111010000001, (outs), (ins GPR:$Rn), NoItinerary, "rfedb", "\t$Rn", [/* For disassembly only; pattern left blank */]>; def t2RFEIAW : T2RFE<0b111010011011, (outs), (ins GPR:$Rn), NoItinerary, "rfeia", "\t$Rn!", [/* For disassembly only; pattern left blank */]>; def t2RFEIA : T2RFE<0b111010011001, (outs), (ins GPR:$Rn), NoItinerary, "rfeia", "\t$Rn", [/* For disassembly only; pattern left blank */]>; // B9.3.19 SUBS PC, LR, #imm (Thumb2) system instruction. // Exception return instruction is "subs pc, lr, #imm". let isReturn = 1, isBarrier = 1, isTerminator = 1, Defs = [PC] in def t2SUBS_PC_LR : T2I <(outs), (ins imm0_255:$imm), NoItinerary, "subs", "\tpc, lr, $imm", [(ARMintretflag imm0_255:$imm)]>, Requires<[IsThumb2,IsNotMClass]> { let Inst{31-8} = 0b111100111101111010001111; bits<8> imm; let Inst{7-0} = imm; } // Hypervisor Call is a system instruction. let isCall = 1 in { def t2HVC : T2XI <(outs), (ins imm0_65535:$imm16), IIC_Br, "hvc.w\t$imm16", []>, Requires<[IsThumb2, HasVirtualization]>, Sched<[WriteBr]> { bits<16> imm16; let Inst{31-20} = 0b111101111110; let Inst{19-16} = imm16{15-12}; let Inst{15-12} = 0b1000; let Inst{11-0} = imm16{11-0}; } } // Alias for HVC without the ".w" optional width specifier def : t2InstAlias<"hvc\t$imm16", (t2HVC imm0_65535:$imm16)>; // ERET - Return from exception in Hypervisor mode. // B9.3.3, B9.3.20: ERET is an alias for "SUBS PC, LR, #0" in an implementation that // includes virtualization extensions. def t2ERET : InstAlias<"eret${p}", (t2SUBS_PC_LR 0, pred:$p), 1>, Requires<[IsThumb2, HasVirtualization]>; //===----------------------------------------------------------------------===// // Non-Instruction Patterns // // 32-bit immediate using movw + movt. // This is a single pseudo instruction to make it re-materializable. // FIXME: Remove this when we can do generalized remat. let isReMaterializable = 1, isMoveImm = 1 in def t2MOVi32imm : PseudoInst<(outs rGPR:$dst), (ins i32imm:$src), IIC_iMOVix2, [(set rGPR:$dst, (i32 imm:$src))]>, Requires<[IsThumb, UseMovt]>; // Pseudo instruction that combines movw + movt + add pc (if pic). // It also makes it possible to rematerialize the instructions. // FIXME: Remove this when we can do generalized remat and when machine licm // can properly the instructions. let isReMaterializable = 1 in { def t2MOV_ga_pcrel : PseudoInst<(outs rGPR:$dst), (ins i32imm:$addr), IIC_iMOVix2addpc, [(set rGPR:$dst, (ARMWrapperPIC tglobaladdr:$addr))]>, Requires<[IsThumb, HasV8MBaseline, UseMovt]>; } def : T2Pat<(ARMWrapperPIC tglobaltlsaddr :$dst), (t2MOV_ga_pcrel tglobaltlsaddr:$dst)>, Requires<[IsThumb2, UseMovt]>; def : T2Pat<(ARMWrapper tglobaltlsaddr:$dst), (t2MOVi32imm tglobaltlsaddr:$dst)>, Requires<[IsThumb2, UseMovt]>; // ConstantPool, GlobalAddress, and JumpTable def : T2Pat<(ARMWrapper tconstpool :$dst), (t2LEApcrel tconstpool :$dst)>; def : T2Pat<(ARMWrapper texternalsym :$dst), (t2MOVi32imm texternalsym :$dst)>, Requires<[IsThumb, HasV8MBaseline, UseMovt]>; def : T2Pat<(ARMWrapper tglobaladdr :$dst), (t2MOVi32imm tglobaladdr :$dst)>, Requires<[IsThumb, HasV8MBaseline, UseMovt]>; def : T2Pat<(ARMWrapperJT tjumptable:$dst), (t2LEApcrelJT tjumptable:$dst)>; // Pseudo instruction that combines ldr from constpool and add pc. This should // be expanded into two instructions late to allow if-conversion and // scheduling. let canFoldAsLoad = 1, isReMaterializable = 1 in def t2LDRpci_pic : PseudoInst<(outs rGPR:$dst), (ins i32imm:$addr, pclabel:$cp), IIC_iLoadiALU, [(set rGPR:$dst, (ARMpic_add (load (ARMWrapper tconstpool:$addr)), imm:$cp))]>, Requires<[IsThumb2]>; // Pseudo isntruction that combines movs + predicated rsbmi // to implement integer ABS let usesCustomInserter = 1, Defs = [CPSR] in { def t2ABS : PseudoInst<(outs rGPR:$dst), (ins rGPR:$src), NoItinerary, []>, Requires<[IsThumb2]>; } //===----------------------------------------------------------------------===// // Coprocessor load/store -- for disassembly only // class T2CI op31_28, dag oops, dag iops, string opc, string asm, list pattern> : T2I { let Inst{31-28} = op31_28; let Inst{27-25} = 0b110; } multiclass t2LdStCop op31_28, bit load, bit Dbit, string asm, list pattern> { def _OFFSET : T2CI { bits<13> addr; bits<4> cop; bits<4> CRd; let Inst{24} = 1; // P = 1 let Inst{23} = addr{8}; let Inst{22} = Dbit; let Inst{21} = 0; // W = 0 let Inst{20} = load; let Inst{19-16} = addr{12-9}; let Inst{15-12} = CRd; let Inst{11-8} = cop; let Inst{7-0} = addr{7-0}; let DecoderMethod = "DecodeCopMemInstruction"; } def _PRE : T2CI { bits<13> addr; bits<4> cop; bits<4> CRd; let Inst{24} = 1; // P = 1 let Inst{23} = addr{8}; let Inst{22} = Dbit; let Inst{21} = 1; // W = 1 let Inst{20} = load; let Inst{19-16} = addr{12-9}; let Inst{15-12} = CRd; let Inst{11-8} = cop; let Inst{7-0} = addr{7-0}; let DecoderMethod = "DecodeCopMemInstruction"; } def _POST: T2CI { bits<9> offset; bits<4> addr; bits<4> cop; bits<4> CRd; let Inst{24} = 0; // P = 0 let Inst{23} = offset{8}; let Inst{22} = Dbit; let Inst{21} = 1; // W = 1 let Inst{20} = load; let Inst{19-16} = addr; let Inst{15-12} = CRd; let Inst{11-8} = cop; let Inst{7-0} = offset{7-0}; let DecoderMethod = "DecodeCopMemInstruction"; } def _OPTION : T2CI { bits<8> option; bits<4> addr; bits<4> cop; bits<4> CRd; let Inst{24} = 0; // P = 0 let Inst{23} = 1; // U = 1 let Inst{22} = Dbit; let Inst{21} = 0; // W = 0 let Inst{20} = load; let Inst{19-16} = addr; let Inst{15-12} = CRd; let Inst{11-8} = cop; let Inst{7-0} = option; let DecoderMethod = "DecodeCopMemInstruction"; } } defm t2LDC : t2LdStCop<0b1110, 1, 0, "ldc", [(int_arm_ldc imm:$cop, imm:$CRd, addrmode5:$addr)]>; defm t2LDCL : t2LdStCop<0b1110, 1, 1, "ldcl", [(int_arm_ldcl imm:$cop, imm:$CRd, addrmode5:$addr)]>; defm t2LDC2 : t2LdStCop<0b1111, 1, 0, "ldc2", [(int_arm_ldc2 imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[PreV8,IsThumb2]>; defm t2LDC2L : t2LdStCop<0b1111, 1, 1, "ldc2l", [(int_arm_ldc2l imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[PreV8,IsThumb2]>; defm t2STC : t2LdStCop<0b1110, 0, 0, "stc", [(int_arm_stc imm:$cop, imm:$CRd, addrmode5:$addr)]>; defm t2STCL : t2LdStCop<0b1110, 0, 1, "stcl", [(int_arm_stcl imm:$cop, imm:$CRd, addrmode5:$addr)]>; defm t2STC2 : t2LdStCop<0b1111, 0, 0, "stc2", [(int_arm_stc2 imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[PreV8,IsThumb2]>; defm t2STC2L : t2LdStCop<0b1111, 0, 1, "stc2l", [(int_arm_stc2l imm:$cop, imm:$CRd, addrmode5:$addr)]>, Requires<[PreV8,IsThumb2]>; //===----------------------------------------------------------------------===// // Move between special register and ARM core register -- for disassembly only // // Move to ARM core register from Special Register // A/R class MRS. // // A/R class can only move from CPSR or SPSR. def t2MRS_AR : T2I<(outs GPR:$Rd), (ins), NoItinerary, "mrs", "\t$Rd, apsr", []>, Requires<[IsThumb2,IsNotMClass]> { bits<4> Rd; let Inst{31-12} = 0b11110011111011111000; let Inst{11-8} = Rd; let Inst{7-0} = 0b00000000; } def : t2InstAlias<"mrs${p} $Rd, cpsr", (t2MRS_AR GPR:$Rd, pred:$p)>; def t2MRSsys_AR: T2I<(outs GPR:$Rd), (ins), NoItinerary, "mrs", "\t$Rd, spsr", []>, Requires<[IsThumb2,IsNotMClass]> { bits<4> Rd; let Inst{31-12} = 0b11110011111111111000; let Inst{11-8} = Rd; let Inst{7-0} = 0b00000000; } def t2MRSbanked : T2I<(outs rGPR:$Rd), (ins banked_reg:$banked), NoItinerary, "mrs", "\t$Rd, $banked", []>, Requires<[IsThumb, HasVirtualization]> { bits<6> banked; bits<4> Rd; let Inst{31-21} = 0b11110011111; let Inst{20} = banked{5}; // R bit let Inst{19-16} = banked{3-0}; let Inst{15-12} = 0b1000; let Inst{11-8} = Rd; let Inst{7-5} = 0b001; let Inst{4} = banked{4}; let Inst{3-0} = 0b0000; } // M class MRS. // // This MRS has a mask field in bits 7-0 and can take more values than // the A/R class (a full msr_mask). def t2MRS_M : T2I<(outs rGPR:$Rd), (ins msr_mask:$SYSm), NoItinerary, "mrs", "\t$Rd, $SYSm", []>, Requires<[IsThumb,IsMClass]> { bits<4> Rd; bits<8> SYSm; let Inst{31-12} = 0b11110011111011111000; let Inst{11-8} = Rd; let Inst{7-0} = SYSm; let Unpredictable{20-16} = 0b11111; let Unpredictable{13} = 0b1; } // Move from ARM core register to Special Register // // A/R class MSR. // // No need to have both system and application versions, the encodings are the // same and the assembly parser has no way to distinguish between them. The mask // operand contains the special register (R Bit) in bit 4 and bits 3-0 contains // the mask with the fields to be accessed in the special register. let Defs = [CPSR] in def t2MSR_AR : T2I<(outs), (ins msr_mask:$mask, rGPR:$Rn), NoItinerary, "msr", "\t$mask, $Rn", []>, Requires<[IsThumb2,IsNotMClass]> { bits<5> mask; bits<4> Rn; let Inst{31-21} = 0b11110011100; let Inst{20} = mask{4}; // R Bit let Inst{19-16} = Rn; let Inst{15-12} = 0b1000; let Inst{11-8} = mask{3-0}; let Inst{7-0} = 0; } // However, the MSR (banked register) system instruction (ARMv7VE) *does* have a // separate encoding (distinguished by bit 5. def t2MSRbanked : T2I<(outs), (ins banked_reg:$banked, rGPR:$Rn), NoItinerary, "msr", "\t$banked, $Rn", []>, Requires<[IsThumb, HasVirtualization]> { bits<6> banked; bits<4> Rn; let Inst{31-21} = 0b11110011100; let Inst{20} = banked{5}; // R bit let Inst{19-16} = Rn; let Inst{15-12} = 0b1000; let Inst{11-8} = banked{3-0}; let Inst{7-5} = 0b001; let Inst{4} = banked{4}; let Inst{3-0} = 0b0000; } // M class MSR. // // Move from ARM core register to Special Register let Defs = [CPSR] in def t2MSR_M : T2I<(outs), (ins msr_mask:$SYSm, rGPR:$Rn), NoItinerary, "msr", "\t$SYSm, $Rn", []>, Requires<[IsThumb,IsMClass]> { bits<12> SYSm; bits<4> Rn; let Inst{31-21} = 0b11110011100; let Inst{20} = 0b0; let Inst{19-16} = Rn; let Inst{15-12} = 0b1000; let Inst{11-10} = SYSm{11-10}; let Inst{9-8} = 0b00; let Inst{7-0} = SYSm{7-0}; let Unpredictable{20} = 0b1; let Unpredictable{13} = 0b1; let Unpredictable{9-8} = 0b11; } //===----------------------------------------------------------------------===// // Move between coprocessor and ARM core register // class t2MovRCopro Op, string opc, bit direction, dag oops, dag iops, list pattern> : T2Cop { let Inst{27-24} = 0b1110; let Inst{20} = direction; let Inst{4} = 1; bits<4> Rt; bits<4> cop; bits<3> opc1; bits<3> opc2; bits<4> CRm; bits<4> CRn; let Inst{15-12} = Rt; let Inst{11-8} = cop; let Inst{23-21} = opc1; let Inst{7-5} = opc2; let Inst{3-0} = CRm; let Inst{19-16} = CRn; } class t2MovRRCopro Op, string opc, bit direction, dag oops, dag iops, list pattern = []> : T2Cop { let Inst{27-24} = 0b1100; let Inst{23-21} = 0b010; let Inst{20} = direction; bits<4> Rt; bits<4> Rt2; bits<4> cop; bits<4> opc1; bits<4> CRm; let Inst{15-12} = Rt; let Inst{19-16} = Rt2; let Inst{11-8} = cop; let Inst{7-4} = opc1; let Inst{3-0} = CRm; } /* from ARM core register to coprocessor */ def t2MCR : t2MovRCopro<0b1110, "mcr", 0, (outs), (ins p_imm:$cop, imm0_7:$opc1, GPR:$Rt, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), [(int_arm_mcr imm:$cop, imm:$opc1, GPR:$Rt, imm:$CRn, imm:$CRm, imm:$opc2)]>, ComplexDeprecationPredicate<"MCR">; def : t2InstAlias<"mcr${p} $cop, $opc1, $Rt, $CRn, $CRm", (t2MCR p_imm:$cop, imm0_7:$opc1, GPR:$Rt, c_imm:$CRn, c_imm:$CRm, 0, pred:$p)>; def t2MCR2 : t2MovRCopro<0b1111, "mcr2", 0, (outs), (ins p_imm:$cop, imm0_7:$opc1, GPR:$Rt, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), [(int_arm_mcr2 imm:$cop, imm:$opc1, GPR:$Rt, imm:$CRn, imm:$CRm, imm:$opc2)]> { let Predicates = [IsThumb2, PreV8]; } def : t2InstAlias<"mcr2${p} $cop, $opc1, $Rt, $CRn, $CRm", (t2MCR2 p_imm:$cop, imm0_7:$opc1, GPR:$Rt, c_imm:$CRn, c_imm:$CRm, 0, pred:$p)>; /* from coprocessor to ARM core register */ def t2MRC : t2MovRCopro<0b1110, "mrc", 1, (outs GPRwithAPSR:$Rt), (ins p_imm:$cop, imm0_7:$opc1, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), []>; def : t2InstAlias<"mrc${p} $cop, $opc1, $Rt, $CRn, $CRm", (t2MRC GPRwithAPSR:$Rt, p_imm:$cop, imm0_7:$opc1, c_imm:$CRn, c_imm:$CRm, 0, pred:$p)>; def t2MRC2 : t2MovRCopro<0b1111, "mrc2", 1, (outs GPRwithAPSR:$Rt), (ins p_imm:$cop, imm0_7:$opc1, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), []> { let Predicates = [IsThumb2, PreV8]; } def : t2InstAlias<"mrc2${p} $cop, $opc1, $Rt, $CRn, $CRm", (t2MRC2 GPRwithAPSR:$Rt, p_imm:$cop, imm0_7:$opc1, c_imm:$CRn, c_imm:$CRm, 0, pred:$p)>; def : T2v6Pat<(int_arm_mrc imm:$cop, imm:$opc1, imm:$CRn, imm:$CRm, imm:$opc2), (t2MRC imm:$cop, imm:$opc1, imm:$CRn, imm:$CRm, imm:$opc2)>; def : T2v6Pat<(int_arm_mrc2 imm:$cop, imm:$opc1, imm:$CRn, imm:$CRm, imm:$opc2), (t2MRC2 imm:$cop, imm:$opc1, imm:$CRn, imm:$CRm, imm:$opc2)>; /* from ARM core register to coprocessor */ def t2MCRR : t2MovRRCopro<0b1110, "mcrr", 0, (outs), (ins p_imm:$cop, imm0_15:$opc1, GPR:$Rt, GPR:$Rt2, c_imm:$CRm), [(int_arm_mcrr imm:$cop, imm:$opc1, GPR:$Rt, GPR:$Rt2, imm:$CRm)]>; def t2MCRR2 : t2MovRRCopro<0b1111, "mcrr2", 0, (outs), (ins p_imm:$cop, imm0_15:$opc1, GPR:$Rt, GPR:$Rt2, c_imm:$CRm), [(int_arm_mcrr2 imm:$cop, imm:$opc1, GPR:$Rt, GPR:$Rt2, imm:$CRm)]> { let Predicates = [IsThumb2, PreV8]; } /* from coprocessor to ARM core register */ def t2MRRC : t2MovRRCopro<0b1110, "mrrc", 1, (outs GPR:$Rt, GPR:$Rt2), (ins p_imm:$cop, imm0_15:$opc1, c_imm:$CRm)>; def t2MRRC2 : t2MovRRCopro<0b1111, "mrrc2", 1, (outs GPR:$Rt, GPR:$Rt2), (ins p_imm:$cop, imm0_15:$opc1, c_imm:$CRm)> { let Predicates = [IsThumb2, PreV8]; } //===----------------------------------------------------------------------===// // Other Coprocessor Instructions. // def t2CDP : T2Cop<0b1110, (outs), (ins p_imm:$cop, imm0_15:$opc1, c_imm:$CRd, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), "cdp", "\t$cop, $opc1, $CRd, $CRn, $CRm, $opc2", [(int_arm_cdp imm:$cop, imm:$opc1, imm:$CRd, imm:$CRn, imm:$CRm, imm:$opc2)]> { let Inst{27-24} = 0b1110; bits<4> opc1; bits<4> CRn; bits<4> CRd; bits<4> cop; bits<3> opc2; bits<4> CRm; let Inst{3-0} = CRm; let Inst{4} = 0; let Inst{7-5} = opc2; let Inst{11-8} = cop; let Inst{15-12} = CRd; let Inst{19-16} = CRn; let Inst{23-20} = opc1; let Predicates = [IsThumb2, PreV8]; } def t2CDP2 : T2Cop<0b1111, (outs), (ins p_imm:$cop, imm0_15:$opc1, c_imm:$CRd, c_imm:$CRn, c_imm:$CRm, imm0_7:$opc2), "cdp2", "\t$cop, $opc1, $CRd, $CRn, $CRm, $opc2", [(int_arm_cdp2 imm:$cop, imm:$opc1, imm:$CRd, imm:$CRn, imm:$CRm, imm:$opc2)]> { let Inst{27-24} = 0b1110; bits<4> opc1; bits<4> CRn; bits<4> CRd; bits<4> cop; bits<3> opc2; bits<4> CRm; let Inst{3-0} = CRm; let Inst{4} = 0; let Inst{7-5} = opc2; let Inst{11-8} = cop; let Inst{15-12} = CRd; let Inst{19-16} = CRn; let Inst{23-20} = opc1; let Predicates = [IsThumb2, PreV8]; } //===----------------------------------------------------------------------===// // ARMv8.1 Privilege Access Never extension // // SETPAN #imm1 def t2SETPAN : T1I<(outs), (ins imm0_1:$imm), NoItinerary, "setpan\t$imm", []>, T1Misc<0b0110000>, Requires<[IsThumb2, HasV8, HasV8_1a]> { bits<1> imm; let Inst{4} = 0b1; let Inst{3} = imm; let Inst{2-0} = 0b000; let Unpredictable{4} = 0b1; let Unpredictable{2-0} = 0b111; } //===----------------------------------------------------------------------===// // ARMv8-M Security Extensions instructions // let hasSideEffects = 1 in def t2SG : T2I<(outs), (ins), NoItinerary, "sg", "", []>, Requires<[Has8MSecExt]> { let Inst = 0xe97fe97f; } class T2TT at, string asm, list pattern> : T2I<(outs rGPR:$Rt), (ins GPRnopc:$Rn), NoItinerary, asm, "\t$Rt, $Rn", pattern> { bits<4> Rn; bits<4> Rt; let Inst{31-20} = 0b111010000100; let Inst{19-16} = Rn; let Inst{15-12} = 0b1111; let Inst{11-8} = Rt; let Inst{7-6} = at; let Inst{5-0} = 0b000000; let Unpredictable{5-0} = 0b111111; } def t2TT : T2TT<0b00, "tt", []>, Requires<[IsThumb,Has8MSecExt]>; def t2TTT : T2TT<0b01, "ttt", []>, Requires<[IsThumb,Has8MSecExt]>; def t2TTA : T2TT<0b10, "tta", []>, Requires<[IsThumb,Has8MSecExt]>; def t2TTAT : T2TT<0b11, "ttat", []>, Requires<[IsThumb,Has8MSecExt]>; //===----------------------------------------------------------------------===// // Non-Instruction Patterns // // SXT/UXT with no rotate let AddedComplexity = 16 in { def : T2Pat<(and rGPR:$Rm, 0x000000FF), (t2UXTB rGPR:$Rm, 0)>, Requires<[IsThumb2]>; def : T2Pat<(and rGPR:$Rm, 0x0000FFFF), (t2UXTH rGPR:$Rm, 0)>, Requires<[IsThumb2]>; def : T2Pat<(and rGPR:$Rm, 0x00FF00FF), (t2UXTB16 rGPR:$Rm, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(add rGPR:$Rn, (and rGPR:$Rm, 0x00FF)), (t2UXTAB rGPR:$Rn, rGPR:$Rm, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(add rGPR:$Rn, (and rGPR:$Rm, 0xFFFF)), (t2UXTAH rGPR:$Rn, rGPR:$Rm, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; } def : T2Pat<(sext_inreg rGPR:$Src, i8), (t2SXTB rGPR:$Src, 0)>, Requires<[IsThumb2]>; def : T2Pat<(sext_inreg rGPR:$Src, i16), (t2SXTH rGPR:$Src, 0)>, Requires<[IsThumb2]>; def : T2Pat<(add rGPR:$Rn, (sext_inreg rGPR:$Rm, i8)), (t2SXTAB rGPR:$Rn, rGPR:$Rm, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; def : T2Pat<(add rGPR:$Rn, (sext_inreg rGPR:$Rm, i16)), (t2SXTAH rGPR:$Rn, rGPR:$Rm, 0)>, Requires<[HasT2ExtractPack, IsThumb2]>; // Atomic load/store patterns def : T2Pat<(atomic_load_8 t2addrmode_imm12:$addr), (t2LDRBi12 t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_load_8 t2addrmode_negimm8:$addr), (t2LDRBi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_load_8 t2addrmode_so_reg:$addr), (t2LDRBs t2addrmode_so_reg:$addr)>; def : T2Pat<(atomic_load_16 t2addrmode_imm12:$addr), (t2LDRHi12 t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_load_16 t2addrmode_negimm8:$addr), (t2LDRHi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_load_16 t2addrmode_so_reg:$addr), (t2LDRHs t2addrmode_so_reg:$addr)>; def : T2Pat<(atomic_load_32 t2addrmode_imm12:$addr), (t2LDRi12 t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_load_32 t2addrmode_negimm8:$addr), (t2LDRi8 t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_load_32 t2addrmode_so_reg:$addr), (t2LDRs t2addrmode_so_reg:$addr)>; def : T2Pat<(atomic_store_8 t2addrmode_imm12:$addr, GPR:$val), (t2STRBi12 GPR:$val, t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_store_8 t2addrmode_negimm8:$addr, GPR:$val), (t2STRBi8 GPR:$val, t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_store_8 t2addrmode_so_reg:$addr, GPR:$val), (t2STRBs GPR:$val, t2addrmode_so_reg:$addr)>; def : T2Pat<(atomic_store_16 t2addrmode_imm12:$addr, GPR:$val), (t2STRHi12 GPR:$val, t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_store_16 t2addrmode_negimm8:$addr, GPR:$val), (t2STRHi8 GPR:$val, t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_store_16 t2addrmode_so_reg:$addr, GPR:$val), (t2STRHs GPR:$val, t2addrmode_so_reg:$addr)>; def : T2Pat<(atomic_store_32 t2addrmode_imm12:$addr, GPR:$val), (t2STRi12 GPR:$val, t2addrmode_imm12:$addr)>; def : T2Pat<(atomic_store_32 t2addrmode_negimm8:$addr, GPR:$val), (t2STRi8 GPR:$val, t2addrmode_negimm8:$addr)>; def : T2Pat<(atomic_store_32 t2addrmode_so_reg:$addr, GPR:$val), (t2STRs GPR:$val, t2addrmode_so_reg:$addr)>; let AddedComplexity = 8 in { def : T2Pat<(atomic_load_acquire_8 addr_offset_none:$addr), (t2LDAB addr_offset_none:$addr)>; def : T2Pat<(atomic_load_acquire_16 addr_offset_none:$addr), (t2LDAH addr_offset_none:$addr)>; def : T2Pat<(atomic_load_acquire_32 addr_offset_none:$addr), (t2LDA addr_offset_none:$addr)>; def : T2Pat<(atomic_store_release_8 addr_offset_none:$addr, GPR:$val), (t2STLB GPR:$val, addr_offset_none:$addr)>; def : T2Pat<(atomic_store_release_16 addr_offset_none:$addr, GPR:$val), (t2STLH GPR:$val, addr_offset_none:$addr)>; def : T2Pat<(atomic_store_release_32 addr_offset_none:$addr, GPR:$val), (t2STL GPR:$val, addr_offset_none:$addr)>; } //===----------------------------------------------------------------------===// // Assembler aliases // // Aliases for ADC without the ".w" optional width specifier. def : t2InstAlias<"adc${s}${p} $Rd, $Rn, $Rm", (t2ADCrr rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"adc${s}${p} $Rd, $Rn, $ShiftedRm", (t2ADCrs rGPR:$Rd, rGPR:$Rn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // Aliases for SBC without the ".w" optional width specifier. def : t2InstAlias<"sbc${s}${p} $Rd, $Rn, $Rm", (t2SBCrr rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"sbc${s}${p} $Rd, $Rn, $ShiftedRm", (t2SBCrs rGPR:$Rd, rGPR:$Rn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // Aliases for ADD without the ".w" optional width specifier. def : t2InstAlias<"add${s}${p} $Rd, $Rn, $imm", (t2ADDri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"add${p} $Rd, $Rn, $imm", (t2ADDri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095:$imm, pred:$p)>; def : t2InstAlias<"add${s}${p} $Rd, $Rn, $Rm", (t2ADDrr GPRnopc:$Rd, GPRnopc:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"add${s}${p} $Rd, $Rn, $ShiftedRm", (t2ADDrs GPRnopc:$Rd, GPRnopc:$Rn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // ... and with the destination and source register combined. def : t2InstAlias<"add${s}${p} $Rdn, $imm", (t2ADDri GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"add${p} $Rdn, $imm", (t2ADDri12 GPRnopc:$Rdn, GPRnopc:$Rdn, imm0_4095:$imm, pred:$p)>; def : t2InstAlias<"add${s}${p} $Rdn, $Rm", (t2ADDrr GPRnopc:$Rdn, GPRnopc:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"add${s}${p} $Rdn, $ShiftedRm", (t2ADDrs GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // add w/ negative immediates is just a sub. def : t2InstAlias<"add${s}${p} $Rd, $Rn, $imm", (t2SUBri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm_neg:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"add${p} $Rd, $Rn, $imm", (t2SUBri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095_neg:$imm, pred:$p)>; def : t2InstAlias<"add${s}${p} $Rdn, $imm", (t2SUBri GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_imm_neg:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"add${p} $Rdn, $imm", (t2SUBri12 GPRnopc:$Rdn, GPRnopc:$Rdn, imm0_4095_neg:$imm, pred:$p)>; def : t2InstAlias<"add${s}${p}.w $Rd, $Rn, $imm", (t2SUBri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm_neg:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"addw${p} $Rd, $Rn, $imm", (t2SUBri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095_neg:$imm, pred:$p)>; def : t2InstAlias<"add${s}${p}.w $Rdn, $imm", (t2SUBri GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_imm_neg:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"addw${p} $Rdn, $imm", (t2SUBri12 GPRnopc:$Rdn, GPRnopc:$Rdn, imm0_4095_neg:$imm, pred:$p)>; // Aliases for SUB without the ".w" optional width specifier. def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $imm", (t2SUBri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"sub${p} $Rd, $Rn, $imm", (t2SUBri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095:$imm, pred:$p)>; def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $Rm", (t2SUBrr GPRnopc:$Rd, GPRnopc:$Rn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"sub${s}${p} $Rd, $Rn, $ShiftedRm", (t2SUBrs GPRnopc:$Rd, GPRnopc:$Rn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // ... and with the destination and source register combined. def : t2InstAlias<"sub${s}${p} $Rdn, $imm", (t2SUBri GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"sub${p} $Rdn, $imm", (t2SUBri12 GPRnopc:$Rdn, GPRnopc:$Rdn, imm0_4095:$imm, pred:$p)>; def : t2InstAlias<"sub${s}${p}.w $Rdn, $Rm", (t2SUBrr GPRnopc:$Rdn, GPRnopc:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"sub${s}${p} $Rdn, $Rm", (t2SUBrr GPRnopc:$Rdn, GPRnopc:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"sub${s}${p} $Rdn, $ShiftedRm", (t2SUBrs GPRnopc:$Rdn, GPRnopc:$Rdn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // Alias for compares without the ".w" optional width specifier. def : t2InstAlias<"cmn${p} $Rn, $Rm", (t2CMNzrr GPRnopc:$Rn, rGPR:$Rm, pred:$p)>; def : t2InstAlias<"teq${p} $Rn, $Rm", (t2TEQrr GPRnopc:$Rn, rGPR:$Rm, pred:$p)>; def : t2InstAlias<"tst${p} $Rn, $Rm", (t2TSTrr GPRnopc:$Rn, rGPR:$Rm, pred:$p)>; // Memory barriers def : InstAlias<"dmb${p}", (t2DMB 0xf, pred:$p), 0>, Requires<[HasDB]>; def : InstAlias<"dsb${p}", (t2DSB 0xf, pred:$p), 0>, Requires<[HasDB]>; def : InstAlias<"isb${p}", (t2ISB 0xf, pred:$p), 0>, Requires<[HasDB]>; // Alias for LDR, LDRB, LDRH, LDRSB, and LDRSH without the ".w" optional // width specifier. def : t2InstAlias<"ldr${p} $Rt, $addr", (t2LDRi12 GPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrb${p} $Rt, $addr", (t2LDRBi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrh${p} $Rt, $addr", (t2LDRHi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrsb${p} $Rt, $addr", (t2LDRSBi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrsh${p} $Rt, $addr", (t2LDRSHi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldr${p} $Rt, $addr", (t2LDRs GPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"ldrb${p} $Rt, $addr", (t2LDRBs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"ldrh${p} $Rt, $addr", (t2LDRHs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"ldrsb${p} $Rt, $addr", (t2LDRSBs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"ldrsh${p} $Rt, $addr", (t2LDRSHs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"ldr${p} $Rt, $addr", (t2LDRpci GPRnopc:$Rt, t2ldrlabel:$addr, pred:$p)>; def : t2InstAlias<"ldrb${p} $Rt, $addr", (t2LDRBpci rGPR:$Rt, t2ldrlabel:$addr, pred:$p)>; def : t2InstAlias<"ldrh${p} $Rt, $addr", (t2LDRHpci rGPR:$Rt, t2ldrlabel:$addr, pred:$p)>; def : t2InstAlias<"ldrsb${p} $Rt, $addr", (t2LDRSBpci rGPR:$Rt, t2ldrlabel:$addr, pred:$p)>; def : t2InstAlias<"ldrsh${p} $Rt, $addr", (t2LDRSHpci rGPR:$Rt, t2ldrlabel:$addr, pred:$p)>; // Alias for MVN with(out) the ".w" optional width specifier. def : t2InstAlias<"mvn${s}${p}.w $Rd, $imm", (t2MVNi rGPR:$Rd, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"mvn${s}${p} $Rd, $Rm", (t2MVNr rGPR:$Rd, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"mvn${s}${p} $Rd, $ShiftedRm", (t2MVNs rGPR:$Rd, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // PKHBT/PKHTB with default shift amount. PKHTB is equivalent to PKHBT with the // input operands swapped when the shift amount is zero (i.e., unspecified). def : InstAlias<"pkhbt${p} $Rd, $Rn, $Rm", (t2PKHBT rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : InstAlias<"pkhtb${p} $Rd, $Rn, $Rm", (t2PKHBT rGPR:$Rd, rGPR:$Rm, rGPR:$Rn, 0, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; // PUSH/POP aliases for STM/LDM def : t2InstAlias<"push${p}.w $regs", (t2STMDB_UPD SP, pred:$p, reglist:$regs)>; def : t2InstAlias<"push${p} $regs", (t2STMDB_UPD SP, pred:$p, reglist:$regs)>; def : t2InstAlias<"pop${p}.w $regs", (t2LDMIA_UPD SP, pred:$p, reglist:$regs)>; def : t2InstAlias<"pop${p} $regs", (t2LDMIA_UPD SP, pred:$p, reglist:$regs)>; // STMIA/STMIA_UPD aliases w/o the optional .w suffix def : t2InstAlias<"stm${p} $Rn, $regs", (t2STMIA GPR:$Rn, pred:$p, reglist:$regs)>; def : t2InstAlias<"stm${p} $Rn!, $regs", (t2STMIA_UPD GPR:$Rn, pred:$p, reglist:$regs)>; // LDMIA/LDMIA_UPD aliases w/o the optional .w suffix def : t2InstAlias<"ldm${p} $Rn, $regs", (t2LDMIA GPR:$Rn, pred:$p, reglist:$regs)>; def : t2InstAlias<"ldm${p} $Rn!, $regs", (t2LDMIA_UPD GPR:$Rn, pred:$p, reglist:$regs)>; // STMDB/STMDB_UPD aliases w/ the optional .w suffix def : t2InstAlias<"stmdb${p}.w $Rn, $regs", (t2STMDB GPR:$Rn, pred:$p, reglist:$regs)>; def : t2InstAlias<"stmdb${p}.w $Rn!, $regs", (t2STMDB_UPD GPR:$Rn, pred:$p, reglist:$regs)>; // LDMDB/LDMDB_UPD aliases w/ the optional .w suffix def : t2InstAlias<"ldmdb${p}.w $Rn, $regs", (t2LDMDB GPR:$Rn, pred:$p, reglist:$regs)>; def : t2InstAlias<"ldmdb${p}.w $Rn!, $regs", (t2LDMDB_UPD GPR:$Rn, pred:$p, reglist:$regs)>; // Alias for REV/REV16/REVSH without the ".w" optional width specifier. def : t2InstAlias<"rev${p} $Rd, $Rm", (t2REV rGPR:$Rd, rGPR:$Rm, pred:$p)>; def : t2InstAlias<"rev16${p} $Rd, $Rm", (t2REV16 rGPR:$Rd, rGPR:$Rm, pred:$p)>; def : t2InstAlias<"revsh${p} $Rd, $Rm", (t2REVSH rGPR:$Rd, rGPR:$Rm, pred:$p)>; // Alias for RSB without the ".w" optional width specifier, and with optional // implied destination register. def : t2InstAlias<"rsb${s}${p} $Rd, $Rn, $imm", (t2RSBri rGPR:$Rd, rGPR:$Rn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"rsb${s}${p} $Rdn, $imm", (t2RSBri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"rsb${s}${p} $Rdn, $Rm", (t2RSBrr rGPR:$Rdn, rGPR:$Rdn, rGPR:$Rm, pred:$p, cc_out:$s)>; def : t2InstAlias<"rsb${s}${p} $Rdn, $ShiftedRm", (t2RSBrs rGPR:$Rdn, rGPR:$Rdn, t2_so_reg:$ShiftedRm, pred:$p, cc_out:$s)>; // SSAT/USAT optional shift operand. def : t2InstAlias<"ssat${p} $Rd, $sat_imm, $Rn", (t2SSAT rGPR:$Rd, imm1_32:$sat_imm, rGPR:$Rn, 0, pred:$p)>; def : t2InstAlias<"usat${p} $Rd, $sat_imm, $Rn", (t2USAT rGPR:$Rd, imm0_31:$sat_imm, rGPR:$Rn, 0, pred:$p)>; // STM w/o the .w suffix. def : t2InstAlias<"stm${p} $Rn, $regs", (t2STMIA GPR:$Rn, pred:$p, reglist:$regs)>; // Alias for STR, STRB, and STRH without the ".w" optional // width specifier. def : t2InstAlias<"str${p} $Rt, $addr", (t2STRi12 GPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"strb${p} $Rt, $addr", (t2STRBi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"strh${p} $Rt, $addr", (t2STRHi12 rGPR:$Rt, t2addrmode_imm12:$addr, pred:$p)>; def : t2InstAlias<"str${p} $Rt, $addr", (t2STRs GPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"strb${p} $Rt, $addr", (t2STRBs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; def : t2InstAlias<"strh${p} $Rt, $addr", (t2STRHs rGPR:$Rt, t2addrmode_so_reg:$addr, pred:$p)>; // Extend instruction optional rotate operand. def : InstAlias<"sxtab${p} $Rd, $Rn, $Rm", (t2SXTAB rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : InstAlias<"sxtah${p} $Rd, $Rn, $Rm", (t2SXTAH rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : InstAlias<"sxtab16${p} $Rd, $Rn, $Rm", (t2SXTAB16 rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : InstAlias<"sxtb16${p} $Rd, $Rm", (t2SXTB16 rGPR:$Rd, rGPR:$Rm, 0, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : t2InstAlias<"sxtb${p} $Rd, $Rm", (t2SXTB rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"sxth${p} $Rd, $Rm", (t2SXTH rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"sxtb${p}.w $Rd, $Rm", (t2SXTB rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"sxth${p}.w $Rd, $Rm", (t2SXTH rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : InstAlias<"uxtab${p} $Rd, $Rn, $Rm", (t2UXTAB rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : InstAlias<"uxtah${p} $Rd, $Rn, $Rm", (t2UXTAH rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : InstAlias<"uxtab16${p} $Rd, $Rn, $Rm", (t2UXTAB16 rGPR:$Rd, rGPR:$Rn, rGPR:$Rm, 0, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : InstAlias<"uxtb16${p} $Rd, $Rm", (t2UXTB16 rGPR:$Rd, rGPR:$Rm, 0, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : t2InstAlias<"uxtb${p} $Rd, $Rm", (t2UXTB rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxth${p} $Rd, $Rm", (t2UXTH rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxtb${p}.w $Rd, $Rm", (t2UXTB rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; def : t2InstAlias<"uxth${p}.w $Rd, $Rm", (t2UXTH rGPR:$Rd, rGPR:$Rm, 0, pred:$p)>; // Extend instruction w/o the ".w" optional width specifier. def : t2InstAlias<"uxtb${p} $Rd, $Rm$rot", (t2UXTB rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p)>; def : InstAlias<"uxtb16${p} $Rd, $Rm$rot", (t2UXTB16 rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : t2InstAlias<"uxth${p} $Rd, $Rm$rot", (t2UXTH rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p)>; def : t2InstAlias<"sxtb${p} $Rd, $Rm$rot", (t2SXTB rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p)>; def : InstAlias<"sxtb16${p} $Rd, $Rm$rot", (t2SXTB16 rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p), 0>, Requires<[HasT2ExtractPack, IsThumb2]>; def : t2InstAlias<"sxth${p} $Rd, $Rm$rot", (t2SXTH rGPR:$Rd, rGPR:$Rm, rot_imm:$rot, pred:$p)>; // "mov Rd, t2_so_imm_not" can be handled via "mvn" in assembly, just like // for isel. def : t2InstAlias<"mov${p} $Rd, $imm", (t2MVNi rGPR:$Rd, t2_so_imm_not:$imm, pred:$p, zero_reg)>; def : t2InstAlias<"mvn${p} $Rd, $imm", (t2MOVi rGPR:$Rd, t2_so_imm_not:$imm, pred:$p, zero_reg)>; // Same for AND <--> BIC def : t2InstAlias<"bic${s}${p} $Rd, $Rn, $imm", (t2ANDri rGPR:$Rd, rGPR:$Rn, t2_so_imm_not:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"bic${s}${p} $Rdn, $imm", (t2ANDri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm_not:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"and${s}${p} $Rd, $Rn, $imm", (t2BICri rGPR:$Rd, rGPR:$Rn, t2_so_imm_not:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"and${s}${p} $Rdn, $imm", (t2BICri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm_not:$imm, pred:$p, cc_out:$s)>; // Likewise, "add Rd, t2_so_imm_neg" -> sub def : t2InstAlias<"add${s}${p} $Rd, $Rn, $imm", (t2SUBri GPRnopc:$Rd, GPRnopc:$Rn, t2_so_imm_neg:$imm, pred:$p, cc_out:$s)>; def : t2InstAlias<"add${s}${p} $Rd, $imm", (t2SUBri GPRnopc:$Rd, GPRnopc:$Rd, t2_so_imm_neg:$imm, pred:$p, cc_out:$s)>; // Same for CMP <--> CMN via t2_so_imm_neg def : t2InstAlias<"cmp${p} $Rd, $imm", (t2CMNri rGPR:$Rd, t2_so_imm_neg:$imm, pred:$p)>; def : t2InstAlias<"cmn${p} $Rd, $imm", (t2CMPri rGPR:$Rd, t2_so_imm_neg:$imm, pred:$p)>; // Wide 'mul' encoding can be specified with only two operands. def : t2InstAlias<"mul${p} $Rn, $Rm", (t2MUL rGPR:$Rn, rGPR:$Rm, rGPR:$Rn, pred:$p)>; // "neg" is and alias for "rsb rd, rn, #0" def : t2InstAlias<"neg${s}${p} $Rd, $Rm", (t2RSBri rGPR:$Rd, rGPR:$Rm, 0, pred:$p, cc_out:$s)>; // MOV so_reg assembler pseudos. InstAlias isn't expressive enough for // these, unfortunately. def t2MOVsi: t2AsmPseudo<"mov${p} $Rd, $shift", (ins rGPR:$Rd, t2_so_reg:$shift, pred:$p)>; def t2MOVSsi: t2AsmPseudo<"movs${p} $Rd, $shift", (ins rGPR:$Rd, t2_so_reg:$shift, pred:$p)>; def t2MOVsr: t2AsmPseudo<"mov${p} $Rd, $shift", (ins rGPR:$Rd, so_reg_reg:$shift, pred:$p)>; def t2MOVSsr: t2AsmPseudo<"movs${p} $Rd, $shift", (ins rGPR:$Rd, so_reg_reg:$shift, pred:$p)>; // ADR w/o the .w suffix def : t2InstAlias<"adr${p} $Rd, $addr", (t2ADR rGPR:$Rd, t2adrlabel:$addr, pred:$p)>; // LDR(literal) w/ alternate [pc, #imm] syntax. def t2LDRpcrel : t2AsmPseudo<"ldr${p} $Rt, $addr", (ins GPR:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; def t2LDRBpcrel : t2AsmPseudo<"ldrb${p} $Rt, $addr", (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; def t2LDRHpcrel : t2AsmPseudo<"ldrh${p} $Rt, $addr", (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; def t2LDRSBpcrel : t2AsmPseudo<"ldrsb${p} $Rt, $addr", (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; def t2LDRSHpcrel : t2AsmPseudo<"ldrsh${p} $Rt, $addr", (ins GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; // Version w/ the .w suffix. def : t2InstAlias<"ldr${p}.w $Rt, $addr", (t2LDRpcrel GPR:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p), 0>; def : t2InstAlias<"ldrb${p}.w $Rt, $addr", (t2LDRBpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrh${p}.w $Rt, $addr", (t2LDRHpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrsb${p}.w $Rt, $addr", (t2LDRSBpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; def : t2InstAlias<"ldrsh${p}.w $Rt, $addr", (t2LDRSHpcrel GPRnopc:$Rt, t2ldr_pcrel_imm12:$addr, pred:$p)>; def : t2InstAlias<"add${p} $Rd, pc, $imm", (t2ADR rGPR:$Rd, imm0_4095:$imm, pred:$p)>; // Pseudo instruction ldr Rt, =immediate def t2LDRConstPool : t2AsmPseudo<"ldr${p} $Rt, $immediate", (ins GPRnopc:$Rt, const_pool_asm_imm:$immediate, pred:$p)>; +// Version w/ the .w suffix. +def : t2InstAlias<"ldr${p}.w $Rt, $immediate", + (t2LDRConstPool GPRnopc:$Rt, + const_pool_asm_imm:$immediate, pred:$p)>; // PLD/PLDW/PLI with alternate literal form. def : t2InstAlias<"pld${p} $addr", (t2PLDpci t2ldr_pcrel_imm12:$addr, pred:$p)>; def : InstAlias<"pli${p} $addr", (t2PLIpci t2ldr_pcrel_imm12:$addr, pred:$p), 0>, Requires<[IsThumb2,HasV7]>; Index: vendor/llvm/dist/lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- vendor/llvm/dist/lib/Target/ARM/AsmParser/ARMAsmParser.cpp (revision 309151) +++ vendor/llvm/dist/lib/Target/ARM/AsmParser/ARMAsmParser.cpp (revision 309152) @@ -1,10303 +1,10306 @@ //===-- ARMAsmParser.cpp - Parse ARM assembly to MCInst instructions ------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "ARMFeatures.h" #include "MCTargetDesc/ARMAddressingModes.h" #include "MCTargetDesc/ARMBaseInfo.h" #include "MCTargetDesc/ARMMCExpr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/MC/MCELFStreamer.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCAsmParserUtils.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/ARMEHABI.h" #include "llvm/Support/COFF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; namespace { class ARMOperand; enum VectorLaneTy { NoLanes, AllLanes, IndexedLane }; class UnwindContext { MCAsmParser &Parser; typedef SmallVector Locs; Locs FnStartLocs; Locs CantUnwindLocs; Locs PersonalityLocs; Locs PersonalityIndexLocs; Locs HandlerDataLocs; int FPReg; public: UnwindContext(MCAsmParser &P) : Parser(P), FPReg(ARM::SP) {} bool hasFnStart() const { return !FnStartLocs.empty(); } bool cantUnwind() const { return !CantUnwindLocs.empty(); } bool hasHandlerData() const { return !HandlerDataLocs.empty(); } bool hasPersonality() const { return !(PersonalityLocs.empty() && PersonalityIndexLocs.empty()); } void recordFnStart(SMLoc L) { FnStartLocs.push_back(L); } void recordCantUnwind(SMLoc L) { CantUnwindLocs.push_back(L); } void recordPersonality(SMLoc L) { PersonalityLocs.push_back(L); } void recordHandlerData(SMLoc L) { HandlerDataLocs.push_back(L); } void recordPersonalityIndex(SMLoc L) { PersonalityIndexLocs.push_back(L); } void saveFPReg(int Reg) { FPReg = Reg; } int getFPReg() const { return FPReg; } void emitFnStartLocNotes() const { for (Locs::const_iterator FI = FnStartLocs.begin(), FE = FnStartLocs.end(); FI != FE; ++FI) Parser.Note(*FI, ".fnstart was specified here"); } void emitCantUnwindLocNotes() const { for (Locs::const_iterator UI = CantUnwindLocs.begin(), UE = CantUnwindLocs.end(); UI != UE; ++UI) Parser.Note(*UI, ".cantunwind was specified here"); } void emitHandlerDataLocNotes() const { for (Locs::const_iterator HI = HandlerDataLocs.begin(), HE = HandlerDataLocs.end(); HI != HE; ++HI) Parser.Note(*HI, ".handlerdata was specified here"); } void emitPersonalityLocNotes() const { for (Locs::const_iterator PI = PersonalityLocs.begin(), PE = PersonalityLocs.end(), PII = PersonalityIndexLocs.begin(), PIE = PersonalityIndexLocs.end(); PI != PE || PII != PIE;) { if (PI != PE && (PII == PIE || PI->getPointer() < PII->getPointer())) Parser.Note(*PI++, ".personality was specified here"); else if (PII != PIE && (PI == PE || PII->getPointer() < PI->getPointer())) Parser.Note(*PII++, ".personalityindex was specified here"); else llvm_unreachable(".personality and .personalityindex cannot be " "at the same location"); } } void reset() { FnStartLocs = Locs(); CantUnwindLocs = Locs(); PersonalityLocs = Locs(); HandlerDataLocs = Locs(); PersonalityIndexLocs = Locs(); FPReg = ARM::SP; } }; class ARMAsmParser : public MCTargetAsmParser { const MCInstrInfo &MII; const MCRegisterInfo *MRI; UnwindContext UC; ARMTargetStreamer &getTargetStreamer() { assert(getParser().getStreamer().getTargetStreamer() && "do not have a target streamer"); MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); return static_cast(TS); } // Map of register aliases registers via the .req directive. StringMap RegisterReqs; bool NextSymbolIsThumb; struct { ARMCC::CondCodes Cond; // Condition for IT block. unsigned Mask:4; // Condition mask for instructions. // Starting at first 1 (from lsb). // '1' condition as indicated in IT. // '0' inverse of condition (else). // Count of instructions in IT block is // 4 - trailingzeroes(mask) bool FirstCond; // Explicit flag for when we're parsing the // First instruction in the IT block. It's // implied in the mask, so needs special // handling. unsigned CurPosition; // Current position in parsing of IT // block. In range [0,3]. Initialized // according to count of instructions in block. // ~0U if no active IT block. } ITState; bool inITBlock() { return ITState.CurPosition != ~0U; } bool lastInITBlock() { return ITState.CurPosition == 4 - countTrailingZeros(ITState.Mask); } void forwardITPosition() { if (!inITBlock()) return; // Move to the next instruction in the IT block, if there is one. If not, // mark the block as done. unsigned TZ = countTrailingZeros(ITState.Mask); if (++ITState.CurPosition == 5 - TZ) ITState.CurPosition = ~0U; // Done with the IT block after this. } void Note(SMLoc L, const Twine &Msg, ArrayRef Ranges = None) { return getParser().Note(L, Msg, Ranges); } bool Warning(SMLoc L, const Twine &Msg, ArrayRef Ranges = None) { return getParser().Warning(L, Msg, Ranges); } bool Error(SMLoc L, const Twine &Msg, ArrayRef Ranges = None) { return getParser().Error(L, Msg, Ranges); } bool validatetLDMRegList(const MCInst &Inst, const OperandVector &Operands, unsigned ListNo, bool IsARPop = false); bool validatetSTMRegList(const MCInst &Inst, const OperandVector &Operands, unsigned ListNo); int tryParseRegister(); bool tryParseRegisterWithWriteBack(OperandVector &); int tryParseShiftRegister(OperandVector &); bool parseRegisterList(OperandVector &); bool parseMemory(OperandVector &); bool parseOperand(OperandVector &, StringRef Mnemonic); bool parsePrefix(ARMMCExpr::VariantKind &RefKind); bool parseMemRegOffsetShift(ARM_AM::ShiftOpc &ShiftType, unsigned &ShiftAmount); bool parseLiteralValues(unsigned Size, SMLoc L); bool parseDirectiveThumb(SMLoc L); bool parseDirectiveARM(SMLoc L); bool parseDirectiveThumbFunc(SMLoc L); bool parseDirectiveCode(SMLoc L); bool parseDirectiveSyntax(SMLoc L); bool parseDirectiveReq(StringRef Name, SMLoc L); bool parseDirectiveUnreq(SMLoc L); bool parseDirectiveArch(SMLoc L); bool parseDirectiveEabiAttr(SMLoc L); bool parseDirectiveCPU(SMLoc L); bool parseDirectiveFPU(SMLoc L); bool parseDirectiveFnStart(SMLoc L); bool parseDirectiveFnEnd(SMLoc L); bool parseDirectiveCantUnwind(SMLoc L); bool parseDirectivePersonality(SMLoc L); bool parseDirectiveHandlerData(SMLoc L); bool parseDirectiveSetFP(SMLoc L); bool parseDirectivePad(SMLoc L); bool parseDirectiveRegSave(SMLoc L, bool IsVector); bool parseDirectiveInst(SMLoc L, char Suffix = '\0'); bool parseDirectiveLtorg(SMLoc L); bool parseDirectiveEven(SMLoc L); bool parseDirectivePersonalityIndex(SMLoc L); bool parseDirectiveUnwindRaw(SMLoc L); bool parseDirectiveTLSDescSeq(SMLoc L); bool parseDirectiveMovSP(SMLoc L); bool parseDirectiveObjectArch(SMLoc L); bool parseDirectiveArchExtension(SMLoc L); bool parseDirectiveAlign(SMLoc L); bool parseDirectiveThumbSet(SMLoc L); StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode, bool &CarrySetting, unsigned &ProcessorIMod, StringRef &ITMask); void getMnemonicAcceptInfo(StringRef Mnemonic, StringRef FullInst, bool &CanAcceptCarrySet, bool &CanAcceptPredicationCode); void tryConvertingToTwoOperandForm(StringRef Mnemonic, bool CarrySetting, OperandVector &Operands); bool isThumb() const { // FIXME: Can tablegen auto-generate this? return getSTI().getFeatureBits()[ARM::ModeThumb]; } bool isThumbOne() const { return isThumb() && !getSTI().getFeatureBits()[ARM::FeatureThumb2]; } bool isThumbTwo() const { return isThumb() && getSTI().getFeatureBits()[ARM::FeatureThumb2]; } bool hasThumb() const { return getSTI().getFeatureBits()[ARM::HasV4TOps]; } bool hasThumb2() const { return getSTI().getFeatureBits()[ARM::FeatureThumb2]; } bool hasV6Ops() const { return getSTI().getFeatureBits()[ARM::HasV6Ops]; } bool hasV6T2Ops() const { return getSTI().getFeatureBits()[ARM::HasV6T2Ops]; } bool hasV6MOps() const { return getSTI().getFeatureBits()[ARM::HasV6MOps]; } bool hasV7Ops() const { return getSTI().getFeatureBits()[ARM::HasV7Ops]; } bool hasV8Ops() const { return getSTI().getFeatureBits()[ARM::HasV8Ops]; } bool hasV8MBaseline() const { return getSTI().getFeatureBits()[ARM::HasV8MBaselineOps]; } bool hasV8MMainline() const { return getSTI().getFeatureBits()[ARM::HasV8MMainlineOps]; } bool has8MSecExt() const { return getSTI().getFeatureBits()[ARM::Feature8MSecExt]; } bool hasARM() const { return !getSTI().getFeatureBits()[ARM::FeatureNoARM]; } bool hasDSP() const { return getSTI().getFeatureBits()[ARM::FeatureDSP]; } bool hasD16() const { return getSTI().getFeatureBits()[ARM::FeatureD16]; } bool hasV8_1aOps() const { return getSTI().getFeatureBits()[ARM::HasV8_1aOps]; } bool hasRAS() const { return getSTI().getFeatureBits()[ARM::FeatureRAS]; } void SwitchMode() { MCSubtargetInfo &STI = copySTI(); uint64_t FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb)); setAvailableFeatures(FB); } void FixModeAfterArchChange(bool WasThumb, SMLoc Loc); bool isMClass() const { return getSTI().getFeatureBits()[ARM::FeatureMClass]; } /// @name Auto-generated Match Functions /// { #define GET_ASSEMBLER_HEADER #include "ARMGenAsmMatcher.inc" /// } OperandMatchResultTy parseITCondCode(OperandVector &); OperandMatchResultTy parseCoprocNumOperand(OperandVector &); OperandMatchResultTy parseCoprocRegOperand(OperandVector &); OperandMatchResultTy parseCoprocOptionOperand(OperandVector &); OperandMatchResultTy parseMemBarrierOptOperand(OperandVector &); OperandMatchResultTy parseInstSyncBarrierOptOperand(OperandVector &); OperandMatchResultTy parseProcIFlagsOperand(OperandVector &); OperandMatchResultTy parseMSRMaskOperand(OperandVector &); OperandMatchResultTy parseBankedRegOperand(OperandVector &); OperandMatchResultTy parsePKHImm(OperandVector &O, StringRef Op, int Low, int High); OperandMatchResultTy parsePKHLSLImm(OperandVector &O) { return parsePKHImm(O, "lsl", 0, 31); } OperandMatchResultTy parsePKHASRImm(OperandVector &O) { return parsePKHImm(O, "asr", 1, 32); } OperandMatchResultTy parseSetEndImm(OperandVector &); OperandMatchResultTy parseShifterImm(OperandVector &); OperandMatchResultTy parseRotImm(OperandVector &); OperandMatchResultTy parseModImm(OperandVector &); OperandMatchResultTy parseBitfield(OperandVector &); OperandMatchResultTy parsePostIdxReg(OperandVector &); OperandMatchResultTy parseAM3Offset(OperandVector &); OperandMatchResultTy parseFPImm(OperandVector &); OperandMatchResultTy parseVectorList(OperandVector &); OperandMatchResultTy parseVectorLane(VectorLaneTy &LaneKind, unsigned &Index, SMLoc &EndLoc); // Asm Match Converter Methods void cvtThumbMultiply(MCInst &Inst, const OperandVector &); void cvtThumbBranches(MCInst &Inst, const OperandVector &); bool validateInstruction(MCInst &Inst, const OperandVector &Ops); bool processInstruction(MCInst &Inst, const OperandVector &Ops, MCStreamer &Out); bool shouldOmitCCOutOperand(StringRef Mnemonic, OperandVector &Operands); bool shouldOmitPredicateOperand(StringRef Mnemonic, OperandVector &Operands); public: enum ARMMatchResultTy { Match_RequiresITBlock = FIRST_TARGET_MATCH_RESULT_TY, Match_RequiresNotITBlock, Match_RequiresV6, Match_RequiresThumb2, Match_RequiresV8, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "ARMGenAsmMatcher.inc" }; ARMAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) : MCTargetAsmParser(Options, STI), MII(MII), UC(Parser) { MCAsmParserExtension::Initialize(Parser); // Cache the MCRegisterInfo. MRI = getContext().getRegisterInfo(); // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); // Not in an ITBlock to start with. ITState.CurPosition = ~0U; NextSymbolIsThumb = false; } // Implementation of the MCTargetAsmParser interface: bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; bool ParseDirective(AsmToken DirectiveID) override; unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; unsigned checkTargetMatchPredicate(MCInst &Inst) override; bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) override; void onLabelParsed(MCSymbol *Symbol) override; }; } // end anonymous namespace namespace { /// ARMOperand - Instances of this class represent a parsed ARM machine /// operand. class ARMOperand : public MCParsedAsmOperand { enum KindTy { k_CondCode, k_CCOut, k_ITCondMask, k_CoprocNum, k_CoprocReg, k_CoprocOption, k_Immediate, k_MemBarrierOpt, k_InstSyncBarrierOpt, k_Memory, k_PostIndexRegister, k_MSRMask, k_BankedReg, k_ProcIFlags, k_VectorIndex, k_Register, k_RegisterList, k_DPRRegisterList, k_SPRRegisterList, k_VectorList, k_VectorListAllLanes, k_VectorListIndexed, k_ShiftedRegister, k_ShiftedImmediate, k_ShifterImmediate, k_RotateImmediate, k_ModifiedImmediate, k_ConstantPoolImmediate, k_BitfieldDescriptor, k_Token, } Kind; SMLoc StartLoc, EndLoc, AlignmentLoc; SmallVector Registers; struct CCOp { ARMCC::CondCodes Val; }; struct CopOp { unsigned Val; }; struct CoprocOptionOp { unsigned Val; }; struct ITMaskOp { unsigned Mask:4; }; struct MBOptOp { ARM_MB::MemBOpt Val; }; struct ISBOptOp { ARM_ISB::InstSyncBOpt Val; }; struct IFlagsOp { ARM_PROC::IFlags Val; }; struct MMaskOp { unsigned Val; }; struct BankedRegOp { unsigned Val; }; struct TokOp { const char *Data; unsigned Length; }; struct RegOp { unsigned RegNum; }; // A vector register list is a sequential list of 1 to 4 registers. struct VectorListOp { unsigned RegNum; unsigned Count; unsigned LaneIndex; bool isDoubleSpaced; }; struct VectorIndexOp { unsigned Val; }; struct ImmOp { const MCExpr *Val; }; /// Combined record for all forms of ARM address expressions. struct MemoryOp { unsigned BaseRegNum; // Offset is in OffsetReg or OffsetImm. If both are zero, no offset // was specified. const MCConstantExpr *OffsetImm; // Offset immediate value unsigned OffsetRegNum; // Offset register num, when OffsetImm == NULL ARM_AM::ShiftOpc ShiftType; // Shift type for OffsetReg unsigned ShiftImm; // shift for OffsetReg. unsigned Alignment; // 0 = no alignment specified // n = alignment in bytes (2, 4, 8, 16, or 32) unsigned isNegative : 1; // Negated OffsetReg? (~'U' bit) }; struct PostIdxRegOp { unsigned RegNum; bool isAdd; ARM_AM::ShiftOpc ShiftTy; unsigned ShiftImm; }; struct ShifterImmOp { bool isASR; unsigned Imm; }; struct RegShiftedRegOp { ARM_AM::ShiftOpc ShiftTy; unsigned SrcReg; unsigned ShiftReg; unsigned ShiftImm; }; struct RegShiftedImmOp { ARM_AM::ShiftOpc ShiftTy; unsigned SrcReg; unsigned ShiftImm; }; struct RotImmOp { unsigned Imm; }; struct ModImmOp { unsigned Bits; unsigned Rot; }; struct BitfieldOp { unsigned LSB; unsigned Width; }; union { struct CCOp CC; struct CopOp Cop; struct CoprocOptionOp CoprocOption; struct MBOptOp MBOpt; struct ISBOptOp ISBOpt; struct ITMaskOp ITMask; struct IFlagsOp IFlags; struct MMaskOp MMask; struct BankedRegOp BankedReg; struct TokOp Tok; struct RegOp Reg; struct VectorListOp VectorList; struct VectorIndexOp VectorIndex; struct ImmOp Imm; struct MemoryOp Memory; struct PostIdxRegOp PostIdxReg; struct ShifterImmOp ShifterImm; struct RegShiftedRegOp RegShiftedReg; struct RegShiftedImmOp RegShiftedImm; struct RotImmOp RotImm; struct ModImmOp ModImm; struct BitfieldOp Bitfield; }; public: ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} /// getStartLoc - Get the location of the first token of this operand. SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Get the location of the last token of this operand. SMLoc getEndLoc() const override { return EndLoc; } /// getLocRange - Get the range between the first and last token of this /// operand. SMRange getLocRange() const { return SMRange(StartLoc, EndLoc); } /// getAlignmentLoc - Get the location of the Alignment token of this operand. SMLoc getAlignmentLoc() const { assert(Kind == k_Memory && "Invalid access!"); return AlignmentLoc; } ARMCC::CondCodes getCondCode() const { assert(Kind == k_CondCode && "Invalid access!"); return CC.Val; } unsigned getCoproc() const { assert((Kind == k_CoprocNum || Kind == k_CoprocReg) && "Invalid access!"); return Cop.Val; } StringRef getToken() const { assert(Kind == k_Token && "Invalid access!"); return StringRef(Tok.Data, Tok.Length); } unsigned getReg() const override { assert((Kind == k_Register || Kind == k_CCOut) && "Invalid access!"); return Reg.RegNum; } const SmallVectorImpl &getRegList() const { assert((Kind == k_RegisterList || Kind == k_DPRRegisterList || Kind == k_SPRRegisterList) && "Invalid access!"); return Registers; } const MCExpr *getImm() const { assert(isImm() && "Invalid access!"); return Imm.Val; } const MCExpr *getConstantPoolImm() const { assert(isConstantPoolImm() && "Invalid access!"); return Imm.Val; } unsigned getVectorIndex() const { assert(Kind == k_VectorIndex && "Invalid access!"); return VectorIndex.Val; } ARM_MB::MemBOpt getMemBarrierOpt() const { assert(Kind == k_MemBarrierOpt && "Invalid access!"); return MBOpt.Val; } ARM_ISB::InstSyncBOpt getInstSyncBarrierOpt() const { assert(Kind == k_InstSyncBarrierOpt && "Invalid access!"); return ISBOpt.Val; } ARM_PROC::IFlags getProcIFlags() const { assert(Kind == k_ProcIFlags && "Invalid access!"); return IFlags.Val; } unsigned getMSRMask() const { assert(Kind == k_MSRMask && "Invalid access!"); return MMask.Val; } unsigned getBankedReg() const { assert(Kind == k_BankedReg && "Invalid access!"); return BankedReg.Val; } bool isCoprocNum() const { return Kind == k_CoprocNum; } bool isCoprocReg() const { return Kind == k_CoprocReg; } bool isCoprocOption() const { return Kind == k_CoprocOption; } bool isCondCode() const { return Kind == k_CondCode; } bool isCCOut() const { return Kind == k_CCOut; } bool isITMask() const { return Kind == k_ITCondMask; } bool isITCondCode() const { return Kind == k_CondCode; } bool isImm() const override { return Kind == k_Immediate; } bool isARMBranchTarget() const { if (!isImm()) return false; if (const MCConstantExpr *CE = dyn_cast(getImm())) return CE->getValue() % 4 == 0; return true; } bool isThumbBranchTarget() const { if (!isImm()) return false; if (const MCConstantExpr *CE = dyn_cast(getImm())) return CE->getValue() % 2 == 0; return true; } // checks whether this operand is an unsigned offset which fits is a field // of specified width and scaled by a specific number of bits template bool isUnsignedOffset() const { if (!isImm()) return false; if (isa(Imm.Val)) return true; if (const MCConstantExpr *CE = dyn_cast(Imm.Val)) { int64_t Val = CE->getValue(); int64_t Align = 1LL << scale; int64_t Max = Align * ((1LL << width) - 1); return ((Val % Align) == 0) && (Val >= 0) && (Val <= Max); } return false; } // checks whether this operand is an signed offset which fits is a field // of specified width and scaled by a specific number of bits template bool isSignedOffset() const { if (!isImm()) return false; if (isa(Imm.Val)) return true; if (const MCConstantExpr *CE = dyn_cast(Imm.Val)) { int64_t Val = CE->getValue(); int64_t Align = 1LL << scale; int64_t Max = Align * ((1LL << (width-1)) - 1); int64_t Min = -Align * (1LL << (width-1)); return ((Val % Align) == 0) && (Val >= Min) && (Val <= Max); } return false; } // checks whether this operand is a memory operand computed as an offset // applied to PC. the offset may have 8 bits of magnitude and is represented // with two bits of shift. textually it may be either [pc, #imm], #imm or // relocable expression... bool isThumbMemPC() const { int64_t Val = 0; if (isImm()) { if (isa(Imm.Val)) return true; const MCConstantExpr *CE = dyn_cast(Imm.Val); if (!CE) return false; Val = CE->getValue(); } else if (isMem()) { if(!Memory.OffsetImm || Memory.OffsetRegNum) return false; if(Memory.BaseRegNum != ARM::PC) return false; Val = Memory.OffsetImm->getValue(); } else return false; return ((Val % 4) == 0) && (Val >= 0) && (Val <= 1020); } bool isFPImm() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int Val = ARM_AM::getFP32Imm(APInt(32, CE->getValue())); return Val != -1; } bool isFBits16() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value <= 16; } bool isFBits32() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 1 && Value <= 32; } bool isImm8s4() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return ((Value & 3) == 0) && Value >= -1020 && Value <= 1020; } bool isImm0_1020s4() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return ((Value & 3) == 0) && Value >= 0 && Value <= 1020; } bool isImm0_508s4() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return ((Value & 3) == 0) && Value >= 0 && Value <= 508; } bool isImm0_508s4Neg() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = -CE->getValue(); // explicitly exclude zero. we want that to use the normal 0_508 version. return ((Value & 3) == 0) && Value > 0 && Value <= 508; } bool isImm0_239() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 240; } bool isImm0_255() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 256; } bool isImm0_4095() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 4096; } bool isImm0_4095Neg() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = -CE->getValue(); return Value > 0 && Value < 4096; } bool isImm0_1() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 2; } bool isImm0_3() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 4; } bool isImm0_7() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 8; } bool isImm0_15() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 16; } bool isImm0_31() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 32; } bool isImm0_63() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 64; } bool isImm8() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value == 8; } bool isImm16() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value == 16; } bool isImm32() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value == 32; } bool isShrImm8() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value <= 8; } bool isShrImm16() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value <= 16; } bool isShrImm32() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value <= 32; } bool isShrImm64() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value <= 64; } bool isImm1_7() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value < 8; } bool isImm1_15() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value < 16; } bool isImm1_31() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value < 32; } bool isImm1_16() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value < 17; } bool isImm1_32() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value < 33; } bool isImm0_32() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 33; } bool isImm0_65535() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 65536; } bool isImm256_65535Expr() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // If it's not a constant expression, it'll generate a fixup and be // handled later. if (!CE) return true; int64_t Value = CE->getValue(); return Value >= 256 && Value < 65536; } bool isImm0_65535Expr() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // If it's not a constant expression, it'll generate a fixup and be // handled later. if (!CE) return true; int64_t Value = CE->getValue(); return Value >= 0 && Value < 65536; } bool isImm24bit() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value <= 0xffffff; } bool isImmThumbSR() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value < 33; } bool isPKHLSLImm() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value >= 0 && Value < 32; } bool isPKHASRImm() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value > 0 && Value <= 32; } bool isAdrLabel() const { // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. if (isImm() && !isa(getImm())) return true; // If it is a constant, it must fit into a modified immediate encoding. if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return (ARM_AM::getSOImmVal(Value) != -1 || ARM_AM::getSOImmVal(-Value) != -1); } bool isT2SOImm() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return ARM_AM::getT2SOImmVal(Value) != -1; } bool isT2SOImmNot() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return ARM_AM::getT2SOImmVal(Value) == -1 && ARM_AM::getT2SOImmVal(~Value) != -1; } bool isT2SOImmNeg() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); // Only use this when not representable as a plain so_imm. return ARM_AM::getT2SOImmVal(Value) == -1 && ARM_AM::getT2SOImmVal(-Value) != -1; } bool isSetEndImm() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return Value == 1 || Value == 0; } bool isReg() const override { return Kind == k_Register; } bool isRegList() const { return Kind == k_RegisterList; } bool isDPRRegList() const { return Kind == k_DPRRegisterList; } bool isSPRRegList() const { return Kind == k_SPRRegisterList; } bool isToken() const override { return Kind == k_Token; } bool isMemBarrierOpt() const { return Kind == k_MemBarrierOpt; } bool isInstSyncBarrierOpt() const { return Kind == k_InstSyncBarrierOpt; } bool isMem() const override { return Kind == k_Memory; } bool isShifterImm() const { return Kind == k_ShifterImmediate; } bool isRegShiftedReg() const { return Kind == k_ShiftedRegister; } bool isRegShiftedImm() const { return Kind == k_ShiftedImmediate; } bool isRotImm() const { return Kind == k_RotateImmediate; } bool isModImm() const { return Kind == k_ModifiedImmediate; } bool isModImmNot() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return ARM_AM::getSOImmVal(~Value) != -1; } bool isModImmNeg() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Value = CE->getValue(); return ARM_AM::getSOImmVal(Value) == -1 && ARM_AM::getSOImmVal(-Value) != -1; } bool isConstantPoolImm() const { return Kind == k_ConstantPoolImmediate; } bool isBitfield() const { return Kind == k_BitfieldDescriptor; } bool isPostIdxRegShifted() const { return Kind == k_PostIndexRegister; } bool isPostIdxReg() const { return Kind == k_PostIndexRegister && PostIdxReg.ShiftTy ==ARM_AM::no_shift; } bool isMemNoOffset(bool alignOK = false, unsigned Alignment = 0) const { if (!isMem()) return false; // No offset of any kind. return Memory.OffsetRegNum == 0 && Memory.OffsetImm == nullptr && (alignOK || Memory.Alignment == Alignment); } bool isMemPCRelImm12() const { if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Base register must be PC. if (Memory.BaseRegNum != ARM::PC) return false; // Immediate offset in range [-4095, 4095]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return (Val > -4096 && Val < 4096) || (Val == INT32_MIN); } bool isAlignedMemory() const { return isMemNoOffset(true); } bool isAlignedMemoryNone() const { return isMemNoOffset(false, 0); } bool isDupAlignedMemoryNone() const { return isMemNoOffset(false, 0); } bool isAlignedMemory16() const { if (isMemNoOffset(false, 2)) // alignment in bytes for 16-bits is 2. return true; return isMemNoOffset(false, 0); } bool isDupAlignedMemory16() const { if (isMemNoOffset(false, 2)) // alignment in bytes for 16-bits is 2. return true; return isMemNoOffset(false, 0); } bool isAlignedMemory32() const { if (isMemNoOffset(false, 4)) // alignment in bytes for 32-bits is 4. return true; return isMemNoOffset(false, 0); } bool isDupAlignedMemory32() const { if (isMemNoOffset(false, 4)) // alignment in bytes for 32-bits is 4. return true; return isMemNoOffset(false, 0); } bool isAlignedMemory64() const { if (isMemNoOffset(false, 8)) // alignment in bytes for 64-bits is 8. return true; return isMemNoOffset(false, 0); } bool isDupAlignedMemory64() const { if (isMemNoOffset(false, 8)) // alignment in bytes for 64-bits is 8. return true; return isMemNoOffset(false, 0); } bool isAlignedMemory64or128() const { if (isMemNoOffset(false, 8)) // alignment in bytes for 64-bits is 8. return true; if (isMemNoOffset(false, 16)) // alignment in bytes for 128-bits is 16. return true; return isMemNoOffset(false, 0); } bool isDupAlignedMemory64or128() const { if (isMemNoOffset(false, 8)) // alignment in bytes for 64-bits is 8. return true; if (isMemNoOffset(false, 16)) // alignment in bytes for 128-bits is 16. return true; return isMemNoOffset(false, 0); } bool isAlignedMemory64or128or256() const { if (isMemNoOffset(false, 8)) // alignment in bytes for 64-bits is 8. return true; if (isMemNoOffset(false, 16)) // alignment in bytes for 128-bits is 16. return true; if (isMemNoOffset(false, 32)) // alignment in bytes for 256-bits is 32. return true; return isMemNoOffset(false, 0); } bool isAddrMode2() const { if (!isMem() || Memory.Alignment != 0) return false; // Check for register offset. if (Memory.OffsetRegNum) return true; // Immediate offset in range [-4095, 4095]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return Val > -4096 && Val < 4096; } bool isAM2OffsetImm() const { if (!isImm()) return false; // Immediate offset in range [-4095, 4095]. const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Val = CE->getValue(); return (Val == INT32_MIN) || (Val > -4096 && Val < 4096); } bool isAddrMode3() const { // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. If it is a constant, it's something else // and we reject it. if (isImm() && !isa(getImm())) return true; if (!isMem() || Memory.Alignment != 0) return false; // No shifts are legal for AM3. if (Memory.ShiftType != ARM_AM::no_shift) return false; // Check for register offset. if (Memory.OffsetRegNum) return true; // Immediate offset in range [-255, 255]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); // The #-0 offset is encoded as INT32_MIN, and we have to check // for this too. return (Val > -256 && Val < 256) || Val == INT32_MIN; } bool isAM3Offset() const { if (Kind != k_Immediate && Kind != k_PostIndexRegister) return false; if (Kind == k_PostIndexRegister) return PostIdxReg.ShiftTy == ARM_AM::no_shift; // Immediate offset in range [-255, 255]. const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Val = CE->getValue(); // Special case, #-0 is INT32_MIN. return (Val > -256 && Val < 256) || Val == INT32_MIN; } bool isAddrMode5() const { // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. If it is a constant, it's something else // and we reject it. if (isImm() && !isa(getImm())) return true; if (!isMem() || Memory.Alignment != 0) return false; // Check for register offset. if (Memory.OffsetRegNum) return false; // Immediate offset in range [-1020, 1020] and a multiple of 4. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return (Val >= -1020 && Val <= 1020 && ((Val & 3) == 0)) || Val == INT32_MIN; } bool isAddrMode5FP16() const { // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. If it is a constant, it's something else // and we reject it. if (isImm() && !isa(getImm())) return true; if (!isMem() || Memory.Alignment != 0) return false; // Check for register offset. if (Memory.OffsetRegNum) return false; // Immediate offset in range [-510, 510] and a multiple of 2. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return (Val >= -510 && Val <= 510 && ((Val & 1) == 0)) || Val == INT32_MIN; } bool isMemTBB() const { if (!isMem() || !Memory.OffsetRegNum || Memory.isNegative || Memory.ShiftType != ARM_AM::no_shift || Memory.Alignment != 0) return false; return true; } bool isMemTBH() const { if (!isMem() || !Memory.OffsetRegNum || Memory.isNegative || Memory.ShiftType != ARM_AM::lsl || Memory.ShiftImm != 1 || Memory.Alignment != 0 ) return false; return true; } bool isMemRegOffset() const { if (!isMem() || !Memory.OffsetRegNum || Memory.Alignment != 0) return false; return true; } bool isT2MemRegOffset() const { if (!isMem() || !Memory.OffsetRegNum || Memory.isNegative || Memory.Alignment != 0 || Memory.BaseRegNum == ARM::PC) return false; // Only lsl #{0, 1, 2, 3} allowed. if (Memory.ShiftType == ARM_AM::no_shift) return true; if (Memory.ShiftType != ARM_AM::lsl || Memory.ShiftImm > 3) return false; return true; } bool isMemThumbRR() const { // Thumb reg+reg addressing is simple. Just two registers, a base and // an offset. No shifts, negations or any other complicating factors. if (!isMem() || !Memory.OffsetRegNum || Memory.isNegative || Memory.ShiftType != ARM_AM::no_shift || Memory.Alignment != 0) return false; return isARMLowRegister(Memory.BaseRegNum) && (!Memory.OffsetRegNum || isARMLowRegister(Memory.OffsetRegNum)); } bool isMemThumbRIs4() const { if (!isMem() || Memory.OffsetRegNum != 0 || !isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0) return false; // Immediate offset, multiple of 4 in range [0, 124]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val <= 124 && (Val % 4) == 0; } bool isMemThumbRIs2() const { if (!isMem() || Memory.OffsetRegNum != 0 || !isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0) return false; // Immediate offset, multiple of 4 in range [0, 62]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val <= 62 && (Val % 2) == 0; } bool isMemThumbRIs1() const { if (!isMem() || Memory.OffsetRegNum != 0 || !isARMLowRegister(Memory.BaseRegNum) || Memory.Alignment != 0) return false; // Immediate offset in range [0, 31]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val <= 31; } bool isMemThumbSPI() const { if (!isMem() || Memory.OffsetRegNum != 0 || Memory.BaseRegNum != ARM::SP || Memory.Alignment != 0) return false; // Immediate offset, multiple of 4 in range [0, 1020]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val <= 1020 && (Val % 4) == 0; } bool isMemImm8s4Offset() const { // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. If it is a constant, it's something else // and we reject it. if (isImm() && !isa(getImm())) return true; if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset a multiple of 4 in range [-1020, 1020]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); // Special case, #-0 is INT32_MIN. return (Val >= -1020 && Val <= 1020 && (Val & 3) == 0) || Val == INT32_MIN; } bool isMemImm0_1020s4Offset() const { if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset a multiple of 4 in range [0, 1020]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val <= 1020 && (Val & 3) == 0; } bool isMemImm8Offset() const { if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Base reg of PC isn't allowed for these encodings. if (Memory.BaseRegNum == ARM::PC) return false; // Immediate offset in range [-255, 255]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return (Val == INT32_MIN) || (Val > -256 && Val < 256); } bool isMemPosImm8Offset() const { if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset in range [0, 255]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return Val >= 0 && Val < 256; } bool isMemNegImm8Offset() const { if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Base reg of PC isn't allowed for these encodings. if (Memory.BaseRegNum == ARM::PC) return false; // Immediate offset in range [-255, -1]. if (!Memory.OffsetImm) return false; int64_t Val = Memory.OffsetImm->getValue(); return (Val == INT32_MIN) || (Val > -256 && Val < 0); } bool isMemUImm12Offset() const { if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset in range [0, 4095]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return (Val >= 0 && Val < 4096); } bool isMemImm12Offset() const { // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. If it is a constant, it's something else // and we reject it. if (isImm() && !isa(getImm())) return true; if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; // Immediate offset in range [-4095, 4095]. if (!Memory.OffsetImm) return true; int64_t Val = Memory.OffsetImm->getValue(); return (Val > -4096 && Val < 4096) || (Val == INT32_MIN); } bool isConstPoolAsmImm() const { // Delay processing of Constant Pool Immediate, this will turn into // a constant. Match no other operand return (isConstantPoolImm()); } bool isPostIdxImm8() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Val = CE->getValue(); return (Val > -256 && Val < 256) || (Val == INT32_MIN); } bool isPostIdxImm8s4() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); if (!CE) return false; int64_t Val = CE->getValue(); return ((Val & 3) == 0 && Val >= -1020 && Val <= 1020) || (Val == INT32_MIN); } bool isMSRMask() const { return Kind == k_MSRMask; } bool isBankedReg() const { return Kind == k_BankedReg; } bool isProcIFlags() const { return Kind == k_ProcIFlags; } // NEON operands. bool isSingleSpacedVectorList() const { return Kind == k_VectorList && !VectorList.isDoubleSpaced; } bool isDoubleSpacedVectorList() const { return Kind == k_VectorList && VectorList.isDoubleSpaced; } bool isVecListOneD() const { if (!isSingleSpacedVectorList()) return false; return VectorList.Count == 1; } bool isVecListDPair() const { if (!isSingleSpacedVectorList()) return false; return (ARMMCRegisterClasses[ARM::DPairRegClassID] .contains(VectorList.RegNum)); } bool isVecListThreeD() const { if (!isSingleSpacedVectorList()) return false; return VectorList.Count == 3; } bool isVecListFourD() const { if (!isSingleSpacedVectorList()) return false; return VectorList.Count == 4; } bool isVecListDPairSpaced() const { if (Kind != k_VectorList) return false; if (isSingleSpacedVectorList()) return false; return (ARMMCRegisterClasses[ARM::DPairSpcRegClassID] .contains(VectorList.RegNum)); } bool isVecListThreeQ() const { if (!isDoubleSpacedVectorList()) return false; return VectorList.Count == 3; } bool isVecListFourQ() const { if (!isDoubleSpacedVectorList()) return false; return VectorList.Count == 4; } bool isSingleSpacedVectorAllLanes() const { return Kind == k_VectorListAllLanes && !VectorList.isDoubleSpaced; } bool isDoubleSpacedVectorAllLanes() const { return Kind == k_VectorListAllLanes && VectorList.isDoubleSpaced; } bool isVecListOneDAllLanes() const { if (!isSingleSpacedVectorAllLanes()) return false; return VectorList.Count == 1; } bool isVecListDPairAllLanes() const { if (!isSingleSpacedVectorAllLanes()) return false; return (ARMMCRegisterClasses[ARM::DPairRegClassID] .contains(VectorList.RegNum)); } bool isVecListDPairSpacedAllLanes() const { if (!isDoubleSpacedVectorAllLanes()) return false; return VectorList.Count == 2; } bool isVecListThreeDAllLanes() const { if (!isSingleSpacedVectorAllLanes()) return false; return VectorList.Count == 3; } bool isVecListThreeQAllLanes() const { if (!isDoubleSpacedVectorAllLanes()) return false; return VectorList.Count == 3; } bool isVecListFourDAllLanes() const { if (!isSingleSpacedVectorAllLanes()) return false; return VectorList.Count == 4; } bool isVecListFourQAllLanes() const { if (!isDoubleSpacedVectorAllLanes()) return false; return VectorList.Count == 4; } bool isSingleSpacedVectorIndexed() const { return Kind == k_VectorListIndexed && !VectorList.isDoubleSpaced; } bool isDoubleSpacedVectorIndexed() const { return Kind == k_VectorListIndexed && VectorList.isDoubleSpaced; } bool isVecListOneDByteIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 1 && VectorList.LaneIndex <= 7; } bool isVecListOneDHWordIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 1 && VectorList.LaneIndex <= 3; } bool isVecListOneDWordIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 1 && VectorList.LaneIndex <= 1; } bool isVecListTwoDByteIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 2 && VectorList.LaneIndex <= 7; } bool isVecListTwoDHWordIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 2 && VectorList.LaneIndex <= 3; } bool isVecListTwoQWordIndexed() const { if (!isDoubleSpacedVectorIndexed()) return false; return VectorList.Count == 2 && VectorList.LaneIndex <= 1; } bool isVecListTwoQHWordIndexed() const { if (!isDoubleSpacedVectorIndexed()) return false; return VectorList.Count == 2 && VectorList.LaneIndex <= 3; } bool isVecListTwoDWordIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 2 && VectorList.LaneIndex <= 1; } bool isVecListThreeDByteIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 3 && VectorList.LaneIndex <= 7; } bool isVecListThreeDHWordIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 3 && VectorList.LaneIndex <= 3; } bool isVecListThreeQWordIndexed() const { if (!isDoubleSpacedVectorIndexed()) return false; return VectorList.Count == 3 && VectorList.LaneIndex <= 1; } bool isVecListThreeQHWordIndexed() const { if (!isDoubleSpacedVectorIndexed()) return false; return VectorList.Count == 3 && VectorList.LaneIndex <= 3; } bool isVecListThreeDWordIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 3 && VectorList.LaneIndex <= 1; } bool isVecListFourDByteIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 4 && VectorList.LaneIndex <= 7; } bool isVecListFourDHWordIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 4 && VectorList.LaneIndex <= 3; } bool isVecListFourQWordIndexed() const { if (!isDoubleSpacedVectorIndexed()) return false; return VectorList.Count == 4 && VectorList.LaneIndex <= 1; } bool isVecListFourQHWordIndexed() const { if (!isDoubleSpacedVectorIndexed()) return false; return VectorList.Count == 4 && VectorList.LaneIndex <= 3; } bool isVecListFourDWordIndexed() const { if (!isSingleSpacedVectorIndexed()) return false; return VectorList.Count == 4 && VectorList.LaneIndex <= 1; } bool isVectorIndex8() const { if (Kind != k_VectorIndex) return false; return VectorIndex.Val < 8; } bool isVectorIndex16() const { if (Kind != k_VectorIndex) return false; return VectorIndex.Val < 4; } bool isVectorIndex32() const { if (Kind != k_VectorIndex) return false; return VectorIndex.Val < 2; } bool isNEONi8splat() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // Must be a constant. if (!CE) return false; int64_t Value = CE->getValue(); // i8 value splatted across 8 bytes. The immediate is just the 8 byte // value. return Value >= 0 && Value < 256; } bool isNEONi16splat() const { if (isNEONByteReplicate(2)) return false; // Leave that for bytes replication and forbid by default. if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // Must be a constant. if (!CE) return false; unsigned Value = CE->getValue(); return ARM_AM::isNEONi16splat(Value); } bool isNEONi16splatNot() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // Must be a constant. if (!CE) return false; unsigned Value = CE->getValue(); return ARM_AM::isNEONi16splat(~Value & 0xffff); } bool isNEONi32splat() const { if (isNEONByteReplicate(4)) return false; // Leave that for bytes replication and forbid by default. if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // Must be a constant. if (!CE) return false; unsigned Value = CE->getValue(); return ARM_AM::isNEONi32splat(Value); } bool isNEONi32splatNot() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // Must be a constant. if (!CE) return false; unsigned Value = CE->getValue(); return ARM_AM::isNEONi32splat(~Value); } bool isNEONByteReplicate(unsigned NumBytes) const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // Must be a constant. if (!CE) return false; int64_t Value = CE->getValue(); if (!Value) return false; // Don't bother with zero. unsigned char B = Value & 0xff; for (unsigned i = 1; i < NumBytes; ++i) { Value >>= 8; if ((Value & 0xff) != B) return false; } return true; } bool isNEONi16ByteReplicate() const { return isNEONByteReplicate(2); } bool isNEONi32ByteReplicate() const { return isNEONByteReplicate(4); } bool isNEONi32vmov() const { if (isNEONByteReplicate(4)) return false; // Let it to be classified as byte-replicate case. if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // Must be a constant. if (!CE) return false; int64_t Value = CE->getValue(); // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X, // for VMOV/VMVN only, 00Xf or 0Xff are also accepted. // FIXME: This is probably wrong and a copy and paste from previous example return (Value >= 0 && Value < 256) || (Value >= 0x0100 && Value <= 0xff00) || (Value >= 0x010000 && Value <= 0xff0000) || (Value >= 0x01000000 && Value <= 0xff000000) || (Value >= 0x01ff && Value <= 0xffff && (Value & 0xff) == 0xff) || (Value >= 0x01ffff && Value <= 0xffffff && (Value & 0xffff) == 0xffff); } bool isNEONi32vmovNeg() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // Must be a constant. if (!CE) return false; int64_t Value = ~CE->getValue(); // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X, // for VMOV/VMVN only, 00Xf or 0Xff are also accepted. // FIXME: This is probably wrong and a copy and paste from previous example return (Value >= 0 && Value < 256) || (Value >= 0x0100 && Value <= 0xff00) || (Value >= 0x010000 && Value <= 0xff0000) || (Value >= 0x01000000 && Value <= 0xff000000) || (Value >= 0x01ff && Value <= 0xffff && (Value & 0xff) == 0xff) || (Value >= 0x01ffff && Value <= 0xffffff && (Value & 0xffff) == 0xffff); } bool isNEONi64splat() const { if (!isImm()) return false; const MCConstantExpr *CE = dyn_cast(getImm()); // Must be a constant. if (!CE) return false; uint64_t Value = CE->getValue(); // i64 value with each byte being either 0 or 0xff. for (unsigned i = 0; i < 8; ++i, Value >>= 8) if ((Value & 0xff) != 0 && (Value & 0xff) != 0xff) return false; return true; } void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediates when possible. Null MCExpr = 0. if (!Expr) Inst.addOperand(MCOperand::createImm(0)); else if (const MCConstantExpr *CE = dyn_cast(Expr)) Inst.addOperand(MCOperand::createImm(CE->getValue())); else Inst.addOperand(MCOperand::createExpr(Expr)); } void addARMBranchTargetOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); } void addThumbBranchTargetOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); } void addCondCodeOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(unsigned(getCondCode()))); unsigned RegNum = getCondCode() == ARMCC::AL ? 0: ARM::CPSR; Inst.addOperand(MCOperand::createReg(RegNum)); } void addCoprocNumOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(getCoproc())); } void addCoprocRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(getCoproc())); } void addCoprocOptionOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(CoprocOption.Val)); } void addITMaskOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(ITMask.Mask)); } void addITCondCodeOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(unsigned(getCondCode()))); } void addCCOutOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getReg())); } void addRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getReg())); } void addRegShiftedRegOperands(MCInst &Inst, unsigned N) const { assert(N == 3 && "Invalid number of operands!"); assert(isRegShiftedReg() && "addRegShiftedRegOperands() on non-RegShiftedReg!"); Inst.addOperand(MCOperand::createReg(RegShiftedReg.SrcReg)); Inst.addOperand(MCOperand::createReg(RegShiftedReg.ShiftReg)); Inst.addOperand(MCOperand::createImm( ARM_AM::getSORegOpc(RegShiftedReg.ShiftTy, RegShiftedReg.ShiftImm))); } void addRegShiftedImmOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); assert(isRegShiftedImm() && "addRegShiftedImmOperands() on non-RegShiftedImm!"); Inst.addOperand(MCOperand::createReg(RegShiftedImm.SrcReg)); // Shift of #32 is encoded as 0 where permitted unsigned Imm = (RegShiftedImm.ShiftImm == 32 ? 0 : RegShiftedImm.ShiftImm); Inst.addOperand(MCOperand::createImm( ARM_AM::getSORegOpc(RegShiftedImm.ShiftTy, Imm))); } void addShifterImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm((ShifterImm.isASR << 5) | ShifterImm.Imm)); } void addRegListOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const SmallVectorImpl &RegList = getRegList(); for (SmallVectorImpl::const_iterator I = RegList.begin(), E = RegList.end(); I != E; ++I) Inst.addOperand(MCOperand::createReg(*I)); } void addDPRRegListOperands(MCInst &Inst, unsigned N) const { addRegListOperands(Inst, N); } void addSPRRegListOperands(MCInst &Inst, unsigned N) const { addRegListOperands(Inst, N); } void addRotImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // Encoded as val>>3. The printer handles display as 8, 16, 24. Inst.addOperand(MCOperand::createImm(RotImm.Imm >> 3)); } void addModImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // Support for fixups (MCFixup) if (isImm()) return addImmOperands(Inst, N); Inst.addOperand(MCOperand::createImm(ModImm.Bits | (ModImm.Rot << 7))); } void addModImmNotOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCConstantExpr *CE = dyn_cast(getImm()); uint32_t Enc = ARM_AM::getSOImmVal(~CE->getValue()); Inst.addOperand(MCOperand::createImm(Enc)); } void addModImmNegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCConstantExpr *CE = dyn_cast(getImm()); uint32_t Enc = ARM_AM::getSOImmVal(-CE->getValue()); Inst.addOperand(MCOperand::createImm(Enc)); } void addBitfieldOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // Munge the lsb/width into a bitfield mask. unsigned lsb = Bitfield.LSB; unsigned width = Bitfield.Width; // Make a 32-bit mask w/ the referenced bits clear and all other bits set. uint32_t Mask = ~(((uint32_t)0xffffffff >> lsb) << (32 - width) >> (32 - (lsb + width))); Inst.addOperand(MCOperand::createImm(Mask)); } void addImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); } void addFBits16Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(16 - CE->getValue())); } void addFBits32Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(32 - CE->getValue())); } void addFPImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCConstantExpr *CE = dyn_cast(getImm()); int Val = ARM_AM::getFP32Imm(APInt(32, CE->getValue())); Inst.addOperand(MCOperand::createImm(Val)); } void addImm8s4Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // FIXME: We really want to scale the value here, but the LDRD/STRD // instruction don't encode operands that way yet. const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(CE->getValue())); } void addImm0_1020s4Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate is scaled by four in the encoding and is stored // in the MCInst as such. Lop off the low two bits here. const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(CE->getValue() / 4)); } void addImm0_508s4NegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate is scaled by four in the encoding and is stored // in the MCInst as such. Lop off the low two bits here. const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(-(CE->getValue() / 4))); } void addImm0_508s4Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate is scaled by four in the encoding and is stored // in the MCInst as such. Lop off the low two bits here. const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(CE->getValue() / 4)); } void addImm1_16Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The constant encodes as the immediate-1, and we store in the instruction // the bits as encoded, so subtract off one here. const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(CE->getValue() - 1)); } void addImm1_32Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The constant encodes as the immediate-1, and we store in the instruction // the bits as encoded, so subtract off one here. const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(CE->getValue() - 1)); } void addImmThumbSROperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The constant encodes as the immediate, except for 32, which encodes as // zero. const MCConstantExpr *CE = dyn_cast(getImm()); unsigned Imm = CE->getValue(); Inst.addOperand(MCOperand::createImm((Imm == 32 ? 0 : Imm))); } void addPKHASRImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // An ASR value of 32 encodes as 0, so that's how we want to add it to // the instruction as well. const MCConstantExpr *CE = dyn_cast(getImm()); int Val = CE->getValue(); Inst.addOperand(MCOperand::createImm(Val == 32 ? 0 : Val)); } void addT2SOImmNotOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The operand is actually a t2_so_imm, but we have its bitwise // negation in the assembly source, so twiddle it here. const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(~CE->getValue())); } void addT2SOImmNegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The operand is actually a t2_so_imm, but we have its // negation in the assembly source, so twiddle it here. const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(-CE->getValue())); } void addImm0_4095NegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The operand is actually an imm0_4095, but we have its // negation in the assembly source, so twiddle it here. const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(-CE->getValue())); } void addUnsignedOffset_b8s2Operands(MCInst &Inst, unsigned N) const { if(const MCConstantExpr *CE = dyn_cast(getImm())) { Inst.addOperand(MCOperand::createImm(CE->getValue() >> 2)); return; } const MCSymbolRefExpr *SR = dyn_cast(Imm.Val); assert(SR && "Unknown value type!"); Inst.addOperand(MCOperand::createExpr(SR)); } void addThumbMemPCOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); if (isImm()) { const MCConstantExpr *CE = dyn_cast(getImm()); if (CE) { Inst.addOperand(MCOperand::createImm(CE->getValue())); return; } const MCSymbolRefExpr *SR = dyn_cast(Imm.Val); assert(SR && "Unknown value type!"); Inst.addOperand(MCOperand::createExpr(SR)); return; } assert(isMem() && "Unknown value type!"); assert(isa(Memory.OffsetImm) && "Unknown value type!"); Inst.addOperand(MCOperand::createImm(Memory.OffsetImm->getValue())); } void addMemBarrierOptOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(unsigned(getMemBarrierOpt()))); } void addInstSyncBarrierOptOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(unsigned(getInstSyncBarrierOpt()))); } void addMemNoOffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); } void addMemPCRelImm12Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); int32_t Imm = Memory.OffsetImm->getValue(); Inst.addOperand(MCOperand::createImm(Imm)); } void addAdrLabelOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); assert(isImm() && "Not an immediate!"); // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. if (!isa(getImm())) { Inst.addOperand(MCOperand::createExpr(getImm())); return; } const MCConstantExpr *CE = dyn_cast(getImm()); int Val = CE->getValue(); Inst.addOperand(MCOperand::createImm(Val)); } void addAlignedMemoryOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Memory.Alignment)); } void addDupAlignedMemoryNoneOperands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addAlignedMemoryNoneOperands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addAlignedMemory16Operands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addDupAlignedMemory16Operands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addAlignedMemory32Operands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addDupAlignedMemory32Operands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addAlignedMemory64Operands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addDupAlignedMemory64Operands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addAlignedMemory64or128Operands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addDupAlignedMemory64or128Operands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addAlignedMemory64or128or256Operands(MCInst &Inst, unsigned N) const { addAlignedMemoryOperands(Inst, N); } void addAddrMode2Operands(MCInst &Inst, unsigned N) const { assert(N == 3 && "Invalid number of operands!"); int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; if (!Memory.OffsetRegNum) { ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; // Special case for #-0 if (Val == INT32_MIN) Val = 0; if (Val < 0) Val = -Val; Val = ARM_AM::getAM2Opc(AddSub, Val, ARM_AM::no_shift); } else { // For register offset, we encode the shift type and negation flag // here. Val = ARM_AM::getAM2Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add, Memory.ShiftImm, Memory.ShiftType); } Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createReg(Memory.OffsetRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addAM2OffsetImmOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); const MCConstantExpr *CE = dyn_cast(getImm()); assert(CE && "non-constant AM2OffsetImm operand!"); int32_t Val = CE->getValue(); ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; // Special case for #-0 if (Val == INT32_MIN) Val = 0; if (Val < 0) Val = -Val; Val = ARM_AM::getAM2Opc(AddSub, Val, ARM_AM::no_shift); Inst.addOperand(MCOperand::createReg(0)); Inst.addOperand(MCOperand::createImm(Val)); } void addAddrMode3Operands(MCInst &Inst, unsigned N) const { assert(N == 3 && "Invalid number of operands!"); // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. If it is a constant, it's something else // and we reject it. if (isImm()) { Inst.addOperand(MCOperand::createExpr(getImm())); Inst.addOperand(MCOperand::createReg(0)); Inst.addOperand(MCOperand::createImm(0)); return; } int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; if (!Memory.OffsetRegNum) { ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; // Special case for #-0 if (Val == INT32_MIN) Val = 0; if (Val < 0) Val = -Val; Val = ARM_AM::getAM3Opc(AddSub, Val); } else { // For register offset, we encode the shift type and negation flag // here. Val = ARM_AM::getAM3Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add, 0); } Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createReg(Memory.OffsetRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addAM3OffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); if (Kind == k_PostIndexRegister) { int32_t Val = ARM_AM::getAM3Opc(PostIdxReg.isAdd ? ARM_AM::add : ARM_AM::sub, 0); Inst.addOperand(MCOperand::createReg(PostIdxReg.RegNum)); Inst.addOperand(MCOperand::createImm(Val)); return; } // Constant offset. const MCConstantExpr *CE = static_cast(getImm()); int32_t Val = CE->getValue(); ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; // Special case for #-0 if (Val == INT32_MIN) Val = 0; if (Val < 0) Val = -Val; Val = ARM_AM::getAM3Opc(AddSub, Val); Inst.addOperand(MCOperand::createReg(0)); Inst.addOperand(MCOperand::createImm(Val)); } void addAddrMode5Operands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. If it is a constant, it's something else // and we reject it. if (isImm()) { Inst.addOperand(MCOperand::createExpr(getImm())); Inst.addOperand(MCOperand::createImm(0)); return; } // The lower two bits are always zero and as such are not encoded. int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() / 4 : 0; ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; // Special case for #-0 if (Val == INT32_MIN) Val = 0; if (Val < 0) Val = -Val; Val = ARM_AM::getAM5Opc(AddSub, Val); Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addAddrMode5FP16Operands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. If it is a constant, it's something else // and we reject it. if (isImm()) { Inst.addOperand(MCOperand::createExpr(getImm())); Inst.addOperand(MCOperand::createImm(0)); return; } // The lower bit is always zero and as such is not encoded. int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() / 2 : 0; ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add; // Special case for #-0 if (Val == INT32_MIN) Val = 0; if (Val < 0) Val = -Val; Val = ARM_AM::getAM5FP16Opc(AddSub, Val); Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addMemImm8s4OffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); // If we have an immediate that's not a constant, treat it as a label // reference needing a fixup. If it is a constant, it's something else // and we reject it. if (isImm()) { Inst.addOperand(MCOperand::createExpr(getImm())); Inst.addOperand(MCOperand::createImm(0)); return; } int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addMemImm0_1020s4OffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); // The lower two bits are always zero and as such are not encoded. int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() / 4 : 0; Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addMemImm8OffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addMemPosImm8OffsetOperands(MCInst &Inst, unsigned N) const { addMemImm8OffsetOperands(Inst, N); } void addMemNegImm8OffsetOperands(MCInst &Inst, unsigned N) const { addMemImm8OffsetOperands(Inst, N); } void addMemUImm12OffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); // If this is an immediate, it's a label reference. if (isImm()) { addExpr(Inst, getImm()); Inst.addOperand(MCOperand::createImm(0)); return; } // Otherwise, it's a normal memory reg+offset. int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addMemImm12OffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); // If this is an immediate, it's a label reference. if (isImm()) { addExpr(Inst, getImm()); Inst.addOperand(MCOperand::createImm(0)); return; } // Otherwise, it's a normal memory reg+offset. int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addConstPoolAsmImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // This is container for the immediate that we will create the constant // pool from addExpr(Inst, getConstantPoolImm()); return; } void addMemTBBOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createReg(Memory.OffsetRegNum)); } void addMemTBHOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createReg(Memory.OffsetRegNum)); } void addMemRegOffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 3 && "Invalid number of operands!"); unsigned Val = ARM_AM::getAM2Opc(Memory.isNegative ? ARM_AM::sub : ARM_AM::add, Memory.ShiftImm, Memory.ShiftType); Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createReg(Memory.OffsetRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addT2MemRegOffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 3 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createReg(Memory.OffsetRegNum)); Inst.addOperand(MCOperand::createImm(Memory.ShiftImm)); } void addMemThumbRROperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createReg(Memory.OffsetRegNum)); } void addMemThumbRIs4Operands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 4) : 0; Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addMemThumbRIs2Operands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 2) : 0; Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addMemThumbRIs1Operands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue()) : 0; Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addMemThumbSPIOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); int64_t Val = Memory.OffsetImm ? (Memory.OffsetImm->getValue() / 4) : 0; Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); Inst.addOperand(MCOperand::createImm(Val)); } void addPostIdxImm8Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCConstantExpr *CE = dyn_cast(getImm()); assert(CE && "non-constant post-idx-imm8 operand!"); int Imm = CE->getValue(); bool isAdd = Imm >= 0; if (Imm == INT32_MIN) Imm = 0; Imm = (Imm < 0 ? -Imm : Imm) | (int)isAdd << 8; Inst.addOperand(MCOperand::createImm(Imm)); } void addPostIdxImm8s4Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCConstantExpr *CE = dyn_cast(getImm()); assert(CE && "non-constant post-idx-imm8s4 operand!"); int Imm = CE->getValue(); bool isAdd = Imm >= 0; if (Imm == INT32_MIN) Imm = 0; // Immediate is scaled by 4. Imm = ((Imm < 0 ? -Imm : Imm) / 4) | (int)isAdd << 8; Inst.addOperand(MCOperand::createImm(Imm)); } void addPostIdxRegOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(PostIdxReg.RegNum)); Inst.addOperand(MCOperand::createImm(PostIdxReg.isAdd)); } void addPostIdxRegShiftedOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(PostIdxReg.RegNum)); // The sign, shift type, and shift amount are encoded in a single operand // using the AM2 encoding helpers. ARM_AM::AddrOpc opc = PostIdxReg.isAdd ? ARM_AM::add : ARM_AM::sub; unsigned Imm = ARM_AM::getAM2Opc(opc, PostIdxReg.ShiftImm, PostIdxReg.ShiftTy); Inst.addOperand(MCOperand::createImm(Imm)); } void addMSRMaskOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(unsigned(getMSRMask()))); } void addBankedRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(unsigned(getBankedReg()))); } void addProcIFlagsOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(unsigned(getProcIFlags()))); } void addVecListOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(VectorList.RegNum)); } void addVecListIndexedOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(VectorList.RegNum)); Inst.addOperand(MCOperand::createImm(VectorList.LaneIndex)); } void addVectorIndex8Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(getVectorIndex())); } void addVectorIndex16Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(getVectorIndex())); } void addVectorIndex32Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createImm(getVectorIndex())); } void addNEONi8splatOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. // Mask in that this is an i8 splat. const MCConstantExpr *CE = dyn_cast(getImm()); Inst.addOperand(MCOperand::createImm(CE->getValue() | 0xe00)); } void addNEONi16splatOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(getImm()); unsigned Value = CE->getValue(); Value = ARM_AM::encodeNEONi16splat(Value); Inst.addOperand(MCOperand::createImm(Value)); } void addNEONi16splatNotOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(getImm()); unsigned Value = CE->getValue(); Value = ARM_AM::encodeNEONi16splat(~Value & 0xffff); Inst.addOperand(MCOperand::createImm(Value)); } void addNEONi32splatOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(getImm()); unsigned Value = CE->getValue(); Value = ARM_AM::encodeNEONi32splat(Value); Inst.addOperand(MCOperand::createImm(Value)); } void addNEONi32splatNotOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(getImm()); unsigned Value = CE->getValue(); Value = ARM_AM::encodeNEONi32splat(~Value); Inst.addOperand(MCOperand::createImm(Value)); } void addNEONinvByteReplicateOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(getImm()); unsigned Value = CE->getValue(); assert((Inst.getOpcode() == ARM::VMOVv8i8 || Inst.getOpcode() == ARM::VMOVv16i8) && "All vmvn instructions that wants to replicate non-zero byte " "always must be replaced with VMOVv8i8 or VMOVv16i8."); unsigned B = ((~Value) & 0xff); B |= 0xe00; // cmode = 0b1110 Inst.addOperand(MCOperand::createImm(B)); } void addNEONi32vmovOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(getImm()); unsigned Value = CE->getValue(); if (Value >= 256 && Value <= 0xffff) Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200); else if (Value > 0xffff && Value <= 0xffffff) Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400); else if (Value > 0xffffff) Value = (Value >> 24) | 0x600; Inst.addOperand(MCOperand::createImm(Value)); } void addNEONvmovByteReplicateOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(getImm()); unsigned Value = CE->getValue(); assert((Inst.getOpcode() == ARM::VMOVv8i8 || Inst.getOpcode() == ARM::VMOVv16i8) && "All instructions that wants to replicate non-zero byte " "always must be replaced with VMOVv8i8 or VMOVv16i8."); unsigned B = Value & 0xff; B |= 0xe00; // cmode = 0b1110 Inst.addOperand(MCOperand::createImm(B)); } void addNEONi32vmovNegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(getImm()); unsigned Value = ~CE->getValue(); if (Value >= 256 && Value <= 0xffff) Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200); else if (Value > 0xffff && Value <= 0xffffff) Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400); else if (Value > 0xffffff) Value = (Value >> 24) | 0x600; Inst.addOperand(MCOperand::createImm(Value)); } void addNEONi64splatOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate encodes the type of constant as well as the value. const MCConstantExpr *CE = dyn_cast(getImm()); uint64_t Value = CE->getValue(); unsigned Imm = 0; for (unsigned i = 0; i < 8; ++i, Value >>= 8) { Imm |= (Value & 1) << i; } Inst.addOperand(MCOperand::createImm(Imm | 0x1e00)); } void print(raw_ostream &OS) const override; static std::unique_ptr CreateITMask(unsigned Mask, SMLoc S) { auto Op = make_unique(k_ITCondMask); Op->ITMask.Mask = Mask; Op->StartLoc = S; Op->EndLoc = S; return Op; } static std::unique_ptr CreateCondCode(ARMCC::CondCodes CC, SMLoc S) { auto Op = make_unique(k_CondCode); Op->CC.Val = CC; Op->StartLoc = S; Op->EndLoc = S; return Op; } static std::unique_ptr CreateCoprocNum(unsigned CopVal, SMLoc S) { auto Op = make_unique(k_CoprocNum); Op->Cop.Val = CopVal; Op->StartLoc = S; Op->EndLoc = S; return Op; } static std::unique_ptr CreateCoprocReg(unsigned CopVal, SMLoc S) { auto Op = make_unique(k_CoprocReg); Op->Cop.Val = CopVal; Op->StartLoc = S; Op->EndLoc = S; return Op; } static std::unique_ptr CreateCoprocOption(unsigned Val, SMLoc S, SMLoc E) { auto Op = make_unique(k_CoprocOption); Op->Cop.Val = Val; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateCCOut(unsigned RegNum, SMLoc S) { auto Op = make_unique(k_CCOut); Op->Reg.RegNum = RegNum; Op->StartLoc = S; Op->EndLoc = S; return Op; } static std::unique_ptr CreateToken(StringRef Str, SMLoc S) { auto Op = make_unique(k_Token); Op->Tok.Data = Str.data(); Op->Tok.Length = Str.size(); Op->StartLoc = S; Op->EndLoc = S; return Op; } static std::unique_ptr CreateReg(unsigned RegNum, SMLoc S, SMLoc E) { auto Op = make_unique(k_Register); Op->Reg.RegNum = RegNum; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateShiftedRegister(ARM_AM::ShiftOpc ShTy, unsigned SrcReg, unsigned ShiftReg, unsigned ShiftImm, SMLoc S, SMLoc E) { auto Op = make_unique(k_ShiftedRegister); Op->RegShiftedReg.ShiftTy = ShTy; Op->RegShiftedReg.SrcReg = SrcReg; Op->RegShiftedReg.ShiftReg = ShiftReg; Op->RegShiftedReg.ShiftImm = ShiftImm; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateShiftedImmediate(ARM_AM::ShiftOpc ShTy, unsigned SrcReg, unsigned ShiftImm, SMLoc S, SMLoc E) { auto Op = make_unique(k_ShiftedImmediate); Op->RegShiftedImm.ShiftTy = ShTy; Op->RegShiftedImm.SrcReg = SrcReg; Op->RegShiftedImm.ShiftImm = ShiftImm; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateShifterImm(bool isASR, unsigned Imm, SMLoc S, SMLoc E) { auto Op = make_unique(k_ShifterImmediate); Op->ShifterImm.isASR = isASR; Op->ShifterImm.Imm = Imm; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateRotImm(unsigned Imm, SMLoc S, SMLoc E) { auto Op = make_unique(k_RotateImmediate); Op->RotImm.Imm = Imm; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateModImm(unsigned Bits, unsigned Rot, SMLoc S, SMLoc E) { auto Op = make_unique(k_ModifiedImmediate); Op->ModImm.Bits = Bits; Op->ModImm.Rot = Rot; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateConstantPoolImm(const MCExpr *Val, SMLoc S, SMLoc E) { auto Op = make_unique(k_ConstantPoolImmediate); Op->Imm.Val = Val; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateBitfield(unsigned LSB, unsigned Width, SMLoc S, SMLoc E) { auto Op = make_unique(k_BitfieldDescriptor); Op->Bitfield.LSB = LSB; Op->Bitfield.Width = Width; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateRegList(SmallVectorImpl> &Regs, SMLoc StartLoc, SMLoc EndLoc) { assert (Regs.size() > 0 && "RegList contains no registers?"); KindTy Kind = k_RegisterList; if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Regs.front().second)) Kind = k_DPRRegisterList; else if (ARMMCRegisterClasses[ARM::SPRRegClassID]. contains(Regs.front().second)) Kind = k_SPRRegisterList; // Sort based on the register encoding values. array_pod_sort(Regs.begin(), Regs.end()); auto Op = make_unique(Kind); for (SmallVectorImpl >::const_iterator I = Regs.begin(), E = Regs.end(); I != E; ++I) Op->Registers.push_back(I->second); Op->StartLoc = StartLoc; Op->EndLoc = EndLoc; return Op; } static std::unique_ptr CreateVectorList(unsigned RegNum, unsigned Count, bool isDoubleSpaced, SMLoc S, SMLoc E) { auto Op = make_unique(k_VectorList); Op->VectorList.RegNum = RegNum; Op->VectorList.Count = Count; Op->VectorList.isDoubleSpaced = isDoubleSpaced; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateVectorListAllLanes(unsigned RegNum, unsigned Count, bool isDoubleSpaced, SMLoc S, SMLoc E) { auto Op = make_unique(k_VectorListAllLanes); Op->VectorList.RegNum = RegNum; Op->VectorList.Count = Count; Op->VectorList.isDoubleSpaced = isDoubleSpaced; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateVectorListIndexed(unsigned RegNum, unsigned Count, unsigned Index, bool isDoubleSpaced, SMLoc S, SMLoc E) { auto Op = make_unique(k_VectorListIndexed); Op->VectorList.RegNum = RegNum; Op->VectorList.Count = Count; Op->VectorList.LaneIndex = Index; Op->VectorList.isDoubleSpaced = isDoubleSpaced; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateVectorIndex(unsigned Idx, SMLoc S, SMLoc E, MCContext &Ctx) { auto Op = make_unique(k_VectorIndex); Op->VectorIndex.Val = Idx; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) { auto Op = make_unique(k_Immediate); Op->Imm.Val = Val; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateMem(unsigned BaseRegNum, const MCConstantExpr *OffsetImm, unsigned OffsetRegNum, ARM_AM::ShiftOpc ShiftType, unsigned ShiftImm, unsigned Alignment, bool isNegative, SMLoc S, SMLoc E, SMLoc AlignmentLoc = SMLoc()) { auto Op = make_unique(k_Memory); Op->Memory.BaseRegNum = BaseRegNum; Op->Memory.OffsetImm = OffsetImm; Op->Memory.OffsetRegNum = OffsetRegNum; Op->Memory.ShiftType = ShiftType; Op->Memory.ShiftImm = ShiftImm; Op->Memory.Alignment = Alignment; Op->Memory.isNegative = isNegative; Op->StartLoc = S; Op->EndLoc = E; Op->AlignmentLoc = AlignmentLoc; return Op; } static std::unique_ptr CreatePostIdxReg(unsigned RegNum, bool isAdd, ARM_AM::ShiftOpc ShiftTy, unsigned ShiftImm, SMLoc S, SMLoc E) { auto Op = make_unique(k_PostIndexRegister); Op->PostIdxReg.RegNum = RegNum; Op->PostIdxReg.isAdd = isAdd; Op->PostIdxReg.ShiftTy = ShiftTy; Op->PostIdxReg.ShiftImm = ShiftImm; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateMemBarrierOpt(ARM_MB::MemBOpt Opt, SMLoc S) { auto Op = make_unique(k_MemBarrierOpt); Op->MBOpt.Val = Opt; Op->StartLoc = S; Op->EndLoc = S; return Op; } static std::unique_ptr CreateInstSyncBarrierOpt(ARM_ISB::InstSyncBOpt Opt, SMLoc S) { auto Op = make_unique(k_InstSyncBarrierOpt); Op->ISBOpt.Val = Opt; Op->StartLoc = S; Op->EndLoc = S; return Op; } static std::unique_ptr CreateProcIFlags(ARM_PROC::IFlags IFlags, SMLoc S) { auto Op = make_unique(k_ProcIFlags); Op->IFlags.Val = IFlags; Op->StartLoc = S; Op->EndLoc = S; return Op; } static std::unique_ptr CreateMSRMask(unsigned MMask, SMLoc S) { auto Op = make_unique(k_MSRMask); Op->MMask.Val = MMask; Op->StartLoc = S; Op->EndLoc = S; return Op; } static std::unique_ptr CreateBankedReg(unsigned Reg, SMLoc S) { auto Op = make_unique(k_BankedReg); Op->BankedReg.Val = Reg; Op->StartLoc = S; Op->EndLoc = S; return Op; } }; } // end anonymous namespace. void ARMOperand::print(raw_ostream &OS) const { switch (Kind) { case k_CondCode: OS << ""; break; case k_CCOut: OS << ""; break; case k_ITCondMask: { static const char *const MaskStr[] = { "()", "(t)", "(e)", "(tt)", "(et)", "(te)", "(ee)", "(ttt)", "(ett)", "(tet)", "(eet)", "(tte)", "(ete)", "(tee)", "(eee)" }; assert((ITMask.Mask & 0xf) == ITMask.Mask); OS << ""; break; } case k_CoprocNum: OS << ""; break; case k_CoprocReg: OS << ""; break; case k_CoprocOption: OS << ""; break; case k_MSRMask: OS << ""; break; case k_BankedReg: OS << ""; break; case k_Immediate: OS << *getImm(); break; case k_MemBarrierOpt: OS << ""; break; case k_InstSyncBarrierOpt: OS << ""; break; case k_Memory: OS << ""; break; case k_PostIndexRegister: OS << "post-idx register " << (PostIdxReg.isAdd ? "" : "-") << PostIdxReg.RegNum; if (PostIdxReg.ShiftTy != ARM_AM::no_shift) OS << ARM_AM::getShiftOpcStr(PostIdxReg.ShiftTy) << " " << PostIdxReg.ShiftImm; OS << ">"; break; case k_ProcIFlags: { OS << "= 0; --i) if (IFlags & (1 << i)) OS << ARM_PROC::IFlagsToString(1 << i); OS << ">"; break; } case k_Register: OS << ""; break; case k_ShifterImmediate: OS << ""; break; case k_ShiftedRegister: OS << ""; break; case k_ShiftedImmediate: OS << ""; break; case k_RotateImmediate: OS << ""; break; case k_ModifiedImmediate: OS << ""; break; case k_ConstantPoolImmediate: OS << ""; break; case k_RegisterList: case k_DPRRegisterList: case k_SPRRegisterList: { OS << " &RegList = getRegList(); for (SmallVectorImpl::const_iterator I = RegList.begin(), E = RegList.end(); I != E; ) { OS << *I; if (++I < E) OS << ", "; } OS << ">"; break; } case k_VectorList: OS << ""; break; case k_VectorListAllLanes: OS << ""; break; case k_VectorListIndexed: OS << ""; break; case k_Token: OS << "'" << getToken() << "'"; break; case k_VectorIndex: OS << ""; break; } } /// @name Auto-generated Match Functions /// { static unsigned MatchRegisterName(StringRef Name); /// } bool ARMAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { const AsmToken &Tok = getParser().getTok(); StartLoc = Tok.getLoc(); EndLoc = Tok.getEndLoc(); RegNo = tryParseRegister(); return (RegNo == (unsigned)-1); } /// Try to parse a register name. The token must be an Identifier when called, /// and if it is a register name the token is eaten and the register number is /// returned. Otherwise return -1. /// int ARMAsmParser::tryParseRegister() { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) return -1; std::string lowerCase = Tok.getString().lower(); unsigned RegNum = MatchRegisterName(lowerCase); if (!RegNum) { RegNum = StringSwitch(lowerCase) .Case("r13", ARM::SP) .Case("r14", ARM::LR) .Case("r15", ARM::PC) .Case("ip", ARM::R12) // Additional register name aliases for 'gas' compatibility. .Case("a1", ARM::R0) .Case("a2", ARM::R1) .Case("a3", ARM::R2) .Case("a4", ARM::R3) .Case("v1", ARM::R4) .Case("v2", ARM::R5) .Case("v3", ARM::R6) .Case("v4", ARM::R7) .Case("v5", ARM::R8) .Case("v6", ARM::R9) .Case("v7", ARM::R10) .Case("v8", ARM::R11) .Case("sb", ARM::R9) .Case("sl", ARM::R10) .Case("fp", ARM::R11) .Default(0); } if (!RegNum) { // Check for aliases registered via .req. Canonicalize to lower case. // That's more consistent since register names are case insensitive, and // it's how the original entry was passed in from MC/MCParser/AsmParser. StringMap::const_iterator Entry = RegisterReqs.find(lowerCase); // If no match, return failure. if (Entry == RegisterReqs.end()) return -1; Parser.Lex(); // Eat identifier token. return Entry->getValue(); } // Some FPUs only have 16 D registers, so D16-D31 are invalid if (hasD16() && RegNum >= ARM::D16 && RegNum <= ARM::D31) return -1; Parser.Lex(); // Eat identifier token. return RegNum; } // Try to parse a shifter (e.g., "lsl "). On success, return 0. // If a recoverable error occurs, return 1. If an irrecoverable error // occurs, return -1. An irrecoverable error is one where tokens have been // consumed in the process of trying to parse the shifter (i.e., when it is // indeed a shifter operand, but malformed). int ARMAsmParser::tryParseShiftRegister(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) return -1; std::string lowerCase = Tok.getString().lower(); ARM_AM::ShiftOpc ShiftTy = StringSwitch(lowerCase) .Case("asl", ARM_AM::lsl) .Case("lsl", ARM_AM::lsl) .Case("lsr", ARM_AM::lsr) .Case("asr", ARM_AM::asr) .Case("ror", ARM_AM::ror) .Case("rrx", ARM_AM::rrx) .Default(ARM_AM::no_shift); if (ShiftTy == ARM_AM::no_shift) return 1; Parser.Lex(); // Eat the operator. // The source register for the shift has already been added to the // operand list, so we need to pop it off and combine it into the shifted // register operand instead. std::unique_ptr PrevOp( (ARMOperand *)Operands.pop_back_val().release()); if (!PrevOp->isReg()) return Error(PrevOp->getStartLoc(), "shift must be of a register"); int SrcReg = PrevOp->getReg(); SMLoc EndLoc; int64_t Imm = 0; int ShiftReg = 0; if (ShiftTy == ARM_AM::rrx) { // RRX Doesn't have an explicit shift amount. The encoder expects // the shift register to be the same as the source register. Seems odd, // but OK. ShiftReg = SrcReg; } else { // Figure out if this is shifted by a constant or a register (for non-RRX). if (Parser.getTok().is(AsmToken::Hash) || Parser.getTok().is(AsmToken::Dollar)) { Parser.Lex(); // Eat hash. SMLoc ImmLoc = Parser.getTok().getLoc(); const MCExpr *ShiftExpr = nullptr; if (getParser().parseExpression(ShiftExpr, EndLoc)) { Error(ImmLoc, "invalid immediate shift value"); return -1; } // The expression must be evaluatable as an immediate. const MCConstantExpr *CE = dyn_cast(ShiftExpr); if (!CE) { Error(ImmLoc, "invalid immediate shift value"); return -1; } // Range check the immediate. // lsl, ror: 0 <= imm <= 31 // lsr, asr: 0 <= imm <= 32 Imm = CE->getValue(); if (Imm < 0 || ((ShiftTy == ARM_AM::lsl || ShiftTy == ARM_AM::ror) && Imm > 31) || ((ShiftTy == ARM_AM::lsr || ShiftTy == ARM_AM::asr) && Imm > 32)) { Error(ImmLoc, "immediate shift value out of range"); return -1; } // shift by zero is a nop. Always send it through as lsl. // ('as' compatibility) if (Imm == 0) ShiftTy = ARM_AM::lsl; } else if (Parser.getTok().is(AsmToken::Identifier)) { SMLoc L = Parser.getTok().getLoc(); EndLoc = Parser.getTok().getEndLoc(); ShiftReg = tryParseRegister(); if (ShiftReg == -1) { Error(L, "expected immediate or register in shift operand"); return -1; } } else { Error(Parser.getTok().getLoc(), "expected immediate or register in shift operand"); return -1; } } if (ShiftReg && ShiftTy != ARM_AM::rrx) Operands.push_back(ARMOperand::CreateShiftedRegister(ShiftTy, SrcReg, ShiftReg, Imm, S, EndLoc)); else Operands.push_back(ARMOperand::CreateShiftedImmediate(ShiftTy, SrcReg, Imm, S, EndLoc)); return 0; } /// Try to parse a register name. The token must be an Identifier when called. /// If it's a register, an AsmOperand is created. Another AsmOperand is created /// if there is a "writeback". 'true' if it's not a register. /// /// TODO this is likely to change to allow different register types and or to /// parse for a specific register type. bool ARMAsmParser::tryParseRegisterWithWriteBack(OperandVector &Operands) { MCAsmParser &Parser = getParser(); const AsmToken &RegTok = Parser.getTok(); int RegNo = tryParseRegister(); if (RegNo == -1) return true; Operands.push_back(ARMOperand::CreateReg(RegNo, RegTok.getLoc(), RegTok.getEndLoc())); const AsmToken &ExclaimTok = Parser.getTok(); if (ExclaimTok.is(AsmToken::Exclaim)) { Operands.push_back(ARMOperand::CreateToken(ExclaimTok.getString(), ExclaimTok.getLoc())); Parser.Lex(); // Eat exclaim token return false; } // Also check for an index operand. This is only legal for vector registers, // but that'll get caught OK in operand matching, so we don't need to // explicitly filter everything else out here. if (Parser.getTok().is(AsmToken::LBrac)) { SMLoc SIdx = Parser.getTok().getLoc(); Parser.Lex(); // Eat left bracket token. const MCExpr *ImmVal; if (getParser().parseExpression(ImmVal)) return true; const MCConstantExpr *MCE = dyn_cast(ImmVal); if (!MCE) return TokError("immediate value expected for vector index"); if (Parser.getTok().isNot(AsmToken::RBrac)) return Error(Parser.getTok().getLoc(), "']' expected"); SMLoc E = Parser.getTok().getEndLoc(); Parser.Lex(); // Eat right bracket token. Operands.push_back(ARMOperand::CreateVectorIndex(MCE->getValue(), SIdx, E, getContext())); } return false; } /// MatchCoprocessorOperandName - Try to parse an coprocessor related /// instruction with a symbolic operand name. /// We accept "crN" syntax for GAS compatibility. /// ::= /// If CoprocOp is 'c', then: /// ::= c | cr /// If CoprocOp is 'p', then : /// ::= p /// ::= integer in range [0, 15] static int MatchCoprocessorOperandName(StringRef Name, char CoprocOp) { // Use the same layout as the tablegen'erated register name matcher. Ugly, // but efficient. if (Name.size() < 2 || Name[0] != CoprocOp) return -1; Name = (Name[1] == 'r') ? Name.drop_front(2) : Name.drop_front(); switch (Name.size()) { default: return -1; case 1: switch (Name[0]) { default: return -1; case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; } case 2: if (Name[0] != '1') return -1; switch (Name[1]) { default: return -1; // CP10 and CP11 are VFP/NEON and so vector instructions should be used. // However, old cores (v5/v6) did use them in that way. case '0': return 10; case '1': return 11; case '2': return 12; case '3': return 13; case '4': return 14; case '5': return 15; } } } /// parseITCondCode - Try to parse a condition code for an IT instruction. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseITCondCode(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (!Tok.is(AsmToken::Identifier)) return MatchOperand_NoMatch; unsigned CC = StringSwitch(Tok.getString().lower()) .Case("eq", ARMCC::EQ) .Case("ne", ARMCC::NE) .Case("hs", ARMCC::HS) .Case("cs", ARMCC::HS) .Case("lo", ARMCC::LO) .Case("cc", ARMCC::LO) .Case("mi", ARMCC::MI) .Case("pl", ARMCC::PL) .Case("vs", ARMCC::VS) .Case("vc", ARMCC::VC) .Case("hi", ARMCC::HI) .Case("ls", ARMCC::LS) .Case("ge", ARMCC::GE) .Case("lt", ARMCC::LT) .Case("gt", ARMCC::GT) .Case("le", ARMCC::LE) .Case("al", ARMCC::AL) .Default(~0U); if (CC == ~0U) return MatchOperand_NoMatch; Parser.Lex(); // Eat the token. Operands.push_back(ARMOperand::CreateCondCode(ARMCC::CondCodes(CC), S)); return MatchOperand_Success; } /// parseCoprocNumOperand - Try to parse an coprocessor number operand. The /// token must be an Identifier when called, and if it is a coprocessor /// number, the token is eaten and the operand is added to the operand list. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseCoprocNumOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) return MatchOperand_NoMatch; int Num = MatchCoprocessorOperandName(Tok.getString(), 'p'); if (Num == -1) return MatchOperand_NoMatch; // ARMv7 and v8 don't allow cp10/cp11 due to VFP/NEON specific instructions if ((hasV7Ops() || hasV8Ops()) && (Num == 10 || Num == 11)) return MatchOperand_NoMatch; Parser.Lex(); // Eat identifier token. Operands.push_back(ARMOperand::CreateCoprocNum(Num, S)); return MatchOperand_Success; } /// parseCoprocRegOperand - Try to parse an coprocessor register operand. The /// token must be an Identifier when called, and if it is a coprocessor /// number, the token is eaten and the operand is added to the operand list. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseCoprocRegOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) return MatchOperand_NoMatch; int Reg = MatchCoprocessorOperandName(Tok.getString(), 'c'); if (Reg == -1) return MatchOperand_NoMatch; Parser.Lex(); // Eat identifier token. Operands.push_back(ARMOperand::CreateCoprocReg(Reg, S)); return MatchOperand_Success; } /// parseCoprocOptionOperand - Try to parse an coprocessor option operand. /// coproc_option : '{' imm0_255 '}' ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseCoprocOptionOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); // If this isn't a '{', this isn't a coprocessor immediate operand. if (Parser.getTok().isNot(AsmToken::LCurly)) return MatchOperand_NoMatch; Parser.Lex(); // Eat the '{' const MCExpr *Expr; SMLoc Loc = Parser.getTok().getLoc(); if (getParser().parseExpression(Expr)) { Error(Loc, "illegal expression"); return MatchOperand_ParseFail; } const MCConstantExpr *CE = dyn_cast(Expr); if (!CE || CE->getValue() < 0 || CE->getValue() > 255) { Error(Loc, "coprocessor option must be an immediate in range [0, 255]"); return MatchOperand_ParseFail; } int Val = CE->getValue(); // Check for and consume the closing '}' if (Parser.getTok().isNot(AsmToken::RCurly)) return MatchOperand_ParseFail; SMLoc E = Parser.getTok().getEndLoc(); Parser.Lex(); // Eat the '}' Operands.push_back(ARMOperand::CreateCoprocOption(Val, S, E)); return MatchOperand_Success; } // For register list parsing, we need to map from raw GPR register numbering // to the enumeration values. The enumeration values aren't sorted by // register number due to our using "sp", "lr" and "pc" as canonical names. static unsigned getNextRegister(unsigned Reg) { // If this is a GPR, we need to do it manually, otherwise we can rely // on the sort ordering of the enumeration since the other reg-classes // are sane. if (!ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg)) return Reg + 1; switch(Reg) { default: llvm_unreachable("Invalid GPR number!"); case ARM::R0: return ARM::R1; case ARM::R1: return ARM::R2; case ARM::R2: return ARM::R3; case ARM::R3: return ARM::R4; case ARM::R4: return ARM::R5; case ARM::R5: return ARM::R6; case ARM::R6: return ARM::R7; case ARM::R7: return ARM::R8; case ARM::R8: return ARM::R9; case ARM::R9: return ARM::R10; case ARM::R10: return ARM::R11; case ARM::R11: return ARM::R12; case ARM::R12: return ARM::SP; case ARM::SP: return ARM::LR; case ARM::LR: return ARM::PC; case ARM::PC: return ARM::R0; } } // Return the low-subreg of a given Q register. static unsigned getDRegFromQReg(unsigned QReg) { switch (QReg) { default: llvm_unreachable("expected a Q register!"); case ARM::Q0: return ARM::D0; case ARM::Q1: return ARM::D2; case ARM::Q2: return ARM::D4; case ARM::Q3: return ARM::D6; case ARM::Q4: return ARM::D8; case ARM::Q5: return ARM::D10; case ARM::Q6: return ARM::D12; case ARM::Q7: return ARM::D14; case ARM::Q8: return ARM::D16; case ARM::Q9: return ARM::D18; case ARM::Q10: return ARM::D20; case ARM::Q11: return ARM::D22; case ARM::Q12: return ARM::D24; case ARM::Q13: return ARM::D26; case ARM::Q14: return ARM::D28; case ARM::Q15: return ARM::D30; } } /// Parse a register list. bool ARMAsmParser::parseRegisterList(OperandVector &Operands) { MCAsmParser &Parser = getParser(); assert(Parser.getTok().is(AsmToken::LCurly) && "Token is not a Left Curly Brace"); SMLoc S = Parser.getTok().getLoc(); Parser.Lex(); // Eat '{' token. SMLoc RegLoc = Parser.getTok().getLoc(); // Check the first register in the list to see what register class // this is a list of. int Reg = tryParseRegister(); if (Reg == -1) return Error(RegLoc, "register expected"); // The reglist instructions have at most 16 registers, so reserve // space for that many. int EReg = 0; SmallVector, 16> Registers; // Allow Q regs and just interpret them as the two D sub-registers. if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) { Reg = getDRegFromQReg(Reg); EReg = MRI->getEncodingValue(Reg); Registers.push_back(std::pair(EReg, Reg)); ++Reg; } const MCRegisterClass *RC; if (ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg)) RC = &ARMMCRegisterClasses[ARM::GPRRegClassID]; else if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg)) RC = &ARMMCRegisterClasses[ARM::DPRRegClassID]; else if (ARMMCRegisterClasses[ARM::SPRRegClassID].contains(Reg)) RC = &ARMMCRegisterClasses[ARM::SPRRegClassID]; else return Error(RegLoc, "invalid register in register list"); // Store the register. EReg = MRI->getEncodingValue(Reg); Registers.push_back(std::pair(EReg, Reg)); // This starts immediately after the first register token in the list, // so we can see either a comma or a minus (range separator) as a legal // next token. while (Parser.getTok().is(AsmToken::Comma) || Parser.getTok().is(AsmToken::Minus)) { if (Parser.getTok().is(AsmToken::Minus)) { Parser.Lex(); // Eat the minus. SMLoc AfterMinusLoc = Parser.getTok().getLoc(); int EndReg = tryParseRegister(); if (EndReg == -1) return Error(AfterMinusLoc, "register expected"); // Allow Q regs and just interpret them as the two D sub-registers. if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(EndReg)) EndReg = getDRegFromQReg(EndReg) + 1; // If the register is the same as the start reg, there's nothing // more to do. if (Reg == EndReg) continue; // The register must be in the same register class as the first. if (!RC->contains(EndReg)) return Error(AfterMinusLoc, "invalid register in register list"); // Ranges must go from low to high. if (MRI->getEncodingValue(Reg) > MRI->getEncodingValue(EndReg)) return Error(AfterMinusLoc, "bad range in register list"); // Add all the registers in the range to the register list. while (Reg != EndReg) { Reg = getNextRegister(Reg); EReg = MRI->getEncodingValue(Reg); Registers.push_back(std::pair(EReg, Reg)); } continue; } Parser.Lex(); // Eat the comma. RegLoc = Parser.getTok().getLoc(); int OldReg = Reg; const AsmToken RegTok = Parser.getTok(); Reg = tryParseRegister(); if (Reg == -1) return Error(RegLoc, "register expected"); // Allow Q regs and just interpret them as the two D sub-registers. bool isQReg = false; if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) { Reg = getDRegFromQReg(Reg); isQReg = true; } // The register must be in the same register class as the first. if (!RC->contains(Reg)) return Error(RegLoc, "invalid register in register list"); // List must be monotonically increasing. if (MRI->getEncodingValue(Reg) < MRI->getEncodingValue(OldReg)) { if (ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg)) Warning(RegLoc, "register list not in ascending order"); else return Error(RegLoc, "register list not in ascending order"); } if (MRI->getEncodingValue(Reg) == MRI->getEncodingValue(OldReg)) { Warning(RegLoc, "duplicated register (" + RegTok.getString() + ") in register list"); continue; } // VFP register lists must also be contiguous. if (RC != &ARMMCRegisterClasses[ARM::GPRRegClassID] && Reg != OldReg + 1) return Error(RegLoc, "non-contiguous register range"); EReg = MRI->getEncodingValue(Reg); Registers.push_back(std::pair(EReg, Reg)); if (isQReg) { EReg = MRI->getEncodingValue(++Reg); Registers.push_back(std::pair(EReg, Reg)); } } if (Parser.getTok().isNot(AsmToken::RCurly)) return Error(Parser.getTok().getLoc(), "'}' expected"); SMLoc E = Parser.getTok().getEndLoc(); Parser.Lex(); // Eat '}' token. // Push the register list operand. Operands.push_back(ARMOperand::CreateRegList(Registers, S, E)); // The ARM system instruction variants for LDM/STM have a '^' token here. if (Parser.getTok().is(AsmToken::Caret)) { Operands.push_back(ARMOperand::CreateToken("^",Parser.getTok().getLoc())); Parser.Lex(); // Eat '^' token. } return false; } // Helper function to parse the lane index for vector lists. ARMAsmParser::OperandMatchResultTy ARMAsmParser:: parseVectorLane(VectorLaneTy &LaneKind, unsigned &Index, SMLoc &EndLoc) { MCAsmParser &Parser = getParser(); Index = 0; // Always return a defined index value. if (Parser.getTok().is(AsmToken::LBrac)) { Parser.Lex(); // Eat the '['. if (Parser.getTok().is(AsmToken::RBrac)) { // "Dn[]" is the 'all lanes' syntax. LaneKind = AllLanes; EndLoc = Parser.getTok().getEndLoc(); Parser.Lex(); // Eat the ']'. return MatchOperand_Success; } // There's an optional '#' token here. Normally there wouldn't be, but // inline assemble puts one in, and it's friendly to accept that. if (Parser.getTok().is(AsmToken::Hash)) Parser.Lex(); // Eat '#' or '$'. const MCExpr *LaneIndex; SMLoc Loc = Parser.getTok().getLoc(); if (getParser().parseExpression(LaneIndex)) { Error(Loc, "illegal expression"); return MatchOperand_ParseFail; } const MCConstantExpr *CE = dyn_cast(LaneIndex); if (!CE) { Error(Loc, "lane index must be empty or an integer"); return MatchOperand_ParseFail; } if (Parser.getTok().isNot(AsmToken::RBrac)) { Error(Parser.getTok().getLoc(), "']' expected"); return MatchOperand_ParseFail; } EndLoc = Parser.getTok().getEndLoc(); Parser.Lex(); // Eat the ']'. int64_t Val = CE->getValue(); // FIXME: Make this range check context sensitive for .8, .16, .32. if (Val < 0 || Val > 7) { Error(Parser.getTok().getLoc(), "lane index out of range"); return MatchOperand_ParseFail; } Index = Val; LaneKind = IndexedLane; return MatchOperand_Success; } LaneKind = NoLanes; return MatchOperand_Success; } // parse a vector register list ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseVectorList(OperandVector &Operands) { MCAsmParser &Parser = getParser(); VectorLaneTy LaneKind; unsigned LaneIndex; SMLoc S = Parser.getTok().getLoc(); // As an extension (to match gas), support a plain D register or Q register // (without encosing curly braces) as a single or double entry list, // respectively. if (Parser.getTok().is(AsmToken::Identifier)) { SMLoc E = Parser.getTok().getEndLoc(); int Reg = tryParseRegister(); if (Reg == -1) return MatchOperand_NoMatch; if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg)) { OperandMatchResultTy Res = parseVectorLane(LaneKind, LaneIndex, E); if (Res != MatchOperand_Success) return Res; switch (LaneKind) { case NoLanes: Operands.push_back(ARMOperand::CreateVectorList(Reg, 1, false, S, E)); break; case AllLanes: Operands.push_back(ARMOperand::CreateVectorListAllLanes(Reg, 1, false, S, E)); break; case IndexedLane: Operands.push_back(ARMOperand::CreateVectorListIndexed(Reg, 1, LaneIndex, false, S, E)); break; } return MatchOperand_Success; } if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) { Reg = getDRegFromQReg(Reg); OperandMatchResultTy Res = parseVectorLane(LaneKind, LaneIndex, E); if (Res != MatchOperand_Success) return Res; switch (LaneKind) { case NoLanes: Reg = MRI->getMatchingSuperReg(Reg, ARM::dsub_0, &ARMMCRegisterClasses[ARM::DPairRegClassID]); Operands.push_back(ARMOperand::CreateVectorList(Reg, 2, false, S, E)); break; case AllLanes: Reg = MRI->getMatchingSuperReg(Reg, ARM::dsub_0, &ARMMCRegisterClasses[ARM::DPairRegClassID]); Operands.push_back(ARMOperand::CreateVectorListAllLanes(Reg, 2, false, S, E)); break; case IndexedLane: Operands.push_back(ARMOperand::CreateVectorListIndexed(Reg, 2, LaneIndex, false, S, E)); break; } return MatchOperand_Success; } Error(S, "vector register expected"); return MatchOperand_ParseFail; } if (Parser.getTok().isNot(AsmToken::LCurly)) return MatchOperand_NoMatch; Parser.Lex(); // Eat '{' token. SMLoc RegLoc = Parser.getTok().getLoc(); int Reg = tryParseRegister(); if (Reg == -1) { Error(RegLoc, "register expected"); return MatchOperand_ParseFail; } unsigned Count = 1; int Spacing = 0; unsigned FirstReg = Reg; // The list is of D registers, but we also allow Q regs and just interpret // them as the two D sub-registers. if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) { FirstReg = Reg = getDRegFromQReg(Reg); Spacing = 1; // double-spacing requires explicit D registers, otherwise // it's ambiguous with four-register single spaced. ++Reg; ++Count; } SMLoc E; if (parseVectorLane(LaneKind, LaneIndex, E) != MatchOperand_Success) return MatchOperand_ParseFail; while (Parser.getTok().is(AsmToken::Comma) || Parser.getTok().is(AsmToken::Minus)) { if (Parser.getTok().is(AsmToken::Minus)) { if (!Spacing) Spacing = 1; // Register range implies a single spaced list. else if (Spacing == 2) { Error(Parser.getTok().getLoc(), "sequential registers in double spaced list"); return MatchOperand_ParseFail; } Parser.Lex(); // Eat the minus. SMLoc AfterMinusLoc = Parser.getTok().getLoc(); int EndReg = tryParseRegister(); if (EndReg == -1) { Error(AfterMinusLoc, "register expected"); return MatchOperand_ParseFail; } // Allow Q regs and just interpret them as the two D sub-registers. if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(EndReg)) EndReg = getDRegFromQReg(EndReg) + 1; // If the register is the same as the start reg, there's nothing // more to do. if (Reg == EndReg) continue; // The register must be in the same register class as the first. if (!ARMMCRegisterClasses[ARM::DPRRegClassID].contains(EndReg)) { Error(AfterMinusLoc, "invalid register in register list"); return MatchOperand_ParseFail; } // Ranges must go from low to high. if (Reg > EndReg) { Error(AfterMinusLoc, "bad range in register list"); return MatchOperand_ParseFail; } // Parse the lane specifier if present. VectorLaneTy NextLaneKind; unsigned NextLaneIndex; if (parseVectorLane(NextLaneKind, NextLaneIndex, E) != MatchOperand_Success) return MatchOperand_ParseFail; if (NextLaneKind != LaneKind || LaneIndex != NextLaneIndex) { Error(AfterMinusLoc, "mismatched lane index in register list"); return MatchOperand_ParseFail; } // Add all the registers in the range to the register list. Count += EndReg - Reg; Reg = EndReg; continue; } Parser.Lex(); // Eat the comma. RegLoc = Parser.getTok().getLoc(); int OldReg = Reg; Reg = tryParseRegister(); if (Reg == -1) { Error(RegLoc, "register expected"); return MatchOperand_ParseFail; } // vector register lists must be contiguous. // It's OK to use the enumeration values directly here rather, as the // VFP register classes have the enum sorted properly. // // The list is of D registers, but we also allow Q regs and just interpret // them as the two D sub-registers. if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) { if (!Spacing) Spacing = 1; // Register range implies a single spaced list. else if (Spacing == 2) { Error(RegLoc, "invalid register in double-spaced list (must be 'D' register')"); return MatchOperand_ParseFail; } Reg = getDRegFromQReg(Reg); if (Reg != OldReg + 1) { Error(RegLoc, "non-contiguous register range"); return MatchOperand_ParseFail; } ++Reg; Count += 2; // Parse the lane specifier if present. VectorLaneTy NextLaneKind; unsigned NextLaneIndex; SMLoc LaneLoc = Parser.getTok().getLoc(); if (parseVectorLane(NextLaneKind, NextLaneIndex, E) != MatchOperand_Success) return MatchOperand_ParseFail; if (NextLaneKind != LaneKind || LaneIndex != NextLaneIndex) { Error(LaneLoc, "mismatched lane index in register list"); return MatchOperand_ParseFail; } continue; } // Normal D register. // Figure out the register spacing (single or double) of the list if // we don't know it already. if (!Spacing) Spacing = 1 + (Reg == OldReg + 2); // Just check that it's contiguous and keep going. if (Reg != OldReg + Spacing) { Error(RegLoc, "non-contiguous register range"); return MatchOperand_ParseFail; } ++Count; // Parse the lane specifier if present. VectorLaneTy NextLaneKind; unsigned NextLaneIndex; SMLoc EndLoc = Parser.getTok().getLoc(); if (parseVectorLane(NextLaneKind, NextLaneIndex, E) != MatchOperand_Success) return MatchOperand_ParseFail; if (NextLaneKind != LaneKind || LaneIndex != NextLaneIndex) { Error(EndLoc, "mismatched lane index in register list"); return MatchOperand_ParseFail; } } if (Parser.getTok().isNot(AsmToken::RCurly)) { Error(Parser.getTok().getLoc(), "'}' expected"); return MatchOperand_ParseFail; } E = Parser.getTok().getEndLoc(); Parser.Lex(); // Eat '}' token. switch (LaneKind) { case NoLanes: // Two-register operands have been converted to the // composite register classes. if (Count == 2) { const MCRegisterClass *RC = (Spacing == 1) ? &ARMMCRegisterClasses[ARM::DPairRegClassID] : &ARMMCRegisterClasses[ARM::DPairSpcRegClassID]; FirstReg = MRI->getMatchingSuperReg(FirstReg, ARM::dsub_0, RC); } Operands.push_back(ARMOperand::CreateVectorList(FirstReg, Count, (Spacing == 2), S, E)); break; case AllLanes: // Two-register operands have been converted to the // composite register classes. if (Count == 2) { const MCRegisterClass *RC = (Spacing == 1) ? &ARMMCRegisterClasses[ARM::DPairRegClassID] : &ARMMCRegisterClasses[ARM::DPairSpcRegClassID]; FirstReg = MRI->getMatchingSuperReg(FirstReg, ARM::dsub_0, RC); } Operands.push_back(ARMOperand::CreateVectorListAllLanes(FirstReg, Count, (Spacing == 2), S, E)); break; case IndexedLane: Operands.push_back(ARMOperand::CreateVectorListIndexed(FirstReg, Count, LaneIndex, (Spacing == 2), S, E)); break; } return MatchOperand_Success; } /// parseMemBarrierOptOperand - Try to parse DSB/DMB data barrier options. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseMemBarrierOptOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); unsigned Opt; if (Tok.is(AsmToken::Identifier)) { StringRef OptStr = Tok.getString(); Opt = StringSwitch(OptStr.slice(0, OptStr.size()).lower()) .Case("sy", ARM_MB::SY) .Case("st", ARM_MB::ST) .Case("ld", ARM_MB::LD) .Case("sh", ARM_MB::ISH) .Case("ish", ARM_MB::ISH) .Case("shst", ARM_MB::ISHST) .Case("ishst", ARM_MB::ISHST) .Case("ishld", ARM_MB::ISHLD) .Case("nsh", ARM_MB::NSH) .Case("un", ARM_MB::NSH) .Case("nshst", ARM_MB::NSHST) .Case("nshld", ARM_MB::NSHLD) .Case("unst", ARM_MB::NSHST) .Case("osh", ARM_MB::OSH) .Case("oshst", ARM_MB::OSHST) .Case("oshld", ARM_MB::OSHLD) .Default(~0U); // ishld, oshld, nshld and ld are only available from ARMv8. if (!hasV8Ops() && (Opt == ARM_MB::ISHLD || Opt == ARM_MB::OSHLD || Opt == ARM_MB::NSHLD || Opt == ARM_MB::LD)) Opt = ~0U; if (Opt == ~0U) return MatchOperand_NoMatch; Parser.Lex(); // Eat identifier token. } else if (Tok.is(AsmToken::Hash) || Tok.is(AsmToken::Dollar) || Tok.is(AsmToken::Integer)) { if (Parser.getTok().isNot(AsmToken::Integer)) Parser.Lex(); // Eat '#' or '$'. SMLoc Loc = Parser.getTok().getLoc(); const MCExpr *MemBarrierID; if (getParser().parseExpression(MemBarrierID)) { Error(Loc, "illegal expression"); return MatchOperand_ParseFail; } const MCConstantExpr *CE = dyn_cast(MemBarrierID); if (!CE) { Error(Loc, "constant expression expected"); return MatchOperand_ParseFail; } int Val = CE->getValue(); if (Val & ~0xf) { Error(Loc, "immediate value out of range"); return MatchOperand_ParseFail; } Opt = ARM_MB::RESERVED_0 + Val; } else return MatchOperand_ParseFail; Operands.push_back(ARMOperand::CreateMemBarrierOpt((ARM_MB::MemBOpt)Opt, S)); return MatchOperand_Success; } /// parseInstSyncBarrierOptOperand - Try to parse ISB inst sync barrier options. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseInstSyncBarrierOptOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); unsigned Opt; if (Tok.is(AsmToken::Identifier)) { StringRef OptStr = Tok.getString(); if (OptStr.equals_lower("sy")) Opt = ARM_ISB::SY; else return MatchOperand_NoMatch; Parser.Lex(); // Eat identifier token. } else if (Tok.is(AsmToken::Hash) || Tok.is(AsmToken::Dollar) || Tok.is(AsmToken::Integer)) { if (Parser.getTok().isNot(AsmToken::Integer)) Parser.Lex(); // Eat '#' or '$'. SMLoc Loc = Parser.getTok().getLoc(); const MCExpr *ISBarrierID; if (getParser().parseExpression(ISBarrierID)) { Error(Loc, "illegal expression"); return MatchOperand_ParseFail; } const MCConstantExpr *CE = dyn_cast(ISBarrierID); if (!CE) { Error(Loc, "constant expression expected"); return MatchOperand_ParseFail; } int Val = CE->getValue(); if (Val & ~0xf) { Error(Loc, "immediate value out of range"); return MatchOperand_ParseFail; } Opt = ARM_ISB::RESERVED_0 + Val; } else return MatchOperand_ParseFail; Operands.push_back(ARMOperand::CreateInstSyncBarrierOpt( (ARM_ISB::InstSyncBOpt)Opt, S)); return MatchOperand_Success; } /// parseProcIFlagsOperand - Try to parse iflags from CPS instruction. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseProcIFlagsOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (!Tok.is(AsmToken::Identifier)) return MatchOperand_NoMatch; StringRef IFlagsStr = Tok.getString(); // An iflags string of "none" is interpreted to mean that none of the AIF // bits are set. Not a terribly useful instruction, but a valid encoding. unsigned IFlags = 0; if (IFlagsStr != "none") { for (int i = 0, e = IFlagsStr.size(); i != e; ++i) { unsigned Flag = StringSwitch(IFlagsStr.substr(i, 1)) .Case("a", ARM_PROC::A) .Case("i", ARM_PROC::I) .Case("f", ARM_PROC::F) .Default(~0U); // If some specific iflag is already set, it means that some letter is // present more than once, this is not acceptable. if (Flag == ~0U || (IFlags & Flag)) return MatchOperand_NoMatch; IFlags |= Flag; } } Parser.Lex(); // Eat identifier token. Operands.push_back(ARMOperand::CreateProcIFlags((ARM_PROC::IFlags)IFlags, S)); return MatchOperand_Success; } /// parseMSRMaskOperand - Try to parse mask flags from MSR instruction. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseMSRMaskOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (!Tok.is(AsmToken::Identifier)) return MatchOperand_NoMatch; StringRef Mask = Tok.getString(); if (isMClass()) { // See ARMv6-M 10.1.1 std::string Name = Mask.lower(); unsigned FlagsVal = StringSwitch(Name) // Note: in the documentation: // ARM deprecates using MSR APSR without a _ qualifier as an alias // for MSR APSR_nzcvq. // but we do make it an alias here. This is so to get the "mask encoding" // bits correct on MSR APSR writes. // // FIXME: Note the 0xc00 "mask encoding" bits version of the registers // should really only be allowed when writing a special register. Note // they get dropped in the MRS instruction reading a special register as // the SYSm field is only 8 bits. .Case("apsr", 0x800) .Case("apsr_nzcvq", 0x800) .Case("apsr_g", 0x400) .Case("apsr_nzcvqg", 0xc00) .Case("iapsr", 0x801) .Case("iapsr_nzcvq", 0x801) .Case("iapsr_g", 0x401) .Case("iapsr_nzcvqg", 0xc01) .Case("eapsr", 0x802) .Case("eapsr_nzcvq", 0x802) .Case("eapsr_g", 0x402) .Case("eapsr_nzcvqg", 0xc02) .Case("xpsr", 0x803) .Case("xpsr_nzcvq", 0x803) .Case("xpsr_g", 0x403) .Case("xpsr_nzcvqg", 0xc03) .Case("ipsr", 0x805) .Case("epsr", 0x806) .Case("iepsr", 0x807) .Case("msp", 0x808) .Case("psp", 0x809) .Case("primask", 0x810) .Case("basepri", 0x811) .Case("basepri_max", 0x812) .Case("faultmask", 0x813) .Case("control", 0x814) .Case("msplim", 0x80a) .Case("psplim", 0x80b) .Case("msp_ns", 0x888) .Case("psp_ns", 0x889) .Case("msplim_ns", 0x88a) .Case("psplim_ns", 0x88b) .Case("primask_ns", 0x890) .Case("basepri_ns", 0x891) .Case("basepri_max_ns", 0x892) .Case("faultmask_ns", 0x893) .Case("control_ns", 0x894) .Case("sp_ns", 0x898) .Default(~0U); if (FlagsVal == ~0U) return MatchOperand_NoMatch; if (!hasDSP() && (FlagsVal & 0x400)) // The _g and _nzcvqg versions are only valid if the DSP extension is // available. return MatchOperand_NoMatch; if (!hasV7Ops() && FlagsVal >= 0x811 && FlagsVal <= 0x813) // basepri, basepri_max and faultmask only valid for V7m. return MatchOperand_NoMatch; if (!has8MSecExt() && (FlagsVal == 0x80a || FlagsVal == 0x80b || (FlagsVal > 0x814 && FlagsVal < 0xc00))) return MatchOperand_NoMatch; if (!hasV8MMainline() && (FlagsVal == 0x88a || FlagsVal == 0x88b || (FlagsVal > 0x890 && FlagsVal <= 0x893))) return MatchOperand_NoMatch; Parser.Lex(); // Eat identifier token. Operands.push_back(ARMOperand::CreateMSRMask(FlagsVal, S)); return MatchOperand_Success; } // Split spec_reg from flag, example: CPSR_sxf => "CPSR" and "sxf" size_t Start = 0, Next = Mask.find('_'); StringRef Flags = ""; std::string SpecReg = Mask.slice(Start, Next).lower(); if (Next != StringRef::npos) Flags = Mask.slice(Next+1, Mask.size()); // FlagsVal contains the complete mask: // 3-0: Mask // 4: Special Reg (cpsr, apsr => 0; spsr => 1) unsigned FlagsVal = 0; if (SpecReg == "apsr") { FlagsVal = StringSwitch(Flags) .Case("nzcvq", 0x8) // same as CPSR_f .Case("g", 0x4) // same as CPSR_s .Case("nzcvqg", 0xc) // same as CPSR_fs .Default(~0U); if (FlagsVal == ~0U) { if (!Flags.empty()) return MatchOperand_NoMatch; else FlagsVal = 8; // No flag } } else if (SpecReg == "cpsr" || SpecReg == "spsr") { // cpsr_all is an alias for cpsr_fc, as is plain cpsr. if (Flags == "all" || Flags == "") Flags = "fc"; for (int i = 0, e = Flags.size(); i != e; ++i) { unsigned Flag = StringSwitch(Flags.substr(i, 1)) .Case("c", 1) .Case("x", 2) .Case("s", 4) .Case("f", 8) .Default(~0U); // If some specific flag is already set, it means that some letter is // present more than once, this is not acceptable. if (FlagsVal == ~0U || (FlagsVal & Flag)) return MatchOperand_NoMatch; FlagsVal |= Flag; } } else // No match for special register. return MatchOperand_NoMatch; // Special register without flags is NOT equivalent to "fc" flags. // NOTE: This is a divergence from gas' behavior. Uncommenting the following // two lines would enable gas compatibility at the expense of breaking // round-tripping. // // if (!FlagsVal) // FlagsVal = 0x9; // Bit 4: Special Reg (cpsr, apsr => 0; spsr => 1) if (SpecReg == "spsr") FlagsVal |= 16; Parser.Lex(); // Eat identifier token. Operands.push_back(ARMOperand::CreateMSRMask(FlagsVal, S)); return MatchOperand_Success; } /// parseBankedRegOperand - Try to parse a banked register (e.g. "lr_irq") for /// use in the MRS/MSR instructions added to support virtualization. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseBankedRegOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); const AsmToken &Tok = Parser.getTok(); if (!Tok.is(AsmToken::Identifier)) return MatchOperand_NoMatch; StringRef RegName = Tok.getString(); // The values here come from B9.2.3 of the ARM ARM, where bits 4-0 are SysM // and bit 5 is R. unsigned Encoding = StringSwitch(RegName.lower()) .Case("r8_usr", 0x00) .Case("r9_usr", 0x01) .Case("r10_usr", 0x02) .Case("r11_usr", 0x03) .Case("r12_usr", 0x04) .Case("sp_usr", 0x05) .Case("lr_usr", 0x06) .Case("r8_fiq", 0x08) .Case("r9_fiq", 0x09) .Case("r10_fiq", 0x0a) .Case("r11_fiq", 0x0b) .Case("r12_fiq", 0x0c) .Case("sp_fiq", 0x0d) .Case("lr_fiq", 0x0e) .Case("lr_irq", 0x10) .Case("sp_irq", 0x11) .Case("lr_svc", 0x12) .Case("sp_svc", 0x13) .Case("lr_abt", 0x14) .Case("sp_abt", 0x15) .Case("lr_und", 0x16) .Case("sp_und", 0x17) .Case("lr_mon", 0x1c) .Case("sp_mon", 0x1d) .Case("elr_hyp", 0x1e) .Case("sp_hyp", 0x1f) .Case("spsr_fiq", 0x2e) .Case("spsr_irq", 0x30) .Case("spsr_svc", 0x32) .Case("spsr_abt", 0x34) .Case("spsr_und", 0x36) .Case("spsr_mon", 0x3c) .Case("spsr_hyp", 0x3e) .Default(~0U); if (Encoding == ~0U) return MatchOperand_NoMatch; Parser.Lex(); // Eat identifier token. Operands.push_back(ARMOperand::CreateBankedReg(Encoding, S)); return MatchOperand_Success; } ARMAsmParser::OperandMatchResultTy ARMAsmParser::parsePKHImm(OperandVector &Operands, StringRef Op, int Low, int High) { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) { Error(Parser.getTok().getLoc(), Op + " operand expected."); return MatchOperand_ParseFail; } StringRef ShiftName = Tok.getString(); std::string LowerOp = Op.lower(); std::string UpperOp = Op.upper(); if (ShiftName != LowerOp && ShiftName != UpperOp) { Error(Parser.getTok().getLoc(), Op + " operand expected."); return MatchOperand_ParseFail; } Parser.Lex(); // Eat shift type token. // There must be a '#' and a shift amount. if (Parser.getTok().isNot(AsmToken::Hash) && Parser.getTok().isNot(AsmToken::Dollar)) { Error(Parser.getTok().getLoc(), "'#' expected"); return MatchOperand_ParseFail; } Parser.Lex(); // Eat hash token. const MCExpr *ShiftAmount; SMLoc Loc = Parser.getTok().getLoc(); SMLoc EndLoc; if (getParser().parseExpression(ShiftAmount, EndLoc)) { Error(Loc, "illegal expression"); return MatchOperand_ParseFail; } const MCConstantExpr *CE = dyn_cast(ShiftAmount); if (!CE) { Error(Loc, "constant expression expected"); return MatchOperand_ParseFail; } int Val = CE->getValue(); if (Val < Low || Val > High) { Error(Loc, "immediate value out of range"); return MatchOperand_ParseFail; } Operands.push_back(ARMOperand::CreateImm(CE, Loc, EndLoc)); return MatchOperand_Success; } ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseSetEndImm(OperandVector &Operands) { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); if (Tok.isNot(AsmToken::Identifier)) { Error(S, "'be' or 'le' operand expected"); return MatchOperand_ParseFail; } int Val = StringSwitch(Tok.getString().lower()) .Case("be", 1) .Case("le", 0) .Default(-1); Parser.Lex(); // Eat the token. if (Val == -1) { Error(S, "'be' or 'le' operand expected"); return MatchOperand_ParseFail; } Operands.push_back(ARMOperand::CreateImm(MCConstantExpr::create(Val, getContext()), S, Tok.getEndLoc())); return MatchOperand_Success; } /// parseShifterImm - Parse the shifter immediate operand for SSAT/USAT /// instructions. Legal values are: /// lsl #n 'n' in [0,31] /// asr #n 'n' in [1,32] /// n == 32 encoded as n == 0. ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseShifterImm(OperandVector &Operands) { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); if (Tok.isNot(AsmToken::Identifier)) { Error(S, "shift operator 'asr' or 'lsl' expected"); return MatchOperand_ParseFail; } StringRef ShiftName = Tok.getString(); bool isASR; if (ShiftName == "lsl" || ShiftName == "LSL") isASR = false; else if (ShiftName == "asr" || ShiftName == "ASR") isASR = true; else { Error(S, "shift operator 'asr' or 'lsl' expected"); return MatchOperand_ParseFail; } Parser.Lex(); // Eat the operator. // A '#' and a shift amount. if (Parser.getTok().isNot(AsmToken::Hash) && Parser.getTok().isNot(AsmToken::Dollar)) { Error(Parser.getTok().getLoc(), "'#' expected"); return MatchOperand_ParseFail; } Parser.Lex(); // Eat hash token. SMLoc ExLoc = Parser.getTok().getLoc(); const MCExpr *ShiftAmount; SMLoc EndLoc; if (getParser().parseExpression(ShiftAmount, EndLoc)) { Error(ExLoc, "malformed shift expression"); return MatchOperand_ParseFail; } const MCConstantExpr *CE = dyn_cast(ShiftAmount); if (!CE) { Error(ExLoc, "shift amount must be an immediate"); return MatchOperand_ParseFail; } int64_t Val = CE->getValue(); if (isASR) { // Shift amount must be in [1,32] if (Val < 1 || Val > 32) { Error(ExLoc, "'asr' shift amount must be in range [1,32]"); return MatchOperand_ParseFail; } // asr #32 encoded as asr #0, but is not allowed in Thumb2 mode. if (isThumb() && Val == 32) { Error(ExLoc, "'asr #32' shift amount not allowed in Thumb mode"); return MatchOperand_ParseFail; } if (Val == 32) Val = 0; } else { // Shift amount must be in [1,32] if (Val < 0 || Val > 31) { Error(ExLoc, "'lsr' shift amount must be in range [0,31]"); return MatchOperand_ParseFail; } } Operands.push_back(ARMOperand::CreateShifterImm(isASR, Val, S, EndLoc)); return MatchOperand_Success; } /// parseRotImm - Parse the shifter immediate operand for SXTB/UXTB family /// of instructions. Legal values are: /// ror #n 'n' in {0, 8, 16, 24} ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseRotImm(OperandVector &Operands) { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); if (Tok.isNot(AsmToken::Identifier)) return MatchOperand_NoMatch; StringRef ShiftName = Tok.getString(); if (ShiftName != "ror" && ShiftName != "ROR") return MatchOperand_NoMatch; Parser.Lex(); // Eat the operator. // A '#' and a rotate amount. if (Parser.getTok().isNot(AsmToken::Hash) && Parser.getTok().isNot(AsmToken::Dollar)) { Error(Parser.getTok().getLoc(), "'#' expected"); return MatchOperand_ParseFail; } Parser.Lex(); // Eat hash token. SMLoc ExLoc = Parser.getTok().getLoc(); const MCExpr *ShiftAmount; SMLoc EndLoc; if (getParser().parseExpression(ShiftAmount, EndLoc)) { Error(ExLoc, "malformed rotate expression"); return MatchOperand_ParseFail; } const MCConstantExpr *CE = dyn_cast(ShiftAmount); if (!CE) { Error(ExLoc, "rotate amount must be an immediate"); return MatchOperand_ParseFail; } int64_t Val = CE->getValue(); // Shift amount must be in {0, 8, 16, 24} (0 is undocumented extension) // normally, zero is represented in asm by omitting the rotate operand // entirely. if (Val != 8 && Val != 16 && Val != 24 && Val != 0) { Error(ExLoc, "'ror' rotate amount must be 8, 16, or 24"); return MatchOperand_ParseFail; } Operands.push_back(ARMOperand::CreateRotImm(Val, S, EndLoc)); return MatchOperand_Success; } ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseModImm(OperandVector &Operands) { MCAsmParser &Parser = getParser(); MCAsmLexer &Lexer = getLexer(); int64_t Imm1, Imm2; SMLoc S = Parser.getTok().getLoc(); // 1) A mod_imm operand can appear in the place of a register name: // add r0, #mod_imm // add r0, r0, #mod_imm // to correctly handle the latter, we bail out as soon as we see an // identifier. // // 2) Similarly, we do not want to parse into complex operands: // mov r0, #mod_imm // mov r0, :lower16:(_foo) if (Parser.getTok().is(AsmToken::Identifier) || Parser.getTok().is(AsmToken::Colon)) return MatchOperand_NoMatch; // Hash (dollar) is optional as per the ARMARM if (Parser.getTok().is(AsmToken::Hash) || Parser.getTok().is(AsmToken::Dollar)) { // Avoid parsing into complex operands (#:) if (Lexer.peekTok().is(AsmToken::Colon)) return MatchOperand_NoMatch; // Eat the hash (dollar) Parser.Lex(); } SMLoc Sx1, Ex1; Sx1 = Parser.getTok().getLoc(); const MCExpr *Imm1Exp; if (getParser().parseExpression(Imm1Exp, Ex1)) { Error(Sx1, "malformed expression"); return MatchOperand_ParseFail; } const MCConstantExpr *CE = dyn_cast(Imm1Exp); if (CE) { // Immediate must fit within 32-bits Imm1 = CE->getValue(); int Enc = ARM_AM::getSOImmVal(Imm1); if (Enc != -1 && Parser.getTok().is(AsmToken::EndOfStatement)) { // We have a match! Operands.push_back(ARMOperand::CreateModImm((Enc & 0xFF), (Enc & 0xF00) >> 7, Sx1, Ex1)); return MatchOperand_Success; } // We have parsed an immediate which is not for us, fallback to a plain // immediate. This can happen for instruction aliases. For an example, // ARMInstrInfo.td defines the alias [mov <-> mvn] which can transform // a mov (mvn) with a mod_imm_neg/mod_imm_not operand into the opposite // instruction with a mod_imm operand. The alias is defined such that the // parser method is shared, that's why we have to do this here. if (Parser.getTok().is(AsmToken::EndOfStatement)) { Operands.push_back(ARMOperand::CreateImm(Imm1Exp, Sx1, Ex1)); return MatchOperand_Success; } } else { // Operands like #(l1 - l2) can only be evaluated at a later stage (via an // MCFixup). Fallback to a plain immediate. Operands.push_back(ARMOperand::CreateImm(Imm1Exp, Sx1, Ex1)); return MatchOperand_Success; } // From this point onward, we expect the input to be a (#bits, #rot) pair if (Parser.getTok().isNot(AsmToken::Comma)) { Error(Sx1, "expected modified immediate operand: #[0, 255], #even[0-30]"); return MatchOperand_ParseFail; } if (Imm1 & ~0xFF) { Error(Sx1, "immediate operand must a number in the range [0, 255]"); return MatchOperand_ParseFail; } // Eat the comma Parser.Lex(); // Repeat for #rot SMLoc Sx2, Ex2; Sx2 = Parser.getTok().getLoc(); // Eat the optional hash (dollar) if (Parser.getTok().is(AsmToken::Hash) || Parser.getTok().is(AsmToken::Dollar)) Parser.Lex(); const MCExpr *Imm2Exp; if (getParser().parseExpression(Imm2Exp, Ex2)) { Error(Sx2, "malformed expression"); return MatchOperand_ParseFail; } CE = dyn_cast(Imm2Exp); if (CE) { Imm2 = CE->getValue(); if (!(Imm2 & ~0x1E)) { // We have a match! Operands.push_back(ARMOperand::CreateModImm(Imm1, Imm2, S, Ex2)); return MatchOperand_Success; } Error(Sx2, "immediate operand must an even number in the range [0, 30]"); return MatchOperand_ParseFail; } else { Error(Sx2, "constant expression expected"); return MatchOperand_ParseFail; } } ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseBitfield(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); // The bitfield descriptor is really two operands, the LSB and the width. if (Parser.getTok().isNot(AsmToken::Hash) && Parser.getTok().isNot(AsmToken::Dollar)) { Error(Parser.getTok().getLoc(), "'#' expected"); return MatchOperand_ParseFail; } Parser.Lex(); // Eat hash token. const MCExpr *LSBExpr; SMLoc E = Parser.getTok().getLoc(); if (getParser().parseExpression(LSBExpr)) { Error(E, "malformed immediate expression"); return MatchOperand_ParseFail; } const MCConstantExpr *CE = dyn_cast(LSBExpr); if (!CE) { Error(E, "'lsb' operand must be an immediate"); return MatchOperand_ParseFail; } int64_t LSB = CE->getValue(); // The LSB must be in the range [0,31] if (LSB < 0 || LSB > 31) { Error(E, "'lsb' operand must be in the range [0,31]"); return MatchOperand_ParseFail; } E = Parser.getTok().getLoc(); // Expect another immediate operand. if (Parser.getTok().isNot(AsmToken::Comma)) { Error(Parser.getTok().getLoc(), "too few operands"); return MatchOperand_ParseFail; } Parser.Lex(); // Eat hash token. if (Parser.getTok().isNot(AsmToken::Hash) && Parser.getTok().isNot(AsmToken::Dollar)) { Error(Parser.getTok().getLoc(), "'#' expected"); return MatchOperand_ParseFail; } Parser.Lex(); // Eat hash token. const MCExpr *WidthExpr; SMLoc EndLoc; if (getParser().parseExpression(WidthExpr, EndLoc)) { Error(E, "malformed immediate expression"); return MatchOperand_ParseFail; } CE = dyn_cast(WidthExpr); if (!CE) { Error(E, "'width' operand must be an immediate"); return MatchOperand_ParseFail; } int64_t Width = CE->getValue(); // The LSB must be in the range [1,32-lsb] if (Width < 1 || Width > 32 - LSB) { Error(E, "'width' operand must be in the range [1,32-lsb]"); return MatchOperand_ParseFail; } Operands.push_back(ARMOperand::CreateBitfield(LSB, Width, S, EndLoc)); return MatchOperand_Success; } ARMAsmParser::OperandMatchResultTy ARMAsmParser::parsePostIdxReg(OperandVector &Operands) { // Check for a post-index addressing register operand. Specifically: // postidx_reg := '+' register {, shift} // | '-' register {, shift} // | register {, shift} // This method must return MatchOperand_NoMatch without consuming any tokens // in the case where there is no match, as other alternatives take other // parse methods. MCAsmParser &Parser = getParser(); AsmToken Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); bool haveEaten = false; bool isAdd = true; if (Tok.is(AsmToken::Plus)) { Parser.Lex(); // Eat the '+' token. haveEaten = true; } else if (Tok.is(AsmToken::Minus)) { Parser.Lex(); // Eat the '-' token. isAdd = false; haveEaten = true; } SMLoc E = Parser.getTok().getEndLoc(); int Reg = tryParseRegister(); if (Reg == -1) { if (!haveEaten) return MatchOperand_NoMatch; Error(Parser.getTok().getLoc(), "register expected"); return MatchOperand_ParseFail; } ARM_AM::ShiftOpc ShiftTy = ARM_AM::no_shift; unsigned ShiftImm = 0; if (Parser.getTok().is(AsmToken::Comma)) { Parser.Lex(); // Eat the ','. if (parseMemRegOffsetShift(ShiftTy, ShiftImm)) return MatchOperand_ParseFail; // FIXME: Only approximates end...may include intervening whitespace. E = Parser.getTok().getLoc(); } Operands.push_back(ARMOperand::CreatePostIdxReg(Reg, isAdd, ShiftTy, ShiftImm, S, E)); return MatchOperand_Success; } ARMAsmParser::OperandMatchResultTy ARMAsmParser::parseAM3Offset(OperandVector &Operands) { // Check for a post-index addressing register operand. Specifically: // am3offset := '+' register // | '-' register // | register // | # imm // | # + imm // | # - imm // This method must return MatchOperand_NoMatch without consuming any tokens // in the case where there is no match, as other alternatives take other // parse methods. MCAsmParser &Parser = getParser(); AsmToken Tok = Parser.getTok(); SMLoc S = Tok.getLoc(); // Do immediates first, as we always parse those if we have a '#'. if (Parser.getTok().is(AsmToken::Hash) || Parser.getTok().is(AsmToken::Dollar)) { Parser.Lex(); // Eat '#' or '$'. // Explicitly look for a '-', as we need to encode negative zero // differently. bool isNegative = Parser.getTok().is(AsmToken::Minus); const MCExpr *Offset; SMLoc E; if (getParser().parseExpression(Offset, E)) return MatchOperand_ParseFail; const MCConstantExpr *CE = dyn_cast(Offset); if (!CE) { Error(S, "constant expression expected"); return MatchOperand_ParseFail; } // Negative zero is encoded as the flag value INT32_MIN. int32_t Val = CE->getValue(); if (isNegative && Val == 0) Val = INT32_MIN; Operands.push_back( ARMOperand::CreateImm(MCConstantExpr::create(Val, getContext()), S, E)); return MatchOperand_Success; } bool haveEaten = false; bool isAdd = true; if (Tok.is(AsmToken::Plus)) { Parser.Lex(); // Eat the '+' token. haveEaten = true; } else if (Tok.is(AsmToken::Minus)) { Parser.Lex(); // Eat the '-' token. isAdd = false; haveEaten = true; } Tok = Parser.getTok(); int Reg = tryParseRegister(); if (Reg == -1) { if (!haveEaten) return MatchOperand_NoMatch; Error(Tok.getLoc(), "register expected"); return MatchOperand_ParseFail; } Operands.push_back(ARMOperand::CreatePostIdxReg(Reg, isAdd, ARM_AM::no_shift, 0, S, Tok.getEndLoc())); return MatchOperand_Success; } /// Convert parsed operands to MCInst. Needed here because this instruction /// only has two register operands, but multiplication is commutative so /// assemblers should accept both "mul rD, rN, rD" and "mul rD, rD, rN". void ARMAsmParser::cvtThumbMultiply(MCInst &Inst, const OperandVector &Operands) { ((ARMOperand &)*Operands[3]).addRegOperands(Inst, 1); ((ARMOperand &)*Operands[1]).addCCOutOperands(Inst, 1); // If we have a three-operand form, make sure to set Rn to be the operand // that isn't the same as Rd. unsigned RegOp = 4; if (Operands.size() == 6 && ((ARMOperand &)*Operands[4]).getReg() == ((ARMOperand &)*Operands[3]).getReg()) RegOp = 5; ((ARMOperand &)*Operands[RegOp]).addRegOperands(Inst, 1); Inst.addOperand(Inst.getOperand(0)); ((ARMOperand &)*Operands[2]).addCondCodeOperands(Inst, 2); } void ARMAsmParser::cvtThumbBranches(MCInst &Inst, const OperandVector &Operands) { int CondOp = -1, ImmOp = -1; switch(Inst.getOpcode()) { case ARM::tB: case ARM::tBcc: CondOp = 1; ImmOp = 2; break; case ARM::t2B: case ARM::t2Bcc: CondOp = 1; ImmOp = 3; break; default: llvm_unreachable("Unexpected instruction in cvtThumbBranches"); } // first decide whether or not the branch should be conditional // by looking at it's location relative to an IT block if(inITBlock()) { // inside an IT block we cannot have any conditional branches. any // such instructions needs to be converted to unconditional form switch(Inst.getOpcode()) { case ARM::tBcc: Inst.setOpcode(ARM::tB); break; case ARM::t2Bcc: Inst.setOpcode(ARM::t2B); break; } } else { // outside IT blocks we can only have unconditional branches with AL // condition code or conditional branches with non-AL condition code unsigned Cond = static_cast(*Operands[CondOp]).getCondCode(); switch(Inst.getOpcode()) { case ARM::tB: case ARM::tBcc: Inst.setOpcode(Cond == ARMCC::AL ? ARM::tB : ARM::tBcc); break; case ARM::t2B: case ARM::t2Bcc: Inst.setOpcode(Cond == ARMCC::AL ? ARM::t2B : ARM::t2Bcc); break; } } // now decide on encoding size based on branch target range switch(Inst.getOpcode()) { // classify tB as either t2B or t1B based on range of immediate operand case ARM::tB: { ARMOperand &op = static_cast(*Operands[ImmOp]); if (!op.isSignedOffset<11, 1>() && isThumb() && hasV8MBaseline()) Inst.setOpcode(ARM::t2B); break; } // classify tBcc as either t2Bcc or t1Bcc based on range of immediate operand case ARM::tBcc: { ARMOperand &op = static_cast(*Operands[ImmOp]); if (!op.isSignedOffset<8, 1>() && isThumb() && hasV8MBaseline()) Inst.setOpcode(ARM::t2Bcc); break; } } ((ARMOperand &)*Operands[ImmOp]).addImmOperands(Inst, 1); ((ARMOperand &)*Operands[CondOp]).addCondCodeOperands(Inst, 2); } /// Parse an ARM memory expression, return false if successful else return true /// or an error. The first token must be a '[' when called. bool ARMAsmParser::parseMemory(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S, E; assert(Parser.getTok().is(AsmToken::LBrac) && "Token is not a Left Bracket"); S = Parser.getTok().getLoc(); Parser.Lex(); // Eat left bracket token. const AsmToken &BaseRegTok = Parser.getTok(); int BaseRegNum = tryParseRegister(); if (BaseRegNum == -1) return Error(BaseRegTok.getLoc(), "register expected"); // The next token must either be a comma, a colon or a closing bracket. const AsmToken &Tok = Parser.getTok(); if (!Tok.is(AsmToken::Colon) && !Tok.is(AsmToken::Comma) && !Tok.is(AsmToken::RBrac)) return Error(Tok.getLoc(), "malformed memory operand"); if (Tok.is(AsmToken::RBrac)) { E = Tok.getEndLoc(); Parser.Lex(); // Eat right bracket token. Operands.push_back(ARMOperand::CreateMem(BaseRegNum, nullptr, 0, ARM_AM::no_shift, 0, 0, false, S, E)); // If there's a pre-indexing writeback marker, '!', just add it as a token // operand. It's rather odd, but syntactically valid. if (Parser.getTok().is(AsmToken::Exclaim)) { Operands.push_back(ARMOperand::CreateToken("!",Parser.getTok().getLoc())); Parser.Lex(); // Eat the '!'. } return false; } assert((Tok.is(AsmToken::Colon) || Tok.is(AsmToken::Comma)) && "Lost colon or comma in memory operand?!"); if (Tok.is(AsmToken::Comma)) { Parser.Lex(); // Eat the comma. } // If we have a ':', it's an alignment specifier. if (Parser.getTok().is(AsmToken::Colon)) { Parser.Lex(); // Eat the ':'. E = Parser.getTok().getLoc(); SMLoc AlignmentLoc = Tok.getLoc(); const MCExpr *Expr; if (getParser().parseExpression(Expr)) return true; // The expression has to be a constant. Memory references with relocations // don't come through here, as they use the