Import LLVM r73984.
It seems I keep importing sources at very unlucky moments. Let's see what this revision of LLVM does.
This commit is contained in:
parent
0408e1d309
commit
f76359690a
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
@ -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:
|
||||
|
51
configure
vendored
51
configure
vendored
@ -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 <<EOF
|
||||
#line 10631 "configure"
|
||||
#line 10632 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -12772,7 +12773,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 12775 "configure"' > 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 <<EOF
|
||||
#line 17317 "configure"
|
||||
#line 17318 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -17414,7 +17415,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 17417 "configure"
|
||||
#line 17418 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -19782,11 +19783,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:19785: $lt_compile\"" >&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
|
||||
|
@ -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
|
||||
|
55
include/llvm/MC/MCImm.h
Normal file
55
include/llvm/MC/MCImm.h
Normal file
@ -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
|
@ -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);
|
||||
|
@ -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<Timer> TimersToPrint;
|
||||
public:
|
||||
TimerGroup() : Name("Miscellaneous Ungrouped Timers"), NumTimers(0) {}
|
||||
explicit TimerGroup(const std::string &name) : Name(name), NumTimers(0) {}
|
||||
~TimerGroup() {
|
||||
assert(NumTimers == 0 &&
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
add_partially_linked_object(LLVMExecutionEngine
|
||||
add_llvm_library(LLVMExecutionEngine
|
||||
ExecutionEngine.cpp
|
||||
ExecutionEngineBindings.cpp
|
||||
)
|
||||
|
@ -1,4 +1,4 @@
|
||||
add_partially_linked_object(LLVMInterpreter
|
||||
add_llvm_library(LLVMInterpreter
|
||||
Execution.cpp
|
||||
ExternalFunctions.cpp
|
||||
Interpreter.cpp
|
||||
|
@ -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
|
||||
|
@ -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 <algorithm>
|
||||
#include <fstream>
|
||||
@ -51,28 +50,37 @@ namespace {
|
||||
cl::Hidden, cl::location(getLibSupportInfoOutputFilename()));
|
||||
}
|
||||
|
||||
static ManagedStatic<sys::SmartMutex<true> > TimerLock;
|
||||
static ManagedStatic<TimerGroup> 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<true> 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<true> Lock(&*TimerLock);
|
||||
TG->addTimer();
|
||||
}
|
||||
|
||||
Timer::Timer(const Timer &T) {
|
||||
sys::SmartScopedLock<true> 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<true> 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<true> 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<std::vector<Timer*> > ActiveTimers;
|
||||
static ManagedStatic<sys::SmartMutex<true> > ActiveTimerLock;
|
||||
|
||||
void Timer::startTimer() {
|
||||
sys::SmartScopedLock<true> Lock(&*ActiveTimerLock);
|
||||
Started = true;
|
||||
ActiveTimers->push_back(this);
|
||||
TimeRecord TR = getTimeRecord(true);
|
||||
@ -150,7 +153,6 @@ void Timer::startTimer() {
|
||||
}
|
||||
|
||||
void Timer::stopTimer() {
|
||||
sys::SmartScopedLock<true> 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<true> Lock(&*ActiveTimerLock);
|
||||
size_t MemUsed = getMemUsage();
|
||||
|
||||
for (std::vector<Timer*>::iterator I = ActiveTimers->begin(),
|
||||
@ -203,10 +204,7 @@ static ManagedStatic<Name2Timer> NamedTimers;
|
||||
|
||||
static ManagedStatic<Name2Pair> NamedGroupedTimers;
|
||||
|
||||
static ManagedStatic<sys::SmartMutex<true> > NamedTimerLock;
|
||||
|
||||
static Timer &getNamedRegionTimer(const std::string &Name) {
|
||||
sys::SmartScopedLock<true> 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<true> 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";
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -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
|
||||
|
@ -751,6 +751,26 @@ class ThumbV5Pat<dag pattern, dag result> : Pat<pattern, result> {
|
||||
list<Predicate> Predicates = [IsThumb, HasV5T];
|
||||
}
|
||||
|
||||
// T2I - Thumb2 instruction.
|
||||
|
||||
class Thumb2I<dag outs, dag ins, AddrMode am, SizeFlagVal sz,
|
||||
string asm, string cstr, list<dag> pattern>
|
||||
: InstARM<am, sz, IndexModeNone, ThumbFrm, cstr> {
|
||||
let OutOperandList = outs;
|
||||
let InOperandList = ins;
|
||||
let AsmString = asm;
|
||||
let Pattern = pattern;
|
||||
list<Predicate> Predicates = [IsThumb, HasThumb2];
|
||||
}
|
||||
|
||||
class T2I<dag outs, dag ins, string asm, list<dag> pattern>
|
||||
: Thumb2I<outs, ins, AddrModeNone, Size4Bytes, asm, "", pattern>;
|
||||
|
||||
// Thumb2Pat - Same as Pat<>, but requires that the compiler be in Thumb2 mode.
|
||||
class Thumb2Pat<dag pattern, dag result> : Pat<pattern, result> {
|
||||
list<Predicate> Predicates = [IsThumb, HasThumb2];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -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()">;
|
||||
|
@ -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<i32>, // reg imm
|
||||
ComplexPattern<i32, 2, "SelectShifterOperand",
|
||||
ComplexPattern<i32, 2, "SelectThumb2ShifterOperandReg",
|
||||
[shl,srl,sra,rotr]> {
|
||||
let PrintMethod = "printSOOperand";
|
||||
let MIOperandInfo = (ops GPR, i32imm);
|
||||
}
|
||||
|
||||
def LO16 : SDNodeXForm<imm, [{
|
||||
// Transformation function: shift the immediate value down into the low bits.
|
||||
return getI32Imm((unsigned short)N->getZExtValue());
|
||||
// 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 : SDNodeXForm<imm, [{
|
||||
return CurDAG->getTargetConstant(
|
||||
ARM_AM::getT2SOImmVal(N->getZExtValue()), MVT::i32);
|
||||
}]>;
|
||||
|
||||
def HI16 : SDNodeXForm<imm, [{
|
||||
// Transformation function: shift the immediate value down into the low bits.
|
||||
return getI32Imm((unsigned)N->getZExtValue() >> 16);
|
||||
// t2_so_imm_not_XFORM - Return the complement of a t2_so_imm value
|
||||
def t2_so_imm_not_XFORM : SDNodeXForm<imm, [{
|
||||
return CurDAG->getTargetConstant(
|
||||
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 : SDNodeXForm<imm, [{
|
||||
return CurDAG->getTargetConstant(
|
||||
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<i32>,
|
||||
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<i32>,
|
||||
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<i32>,
|
||||
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 (#<const>)
|
||||
// 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<i32>,
|
||||
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 : SDNodeXForm<imm, [{
|
||||
return CurDAG->getTargetConstant((uint32_t)N->getZExtValue() & 0xffff,
|
||||
MVT::i32);
|
||||
}]>;
|
||||
|
||||
def t2_hi16 : SDNodeXForm<imm, [{
|
||||
return CurDAG->getTargetConstant((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<string opc, PatFrag opnode> {
|
||||
multiclass T2I_bin_is<string opc, PatFrag opnode> {
|
||||
// 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<string opc, PatFrag opnode> {
|
||||
// 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<string opc, PatFrag opnode> {
|
||||
multiclass T2I_bin_s_is<string opc, PatFrag opnode> {
|
||||
// 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<string opc, PatFrag opnode> {
|
||||
// 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<string opc, PatFrag opnode> {
|
||||
// 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<string opc, PatFrag opnode> {
|
||||
multiclass T2I_bin_c_is<string opc, PatFrag opnode> {
|
||||
// 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<string opc, PatFrag opnode> {
|
||||
// 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<string opc, PatFrag opnode> {
|
||||
// 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<string opc, PatFrag opnode> {
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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))>;
|
||||
|
@ -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);
|
||||
|
@ -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})
|
||||
|
@ -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})
|
||||
|
@ -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})
|
||||
|
@ -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})
|
||||
|
@ -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})
|
||||
|
@ -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})
|
||||
|
@ -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})
|
||||
|
@ -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})
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
14
test/FrontendC/2009-02-13-zerosize-union-field-ppc.c
Normal file
14
test/FrontendC/2009-02-13-zerosize-union-field-ppc.c
Normal file
@ -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));
|
||||
}
|
@ -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;
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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<X86Operand> 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.
|
||||
|
@ -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
|
||||
|
@ -4,4 +4,5 @@ add_llvm_tool(llvm-mc
|
||||
llvm-mc.cpp
|
||||
AsmLexer.cpp
|
||||
AsmParser.cpp
|
||||
MC-X86Specific.cpp
|
||||
)
|
||||
|
222
tools/llvm-mc/MC-X86Specific.cpp
Normal file
222
tools/llvm-mc/MC-X86Specific.cpp
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user