diff --git a/CMakeLists.txt b/CMakeLists.txt index 543ee7f88079..d94506ff4639 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,24 +100,6 @@ configure_file( set(llvm_builded_incs_dir ${LLVM_BINARY_DIR}/include/llvm) -# The USE_EXPLICIT_DEPENDENCIES variable will be TRUE to indicate that -# we should use the library dependencies explicitly specified in the -# CMakeLists.txt files rather than those determined by -# llvm-config. This value must be true for non-make and IDE -# generators. -if (MSVC_IDE) - set(DEFAULT_USE_EXPLICIT_DEPENDENCIES ON) -elseif (XCODE) - set(DEFAULT_USE_EXPLICIT_DEPENDENCIES ON) -else () - set(DEFAULT_USE_EXPLICIT_DEPENDENCIES OFF) -endif () - -option(USE_EXPLICIT_DEPENDENCIES - "Use explicit dependencies instead of llvm-config" - ${DEFAULT_USE_EXPLICIT_DEPENDENCIES}) -mark_as_advanced(USE_EXPLICIT_DEPENDENCIES) - # Add path for custom modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} @@ -180,9 +162,6 @@ set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/lib ) add_llvm_definitions( -D__STDC_LIMIT_MACROS ) add_llvm_definitions( -D__STDC_CONSTANT_MACROS ) -set(LLVM_PLO_FLAGS "" CACHE - STRING "Flags for creating partially linked objects.") - 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) @@ -221,7 +200,6 @@ endif( MSVC ) include_directories( ${LLVM_BINARY_DIR}/include ${LLVM_MAIN_INCLUDE_DIR}) include(AddLLVM) -include(AddPartiallyLinkedObject) include(TableGen) add_subdirectory(lib/Support) diff --git a/CREDITS.TXT b/CREDITS.TXT index 76b7296bc2af..e1bad67c0cd7 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -302,3 +302,7 @@ D: Thread Local Storage implementation N: Bill Wendling E: isanbard@gmail.com D: Bunches of stuff + +N: Bob Wilson +E: bob.wilson@acm.org +D: Advanced SIMD (NEON) support in the ARM backend diff --git a/autoconf/configure.ac b/autoconf/configure.ac index bd05891a9dc7..0abe2347957d 100644 --- a/autoconf/configure.ac +++ b/autoconf/configure.ac @@ -447,7 +447,8 @@ AC_SUBST(TARGETS_TO_BUILD,$TARGETS_TO_BUILD) # If so, define LLVM_NATIVE_ARCH to that LLVM target. for a_target in $TARGETS_TO_BUILD; do if test "$a_target" = "$LLVM_NATIVE_ARCH"; then - AC_DEFINE_UNQUOTED(LLVM_NATIVE_ARCH,$LLVM_NATIVE_ARCH, + LLVM_NATIVE_ARCHTARGET="${LLVM_NATIVE_ARCH}Target" + AC_DEFINE_UNQUOTED(LLVM_NATIVE_ARCH,$LLVM_NATIVE_ARCHTARGET, [LLVM architecture name for the native architecture, if available]) fi done diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake index e5256746bcc6..b196c63e7bee 100755 --- a/cmake/modules/AddLLVM.cmake +++ b/cmake/modules/AddLLVM.cmake @@ -26,11 +26,7 @@ macro(add_llvm_executable name) if( LLVM_LINK_COMPONENTS ) llvm_config(${name} ${LLVM_LINK_COMPONENTS}) endif( LLVM_LINK_COMPONENTS ) - if( USE_EXPLICIT_DEPENDENCIES ) - target_link_libraries(${name} ${llvm_libs}) - else( ) - add_dependencies(${name} llvm-config.target) - endif( ) + target_link_libraries(${name} ${llvm_libs}) get_system_libs(llvm_system_libs) if( llvm_system_libs ) target_link_libraries(${name} ${llvm_system_libs}) @@ -61,8 +57,5 @@ macro(add_llvm_target target_name) add_dependencies(${target_name}Table_gen ${LLVM_COMMON_DEPENDS}) endif( TABLEGEN_OUTPUT ) include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) - add_partially_linked_object(LLVM${target_name} ${ARGN}) - if( TABLEGEN_OUTPUT ) - add_dependencies(LLVM${target_name} ${target_name}Table_gen) - endif( TABLEGEN_OUTPUT ) + add_llvm_library(LLVM${target_name} ${ARGN} ${TABLEGEN_OUTPUT}) endmacro(add_llvm_target) diff --git a/cmake/modules/AddPartiallyLinkedObject.cmake b/cmake/modules/AddPartiallyLinkedObject.cmake deleted file mode 100755 index 0f92455eacda..000000000000 --- a/cmake/modules/AddPartiallyLinkedObject.cmake +++ /dev/null @@ -1,42 +0,0 @@ -include(LLVMProcessSources) - -macro(target_name_of_partially_linked_object lib var) - if( USE_EXPLICIT_DEPENDENCIES ) - set(${var} ${lib}) - else( ) - set(${var} ${lib}_pll) - endif( ) -endmacro(target_name_of_partially_linked_object lib var) - - -macro(add_partially_linked_object lib) - if( USE_EXPLICIT_DEPENDENCIES ) - add_llvm_library( ${lib} ${ARGN}) - else( ) - set(pll ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/${lib}.o) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/temp_lib) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/temp_lib) - llvm_process_sources( ALL_FILES ${ARGN} ) - if( BUILD_SHARED_LIBS AND SUPPORTS_FPIC_FLAG ) - add_definitions(-fPIC) - endif() - add_library( ${lib} STATIC ${ALL_FILES}) - if( LLVM_COMMON_DEPENDS ) - add_dependencies( ${lib} ${LLVM_COMMON_DEPENDS} ) - endif( LLVM_COMMON_DEPENDS ) - add_custom_command(OUTPUT ${pll} - COMMENT "Building ${lib}.o..." - DEPENDS ${lib} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/temp_lib/${CMAKE_CFG_INTDIR} - COMMAND ar x ${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX} - COMMAND ${CMAKE_LINKER} "${LLVM_PLO_FLAGS}" -r "*${CMAKE_CXX_OUTPUT_EXTENSION}" -o ${pll} - COMMAND ${CMAKE_COMMAND} -E remove -f *${CMAKE_CXX_OUTPUT_EXTENSION} - ) - target_name_of_partially_linked_object(${lib} tnplo) - add_custom_target(${tnplo} ALL DEPENDS ${pll}) - set( llvm_libs ${llvm_libs} ${pll} PARENT_SCOPE) - set( llvm_lib_targets ${llvm_lib_targets} ${tnplo} PARENT_SCOPE ) - endif( ) - install(FILES ${pll} - DESTINATION lib${LLVM_LIBDIR_SUFFIX}) -endmacro(add_partially_linked_object lib) diff --git a/cmake/modules/LLVMConfig.cmake b/cmake/modules/LLVMConfig.cmake index fd9249518747..5fa08a39d6a8 100755 --- a/cmake/modules/LLVMConfig.cmake +++ b/cmake/modules/LLVMConfig.cmake @@ -20,12 +20,7 @@ endfunction(get_system_libs) macro(llvm_config executable) - # extra args is the list of link components. - if( USE_EXPLICIT_DEPENDENCIES ) - explicit_llvm_config(${executable} ${ARGN}) - else( ) - nix_llvm_config(${executable} ${ARGN}) - endif( ) + explicit_llvm_config(${executable} ${ARGN}) endmacro(llvm_config) @@ -127,44 +122,7 @@ function(explicit_map_components_to_libraries out_libs) set(${out_libs} ${result} PARENT_SCOPE) endfunction(explicit_map_components_to_libraries) - -macro(nix_llvm_config executable) - set(lc "") - foreach(c ${ARGN}) - set(lc "${lc} ${c}") - endforeach(c) - if( NOT HAVE_LLVM_CONFIG ) - target_link_libraries(${executable} - "`${LLVM_TOOLS_BINARY_DIR}/llvm-config --libs ${lc}`") - else( NOT HAVE_LLVM_CONFIG ) - # tbi: Error handling. - if( NOT PERL_EXECUTABLE ) - message(FATAL_ERROR "Perl required but not found!") - endif( NOT PERL_EXECUTABLE ) - execute_process( - COMMAND sh -c "${PERL_EXECUTABLE} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/llvm-config --libs ${lc}" - RESULT_VARIABLE rv - OUTPUT_VARIABLE libs - OUTPUT_STRIP_TRAILING_WHITESPACE) - if(NOT rv EQUAL 0) - message(FATAL_ERROR "llvm-config failed for executable ${executable}") - endif(NOT rv EQUAL 0) - string(REPLACE " " ";" libs ${libs}) - foreach(c ${libs}) - if(c MATCHES ".*\\.o") - get_filename_component(fn ${c} NAME) - target_link_libraries(${executable} - ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/${fn}) - else(c MATCHES ".*\\.o") - string(REPLACE "-l" "" fn ${c}) - target_link_libraries(${executable} ${fn}) - endif(c MATCHES ".*\\.o") - endforeach(c) - endif( NOT HAVE_LLVM_CONFIG ) -endmacro(nix_llvm_config) - - -# This data is used on MSVC for stablishing executable/library +# This data is used to establish executable/library # dependencies. Comes from the llvm-config script, which is built and # installed on the bin directory for MinGW or Linux. At the end of the # script, you'll see lines like this: diff --git a/configure b/configure index 3c9925153abe..4d0d90f5ef33 100755 --- a/configure +++ b/configure @@ -4972,9 +4972,10 @@ TARGETS_TO_BUILD=$TARGETS_TO_BUILD # If so, define LLVM_NATIVE_ARCH to that LLVM target. for a_target in $TARGETS_TO_BUILD; do if test "$a_target" = "$LLVM_NATIVE_ARCH"; then + LLVM_NATIVE_ARCHTARGET="${LLVM_NATIVE_ARCH}Target" cat >>confdefs.h <<_ACEOF -#define LLVM_NATIVE_ARCH $LLVM_NATIVE_ARCH +#define LLVM_NATIVE_ARCH $LLVM_NATIVE_ARCHTARGET _ACEOF fi @@ -10628,7 +10629,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext + echo '#line 12776 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -14490,11 +14491,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14493: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14494: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14497: \$? = $ac_status" >&5 + echo "$as_me:14498: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -14758,11 +14759,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14761: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14762: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14765: \$? = $ac_status" >&5 + echo "$as_me:14766: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -14862,11 +14863,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14865: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14866: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14869: \$? = $ac_status" >&5 + echo "$as_me:14870: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -17314,7 +17315,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:19786: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:19789: \$? = $ac_status" >&5 + echo "$as_me:19790: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -19886,11 +19887,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:19889: $lt_compile\"" >&5) + (eval echo "\"\$as_me:19890: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:19893: \$? = $ac_status" >&5 + echo "$as_me:19894: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -21456,11 +21457,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:21459: $lt_compile\"" >&5) + (eval echo "\"\$as_me:21460: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:21463: \$? = $ac_status" >&5 + echo "$as_me:21464: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -21560,11 +21561,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:21563: $lt_compile\"" >&5) + (eval echo "\"\$as_me:21564: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:21567: \$? = $ac_status" >&5 + echo "$as_me:21568: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -23795,11 +23796,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:23798: $lt_compile\"" >&5) + (eval echo "\"\$as_me:23799: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:23802: \$? = $ac_status" >&5 + echo "$as_me:23803: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -24063,11 +24064,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:24066: $lt_compile\"" >&5) + (eval echo "\"\$as_me:24067: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:24070: \$? = $ac_status" >&5 + echo "$as_me:24071: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -24167,11 +24168,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:24170: $lt_compile\"" >&5) + (eval echo "\"\$as_me:24171: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:24174: \$? = $ac_status" >&5 + echo "$as_me:24175: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized diff --git a/include/llvm/Config/config.h.cmake b/include/llvm/Config/config.h.cmake index c59ed23d8b25..4356e7dc1452 100644 --- a/include/llvm/Config/config.h.cmake +++ b/include/llvm/Config/config.h.cmake @@ -582,4 +582,4 @@ #cmakedefine strdup ${strdup} /* Native LLVM architecture */ -#cmakedefine LLVM_NATIVE_ARCH ${LLVM_NATIVE_ARCH} +#cmakedefine LLVM_NATIVE_ARCH ${LLVM_NATIVE_ARCH}Target diff --git a/include/llvm/MC/MCImm.h b/include/llvm/MC/MCImm.h new file mode 100644 index 000000000000..5b1efd88206a --- /dev/null +++ b/include/llvm/MC/MCImm.h @@ -0,0 +1,55 @@ +//===-- llvm/MC/MCImm.h - MCImm class ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the MCInst and MCOperand classes, which +// is the basic representation used to represent low-level machine code +// instructions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCIMM_H +#define LLVM_MC_MCIMM_H + +namespace llvm { +class MCSymbol; + +/// MCImm - This represents an "assembler immediate". In its most general form, +/// this can hold "SymbolA - SymbolB + imm64". Not all targets supports +/// relocations of this general form, but we need to represent this anyway. +class MCImm { + MCSymbol *SymA, *SymB; + int64_t Cst; +public: + + int64_t getCst() const { return Cst; } + MCSymbol *getSymA() const { return SymA; } + MCSymbol *getSymB() const { return SymB; } + + + static MCImm get(MCSymbol *SymA, MCSymbol *SymB = 0, int64_t Val = 0) { + MCImm R; + R.Cst = Val; + R.SymA = SymA; + R.SymB = SymB; + return R; + } + + static MCImm get(int64_t Val) { + MCImm R; + R.Cst = Val; + R.SymA = 0; + R.SymB = 0; + return R; + } + +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/MC/MCInst.h b/include/llvm/MC/MCInst.h index cadc23ab7109..457c2ae2ee65 100644 --- a/include/llvm/MC/MCInst.h +++ b/include/llvm/MC/MCInst.h @@ -13,10 +13,10 @@ // //===----------------------------------------------------------------------===// - #ifndef LLVM_MC_MCINST_H #define LLVM_MC_MCINST_H +#include "llvm/MC/MCImm.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/DebugLoc.h" @@ -30,13 +30,15 @@ class MCOperand { kInvalid, ///< Uninitialized. kRegister, ///< Register operand. kImmediate, ///< Immediate operand. - kMBBLabel ///< Basic block label. + kMBBLabel, ///< Basic block label. + kMCImm }; unsigned char Kind; union { unsigned RegVal; int64_t ImmVal; + MCImm MCImmVal; struct { unsigned FunctionNo; unsigned BlockNo; @@ -112,6 +114,7 @@ class MCInst { const MCOperand &getOperand(unsigned i) const { return Operands[i]; } MCOperand &getOperand(unsigned i) { return Operands[i]; } + unsigned getNumOperands() const { return Operands.size(); } void addOperand(const MCOperand &Op) { Operands.push_back(Op); diff --git a/include/llvm/Support/Timer.h b/include/llvm/Support/Timer.h index 9a8247071c34..f34fc9541016 100644 --- a/include/llvm/Support/Timer.h +++ b/include/llvm/Support/Timer.h @@ -34,12 +34,12 @@ class TimerGroup; /// if they are never started. /// class Timer { - double Elapsed; // Wall clock time elapsed in seconds - double UserTime; // User time elapsed - double SystemTime; // System time elapsed - ssize_t MemUsed; // Memory allocated (in bytes) - size_t PeakMem; // Peak memory used - size_t PeakMemBase; // Temporary for peak calculation... + int64_t Elapsed; // Wall clock time elapsed in seconds + int64_t UserTime; // User time elapsed + int64_t SystemTime; // System time elapsed + int64_t MemUsed; // Memory allocated (in bytes) + int64_t PeakMem; // Peak memory used + int64_t PeakMemBase; // Temporary for peak calculation... std::string Name; // The name of this time variable bool Started; // Has this time variable ever been started? TimerGroup *TG; // The TimerGroup this Timer is in. @@ -49,10 +49,10 @@ class Timer { Timer(const Timer &T); ~Timer(); - double getProcessTime() const { return UserTime+SystemTime; } - double getWallTime() const { return Elapsed; } - ssize_t getMemUsed() const { return MemUsed; } - size_t getPeakMem() const { return PeakMem; } + int64_t getProcessTime() const { return UserTime+SystemTime; } + int64_t getWallTime() const { return Elapsed; } + int64_t getMemUsed() const { return MemUsed; } + int64_t getPeakMem() const { return PeakMem; } std::string getName() const { return Name; } const Timer &operator=(const Timer &T) { @@ -152,7 +152,6 @@ class TimerGroup { unsigned NumTimers; std::vector TimersToPrint; public: - TimerGroup() : Name("Miscellaneous Ungrouped Timers"), NumTimers(0) {} explicit TimerGroup(const std::string &name) : Name(name), NumTimers(0) {} ~TimerGroup() { assert(NumTimers == 0 && diff --git a/include/llvm/System/Atomic.h b/include/llvm/System/Atomic.h index adbb975298e8..c0612f9976c4 100644 --- a/include/llvm/System/Atomic.h +++ b/include/llvm/System/Atomic.h @@ -20,12 +20,14 @@ namespace llvm { namespace sys { void MemoryFence(); - typedef uint32_t cas_flag; - cas_flag CompareAndSwap(volatile cas_flag* ptr, - cas_flag new_value, - cas_flag old_value); - cas_flag AtomicIncrement(volatile cas_flag* ptr); - cas_flag AtomicDecrement(volatile cas_flag* ptr); + uint32_t CompareAndSwap32(volatile uint32_t* ptr, + uint32_t new_value, + uint32_t old_value); + int32_t AtomicIncrement32(volatile int32_t* ptr); + int32_t AtomicDecrement32(volatile int32_t* ptr); + int32_t AtomicAdd32(volatile int32_t* ptr, int32_t val); + + int64_t AtomicAdd64(volatile int64_t* ptr, int64_t val); } } diff --git a/include/llvm/Target/TargetSelect.h b/include/llvm/Target/TargetSelect.h index 8544eed76be7..8aa314ac7747 100644 --- a/include/llvm/Target/TargetSelect.h +++ b/include/llvm/Target/TargetSelect.h @@ -50,9 +50,9 @@ namespace llvm { inline bool InitializeNativeTarget() { // If we have a native target, initialize it to ensure it is linked in. #ifdef LLVM_NATIVE_ARCH -#define DoInit2(TARG, MOD) llvm::Initialize ## TARG ## MOD() -#define DoInit(T, M) DoInit2(T, M) - DoInit(LLVM_NATIVE_ARCH, Target); +#define DoInit2(TARG) llvm::Initialize ## TARG () +#define DoInit(T) DoInit2(T) + DoInit(LLVM_NATIVE_ARCH); return false; #undef DoInit #undef DoInit2 diff --git a/include/llvm/Type.h b/include/llvm/Type.h index d439233d8c05..97d5043dc416 100644 --- a/include/llvm/Type.h +++ b/include/llvm/Type.h @@ -103,7 +103,7 @@ class Type : public AbstractTypeUser { /// has no AbstractTypeUsers, the type is deleted. This is only sensical for /// derived types. /// - mutable sys::cas_flag RefCount; + mutable int32_t RefCount; const Type *getForwardedTypeInternal() const; @@ -338,7 +338,7 @@ class Type : public AbstractTypeUser { void addRef() const { assert(isAbstract() && "Cannot add a reference to a non-abstract type!"); - sys::AtomicIncrement(&RefCount); + sys::AtomicIncrement32(&RefCount); } void dropRef() const { @@ -347,8 +347,8 @@ class Type : public AbstractTypeUser { // If this is the last PATypeHolder using this object, and there are no // PATypeHandles using it, the type is dead, delete it now. - sys::cas_flag OldCount = sys::AtomicDecrement(&RefCount); - if (OldCount == 0 && AbstractTypeUsers.empty()) + int32_t Count = sys::AtomicDecrement32(&RefCount); + if (Count == 0 && AbstractTypeUsers.empty()) this->destroy(); } diff --git a/lib/ExecutionEngine/CMakeLists.txt b/lib/ExecutionEngine/CMakeLists.txt index e26b98fb9d43..0e118ccd904f 100644 --- a/lib/ExecutionEngine/CMakeLists.txt +++ b/lib/ExecutionEngine/CMakeLists.txt @@ -1,4 +1,4 @@ -add_partially_linked_object(LLVMExecutionEngine +add_llvm_library(LLVMExecutionEngine ExecutionEngine.cpp ExecutionEngineBindings.cpp ) diff --git a/lib/ExecutionEngine/Interpreter/CMakeLists.txt b/lib/ExecutionEngine/Interpreter/CMakeLists.txt index 626e804e78e6..dff97fa26e8f 100644 --- a/lib/ExecutionEngine/Interpreter/CMakeLists.txt +++ b/lib/ExecutionEngine/Interpreter/CMakeLists.txt @@ -1,4 +1,4 @@ -add_partially_linked_object(LLVMInterpreter +add_llvm_library(LLVMInterpreter Execution.cpp ExternalFunctions.cpp Interpreter.cpp diff --git a/lib/ExecutionEngine/JIT/CMakeLists.txt b/lib/ExecutionEngine/JIT/CMakeLists.txt index d7980d077282..e0c13a10f0b3 100644 --- a/lib/ExecutionEngine/JIT/CMakeLists.txt +++ b/lib/ExecutionEngine/JIT/CMakeLists.txt @@ -1,7 +1,7 @@ # TODO: Support other architectures. See Makefile. add_definitions(-DENABLE_X86_JIT) -add_partially_linked_object(LLVMJIT +add_llvm_library(LLVMJIT Intercept.cpp JIT.cpp JITDwarfEmitter.cpp diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp index c4920f0ba573..69f967c73897 100644 --- a/lib/Support/Timer.cpp +++ b/lib/Support/Timer.cpp @@ -15,7 +15,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Streams.h" -#include "llvm/System/Mutex.h" #include "llvm/System/Process.h" #include #include @@ -51,28 +50,37 @@ namespace { cl::Hidden, cl::location(getLibSupportInfoOutputFilename())); } -static ManagedStatic > TimerLock; -static ManagedStatic DefaultTimerGroup; +static TimerGroup *DefaultTimerGroup = 0; static TimerGroup *getDefaultTimerGroup() { - return &*DefaultTimerGroup; + TimerGroup* tmp = DefaultTimerGroup; + sys::MemoryFence(); + if (!tmp) { + llvm_acquire_global_lock(); + tmp = DefaultTimerGroup; + if (!tmp) { + tmp = new TimerGroup("Miscellaneous Ungrouped Timers"); + sys::MemoryFence(); + DefaultTimerGroup = tmp; + } + llvm_release_global_lock(); + } + + return tmp; } Timer::Timer(const std::string &N) : Elapsed(0), UserTime(0), SystemTime(0), MemUsed(0), PeakMem(0), Name(N), Started(false), TG(getDefaultTimerGroup()) { - sys::SmartScopedLock Lock(&*TimerLock); TG->addTimer(); } Timer::Timer(const std::string &N, TimerGroup &tg) : Elapsed(0), UserTime(0), SystemTime(0), MemUsed(0), PeakMem(0), Name(N), Started(false), TG(&tg) { - sys::SmartScopedLock Lock(&*TimerLock); TG->addTimer(); } Timer::Timer(const Timer &T) { - sys::SmartScopedLock Lock(&*TimerLock); TG = T.TG; if (TG) TG->addTimer(); operator=(T); @@ -81,7 +89,6 @@ Timer::Timer(const Timer &T) { // Copy ctor, initialize with no TG member. Timer::Timer(bool, const Timer &T) { - sys::SmartScopedLock Lock(&*TimerLock); TG = T.TG; // Avoid assertion in operator= operator=(T); // Copy contents TG = 0; @@ -89,7 +96,6 @@ Timer::Timer(bool, const Timer &T) { Timer::~Timer() { - sys::SmartScopedLock Lock(&*TimerLock); if (TG) { if (Started) { Started = false; @@ -106,8 +112,7 @@ static inline size_t getMemUsage() { } struct TimeRecord { - double Elapsed, UserTime, SystemTime; - ssize_t MemUsed; + int64_t Elapsed, UserTime, SystemTime, MemUsed; }; static TimeRecord getTimeRecord(bool Start) { @@ -117,7 +122,7 @@ static TimeRecord getTimeRecord(bool Start) { sys::TimeValue user(0,0); sys::TimeValue sys(0,0); - ssize_t MemUsed = 0; + int64_t MemUsed = 0; if (Start) { MemUsed = getMemUsage(); sys::Process::GetTimeUsage(now,user,sys); @@ -126,19 +131,17 @@ static TimeRecord getTimeRecord(bool Start) { MemUsed = getMemUsage(); } - Result.Elapsed = now.seconds() + now.microseconds() / 1000000.0; - Result.UserTime = user.seconds() + user.microseconds() / 1000000.0; - Result.SystemTime = sys.seconds() + sys.microseconds() / 1000000.0; + Result.Elapsed = now.seconds() * 1000000 + now.microseconds(); + Result.UserTime = user.seconds() * 1000000 + user.microseconds(); + Result.SystemTime = sys.seconds() * 1000000 + sys.microseconds(); Result.MemUsed = MemUsed; return Result; } static ManagedStatic > ActiveTimers; -static ManagedStatic > ActiveTimerLock; void Timer::startTimer() { - sys::SmartScopedLock Lock(&*ActiveTimerLock); Started = true; ActiveTimers->push_back(this); TimeRecord TR = getTimeRecord(true); @@ -150,7 +153,6 @@ void Timer::startTimer() { } void Timer::stopTimer() { - sys::SmartScopedLock Lock(&*ActiveTimerLock); TimeRecord TR = getTimeRecord(false); Elapsed += TR.Elapsed; UserTime += TR.UserTime; @@ -180,7 +182,6 @@ void Timer::sum(const Timer &T) { /// currently active timers, which will be printed when the timer group prints /// void Timer::addPeakMemoryMeasurement() { - sys::SmartScopedLock Lock(&*ActiveTimerLock); size_t MemUsed = getMemUsage(); for (std::vector::iterator I = ActiveTimers->begin(), @@ -203,10 +204,7 @@ static ManagedStatic NamedTimers; static ManagedStatic NamedGroupedTimers; -static ManagedStatic > NamedTimerLock; - static Timer &getNamedRegionTimer(const std::string &Name) { - sys::SmartScopedLock Lock(&*NamedTimerLock); Name2Timer::iterator I = NamedTimers->find(Name); if (I != NamedTimers->end()) return I->second; @@ -216,7 +214,6 @@ static Timer &getNamedRegionTimer(const std::string &Name) { static Timer &getNamedRegionTimer(const std::string &Name, const std::string &GroupName) { - sys::SmartScopedLock Lock(&*NamedTimerLock); Name2Pair::iterator I = NamedGroupedTimers->find(GroupName); if (I == NamedGroupedTimers->end()) { @@ -279,12 +276,13 @@ static void printVal(double Val, double Total, std::ostream &OS) { void Timer::print(const Timer &Total, std::ostream &OS) { if (Total.UserTime) - printVal(UserTime, Total.UserTime, OS); + printVal(UserTime / 1000000.0, Total.UserTime / 1000000.0, OS); if (Total.SystemTime) - printVal(SystemTime, Total.SystemTime, OS); + printVal(SystemTime / 1000000.0, Total.SystemTime / 1000000.0, OS); if (Total.getProcessTime()) - printVal(getProcessTime(), Total.getProcessTime(), OS); - printVal(Elapsed, Total.Elapsed, OS); + printVal(getProcessTime() / 1000000.0, + Total.getProcessTime() / 1000000.0, OS); + printVal(Elapsed / 1000000.0, Total.Elapsed / 1000000.0, OS); OS << " "; @@ -354,26 +352,26 @@ void TimerGroup::removeTimer() { // If this is not an collection of ungrouped times, print the total time. // Ungrouped timers don't really make sense to add up. We still print the // TOTAL line to make the percentages make sense. - if (this != &*DefaultTimerGroup) { + if (this != DefaultTimerGroup) { *OutStream << " Total Execution Time: "; - printAlignedFP(Total.getProcessTime(), 4, 5, *OutStream); + printAlignedFP(Total.getProcessTime() / 1000000.0, 4, 5, *OutStream); *OutStream << " seconds ("; - printAlignedFP(Total.getWallTime(), 4, 5, *OutStream); + printAlignedFP(Total.getWallTime() / 1000000.0, 4, 5, *OutStream); *OutStream << " wall clock)\n"; } *OutStream << "\n"; - if (Total.UserTime) + if (Total.UserTime / 1000000.0) *OutStream << " ---User Time---"; - if (Total.SystemTime) + if (Total.SystemTime / 1000000.0) *OutStream << " --System Time--"; - if (Total.getProcessTime()) + if (Total.getProcessTime() / 1000000.0) *OutStream << " --User+System--"; *OutStream << " ---Wall Time---"; - if (Total.getMemUsed()) + if (Total.getMemUsed() / 1000000.0) *OutStream << " ---Mem---"; - if (Total.getPeakMem()) + if (Total.getPeakMem() / 1000000.0) *OutStream << " -PeakMem-"; *OutStream << " --- Name ---\n"; diff --git a/lib/System/Atomic.cpp b/lib/System/Atomic.cpp index 416f981df827..fda27088da13 100644 --- a/lib/System/Atomic.cpp +++ b/lib/System/Atomic.cpp @@ -35,11 +35,11 @@ void sys::MemoryFence() { #endif } -sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr, - sys::cas_flag new_value, - sys::cas_flag old_value) { +uint32_t sys::CompareAndSwap32(volatile uint32_t* ptr, + uint32_t new_value, + uint32_t old_value) { #if LLVM_MULTITHREADED==0 - sys::cas_flag result = *ptr; + uint32_t result = *ptr; if (result == old_value) *ptr = new_value; return result; @@ -52,7 +52,7 @@ sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr, #endif } -sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) { +int32_t sys::AtomicIncrement32(volatile int32_t* ptr) { #if LLVM_MULTITHREADED==0 ++(*ptr); return *ptr; @@ -65,7 +65,7 @@ sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) { #endif } -sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) { +int32_t sys::AtomicDecrement32(volatile int32_t* ptr) { #if LLVM_MULTITHREADED==0 --(*ptr); return *ptr; @@ -78,4 +78,29 @@ sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) { #endif } +int32_t sys::AtomicAdd32(volatile int32_t* ptr, int32_t val) { +#if LLVM_MULTITHREADED==0 + *ptr += val; + return *ptr; +#elif defined(__GNUC__) + return __sync_add_and_fetch(ptr, val); +#elif defined(_MSC_VER) + return InterlockedAdd(ptr, val); +#else +# error No atomic add implementation for your platform! +#endif +} + +int64_t sys::AtomicAdd64(volatile int64_t* ptr, int64_t val) { +#if LLVM_MULTITHREADED==0 + *ptr += val; + return *ptr; +#elif defined(__GNUC__) + return __sync_add_and_fetch(ptr, val); +#elif defined(_MSC_VER) + return InterlockedAdd64(ptr, val); +#else +# error No atomic add implementation for your platform! +#endif +} diff --git a/lib/Target/ARM/ARMAddressingModes.h b/lib/Target/ARM/ARMAddressingModes.h index 6d9b9ee88000..005eb7a10f91 100644 --- a/lib/Target/ARM/ARMAddressingModes.h +++ b/lib/Target/ARM/ARMAddressingModes.h @@ -248,12 +248,122 @@ namespace ARM_AM { return V == 0; } + /// getThumbImm16ValShift - Try to handle Imm with a 16-bit immediate followed + /// by a left shift. Returns the shift amount to use. + static inline unsigned getThumbImm16ValShift(unsigned Imm) { + // 16-bit (or less) immediates are trivially immediate operand with a shift + // of zero. + if ((Imm & ~65535U) == 0) return 0; + + // Use CTZ to compute the shift amount. + return CountTrailingZeros_32(Imm); + } + + /// isThumbImm16ShiftedVal - Return true if the specified value can be + /// obtained by left shifting a 16-bit immediate. + static inline bool isThumbImm16ShiftedVal(unsigned V) { + // If this can be handled with + V = (~65535U << getThumbImm16ValShift(V)) & V; + return V == 0; + } + /// getThumbImmNonShiftedVal - If V is a value that satisfies /// isThumbImmShiftedVal, return the non-shiftd value. static inline unsigned getThumbImmNonShiftedVal(unsigned V) { return V >> getThumbImmValShift(V); } + /// getT2SOImmValDecode - Given a 12-bit encoded Thumb-2 modified immediate, + /// return the corresponding 32-bit immediate value. + /// See ARM Reference Manual A6.3.2. + static inline unsigned getT2SOImmValDecode(unsigned Imm) { + unsigned Base = Imm & 0xff; + switch ((Imm >> 8) & 0xf) { + case 0: + return Base; + case 1: + return Base | (Base << 16); + case 2: + return (Base << 8) | (Base << 24); + case 3: + return Base | (Base << 8) | (Base << 16) | (Base << 24); + default: + break; + } + + // shifted immediate + unsigned RotAmount = ((Imm >> 7) & 0x1f) - 8; + return (Base | 0x80) << (24 - RotAmount); + } + + /// getT2SOImmValSplat - Return the 12-bit encoded representation + /// if the specified value can be obtained by splatting the low 8 bits + /// into every other byte or every byte of a 32-bit value. i.e., + /// 00000000 00000000 00000000 abcdefgh control = 0 + /// 00000000 abcdefgh 00000000 abcdefgh control = 1 + /// abcdefgh 00000000 abcdefgh 00000000 control = 2 + /// abcdefgh abcdefgh abcdefgh abcdefgh control = 3 + /// Return -1 if none of the above apply. + /// See ARM Reference Manual A6.3.2. + static inline int getT2SOImmValSplat (unsigned V) { + unsigned u, Vs, Imm; + // control = 0 + if ((V & 0xffffff00) == 0) + return V; + + // If the value is zeroes in the first byte, just shift those off + Vs = ((V & 0xff) == 0) ? V >> 8 : V; + // Any passing value only has 8 bits of payload, splatted across the word + Imm = Vs & 0xff; + // Likewise, any passing values have the payload splatted into the 3rd byte + u = Imm | (Imm << 16); + + // control = 1 or 2 + if (Vs == u) + return (((Vs == V) ? 1 : 2) << 8) | Imm; + + // control = 3 + if (Vs == (u | (u << 8))) + return (3 << 8) | Imm; + + return -1; + } + + /// getT2SOImmValRotate - Return the 12-bit encoded representation if the + /// specified value is a rotated 8-bit value. Return -1 if no rotation + /// encoding is possible. + /// See ARM Reference Manual A6.3.2. + static inline int getT2SOImmValRotate (unsigned V) { + unsigned RotAmt = CountLeadingZeros_32(V); + if (RotAmt >= 24) + return -1; + + // If 'Arg' can be handled with a single shifter_op return the value. + if ((rotr32(0xff000000U, RotAmt) & V) == V) + return (rotr32(V, 24 - RotAmt) & 0x7f) | ((RotAmt + 8) << 7); + + return -1; + } + + /// getT2SOImmVal - Given a 32-bit immediate, if it is something that can fit + /// into a Thumb-2 shifter_operand immediate operand, return the 12-bit + /// encoding for it. If not, return -1. + /// See ARM Reference Manual A6.3.2. + static inline int getT2SOImmVal(unsigned Arg) { + // If 'Arg' is an 8-bit splat, then get the encoded value. + int Splat = getT2SOImmValSplat(Arg); + if (Splat != -1) + return Splat; + + // If 'Arg' can be handled with a single shifter_op return the value. + int Rot = getT2SOImmValRotate(Arg); + if (Rot != -1) + return Rot; + + return -1; + } + + //===--------------------------------------------------------------------===// // Addressing Mode #2 //===--------------------------------------------------------------------===// diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index ee9dadff151b..be543a91ef26 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -92,8 +92,8 @@ class ARMDAGToDAGISel : public SelectionDAGISel { bool SelectThumbAddrModeSP(SDValue Op, SDValue N, SDValue &Base, SDValue &OffImm); - bool SelectShifterOperand(SDValue Op, SDValue N, - SDValue &BaseReg, SDValue &Opc); + bool SelectThumb2ShifterOperandReg(SDValue Op, SDValue N, + SDValue &BaseReg, SDValue &Opc); bool SelectShifterOperandReg(SDValue Op, SDValue N, SDValue &A, SDValue &B, SDValue &C); @@ -520,10 +520,10 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue Op, SDValue N, return false; } -bool ARMDAGToDAGISel::SelectShifterOperand(SDValue Op, - SDValue N, - SDValue &BaseReg, - SDValue &Opc) { +bool ARMDAGToDAGISel::SelectThumb2ShifterOperandReg(SDValue Op, + SDValue N, + SDValue &BaseReg, + SDValue &Opc) { ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N); // Don't match base register only case. That is matched to a separate diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index 14cca7a6e5cb..d70d2e2d1709 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -751,6 +751,26 @@ class ThumbV5Pat : Pat { list Predicates = [IsThumb, HasV5T]; } +// T2I - Thumb2 instruction. + +class Thumb2I pattern> + : InstARM { + let OutOperandList = outs; + let InOperandList = ins; + let AsmString = asm; + let Pattern = pattern; + list Predicates = [IsThumb, HasThumb2]; +} + +class T2I pattern> + : Thumb2I; + +// Thumb2Pat - Same as Pat<>, but requires that the compiler be in Thumb2 mode. +class Thumb2Pat : Pat { + list Predicates = [IsThumb, HasThumb2]; +} + //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 44e67e9fc524..7003a6587ad8 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -98,6 +98,7 @@ def HasVFP2 : Predicate<"Subtarget->hasVFP2()">; def HasVFP3 : Predicate<"Subtarget->hasVFP3()">; def HasNEON : Predicate<"Subtarget->hasNEON()">; def IsThumb : Predicate<"Subtarget->isThumb()">; +def IsThumb1Only : Predicate<"Subtarget->isThumb1Only()">; def HasThumb2 : Predicate<"Subtarget->hasThumb2()">; def IsARM : Predicate<"!Subtarget->isThumb()">; def IsDarwin : Predicate<"Subtarget->isTargetDarwin()">; diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 0aba2d522809..e0617e466208 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -14,137 +14,239 @@ // 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 PrintMethod = "printSOOperand"; let MIOperandInfo = (ops GPR, i32imm); } -def LO16 : SDNodeXFormgetZExtValue()); +// t2_so_imm_XFORM - Return a t2_so_imm value packed into the format +// described for t2_so_imm def below. +def t2_so_imm_XFORM : SDNodeXFormgetTargetConstant( + ARM_AM::getT2SOImmVal(N->getZExtValue()), MVT::i32); }]>; -def HI16 : SDNodeXFormgetZExtValue() >> 16); +// t2_so_imm_not_XFORM - Return the complement of a t2_so_imm value +def t2_so_imm_not_XFORM : SDNodeXFormgetTargetConstant( + ARM_AM::getT2SOImmVal(~((uint32_t)N->getZExtValue())), MVT::i32); }]>; -def imm16high : PatLeaf<(i32 imm), [{ - // Returns true if all bits out of the [31..16] range are 0. - return ((N->getZExtValue() & 0xFFFF0000ULL) == N->getZExtValue()); -}], HI16>; +// t2_so_imm_neg_XFORM - Return the negation of a t2_so_imm value +def t2_so_imm_neg_XFORM : SDNodeXFormgetTargetConstant( + ARM_AM::getT2SOImmVal(-((int)N->getZExtValue())), MVT::i32); +}]>; -def imm16high0xffff : PatLeaf<(i32 imm), [{ - // Returns true if lo 16 bits are set and this is a 32-bit value. - return ((N->getZExtValue() & 0x0000FFFFULL) == 0xFFFFULL); -}], HI16>; +// 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. t2_so_imm values are +// represented in the imm field in the same 12-bit form that they are encoded +// into t2_so_imm instructions: the 8-bit immediate is the least significant bits +// [bits 0-7], the 4-bit shift/splat amount is the next 4 bits [bits 8-11]. +def t2_so_imm : Operand, + PatLeaf<(imm), [{ + return ARM_AM::getT2SOImmVal((uint32_t)N->getZExtValue()) != -1; + }], t2_so_imm_XFORM> { + let PrintMethod = "printT2SOImmOperand"; +} -def imm0_4095 : PatLeaf<(i32 imm), [{ - return (uint32_t)N->getZExtValue() < 4096; -}]>; +// t2_so_imm_not - Match an immediate that is a complement +// of a t2_so_imm. +def t2_so_imm_not : Operand, + PatLeaf<(imm), [{ + return ARM_AM::getT2SOImmVal(~((uint32_t)N->getZExtValue())) != -1; + }], t2_so_imm_not_XFORM> { + let PrintMethod = "printT2SOImmOperand"; +} + +// t2_so_imm_neg - Match an immediate that is a negation of a t2_so_imm. +def t2_so_imm_neg : Operand, + PatLeaf<(imm), [{ + return ARM_AM::getT2SOImmVal(-((int)N->getZExtValue())) != -1; + }], t2_so_imm_neg_XFORM> { + let PrintMethod = "printT2SOImmOperand"; +} + +/// imm0_4095 predicate - True if the 32-bit immediate is in the range [0.4095]. +def imm0_4095 : PatLeaf<(i32 imm), [{ + return (uint32_t)N->getZExtValue() < 4096; +}]>; def imm0_4095_neg : PatLeaf<(i32 imm), [{ - return (uint32_t)-N->getZExtValue() < 4096; + return (uint32_t)(-N->getZExtValue()) < 4096; }], imm_neg_XFORM>; -def imm0_65535 : PatLeaf<(i32 imm), [{ - return N->getZExtValue() < 65536; -}]>; - -// A6.3.2 Modified immediate constants in Thumb instructions (#) -// FIXME: Move it the the addrmode matcher code. -def t2_so_imm : PatLeaf<(i32 imm), [{ - uint64_t v = N->getZExtValue(); - if (v == 0 || v > 0xffffffffUL) return false; - // variant1 - 0b0000x - 8-bit which could be zero (not supported for now) - - // variant2 - 0b00nnx - 8-bit repeated inside the 32-bit room - unsigned hi16 = (unsigned)(v >> 16); - unsigned lo16 = (unsigned)(v & 0xffffUL); - bool valid = (hi16 == lo16) && ( - (v & 0x00ff00ffUL) == 0 || // type 0001x - (v & 0xff00ff00UL) == 0 || // type 0010x - ((lo16 >> 8) == (lo16 & 0xff))); // type 0011x - if (valid) return true; - - // variant3 - 0b01000..0b11111 - 8-bit shifted inside the 32-bit room - unsigned shift = CountLeadingZeros_32(v); - uint64_t mask = (0xff000000ULL >> shift); - // If valid, it is type 01000 + shift - return ((shift < 24) && (v & mask) > 0) && ((v & (~mask)) == 0); +/// imm0_65535 predicate - True if the 32-bit immediate is in the range +/// [0.65535]. +def imm0_65535 : PatLeaf<(i32 imm), [{ + return (uint32_t)N->getZExtValue() < 65536; }]>; +/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield +/// e.g., 0xf000ffff +def bf_inv_mask_imm : Operand, + PatLeaf<(imm), [{ + uint32_t v = (uint32_t)N->getZExtValue(); + if (v == 0xffffffff) + return 0; + // naive checker. should do better, but simple is best for now since it's + // more likely to be correct. + while (v & 1) v >>= 1; // shift off the leading 1's + if (v) + { + while (!(v & 1)) v >>=1; // shift off the mask + while (v & 1) v >>= 1; // shift off the trailing 1's + } + // if this is a mask for clearing a bitfield, what's left should be zero. + return (v == 0); +}] > { + let PrintMethod = "printBitfieldInvMaskImmOperand"; +} + +/// Split a 32-bit immediate into two 16 bit parts. +def t2_lo16 : SDNodeXFormgetTargetConstant((uint32_t)N->getZExtValue() & 0xffff, + MVT::i32); +}]>; + +def t2_hi16 : SDNodeXFormgetTargetConstant((uint32_t)N->getZExtValue() >> 16, MVT::i32); +}]>; + +def t2_lo16AllZero : PatLeaf<(i32 imm), [{ + // Returns true if all low 16-bits are 0. + return (((uint32_t)N->getZExtValue()) & 0xFFFFUL) == 0; + }], t2_hi16>; + //===----------------------------------------------------------------------===// -// Thumb-2 to cover the functionality of the ARM instruction set. +// Thumb2 to cover the functionality of the ARM instruction set. // -/// T2I_bin_irs - Defines a set of (op reg, {so_imm|reg|so_reg}) patterns for a +/// T2I_bin_is - Defines a set of (op reg, {so_imm|so_reg}) patterns for a // binary operation that produces a value. -multiclass T2I_bin_irs { +multiclass T2I_bin_is { // shifted imm - def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs), - !strconcat(opc, " $dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>, - Requires<[HasThumb2]>; - // register - def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), - !strconcat(opc, " $dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>, - Requires<[HasThumb2]>; + def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>; // shifted register - def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), - !strconcat(opc, " $dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>, - Requires<[HasThumb2]>; + def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>; } -/// T2I_bin_s_irs - Similar to T2I_bin_irs except it sets the 's' bit so the +/// T2I_2bin_is - Same as T2I_bin_is except the order of operands are reversed. +multiclass T2I_rbin_is { + // shifted imm + def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>; + // shifted register + def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>; +} + +/// T2I_bin_s_is - Similar to T2I_bin_is except it sets the 's' bit so the /// instruction modifies the CPSR register. let Defs = [CPSR] in { -multiclass T2I_bin_s_irs { +multiclass T2I_bin_s_is { // shifted imm - def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs), - !strconcat(opc, "s $dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>, - Requires<[HasThumb2]>; - - // register - def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), - !strconcat(opc, "s $dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>, - Requires<[HasThumb2]>; + def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), + !strconcat(opc, "s $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>; // shifted register - def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), - !strconcat(opc, "s $dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>, - Requires<[HasThumb2]>; + def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), + !strconcat(opc, "s $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>; } } -/// T2I_bin_c_irs - Similar to T2I_bin_irs except it uses the 's' bit. Also the -/// instruction can optionally set the CPSR register. +/// T2I_rbin_s_is - Same as T2I_bin_s_is except the order of operands are +/// reversed. +let Defs = [CPSR] in { +multiclass T2I_rbin_s_is { + // shifted imm + def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs), + !strconcat(opc, "s $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>; + + // shifted register + def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs), + !strconcat(opc, "s $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>; +} +} + +/// T2I_bin_ii12s - Defines a set of (op reg, {so_imm|imm0_4095|so_reg}) patterns +/// for a binary operation that produces a value. +multiclass T2I_bin_ii12s { + // shifted imm + def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>; + // 12-bit imm + def ri12 : T2I<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs), + !strconcat(opc, "w $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, imm0_4095:$rhs))]>; + // shifted register + def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>; +} + +/// T2I_bin_c_is - Defines a set of (op reg, {so_imm|reg}) patterns for a +// binary operation that produces a value and set the carry bit. It can also +/// optionally set CPSR. let Uses = [CPSR] in { -multiclass T2I_bin_c_irs { +multiclass T2I_bin_c_is { // shifted imm - def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs, cc_out:$s), - !strconcat(opc, "${s} $dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>, - Requires<[HasThumb2]>; - - // register - def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs, cc_out:$s), - !strconcat(opc, "${s} $dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>, - Requires<[HasThumb2]>; + def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs, cc_out:$s), + !strconcat(opc, "${s} $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>; // shifted register - def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs, cc_out:$s), - !strconcat(opc, "${s} $dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>, - Requires<[HasThumb2]>; + def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs, cc_out:$s), + !strconcat(opc, "${s} $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>; +} +} + +/// T2I_rbin_c_is - Same as T2I_bin_c_is except the order of operands are +/// reversed. +let Uses = [CPSR] in { +multiclass T2I_rbin_c_is { + // shifted imm + def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs, cc_out:$s), + !strconcat(opc, "${s} $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>; + + // shifted register + def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs, cc_out:$s), + !strconcat(opc, "${s} $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>; +} +} + + +/// T21_cmp_irs - Defines a set of (op r, {so_imm|so_reg}) cmp / test +/// patterns. Similar to T2I_bin_is except the instruction does not produce +/// a explicit result, only implicitly set CPSR. +let Uses = [CPSR] in { +multiclass T2I_cmp_is { + // shifted imm + def ri : T2I<(outs), (ins GPR:$lhs, t2_so_imm:$rhs), + !strconcat(opc, " $lhs, $rhs"), + [(opnode GPR:$lhs, t2_so_imm:$rhs)]>; + + // shifted register + def rs : T2I<(outs), (ins GPR:$lhs, t2_so_reg:$rhs), + !strconcat(opc, " $lhs, $rhs"), + [(opnode GPR:$lhs, t2_so_reg:$rhs)]>; } } @@ -155,54 +257,184 @@ multiclass T2I_bin_c_irs { //===----------------------------------------------------------------------===// // Move Instructions. // -def tMOVi16 : PseudoInst<(outs GPR:$dst), (ins i32imm:$src), - "movw $dst, $src", - [(set GPR:$dst, imm0_65535:$src)]>, - Requires<[HasThumb2]>; +let neverHasSideEffects = 1 in +def t2MOVr : T2I<(outs GPR:$dst), (ins GPR:$src), + "mov $dst, $src", []>; + +def t2MOVi16 : T2I<(outs GPR:$dst), (ins i32imm:$src), + "movw $dst, $src", + [(set GPR:$dst, imm0_65535:$src)]>; + + +// FIXME: Move (shifted register) is a pseudo-instruction for ASR, LSL, LSR, +// ROR, and RRX. Consider splitting into multiple instructions. +def t2MOVs : T2I<(outs GPR:$dst), (ins t2_so_reg:$src), + "mov $dst, $src", + [(set GPR:$dst, t2_so_reg:$src)]>; +def t2MOVrx : T2I<(outs GPR:$dst), (ins GPR:$src), + "mov $dst, $src, rrx", + [(set GPR:$dst, (ARMrrx GPR:$src))]>; + + +// FIXME: Also available in ARM mode. let Constraints = "$src = $dst" in -def tMOVTi16 : PseudoInst<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm), - "movt $dst, $imm", - [(set GPR:$dst, (or (and GPR:$src, 0xffff), - imm16high:$imm))]>, - Requires<[HasThumb2]>; - -def : Pat<(and (or GPR:$src, imm16high:$imm1), imm16high0xffff:$imm2), - (tMOVTi16 GPR:$src, (HI16 imm16high:$imm1))>, - Requires<[HasThumb2]>; - -def : Pat<(i32 imm:$imm), - (tMOVTi16 (tMOVi16 (LO16 imm:$imm)),(HI16 imm:$imm))>, - Requires<[HasThumb2]>; +def t2MOVTi16 : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm), + "movt $dst, $imm", + [(set GPR:$dst, + (or (and GPR:$src, 0xffff), t2_lo16AllZero:$imm))]>; //===----------------------------------------------------------------------===// // Arithmetic Instructions. // -defm t2ADD : T2I_bin_irs <"add", BinOpFrag<(add node:$LHS, node:$RHS)>>; -defm t2SUB : T2I_bin_irs <"sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>; -def tADDri12 : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs), - "add $dst, $lhs, $rhs", - [(set GPR:$dst, (add GPR:$lhs, imm0_4095:$rhs))]>, - Requires<[HasThumb2]>; -def tSUBri12 : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs), - "sub $dst, $lhs, $rhs", - [(set GPR:$dst, (add GPR:$lhs, imm0_4095_neg:$rhs))]>, - Requires<[HasThumb2]>; +defm t2ADD : T2I_bin_ii12s<"add", BinOpFrag<(add node:$LHS, node:$RHS)>>; +defm t2SUB : T2I_bin_ii12s<"sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>; -defm t2ADDS : T2I_bin_s_irs<"add", BinOpFrag<(addc node:$LHS, node:$RHS)>>; -defm t2SUBS : T2I_bin_s_irs<"sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>; +// ADD and SUB with 's' bit set. No 12-bit immediate (T4) variants. +defm t2ADDS : T2I_bin_s_is<"add", BinOpFrag<(addc node:$LHS, node:$RHS)>>; +defm t2SUBS : T2I_bin_s_is<"sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>; -defm t2ADC : T2I_bin_c_irs<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>; -defm t2SBC : T2I_bin_c_irs<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>; +// FIXME: predication support +defm t2ADC : T2I_bin_c_is<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>; +defm t2SBC : T2I_bin_c_is<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>; + +// RSB, RSC +defm t2RSB : T2I_rbin_is <"rsb", BinOpFrag<(sub node:$LHS, node:$RHS)>>; +defm t2RSBS : T2I_rbin_c_is<"rsb", BinOpFrag<(subc node:$LHS, node:$RHS)>>; +defm t2RSC : T2I_rbin_s_is<"rsc", BinOpFrag<(sube node:$LHS, node:$RHS)>>; + +// (sub X, imm) gets canonicalized to (add X, -imm). Match this form. +def : Thumb2Pat<(add GPR:$src, t2_so_imm_neg:$imm), + (t2SUBri GPR:$src, t2_so_imm_neg:$imm)>; +def : Thumb2Pat<(add GPR:$src, imm0_4095_neg:$imm), + (t2SUBri12 GPR:$src, imm0_4095_neg:$imm)>; -def tMLS : PseudoInst<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), - "mls $dst, $a, $b, $c", - [(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]>, - Requires<[HasThumb2]>; +//===----------------------------------------------------------------------===// +// Bitwise Instructions. +// -def tORNrs : PseudoInst<(outs GPR:$dst), (ins GPR:$src1, t2_so_reg:$src2), - "orn $dst, $src1, $src2", - [(set GPR:$dst, (or GPR:$src1, (not t2_so_reg: $src2)))]>, - Requires<[HasThumb2]>; +defm t2AND : T2I_bin_is <"and", BinOpFrag<(and node:$LHS, node:$RHS)>>; +defm t2ORR : T2I_bin_is <"orr", BinOpFrag<(or node:$LHS, node:$RHS)>>; +defm t2EOR : T2I_bin_is <"eor", BinOpFrag<(xor node:$LHS, node:$RHS)>>; + +defm t2BIC : T2I_bin_is <"bic", BinOpFrag<(and node:$LHS, (not node:$RHS))>>; + +def : Thumb2Pat<(and GPR:$src, t2_so_imm_not:$imm), + (t2BICri GPR:$src, t2_so_imm_not:$imm)>; + +defm t2ORN : T2I_bin_is <"orn", BinOpFrag<(or node:$LHS, (not node:$RHS))>>; + +def : Thumb2Pat<(or GPR:$src, t2_so_imm_not:$imm), + (t2ORNri GPR:$src, t2_so_imm_not:$imm)>; + + +def t2MVNr : T2I<(outs GPR:$dst), (ins t2_so_reg:$rhs), + "mvn $dst, $rhs", + [(set GPR:$dst, (not t2_so_reg:$rhs))]>; +let isReMaterializable = 1, isAsCheapAsAMove = 1 in +def t2MVNi : T2I<(outs GPR:$dst), (ins t2_so_imm_not:$rhs), + "mvn $dst, $rhs", + [(set GPR:$dst, t2_so_imm_not:$rhs)]>; + +// A8.6.17 BFC - Bitfield clear +// FIXME: Also available in ARM mode. +let Constraints = "$src = $dst" in +def t2BFC : T2I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm), + "bfc $dst, $imm", + [(set GPR:$dst, (and GPR:$src, bf_inv_mask_imm:$imm))]>; + +// FIXME: A8.6.18 BFI - Bitfield insert (Encoding T1) + +//===----------------------------------------------------------------------===// +// Multiply Instructions. +// +def t2MUL: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), + "mul $dst, $a, $b", + [(set GPR:$dst, (mul GPR:$a, GPR:$b))]>; + +def t2MLA: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), + "mla $dst, $a, $b, $c", + [(set GPR:$dst, (add (mul GPR:$a, GPR:$b), GPR:$c))]>; + +def t2MLS: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), + "mls $dst, $a, $b, $c", + [(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]>; + +// FIXME: SMULL, etc. + +//===----------------------------------------------------------------------===// +// Misc. Arithmetic Instructions. +// + +///// +/// A8.6.31 CLZ +///// +// FIXME not firing? but ARM version does... +def t2CLZ : T2I<(outs GPR:$dst), (ins GPR:$src), + "clz $dst, $src", + [(set GPR:$dst, (ctlz GPR:$src))]>; + +def t2REV : T2I<(outs GPR:$dst), (ins GPR:$src), + "rev $dst, $src", + [(set GPR:$dst, (bswap GPR:$src))]>; + +def t2REV16 : T2I<(outs GPR:$dst), (ins GPR:$src), + "rev16 $dst, $src", + [(set GPR:$dst, + (or (and (srl GPR:$src, (i32 8)), 0xFF), + (or (and (shl GPR:$src, (i32 8)), 0xFF00), + (or (and (srl GPR:$src, (i32 8)), 0xFF0000), + (and (shl GPR:$src, (i32 8)), 0xFF000000)))))]>; + +///// +/// A8.6.137 REVSH +///// +def t2REVSH : T2I<(outs GPR:$dst), (ins GPR:$src), + "revsh $dst, $src", + [(set GPR:$dst, + (sext_inreg + (or (srl (and GPR:$src, 0xFFFF), (i32 8)), + (shl GPR:$src, (i32 8))), i16))]>; + +// FIXME: PKHxx etc. + +//===----------------------------------------------------------------------===// +// Comparison Instructions... +// + +defm t2CMP : T2I_cmp_is<"cmp", + BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>; +defm t2CMPnz : T2I_cmp_is<"cmp", + BinOpFrag<(ARMcmpNZ node:$LHS, node:$RHS)>>; + +defm t2CMN : T2I_cmp_is<"cmn", + BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>; +defm t2CMNnz : T2I_cmp_is<"cmn", + BinOpFrag<(ARMcmpNZ node:$LHS,(ineg node:$RHS))>>; + +def : Thumb2Pat<(ARMcmp GPR:$src, t2_so_imm_neg:$imm), + (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>; + +def : Thumb2Pat<(ARMcmpNZ GPR:$src, t2_so_imm_neg:$imm), + (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>; + +// FIXME: TST, TEQ, etc. + +// A8.6.27 CBNZ, CBZ - Compare and branch on (non)zero. +// Short range conditional branch. Looks awesome for loops. Need to figure +// out how to use this one. + +// FIXME: Conditional moves + + +//===----------------------------------------------------------------------===// +// Non-Instruction Patterns +// + +// Large immediate handling. + +def : Thumb2Pat<(i32 imm:$src), + (t2MOVTi16 (t2MOVi16 (t2_lo16 imm:$src)), + (t2_hi16 imm:$src))>; diff --git a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp index 58ba50e7ed77..fe1c9806cbb9 100644 --- a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp @@ -98,6 +98,7 @@ namespace { void printSOImm2PartOperand(const MachineInstr *MI, int opNum); void printSOOperand(const MachineInstr *MI, int OpNum); void printSORegOperand(const MachineInstr *MI, int opNum); + void printT2SOImmOperand(const MachineInstr *MI, int opNum); void printAddrMode2Operand(const MachineInstr *MI, int OpNo); void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNo); void printAddrMode3Operand(const MachineInstr *MI, int OpNo); @@ -108,6 +109,7 @@ namespace { const char *Modifier = 0); void printAddrModePCOperand(const MachineInstr *MI, int OpNo, const char *Modifier = 0); + void printBitfieldInvMaskImmOperand (const MachineInstr *MI, int OpNo); void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNo); void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNo, unsigned Scale); @@ -455,6 +457,24 @@ void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op) { } } +static void printT2SOImm(raw_ostream &O, int64_t V) { + unsigned Imm = ARM_AM::getT2SOImmValDecode(V); + + // Always print the immediate directly, as the "rotate" form + // is deprecated in some contexts. + O << "#" << Imm; +} + +/// printT2SOImmOperand - T2SOImm is: +/// 1. a 4-bit splat control value and 8 bit immediate value +/// 2. a 5-bit rotate amount and a non-zero 8-bit immediate value +/// represented by a normalizedin 7-bit value (msb is always 1) +void ARMAsmPrinter::printT2SOImmOperand(const MachineInstr *MI, int OpNum) { + const MachineOperand &MO = MI->getOperand(OpNum); + assert(MO.isImm() && "Not a valid so_imm value!"); + printT2SOImm(O, MO.getImm()); +} + void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); @@ -619,6 +639,16 @@ void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op, O << "[pc, +" << TM.getRegisterInfo()->get(MO1.getReg()).AsmName << "]"; } +void +ARMAsmPrinter::printBitfieldInvMaskImmOperand(const MachineInstr *MI, int Op) { + const MachineOperand &MO = MI->getOperand(Op); + uint32_t v = ~MO.getImm(); + int32_t lsb = ffs (v) - 1; + int32_t width = fls (v) - lsb; + assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!"); + O << "#" << lsb << ", #" << width; +} + void ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op) { const MachineOperand &MO1 = MI->getOperand(Op); diff --git a/lib/Target/ARM/AsmPrinter/CMakeLists.txt b/lib/Target/ARM/AsmPrinter/CMakeLists.txt index 524a748665be..c22964f6c879 100644 --- a/lib/Target/ARM/AsmPrinter/CMakeLists.txt +++ b/lib/Target/ARM/AsmPrinter/CMakeLists.txt @@ -1,9 +1,5 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) -add_partially_linked_object(LLVMARMAsmPrinter +add_llvm_library(LLVMARMAsmPrinter ARMAsmPrinter.cpp ) - -target_name_of_partially_linked_object(LLVMARMCodeGen n) - -add_dependencies(LLVMARMAsmPrinter ${n}) diff --git a/lib/Target/Alpha/AsmPrinter/CMakeLists.txt b/lib/Target/Alpha/AsmPrinter/CMakeLists.txt index b62a7f683568..bf047625bac4 100644 --- a/lib/Target/Alpha/AsmPrinter/CMakeLists.txt +++ b/lib/Target/Alpha/AsmPrinter/CMakeLists.txt @@ -1,9 +1,5 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) -add_partially_linked_object(LLVMAlphaAsmPrinter +add_llvm_library(LLVMAlphaAsmPrinter AlphaAsmPrinter.cpp ) - -target_name_of_partially_linked_object(LLVMAlphaCodeGen n) - -add_dependencies(LLVMAlphaAsmPrinter ${n}) diff --git a/lib/Target/CellSPU/AsmPrinter/CMakeLists.txt b/lib/Target/CellSPU/AsmPrinter/CMakeLists.txt index 4336b057a346..0dad08340414 100644 --- a/lib/Target/CellSPU/AsmPrinter/CMakeLists.txt +++ b/lib/Target/CellSPU/AsmPrinter/CMakeLists.txt @@ -3,10 +3,6 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ) -add_partially_linked_object(LLVMCellSPUAsmPrinter +add_llvm_library(LLVMCellSPUAsmPrinter SPUAsmPrinter.cpp ) - -target_name_of_partially_linked_object(LLVMCellSPUCodeGen n) - -add_dependencies(LLVMCellSPUAsmPrinter ${n}) diff --git a/lib/Target/IA64/AsmPrinter/CMakeLists.txt b/lib/Target/IA64/AsmPrinter/CMakeLists.txt index 1d552bd5551c..b81ed4a8d0d1 100644 --- a/lib/Target/IA64/AsmPrinter/CMakeLists.txt +++ b/lib/Target/IA64/AsmPrinter/CMakeLists.txt @@ -3,10 +3,6 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ) -add_partially_linked_object(LLVMIA64AsmPrinter +add_llvm_library(LLVMIA64AsmPrinter IA64AsmPrinter.cpp ) - -target_name_of_partially_linked_object(LLVMIA64CodeGen n) - -add_dependencies(LLVMIA64AsmPrinter ${n}) diff --git a/lib/Target/Mips/AsmPrinter/CMakeLists.txt b/lib/Target/Mips/AsmPrinter/CMakeLists.txt index 6a868c2fc78c..942548dfc477 100644 --- a/lib/Target/Mips/AsmPrinter/CMakeLists.txt +++ b/lib/Target/Mips/AsmPrinter/CMakeLists.txt @@ -3,10 +3,6 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ) -add_partially_linked_object(LLVMMipsAsmPrinter +add_llvm_library(LLVMMipsAsmPrinter MipsAsmPrinter.cpp ) - -target_name_of_partially_linked_object(LLVMMipsCodeGen n) - -add_dependencies(LLVMMipsAsmPrinter ${n}) diff --git a/lib/Target/PowerPC/AsmPrinter/CMakeLists.txt b/lib/Target/PowerPC/AsmPrinter/CMakeLists.txt index 1ed483ab21e9..1f80b17a3843 100644 --- a/lib/Target/PowerPC/AsmPrinter/CMakeLists.txt +++ b/lib/Target/PowerPC/AsmPrinter/CMakeLists.txt @@ -1,9 +1,5 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) -add_partially_linked_object(LLVMPowerPCAsmPrinter +add_llvm_library(LLVMPowerPCAsmPrinter PPCAsmPrinter.cpp ) - -target_name_of_partially_linked_object(LLVMPowerPCCodeGen n) - -add_dependencies(LLVMPowerPCAsmPrinter ${n}) diff --git a/lib/Target/Sparc/AsmPrinter/CMakeLists.txt b/lib/Target/Sparc/AsmPrinter/CMakeLists.txt index 394b4cd40e76..de905a92128a 100644 --- a/lib/Target/Sparc/AsmPrinter/CMakeLists.txt +++ b/lib/Target/Sparc/AsmPrinter/CMakeLists.txt @@ -1,9 +1,5 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) -add_partially_linked_object(LLVMSparcAsmPrinter +add_llvm_library(LLVMSparcAsmPrinter SparcAsmPrinter.cpp ) - -target_name_of_partially_linked_object(LLVMSparcCodeGen n) - -add_dependencies(LLVMSparcAsmPrinter ${n}) diff --git a/lib/Target/X86/AsmPrinter/CMakeLists.txt b/lib/Target/X86/AsmPrinter/CMakeLists.txt index 368bcaa5ce34..2079a9fd271b 100644 --- a/lib/Target/X86/AsmPrinter/CMakeLists.txt +++ b/lib/Target/X86/AsmPrinter/CMakeLists.txt @@ -1,12 +1,8 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) -add_partially_linked_object(LLVMX86AsmPrinter +add_llvm_library(LLVMX86AsmPrinter X86ATTAsmPrinter.cpp X86ATTInstPrinter.cpp X86AsmPrinter.cpp X86IntelAsmPrinter.cpp ) - -target_name_of_partially_linked_object(LLVMX86CodeGen n) - -add_dependencies(LLVMX86AsmPrinter ${n}) diff --git a/lib/VMCore/Mangler.cpp b/lib/VMCore/Mangler.cpp index 1a68b890542f..6be06d22168a 100644 --- a/lib/VMCore/Mangler.cpp +++ b/lib/VMCore/Mangler.cpp @@ -165,10 +165,10 @@ std::string Mangler::getValueName(const GlobalValue *GV, const char * Suffix) { } else if (!GV->hasName()) { // Must mangle the global into a unique ID. unsigned TypeUniqueID = getTypeID(GV->getType()); - static uint32_t GlobalID = 0; + static int32_t GlobalID = 0; - unsigned OldID = GlobalID; - sys::AtomicIncrement(&GlobalID); + int32_t OldID = GlobalID; + sys::AtomicIncrement32(&GlobalID); Name = "__unnamed_" + utostr(TypeUniqueID) + "_" + utostr(OldID); } else { diff --git a/test/FrontendC/2007-05-07-PaddingElements.c b/test/FrontendC/2007-05-07-PaddingElements.c index c0a65f054acc..9be8850895ae 100644 --- a/test/FrontendC/2007-05-07-PaddingElements.c +++ b/test/FrontendC/2007-05-07-PaddingElements.c @@ -1,5 +1,5 @@ // PR 1278 -// RUN: %llvmgcc %s -S -emit-llvm -O0 -o - | not grep "4 x i8] zeroinitializer" +// RUN: %llvmgcc %s -S -emit-llvm -O0 -o - | grep {struct.s} | not grep "4 x i8] zeroinitializer" // RUN: %llvmgcc %s -S -emit-llvm -O0 -o - | not grep "i32 0, i32 2" struct s { double d1; diff --git a/test/FrontendC/2008-03-24-BitField-And-Alloca.c b/test/FrontendC/2008-03-24-BitField-And-Alloca.c index 7963805ba811..5fac2a9ca556 100644 --- a/test/FrontendC/2008-03-24-BitField-And-Alloca.c +++ b/test/FrontendC/2008-03-24-BitField-And-Alloca.c @@ -1,5 +1,5 @@ // RUN: %llvmgcc -O2 -S %s -o - | not grep alloca -// RUN: %llvmgcc -m32 -S %s -o - | grep store | not grep {align 8} +// RUN: %llvmgcc -m32 -O2 -S %s -o - | grep store | not grep {align 8} enum { PP_C, diff --git a/test/FrontendC/2009-02-13-zerosize-union-field-ppc.c b/test/FrontendC/2009-02-13-zerosize-union-field-ppc.c new file mode 100644 index 000000000000..947166d54ac4 --- /dev/null +++ b/test/FrontendC/2009-02-13-zerosize-union-field-ppc.c @@ -0,0 +1,14 @@ +// RUN: %llvmgcc %s -m32 -S -o - | grep {i32 32} | count 3 +// XFAIL: * +// XTARGET: powerpc +// Every printf has 'i32 0' for the GEP of the string; no point counting those. +typedef unsigned int Foo __attribute__((aligned(32))); +typedef union{Foo:0;}a; +typedef union{int x; Foo:0;}b; +extern int printf(const char*, ...); +main() { + printf("%ld\n", sizeof(a)); + printf("%ld\n", __alignof__(a)); + printf("%ld\n", sizeof(b)); + printf("%ld\n", __alignof__(b)); +} diff --git a/test/FrontendC/2009-02-13-zerosize-union-field.c b/test/FrontendC/2009-02-13-zerosize-union-field.c index 044cbd5a5567..ad335583d46f 100644 --- a/test/FrontendC/2009-02-13-zerosize-union-field.c +++ b/test/FrontendC/2009-02-13-zerosize-union-field.c @@ -1,5 +1,6 @@ // RUN: %llvmgcc %s -m32 -S -o - | grep {i32 1} | count 1 // RUN: %llvmgcc %s -m32 -S -o - | grep {i32 4} | count 2 +// XFAIL: powerpc // Every printf has 'i32 0' for the GEP of the string; no point counting those. typedef unsigned int Foo __attribute__((aligned(32))); typedef union{Foo:0;}a; diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 7191d8035412..1273c25cd79e 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -2,7 +2,9 @@ # large and three small executables. This is done to minimize memory load # in parallel builds. Please retain this ordering. -if (NOT USE_EXPLICIT_DEPENDENCIES) +# FIXME: We don't yet have the ability to build llvm-config with CMake +# based on explicit dependencies. +if (FALSE) add_subdirectory(llvm-config) endif() diff --git a/tools/llvm-mc/AsmParser.cpp b/tools/llvm-mc/AsmParser.cpp index 9e8b3cf2effe..04c1d0301cbf 100644 --- a/tools/llvm-mc/AsmParser.cpp +++ b/tools/llvm-mc/AsmParser.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "AsmParser.h" +#include "llvm/MC/MCInst.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -49,182 +50,6 @@ void AsmParser::EatToEndOfStatement() { } -struct AsmParser::X86Operand { - enum { - Register, - Immediate, - Memory - } Kind; - - union { - struct { - unsigned RegNo; - } Reg; - - struct { - // FIXME: Should be a general expression. - int64_t Val; - } Imm; - - struct { - unsigned SegReg; - int64_t Disp; // FIXME: Should be a general expression. - unsigned BaseReg; - unsigned Scale; - unsigned ScaleReg; - } Mem; - }; - - static X86Operand CreateReg(unsigned RegNo) { - X86Operand Res; - Res.Kind = Register; - Res.Reg.RegNo = RegNo; - return Res; - } - static X86Operand CreateImm(int64_t Val) { - X86Operand Res; - Res.Kind = Immediate; - Res.Imm.Val = Val; - return Res; - } - static X86Operand CreateMem(unsigned SegReg, int64_t Disp, unsigned BaseReg, - unsigned Scale, unsigned ScaleReg) { - X86Operand Res; - Res.Kind = Memory; - Res.Mem.SegReg = SegReg; - Res.Mem.Disp = Disp; - Res.Mem.BaseReg = BaseReg; - Res.Mem.Scale = Scale; - Res.Mem.ScaleReg = ScaleReg; - return Res; - } -}; - -bool AsmParser::ParseX86Operand(X86Operand &Op) { - switch (Lexer.getKind()) { - default: - return ParseX86MemOperand(Op); - case asmtok::Register: - // FIXME: Decode reg #. - // FIXME: if a segment register, this could either be just the seg reg, or - // the start of a memory operand. - Op = X86Operand::CreateReg(123); - Lexer.Lex(); // Eat register. - return false; - case asmtok::Dollar: { - // $42 -> immediate. - Lexer.Lex(); - int64_t Val; - if (ParseExpression(Val)) - return TokError("expected integer constant"); - Op = X86Operand::CreateReg(Val); - return false; - case asmtok::Star: - Lexer.Lex(); // Eat the star. - - if (Lexer.is(asmtok::Register)) { - Op = X86Operand::CreateReg(123); - Lexer.Lex(); // Eat register. - } else if (ParseX86MemOperand(Op)) - return true; - - // FIXME: Note that these are 'dereferenced' so that clients know the '*' is - // there. - return false; - } - } -} - -/// ParseX86MemOperand: segment: disp(basereg, indexreg, scale) -bool AsmParser::ParseX86MemOperand(X86Operand &Op) { - // FIXME: If SegReg ':' (e.g. %gs:), eat and remember. - unsigned SegReg = 0; - - - // We have to disambiguate a parenthesized expression "(4+5)" from the start - // of a memory operand with a missing displacement "(%ebx)" or "(,%eax)". The - // only way to do this without lookahead is to eat the ( and see what is after - // it. - int64_t Disp = 0; - if (Lexer.isNot(asmtok::LParen)) { - if (ParseExpression(Disp)) return true; - - // After parsing the base expression we could either have a parenthesized - // memory address or not. If not, return now. If so, eat the (. - if (Lexer.isNot(asmtok::LParen)) { - Op = X86Operand::CreateMem(SegReg, Disp, 0, 0, 0); - return false; - } - - // Eat the '('. - Lexer.Lex(); - } else { - // Okay, we have a '('. We don't know if this is an expression or not, but - // so we have to eat the ( to see beyond it. - Lexer.Lex(); // Eat the '('. - - if (Lexer.is(asmtok::Register) || Lexer.is(asmtok::Comma)) { - // Nothing to do here, fall into the code below with the '(' part of the - // memory operand consumed. - } else { - // It must be an parenthesized expression, parse it now. - if (ParseParenExpr(Disp) || - ParseBinOpRHS(1, Disp)) - return true; - - // After parsing the base expression we could either have a parenthesized - // memory address or not. If not, return now. If so, eat the (. - if (Lexer.isNot(asmtok::LParen)) { - Op = X86Operand::CreateMem(SegReg, Disp, 0, 0, 0); - return false; - } - - // Eat the '('. - Lexer.Lex(); - } - } - - // If we reached here, then we just ate the ( of the memory operand. Process - // the rest of the memory operand. - unsigned BaseReg = 0, ScaleReg = 0, Scale = 0; - - if (Lexer.is(asmtok::Register)) { - BaseReg = 123; // FIXME: decode reg # - Lexer.Lex(); // eat the register. - } - - if (Lexer.is(asmtok::Comma)) { - Lexer.Lex(); // eat the comma. - - if (Lexer.is(asmtok::Register)) { - ScaleReg = 123; // FIXME: decode reg # - Lexer.Lex(); // eat the register. - Scale = 1; // If not specified, the scale defaults to 1. - } - - if (Lexer.is(asmtok::Comma)) { - Lexer.Lex(); // eat the comma. - - // If present, get and validate scale amount. - if (Lexer.is(asmtok::IntVal)) { - int64_t ScaleVal = Lexer.getCurIntVal(); - if (ScaleVal != 1 && ScaleVal != 2 && ScaleVal != 4 && ScaleVal != 8) - return TokError("scale factor in address must be 1, 2, 4 or 8"); - Lexer.Lex(); // eat the scale. - Scale = (unsigned)ScaleVal; - } - } - } - - // Ok, we've eaten the memory operand, verify we have a ')' and eat it too. - if (Lexer.isNot(asmtok::RParen)) - return TokError("unexpected token in memory operand"); - Lexer.Lex(); // Eat the ')'. - - Op = X86Operand::CreateMem(SegReg, Disp, BaseReg, Scale, ScaleReg); - return false; -} - /// ParseParenExpr - Parse a paren expression and return it. /// NOTE: This assumes the leading '(' has already been consumed. /// @@ -368,27 +193,10 @@ bool AsmParser::ParseStatement() { return false; } - // If it's an instruction, parse an operand list. - std::vector Operands; - - // Read the first operand, if present. Note that we require a newline at the - // end of file, so we don't have to worry about Eof here. - if (Lexer.isNot(asmtok::EndOfStatement)) { - X86Operand Op; - if (ParseX86Operand(Op)) - return true; - Operands.push_back(Op); - } - while (Lexer.is(asmtok::Comma)) { - Lexer.Lex(); // Eat the comma. - - // Parse and remember the operand. - X86Operand Op; - if (ParseX86Operand(Op)) - return true; - Operands.push_back(Op); - } + MCInst Inst; + if (ParseX86InstOperands(Inst)) + return true; if (Lexer.isNot(asmtok::EndOfStatement)) return TokError("unexpected token in operand list"); @@ -397,7 +205,7 @@ bool AsmParser::ParseStatement() { Lexer.Lex(); // Instruction is good, process it. - outs() << "Found instruction: " << IDVal << " with " << Operands.size() + outs() << "Found instruction: " << IDVal << " with " << Inst.getNumOperands() << " operands.\n"; // Skip to end of line for now. diff --git a/tools/llvm-mc/AsmParser.h b/tools/llvm-mc/AsmParser.h index 1dadb40ce2b8..c13334579b55 100644 --- a/tools/llvm-mc/AsmParser.h +++ b/tools/llvm-mc/AsmParser.h @@ -17,6 +17,7 @@ #include "AsmLexer.h" namespace llvm { +class MCInst; class AsmParser { AsmLexer Lexer; @@ -36,12 +37,15 @@ class AsmParser { void EatToEndOfStatement(); - bool ParseX86Operand(X86Operand &Op); - bool ParseX86MemOperand(X86Operand &Op); bool ParseExpression(int64_t &Res); bool ParsePrimaryExpr(int64_t &Res); bool ParseBinOpRHS(unsigned Precedence, int64_t &Res); bool ParseParenExpr(int64_t &Res); + + // X86 specific. + bool ParseX86InstOperands(MCInst &Inst); + bool ParseX86Operand(X86Operand &Op); + bool ParseX86MemOperand(X86Operand &Op); }; } // end namespace llvm diff --git a/tools/llvm-mc/CMakeLists.txt b/tools/llvm-mc/CMakeLists.txt index d8195e7418c3..369d52237067 100644 --- a/tools/llvm-mc/CMakeLists.txt +++ b/tools/llvm-mc/CMakeLists.txt @@ -4,4 +4,5 @@ add_llvm_tool(llvm-mc llvm-mc.cpp AsmLexer.cpp AsmParser.cpp + MC-X86Specific.cpp ) diff --git a/tools/llvm-mc/MC-X86Specific.cpp b/tools/llvm-mc/MC-X86Specific.cpp new file mode 100644 index 000000000000..45774cf48c8b --- /dev/null +++ b/tools/llvm-mc/MC-X86Specific.cpp @@ -0,0 +1,222 @@ +//===- MC-X86Specific.cpp - X86-Specific code for MC ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements X86-specific parsing, encoding and decoding stuff for +// MC. +// +//===----------------------------------------------------------------------===// + +#include "AsmParser.h" +#include "llvm/MC/MCInst.h" +using namespace llvm; + +/// X86Operand - Instances of this class represent one X86 machine instruction. +struct AsmParser::X86Operand { + enum { + Register, + Immediate, + Memory + } Kind; + + union { + struct { + unsigned RegNo; + } Reg; + + struct { + // FIXME: Should be a general expression. + int64_t Val; + } Imm; + + struct { + unsigned SegReg; + int64_t Disp; // FIXME: Should be a general expression. + unsigned BaseReg; + unsigned Scale; + unsigned ScaleReg; + } Mem; + }; + + static X86Operand CreateReg(unsigned RegNo) { + X86Operand Res; + Res.Kind = Register; + Res.Reg.RegNo = RegNo; + return Res; + } + static X86Operand CreateImm(int64_t Val) { + X86Operand Res; + Res.Kind = Immediate; + Res.Imm.Val = Val; + return Res; + } + static X86Operand CreateMem(unsigned SegReg, int64_t Disp, unsigned BaseReg, + unsigned Scale, unsigned ScaleReg) { + X86Operand Res; + Res.Kind = Memory; + Res.Mem.SegReg = SegReg; + Res.Mem.Disp = Disp; + Res.Mem.BaseReg = BaseReg; + Res.Mem.Scale = Scale; + Res.Mem.ScaleReg = ScaleReg; + return Res; + } + + void AddToMCInst(MCInst &I) { + // FIXME: Add in x86 order here. + } +}; + +bool AsmParser::ParseX86Operand(X86Operand &Op) { + switch (Lexer.getKind()) { + default: + return ParseX86MemOperand(Op); + case asmtok::Register: + // FIXME: Decode reg #. + // FIXME: if a segment register, this could either be just the seg reg, or + // the start of a memory operand. + Op = X86Operand::CreateReg(123); + Lexer.Lex(); // Eat register. + return false; + case asmtok::Dollar: { + // $42 -> immediate. + Lexer.Lex(); + int64_t Val; + if (ParseExpression(Val)) + return TokError("expected integer constant"); + Op = X86Operand::CreateReg(Val); + return false; + case asmtok::Star: + Lexer.Lex(); // Eat the star. + + if (Lexer.is(asmtok::Register)) { + Op = X86Operand::CreateReg(123); + Lexer.Lex(); // Eat register. + } else if (ParseX86MemOperand(Op)) + return true; + + // FIXME: Note that these are 'dereferenced' so that clients know the '*' is + // there. + return false; + } + } +} + +/// ParseX86MemOperand: segment: disp(basereg, indexreg, scale) +bool AsmParser::ParseX86MemOperand(X86Operand &Op) { + // FIXME: If SegReg ':' (e.g. %gs:), eat and remember. + unsigned SegReg = 0; + + // We have to disambiguate a parenthesized expression "(4+5)" from the start + // of a memory operand with a missing displacement "(%ebx)" or "(,%eax)". The + // only way to do this without lookahead is to eat the ( and see what is after + // it. + int64_t Disp = 0; + if (Lexer.isNot(asmtok::LParen)) { + if (ParseExpression(Disp)) return true; + + // After parsing the base expression we could either have a parenthesized + // memory address or not. If not, return now. If so, eat the (. + if (Lexer.isNot(asmtok::LParen)) { + Op = X86Operand::CreateMem(SegReg, Disp, 0, 0, 0); + return false; + } + + // Eat the '('. + Lexer.Lex(); + } else { + // Okay, we have a '('. We don't know if this is an expression or not, but + // so we have to eat the ( to see beyond it. + Lexer.Lex(); // Eat the '('. + + if (Lexer.is(asmtok::Register) || Lexer.is(asmtok::Comma)) { + // Nothing to do here, fall into the code below with the '(' part of the + // memory operand consumed. + } else { + // It must be an parenthesized expression, parse it now. + if (ParseParenExpr(Disp) || + ParseBinOpRHS(1, Disp)) + return true; + + // After parsing the base expression we could either have a parenthesized + // memory address or not. If not, return now. If so, eat the (. + if (Lexer.isNot(asmtok::LParen)) { + Op = X86Operand::CreateMem(SegReg, Disp, 0, 0, 0); + return false; + } + + // Eat the '('. + Lexer.Lex(); + } + } + + // If we reached here, then we just ate the ( of the memory operand. Process + // the rest of the memory operand. + unsigned BaseReg = 0, ScaleReg = 0, Scale = 0; + + if (Lexer.is(asmtok::Register)) { + BaseReg = 123; // FIXME: decode reg # + Lexer.Lex(); // eat the register. + } + + if (Lexer.is(asmtok::Comma)) { + Lexer.Lex(); // eat the comma. + + if (Lexer.is(asmtok::Register)) { + ScaleReg = 123; // FIXME: decode reg # + Lexer.Lex(); // eat the register. + Scale = 1; // If not specified, the scale defaults to 1. + } + + if (Lexer.is(asmtok::Comma)) { + Lexer.Lex(); // eat the comma. + + // If present, get and validate scale amount. + if (Lexer.is(asmtok::IntVal)) { + int64_t ScaleVal = Lexer.getCurIntVal(); + if (ScaleVal != 1 && ScaleVal != 2 && ScaleVal != 4 && ScaleVal != 8) + return TokError("scale factor in address must be 1, 2, 4 or 8"); + Lexer.Lex(); // eat the scale. + Scale = (unsigned)ScaleVal; + } + } + } + + // Ok, we've eaten the memory operand, verify we have a ')' and eat it too. + if (Lexer.isNot(asmtok::RParen)) + return TokError("unexpected token in memory operand"); + Lexer.Lex(); // Eat the ')'. + + Op = X86Operand::CreateMem(SegReg, Disp, BaseReg, Scale, ScaleReg); + return false; +} + +/// ParseX86InstOperands - Parse the operands of an X86 instruction and return +/// them as the operands of an MCInst. +bool AsmParser::ParseX86InstOperands(MCInst &Inst) { + // If no operands are present, just return. + if (Lexer.is(asmtok::EndOfStatement)) + return false; + + // Read the first operand. + X86Operand Op; + if (ParseX86Operand(Op)) + return true; + Op.AddToMCInst(Inst); + + while (Lexer.is(asmtok::Comma)) { + Lexer.Lex(); // Eat the comma. + + // Parse and remember the operand. + Op = X86Operand(); + if (ParseX86Operand(Op)) + return true; + Op.AddToMCInst(Inst); + } + return false; +}