diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2010-03-16 16:51:38 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2010-03-16 16:51:38 +0000 |
commit | c69102774f9739c81ae1285ed9ae62405071c63c (patch) | |
tree | 458dd25677a43aef6390ecadb4423817f00e08b0 | |
parent | ea5b2dd11c0526581803e7eb58224a2eabf191e6 (diff) | |
download | src-c69102774f9739c81ae1285ed9ae62405071c63c.tar.gz src-c69102774f9739c81ae1285ed9ae62405071c63c.zip |
Update LLVM to r98631.
Notes
Notes:
svn path=/vendor/llvm/dist/; revision=205218
414 files changed, 14628 insertions, 4899 deletions
diff --git a/Makefile.rules b/Makefile.rules index fcddd50c3a28..20e642a4505b 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -1329,7 +1329,7 @@ uninstall-local:: # TOOLALIAS install. ifdef TOOLALIAS -DestToolAlias = $(PROJ_bindir)/$(TOOLALIAS)$(EXEEXT) +DestToolAlias = $(DESTDIR)$(PROJ_bindir)/$(TOOLALIAS)$(EXEEXT) install-local:: $(DestToolAlias) diff --git a/autoconf/configure.ac b/autoconf/configure.ac index a5cb788b2a90..22f15b7feb01 100644 --- a/autoconf/configure.ac +++ b/autoconf/configure.ac @@ -1210,6 +1210,7 @@ AC_CHECK_HEADERS([malloc.h setjmp.h signal.h stdint.h termios.h unistd.h]) AC_CHECK_HEADERS([utime.h windows.h]) AC_CHECK_HEADERS([sys/mman.h sys/param.h sys/resource.h sys/time.h]) AC_CHECK_HEADERS([sys/types.h sys/ioctl.h malloc/malloc.h mach/mach.h]) +AC_CHECK_HEADERS([valgrind/valgrind.h]) if test "$ENABLE_THREADS" -eq 1 ; then AC_CHECK_HEADERS(pthread.h, AC_SUBST(HAVE_PTHREAD, 1), diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 3a2b91cc33cf..e72560bcef19 100755 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -67,6 +67,7 @@ check_include_file(sys/wait.h HAVE_SYS_WAIT_H) check_include_file(termios.h HAVE_TERMIOS_H) check_include_file(unistd.h HAVE_UNISTD_H) check_include_file(utime.h HAVE_UTIME_H) +check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H) check_include_file(windows.h HAVE_WINDOWS_H) # library checks diff --git a/cmake/modules/LLVMLibDeps.cmake b/cmake/modules/LLVMLibDeps.cmake index e1c470fea688..c9798485dec6 100644 --- a/cmake/modules/LLVMLibDeps.cmake +++ b/cmake/modules/LLVMLibDeps.cmake @@ -1,8 +1,8 @@ set(MSVC_LIB_DEPS_LLVMARMAsmParser LLVMARMInfo LLVMMCParser LLVMSupport) -set(MSVC_LIB_DEPS_LLVMARMAsmPrinter LLVMARMCodeGen LLVMARMInfo LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMARMAsmPrinter LLVMARMCodeGen LLVMARMInfo LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMARMCodeGen LLVMARMInfo LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMARMInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMAlphaAsmPrinter LLVMAlphaInfo LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMAlphaAsmPrinter LLVMAlphaInfo LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMAlphaCodeGen LLVMAlphaInfo LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMAlphaInfo LLVMSupport) set(MSVC_LIB_DEPS_LLVMAnalysis LLVMCore LLVMSupport LLVMSystem LLVMTarget) @@ -11,12 +11,12 @@ set(MSVC_LIB_DEPS_LLVMAsmParser LLVMCore LLVMSupport) set(MSVC_LIB_DEPS_LLVMAsmPrinter LLVMAnalysis LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMBitReader LLVMCore LLVMSupport) set(MSVC_LIB_DEPS_LLVMBitWriter LLVMCore LLVMSupport LLVMSystem) -set(MSVC_LIB_DEPS_LLVMBlackfinAsmPrinter LLVMAsmPrinter LLVMBlackfinInfo LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMBlackfinAsmPrinter LLVMAsmPrinter LLVMBlackfinInfo LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMBlackfinCodeGen LLVMBlackfinInfo LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMBlackfinInfo LLVMSupport) set(MSVC_LIB_DEPS_LLVMCBackend LLVMAnalysis LLVMCBackendInfo LLVMCodeGen LLVMCore LLVMMC LLVMScalarOpts LLVMSupport LLVMSystem LLVMTarget LLVMTransformUtils LLVMipa) set(MSVC_LIB_DEPS_LLVMCBackendInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMCellSPUAsmPrinter LLVMAsmPrinter LLVMCellSPUInfo LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMCellSPUAsmPrinter LLVMAsmPrinter LLVMCellSPUInfo LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMCellSPUCodeGen LLVMCellSPUInfo LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMCellSPUInfo LLVMSupport) set(MSVC_LIB_DEPS_LLVMCodeGen LLVMAnalysis LLVMCore LLVMMC LLVMScalarOpts LLVMSupport LLVMSystem LLVMTarget LLVMTransformUtils) @@ -29,41 +29,44 @@ set(MSVC_LIB_DEPS_LLVMInstrumentation LLVMAnalysis LLVMCore LLVMSupport LLVMSyst set(MSVC_LIB_DEPS_LLVMInterpreter LLVMCodeGen LLVMCore LLVMExecutionEngine LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMJIT LLVMAnalysis LLVMCodeGen LLVMCore LLVMExecutionEngine LLVMMC LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMLinker LLVMArchive LLVMBitReader LLVMCore LLVMSupport LLVMSystem) +set(MSVC_LIB_DEPS_LLVMMBlazeAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMBlazeCodeGen LLVMMBlazeInfo LLVMMC LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMMBlazeCodeGen LLVMCodeGen LLVMCore LLVMMBlazeInfo LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMMBlazeInfo LLVMSupport) set(MSVC_LIB_DEPS_LLVMMC LLVMSupport LLVMSystem) set(MSVC_LIB_DEPS_LLVMMCParser LLVMMC LLVMSupport) set(MSVC_LIB_DEPS_LLVMMSIL LLVMAnalysis LLVMCodeGen LLVMCore LLVMMSILInfo LLVMScalarOpts LLVMSupport LLVMTarget LLVMTransformUtils LLVMipa) set(MSVC_LIB_DEPS_LLVMMSILInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMMSP430AsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMMSP430Info LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMMSP430AsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMMSP430Info LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMMSP430CodeGen LLVMCodeGen LLVMCore LLVMMC LLVMMSP430Info LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMMSP430Info LLVMSupport) -set(MSVC_LIB_DEPS_LLVMMipsAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMMipsCodeGen LLVMMipsInfo LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMMipsAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMMipsCodeGen LLVMMipsInfo LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMMipsCodeGen LLVMCodeGen LLVMCore LLVMMC LLVMMipsInfo LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMMipsInfo LLVMSupport) set(MSVC_LIB_DEPS_LLVMPIC16 LLVMAnalysis LLVMCodeGen LLVMCore LLVMMC LLVMPIC16Info LLVMSelectionDAG LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMPIC16AsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMPIC16 LLVMPIC16Info LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMPIC16Info LLVMSupport) -set(MSVC_LIB_DEPS_LLVMPowerPCAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMPowerPCInfo LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMPowerPCAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMPowerPCInfo LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMPowerPCCodeGen LLVMCodeGen LLVMCore LLVMMC LLVMPowerPCInfo LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMPowerPCInfo LLVMSupport) set(MSVC_LIB_DEPS_LLVMScalarOpts LLVMAnalysis LLVMCore LLVMInstCombine LLVMSupport LLVMSystem LLVMTarget LLVMTransformUtils) -set(MSVC_LIB_DEPS_LLVMSelectionDAG LLVMAnalysis LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMSparcAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSparcInfo LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMSelectionDAG LLVMAnalysis LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMSparcAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSparcInfo LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMSparcCodeGen LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSparcInfo LLVMSupport LLVMSystem LLVMTarget) set(MSVC_LIB_DEPS_LLVMSparcInfo LLVMSupport) set(MSVC_LIB_DEPS_LLVMSupport LLVMSystem) set(MSVC_LIB_DEPS_LLVMSystem ) -set(MSVC_LIB_DEPS_LLVMSystemZAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystem LLVMSystemZInfo LLVMTarget) +set(MSVC_LIB_DEPS_LLVMSystemZAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystemZInfo LLVMTarget) set(MSVC_LIB_DEPS_LLVMSystemZCodeGen LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystemZInfo LLVMTarget) set(MSVC_LIB_DEPS_LLVMSystemZInfo LLVMSupport) set(MSVC_LIB_DEPS_LLVMTarget LLVMCore LLVMMC LLVMSupport) set(MSVC_LIB_DEPS_LLVMTransformUtils LLVMAnalysis LLVMCore LLVMSupport LLVMSystem LLVMTarget LLVMipa) -set(MSVC_LIB_DEPS_LLVMX86AsmParser LLVMMC LLVMMCParser LLVMSupport LLVMX86Info) -set(MSVC_LIB_DEPS_LLVMX86AsmPrinter LLVMAnalysis LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystem LLVMTarget LLVMX86CodeGen LLVMX86Info) +set(MSVC_LIB_DEPS_LLVMX86AsmParser LLVMMC LLVMMCParser LLVMSupport LLVMTarget LLVMX86Info) +set(MSVC_LIB_DEPS_LLVMX86AsmPrinter LLVMAnalysis LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget LLVMX86CodeGen LLVMX86Info) set(MSVC_LIB_DEPS_LLVMX86CodeGen LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget LLVMX86Info) set(MSVC_LIB_DEPS_LLVMX86Disassembler LLVMMC LLVMSupport LLVMX86Info) set(MSVC_LIB_DEPS_LLVMX86Info LLVMSupport) set(MSVC_LIB_DEPS_LLVMXCore LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget LLVMXCoreInfo) -set(MSVC_LIB_DEPS_LLVMXCoreAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystem LLVMTarget LLVMXCoreInfo) +set(MSVC_LIB_DEPS_LLVMXCoreAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget LLVMXCoreInfo) set(MSVC_LIB_DEPS_LLVMXCoreInfo LLVMSupport) set(MSVC_LIB_DEPS_LLVMipa LLVMAnalysis LLVMCore LLVMSupport LLVMSystem) set(MSVC_LIB_DEPS_LLVMipo LLVMAnalysis LLVMCore LLVMSupport LLVMSystem LLVMTarget LLVMTransformUtils LLVMipa) diff --git a/configure b/configure index 2b597a12dbba..175297e543cd 100755 --- a/configure +++ b/configure @@ -16177,6 +16177,175 @@ fi done + +for ac_header in valgrind/valgrind.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ----------------------------------- ## +## Report this to llvmbugs@cs.uiuc.edu ## +## ----------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + if test "$ENABLE_THREADS" -eq 1 ; then for ac_header in pthread.h diff --git a/docs/CodeGenerator.html b/docs/CodeGenerator.html index dcfe7941c556..c8a0cd59721b 100644 --- a/docs/CodeGenerator.html +++ b/docs/CodeGenerator.html @@ -1679,7 +1679,8 @@ $ llc -regalloc=linearscan file.bc -o ln.s; supported on x86/x86-64 and PowerPC. It is performed if:</p> <ul> - <li>Caller and callee have the calling convention <tt>fastcc</tt>.</li> + <li>Caller and callee have the calling convention <tt>fastcc</tt> or + <tt>cc 10</tt> (GHC call convention).</li> <li>The call is a tail call - in tail position (ret immediately follows call and ret uses value of call or is void).</li> @@ -2161,7 +2162,7 @@ MOVSX32rm16 -> movsx, 32-bit register, 16-bit memory <a href="mailto:sabre@nondot.org">Chris Lattner</a><br> <a href="http://llvm.org">The LLVM Compiler Infrastructure</a><br> - Last modified: $Date: 2010-03-08 22:05:02 +0100 (Mon, 08 Mar 2010) $ + Last modified: $Date: 2010-03-11 01:22:57 +0100 (Thu, 11 Mar 2010) $ </address> </body> diff --git a/docs/LangRef.html b/docs/LangRef.html index f1abdb5c2ca8..04eb45d59805 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -255,6 +255,12 @@ <li><a href="#int_umul_overflow">'<tt>llvm.umul.with.overflow.*</tt> Intrinsics</a></li> </ol> </li> + <li><a href="#int_fp16">Half Precision Floating Point Intrinsics</a> + <ol> + <li><a href="#int_convert_to_fp16">'<tt>llvm.convert.to.fp16</tt>' Intrinsic</a></li> + <li><a href="#int_convert_from_fp16">'<tt>llvm.convert.from.fp16</tt>' Intrinsic</a></li> + </ol> + </li> <li><a href="#int_debugger">Debugger intrinsics</a></li> <li><a href="#int_eh">Exception Handling intrinsics</a></li> <li><a href="#int_trampoline">Trampoline Intrinsic</a> @@ -691,9 +697,9 @@ define i32 @main() { <i>; i32()* </i> target, without having to conform to an externally specified ABI (Application Binary Interface). <a href="CodeGenerator.html#tailcallopt">Tail calls can only be optimized - when this convention is used.</a> This calling convention does not - support varargs and requires the prototype of all callees to exactly match - the prototype of the function definition.</dd> + when this or the GHC convention is used.</a> This calling convention + does not support varargs and requires the prototype of all callees to + exactly match the prototype of the function definition.</dd> <dt><b>"<tt>coldcc</tt>" - The cold calling convention</b>:</dt> <dd>This calling convention attempts to make code in the caller as efficient @@ -703,6 +709,26 @@ define i32 @main() { <i>; i32()* </i> does not support varargs and requires the prototype of all callees to exactly match the prototype of the function definition.</dd> + <dt><b>"<tt>cc <em>10</em></tt>" - GHC convention</b>:</dt> + <dd>This calling convention has been implemented specifically for use by the + <a href="http://www.haskell.org/ghc">Glasgow Haskell Compiler (GHC)</a>. + It passes everything in registers, going to extremes to achieve this by + disabling callee save registers. This calling convention should not be + used lightly but only for specific situations such as an alternative to + the <em>register pinning</em> performance technique often used when + implementing functional programming languages.At the moment only X86 + supports this convention and it has the following limitations: + <ul> + <li>On <em>X86-32</em> only supports up to 4 bit type parameters. No + floating point types are supported.</li> + <li>On <em>X86-64</em> only supports up to 10 bit type parameters and + 6 floating point parameters.</li> + </ul> + This calling convention supports + <a href="CodeGenerator.html#tailcallopt">tail call optimization</a> but + requires both the caller and callee are using it. + </dd> + <dt><b>"<tt>cc <<em>n</em>></tt>" - Numbered convention</b>:</dt> <dd>Any calling convention may be specified by number, allowing target-specific calling conventions to be used. Target specific calling @@ -6588,6 +6614,97 @@ LLVM</a>.</p> <!-- ======================================================================= --> <div class="doc_subsection"> + <a name="int_fp16">Half Precision Floating Point Intrinsics</a> +</div> + +<div class="doc_text"> + +<p>Half precision floating point is a storage-only format. This means that it is + a dense encoding (in memory) but does not support computation in the + format.</p> + +<p>This means that code must first load the half-precision floating point + value as an i16, then convert it to float with <a + href="#int_convert_from_fp16"><tt>llvm.convert.from.fp16</tt></a>. + Computation can then be performed on the float value (including extending to + double etc). To store the value back to memory, it is first converted to + float if needed, then converted to i16 with + <a href="#int_convert_to_fp16"><tt>llvm.convert.to.fp16</tt></a>, then + storing as an i16 value.</p> +</div> + +<!-- _______________________________________________________________________ --> +<div class="doc_subsubsection"> + <a name="int_convert_to_fp16">'<tt>llvm.convert.to.fp16</tt>' Intrinsic</a> +</div> + +<div class="doc_text"> + +<h5>Syntax:</h5> +<pre> + declare i16 @llvm.convert.to.fp16(f32 %a) +</pre> + +<h5>Overview:</h5> +<p>The '<tt>llvm.convert.to.fp16</tt>' intrinsic function performs + a conversion from single precision floating point format to half precision + floating point format.</p> + +<h5>Arguments:</h5> +<p>The intrinsic function contains single argument - the value to be + converted.</p> + +<h5>Semantics:</h5> +<p>The '<tt>llvm.convert.to.fp16</tt>' intrinsic function performs + a conversion from single precision floating point format to half precision + floating point format. The return value is an <tt>i16</tt> which + contains the converted number.</p> + +<h5>Examples:</h5> +<pre> + %res = call i16 @llvm.convert.to.fp16(f32 %a) + store i16 %res, i16* @x, align 2 +</pre> + +</div> + +<!-- _______________________________________________________________________ --> +<div class="doc_subsubsection"> + <a name="int_convert_from_fp16">'<tt>llvm.convert.from.fp16</tt>' Intrinsic</a> +</div> + +<div class="doc_text"> + +<h5>Syntax:</h5> +<pre> + declare f32 @llvm.convert.from.fp16(i16 %a) +</pre> + +<h5>Overview:</h5> +<p>The '<tt>llvm.convert.from.fp16</tt>' intrinsic function performs + a conversion from half precision floating point format to single precision + floating point format.</p> + +<h5>Arguments:</h5> +<p>The intrinsic function contains single argument - the value to be + converted.</p> + +<h5>Semantics:</h5> +<p>The '<tt>llvm.convert.from.fp16</tt>' intrinsic function performs a + conversion from half single precision floating point format to single + precision floating point format. The input half-float value is represented by + an <tt>i16</tt> value.</p> + +<h5>Examples:</h5> +<pre> + %a = load i16* @x, align 2 + %res = call f32 @llvm.convert.from.fp16(i16 %a) +</pre> + +</div> + +<!-- ======================================================================= --> +<div class="doc_subsection"> <a name="int_debugger">Debugger Intrinsics</a> </div> @@ -7473,7 +7590,7 @@ LLVM</a>.</p> <a href="mailto:sabre@nondot.org">Chris Lattner</a><br> <a href="http://llvm.org">The LLVM Compiler Infrastructure</a><br> - Last modified: $Date: 2010-03-08 22:05:02 +0100 (Mon, 08 Mar 2010) $ + Last modified: $Date: 2010-03-15 05:12:21 +0100 (Mon, 15 Mar 2010) $ </address> </body> diff --git a/examples/OCaml-Kaleidoscope/Chapter2/Makefile b/examples/OCaml-Kaleidoscope/Chapter2/Makefile new file mode 100644 index 000000000000..8fc03da0fbd4 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter2/Makefile @@ -0,0 +1,22 @@ +##===- examples/OCaml-Kaleidoscope/Chapter2/Makefile -------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 2. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../../.. +TOOLNAME := OCaml-Kaleidoscope-Ch2 +EXAMPLE_TOOL := 1 +UsedComponents := core +UsedOcamLibs := llvm + +OCAMLCFLAGS += -pp camlp4of + +include $(LEVEL)/bindings/ocaml/Makefile.ocaml diff --git a/examples/OCaml-Kaleidoscope/Chapter2/_tags b/examples/OCaml-Kaleidoscope/Chapter2/_tags new file mode 100644 index 000000000000..7b9b80b1e949 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter2/_tags @@ -0,0 +1 @@ +<{lexer,parser}.ml>: use_camlp4, pp(camlp4of) diff --git a/examples/OCaml-Kaleidoscope/Chapter2/ast.ml b/examples/OCaml-Kaleidoscope/Chapter2/ast.ml new file mode 100644 index 000000000000..4cc2dea86b78 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter2/ast.ml @@ -0,0 +1,25 @@ +(*===----------------------------------------------------------------------=== + * Abstract Syntax Tree (aka Parse Tree) + *===----------------------------------------------------------------------===*) + +(* expr - Base type for all expression nodes. *) +type expr = + (* variant for numeric literals like "1.0". *) + | Number of float + + (* variant for referencing a variable, like "a". *) + | Variable of string + + (* variant for a binary operator. *) + | Binary of char * expr * expr + + (* variant for function calls. *) + | Call of string * expr array + +(* proto - This type represents the "prototype" for a function, which captures + * its name, and its argument names (thus implicitly the number of arguments the + * function takes). *) +type proto = Prototype of string * string array + +(* func - This type represents a function definition itself. *) +type func = Function of proto * expr diff --git a/examples/OCaml-Kaleidoscope/Chapter2/lexer.ml b/examples/OCaml-Kaleidoscope/Chapter2/lexer.ml new file mode 100644 index 000000000000..22a915552f03 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter2/lexer.ml @@ -0,0 +1,52 @@ +(*===----------------------------------------------------------------------=== + * Lexer + *===----------------------------------------------------------------------===*) + +let rec lex = parser + (* Skip any whitespace. *) + | [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream + + (* identifier: [a-zA-Z][a-zA-Z0-9] *) + | [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_ident buffer stream + + (* number: [0-9.]+ *) + | [< ' ('0' .. '9' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_number buffer stream + + (* Comment until end of line. *) + | [< ' ('#'); stream >] -> + lex_comment stream + + (* Otherwise, just return the character as its ascii value. *) + | [< 'c; stream >] -> + [< 'Token.Kwd c; lex stream >] + + (* end of stream. *) + | [< >] -> [< >] + +and lex_number buffer = parser + | [< ' ('0' .. '9' | '.' as c); stream >] -> + Buffer.add_char buffer c; + lex_number buffer stream + | [< stream=lex >] -> + [< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >] + +and lex_ident buffer = parser + | [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] -> + Buffer.add_char buffer c; + lex_ident buffer stream + | [< stream=lex >] -> + match Buffer.contents buffer with + | "def" -> [< 'Token.Def; stream >] + | "extern" -> [< 'Token.Extern; stream >] + | id -> [< 'Token.Ident id; stream >] + +and lex_comment = parser + | [< ' ('\n'); stream=lex >] -> stream + | [< 'c; e=lex_comment >] -> e + | [< >] -> [< >] diff --git a/examples/OCaml-Kaleidoscope/Chapter2/parser.ml b/examples/OCaml-Kaleidoscope/Chapter2/parser.ml new file mode 100644 index 000000000000..83d9874a4ab6 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter2/parser.ml @@ -0,0 +1,122 @@ +(*===---------------------------------------------------------------------=== + * Parser + *===---------------------------------------------------------------------===*) + +(* binop_precedence - This holds the precedence for each binary operator that is + * defined *) +let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10 + +(* precedence - Get the precedence of the pending binary operator token. *) +let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1 + +(* primary + * ::= identifier + * ::= numberexpr + * ::= parenexpr *) +let rec parse_primary = parser + (* numberexpr ::= number *) + | [< 'Token.Number n >] -> Ast.Number n + + (* parenexpr ::= '(' expression ')' *) + | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e + + (* identifierexpr + * ::= identifier + * ::= identifier '(' argumentexpr ')' *) + | [< 'Token.Ident id; stream >] -> + let rec parse_args accumulator = parser + | [< e=parse_expr; stream >] -> + begin parser + | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e + | [< >] -> e :: accumulator + end stream + | [< >] -> accumulator + in + let rec parse_ident id = parser + (* Call. *) + | [< 'Token.Kwd '('; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')'">] -> + Ast.Call (id, Array.of_list (List.rev args)) + + (* Simple variable ref. *) + | [< >] -> Ast.Variable id + in + parse_ident id stream + + | [< >] -> raise (Stream.Error "unknown token when expecting an expression.") + +(* binoprhs + * ::= ('+' primary)* *) +and parse_bin_rhs expr_prec lhs stream = + match Stream.peek stream with + (* If this is a binop, find its precedence. *) + | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c -> + let token_prec = precedence c in + + (* If this is a binop that binds at least as tightly as the current binop, + * consume it, otherwise we are done. *) + if token_prec < expr_prec then lhs else begin + (* Eat the binop. *) + Stream.junk stream; + + (* Parse the primary expression after the binary operator. *) + let rhs = parse_primary stream in + + (* Okay, we know this is a binop. *) + let rhs = + match Stream.peek stream with + | Some (Token.Kwd c2) -> + (* If BinOp binds less tightly with rhs than the operator after + * rhs, let the pending operator take rhs as its lhs. *) + let next_prec = precedence c2 in + if token_prec < next_prec + then parse_bin_rhs (token_prec + 1) rhs stream + else rhs + | _ -> rhs + in + + (* Merge lhs/rhs. *) + let lhs = Ast.Binary (c, lhs, rhs) in + parse_bin_rhs expr_prec lhs stream + end + | _ -> lhs + +(* expression + * ::= primary binoprhs *) +and parse_expr = parser + | [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream + +(* prototype + * ::= id '(' id* ')' *) +let parse_prototype = + let rec parse_args accumulator = parser + | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e + | [< >] -> accumulator + in + + parser + | [< 'Token.Ident id; + 'Token.Kwd '(' ?? "expected '(' in prototype"; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')' in prototype" >] -> + (* success. *) + Ast.Prototype (id, Array.of_list (List.rev args)) + + | [< >] -> + raise (Stream.Error "expected function name in prototype") + +(* definition ::= 'def' prototype expression *) +let parse_definition = parser + | [< 'Token.Def; p=parse_prototype; e=parse_expr >] -> + Ast.Function (p, e) + +(* toplevelexpr ::= expression *) +let parse_toplevel = parser + | [< e=parse_expr >] -> + (* Make an anonymous proto. *) + Ast.Function (Ast.Prototype ("", [||]), e) + +(* external ::= 'extern' prototype *) +let parse_extern = parser + | [< 'Token.Extern; e=parse_prototype >] -> e diff --git a/examples/OCaml-Kaleidoscope/Chapter2/token.ml b/examples/OCaml-Kaleidoscope/Chapter2/token.ml new file mode 100644 index 000000000000..2ca782e14997 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter2/token.ml @@ -0,0 +1,15 @@ +(*===----------------------------------------------------------------------=== + * Lexer Tokens + *===----------------------------------------------------------------------===*) + +(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of + * these others for known things. *) +type token = + (* commands *) + | Def | Extern + + (* primary *) + | Ident of string | Number of float + + (* unknown *) + | Kwd of char diff --git a/examples/OCaml-Kaleidoscope/Chapter2/toplevel.ml b/examples/OCaml-Kaleidoscope/Chapter2/toplevel.ml new file mode 100644 index 000000000000..01c85bd70d29 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter2/toplevel.ml @@ -0,0 +1,34 @@ +(*===----------------------------------------------------------------------=== + * Top-Level parsing and JIT Driver + *===----------------------------------------------------------------------===*) + +(* top ::= definition | external | expression | ';' *) +let rec main_loop stream = + match Stream.peek stream with + | None -> () + + (* ignore top-level semicolons. *) + | Some (Token.Kwd ';') -> + Stream.junk stream; + main_loop stream + + | Some token -> + begin + try match token with + | Token.Def -> + ignore(Parser.parse_definition stream); + print_endline "parsed a function definition."; + | Token.Extern -> + ignore(Parser.parse_extern stream); + print_endline "parsed an extern."; + | _ -> + (* Evaluate a top-level expression into an anonymous function. *) + ignore(Parser.parse_toplevel stream); + print_endline "parsed a top-level expr"; + with Stream.Error s -> + (* Skip token for error recovery. *) + Stream.junk stream; + print_endline s; + end; + print_string "ready> "; flush stdout; + main_loop stream diff --git a/examples/OCaml-Kaleidoscope/Chapter2/toy.ml b/examples/OCaml-Kaleidoscope/Chapter2/toy.ml new file mode 100644 index 000000000000..42b19fec0019 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter2/toy.ml @@ -0,0 +1,21 @@ +(*===----------------------------------------------------------------------=== + * Main driver code. + *===----------------------------------------------------------------------===*) + +let main () = + (* Install standard binary operators. + * 1 is the lowest precedence. *) + Hashtbl.add Parser.binop_precedence '<' 10; + Hashtbl.add Parser.binop_precedence '+' 20; + Hashtbl.add Parser.binop_precedence '-' 20; + Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *) + + (* Prime the first token. *) + print_string "ready> "; flush stdout; + let stream = Lexer.lex (Stream.of_channel stdin) in + + (* Run the main "interpreter loop" now. *) + Toplevel.main_loop stream; +;; + +main () diff --git a/examples/OCaml-Kaleidoscope/Chapter3/Makefile b/examples/OCaml-Kaleidoscope/Chapter3/Makefile new file mode 100644 index 000000000000..fdbcd5191f40 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter3/Makefile @@ -0,0 +1,24 @@ +##===- examples/OCaml-Kaleidoscope/Chapter3/Makefile -------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 3. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../../.. +TOOLNAME := OCaml-Kaleidoscope-Ch3 +EXAMPLE_TOOL := 1 +UsedComponents := core +UsedOcamLibs := llvm llvm_analysis + +OCAMLCFLAGS += -pp camlp4of + +ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml + +include $(LEVEL)/bindings/ocaml/Makefile.ocaml diff --git a/examples/OCaml-Kaleidoscope/Chapter3/_tags b/examples/OCaml-Kaleidoscope/Chapter3/_tags new file mode 100644 index 000000000000..990490a5db25 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter3/_tags @@ -0,0 +1,2 @@ +<{lexer,parser}.ml>: use_camlp4, pp(camlp4of) +<*.{byte,native}>: g++, use_llvm, use_llvm_analysis diff --git a/examples/OCaml-Kaleidoscope/Chapter3/ast.ml b/examples/OCaml-Kaleidoscope/Chapter3/ast.ml new file mode 100644 index 000000000000..4cc2dea86b78 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter3/ast.ml @@ -0,0 +1,25 @@ +(*===----------------------------------------------------------------------=== + * Abstract Syntax Tree (aka Parse Tree) + *===----------------------------------------------------------------------===*) + +(* expr - Base type for all expression nodes. *) +type expr = + (* variant for numeric literals like "1.0". *) + | Number of float + + (* variant for referencing a variable, like "a". *) + | Variable of string + + (* variant for a binary operator. *) + | Binary of char * expr * expr + + (* variant for function calls. *) + | Call of string * expr array + +(* proto - This type represents the "prototype" for a function, which captures + * its name, and its argument names (thus implicitly the number of arguments the + * function takes). *) +type proto = Prototype of string * string array + +(* func - This type represents a function definition itself. *) +type func = Function of proto * expr diff --git a/examples/OCaml-Kaleidoscope/Chapter3/codegen.ml b/examples/OCaml-Kaleidoscope/Chapter3/codegen.ml new file mode 100644 index 000000000000..275cd0bee041 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter3/codegen.ml @@ -0,0 +1,100 @@ +(*===----------------------------------------------------------------------=== + * Code Generation + *===----------------------------------------------------------------------===*) + +open Llvm + +exception Error of string + +let context = global_context () +let the_module = create_module context "my cool jit" +let builder = builder context +let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10 +let double_type = double_type context + +let rec codegen_expr = function + | Ast.Number n -> const_float double_type n + | Ast.Variable name -> + (try Hashtbl.find named_values name with + | Not_found -> raise (Error "unknown variable name")) + | Ast.Binary (op, lhs, rhs) -> + let lhs_val = codegen_expr lhs in + let rhs_val = codegen_expr rhs in + begin + match op with + | '+' -> build_add lhs_val rhs_val "addtmp" builder + | '-' -> build_sub lhs_val rhs_val "subtmp" builder + | '*' -> build_mul lhs_val rhs_val "multmp" builder + | '<' -> + (* Convert bool 0/1 to double 0.0 or 1.0 *) + let i = build_fcmp Fcmp.Ult lhs_val rhs_val "cmptmp" builder in + build_uitofp i double_type "booltmp" builder + | _ -> raise (Error "invalid binary operator") + end + | Ast.Call (callee, args) -> + (* Look up the name in the module table. *) + let callee = + match lookup_function callee the_module with + | Some callee -> callee + | None -> raise (Error "unknown function referenced") + in + let params = params callee in + + (* If argument mismatch error. *) + if Array.length params == Array.length args then () else + raise (Error "incorrect # arguments passed"); + let args = Array.map codegen_expr args in + build_call callee args "calltmp" builder + +let codegen_proto = function + | Ast.Prototype (name, args) -> + (* Make the function type: double(double,double) etc. *) + let doubles = Array.make (Array.length args) double_type in + let ft = function_type double_type doubles in + let f = + match lookup_function name the_module with + | None -> declare_function name ft the_module + + (* If 'f' conflicted, there was already something named 'name'. If it + * has a body, don't allow redefinition or reextern. *) + | Some f -> + (* If 'f' already has a body, reject this. *) + if block_begin f <> At_end f then + raise (Error "redefinition of function"); + + (* If 'f' took a different number of arguments, reject. *) + if element_type (type_of f) <> ft then + raise (Error "redefinition of function with different # args"); + f + in + + (* Set names for all arguments. *) + Array.iteri (fun i a -> + let n = args.(i) in + set_value_name n a; + Hashtbl.add named_values n a; + ) (params f); + f + +let codegen_func = function + | Ast.Function (proto, body) -> + Hashtbl.clear named_values; + let the_function = codegen_proto proto in + + (* Create a new basic block to start insertion into. *) + let bb = append_block context "entry" the_function in + position_at_end bb builder; + + try + let ret_val = codegen_expr body in + + (* Finish off the function. *) + let _ = build_ret ret_val builder in + + (* Validate the generated code, checking for consistency. *) + Llvm_analysis.assert_valid_function the_function; + + the_function + with e -> + delete_function the_function; + raise e diff --git a/examples/OCaml-Kaleidoscope/Chapter3/lexer.ml b/examples/OCaml-Kaleidoscope/Chapter3/lexer.ml new file mode 100644 index 000000000000..22a915552f03 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter3/lexer.ml @@ -0,0 +1,52 @@ +(*===----------------------------------------------------------------------=== + * Lexer + *===----------------------------------------------------------------------===*) + +let rec lex = parser + (* Skip any whitespace. *) + | [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream + + (* identifier: [a-zA-Z][a-zA-Z0-9] *) + | [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_ident buffer stream + + (* number: [0-9.]+ *) + | [< ' ('0' .. '9' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_number buffer stream + + (* Comment until end of line. *) + | [< ' ('#'); stream >] -> + lex_comment stream + + (* Otherwise, just return the character as its ascii value. *) + | [< 'c; stream >] -> + [< 'Token.Kwd c; lex stream >] + + (* end of stream. *) + | [< >] -> [< >] + +and lex_number buffer = parser + | [< ' ('0' .. '9' | '.' as c); stream >] -> + Buffer.add_char buffer c; + lex_number buffer stream + | [< stream=lex >] -> + [< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >] + +and lex_ident buffer = parser + | [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] -> + Buffer.add_char buffer c; + lex_ident buffer stream + | [< stream=lex >] -> + match Buffer.contents buffer with + | "def" -> [< 'Token.Def; stream >] + | "extern" -> [< 'Token.Extern; stream >] + | id -> [< 'Token.Ident id; stream >] + +and lex_comment = parser + | [< ' ('\n'); stream=lex >] -> stream + | [< 'c; e=lex_comment >] -> e + | [< >] -> [< >] diff --git a/examples/OCaml-Kaleidoscope/Chapter3/myocamlbuild.ml b/examples/OCaml-Kaleidoscope/Chapter3/myocamlbuild.ml new file mode 100644 index 000000000000..b71f5d717ef7 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter3/myocamlbuild.ml @@ -0,0 +1,6 @@ +open Ocamlbuild_plugin;; + +ocaml_lib ~extern:true "llvm";; +ocaml_lib ~extern:true "llvm_analysis";; + +flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"]);; diff --git a/examples/OCaml-Kaleidoscope/Chapter3/parser.ml b/examples/OCaml-Kaleidoscope/Chapter3/parser.ml new file mode 100644 index 000000000000..83d9874a4ab6 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter3/parser.ml @@ -0,0 +1,122 @@ +(*===---------------------------------------------------------------------=== + * Parser + *===---------------------------------------------------------------------===*) + +(* binop_precedence - This holds the precedence for each binary operator that is + * defined *) +let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10 + +(* precedence - Get the precedence of the pending binary operator token. *) +let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1 + +(* primary + * ::= identifier + * ::= numberexpr + * ::= parenexpr *) +let rec parse_primary = parser + (* numberexpr ::= number *) + | [< 'Token.Number n >] -> Ast.Number n + + (* parenexpr ::= '(' expression ')' *) + | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e + + (* identifierexpr + * ::= identifier + * ::= identifier '(' argumentexpr ')' *) + | [< 'Token.Ident id; stream >] -> + let rec parse_args accumulator = parser + | [< e=parse_expr; stream >] -> + begin parser + | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e + | [< >] -> e :: accumulator + end stream + | [< >] -> accumulator + in + let rec parse_ident id = parser + (* Call. *) + | [< 'Token.Kwd '('; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')'">] -> + Ast.Call (id, Array.of_list (List.rev args)) + + (* Simple variable ref. *) + | [< >] -> Ast.Variable id + in + parse_ident id stream + + | [< >] -> raise (Stream.Error "unknown token when expecting an expression.") + +(* binoprhs + * ::= ('+' primary)* *) +and parse_bin_rhs expr_prec lhs stream = + match Stream.peek stream with + (* If this is a binop, find its precedence. *) + | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c -> + let token_prec = precedence c in + + (* If this is a binop that binds at least as tightly as the current binop, + * consume it, otherwise we are done. *) + if token_prec < expr_prec then lhs else begin + (* Eat the binop. *) + Stream.junk stream; + + (* Parse the primary expression after the binary operator. *) + let rhs = parse_primary stream in + + (* Okay, we know this is a binop. *) + let rhs = + match Stream.peek stream with + | Some (Token.Kwd c2) -> + (* If BinOp binds less tightly with rhs than the operator after + * rhs, let the pending operator take rhs as its lhs. *) + let next_prec = precedence c2 in + if token_prec < next_prec + then parse_bin_rhs (token_prec + 1) rhs stream + else rhs + | _ -> rhs + in + + (* Merge lhs/rhs. *) + let lhs = Ast.Binary (c, lhs, rhs) in + parse_bin_rhs expr_prec lhs stream + end + | _ -> lhs + +(* expression + * ::= primary binoprhs *) +and parse_expr = parser + | [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream + +(* prototype + * ::= id '(' id* ')' *) +let parse_prototype = + let rec parse_args accumulator = parser + | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e + | [< >] -> accumulator + in + + parser + | [< 'Token.Ident id; + 'Token.Kwd '(' ?? "expected '(' in prototype"; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')' in prototype" >] -> + (* success. *) + Ast.Prototype (id, Array.of_list (List.rev args)) + + | [< >] -> + raise (Stream.Error "expected function name in prototype") + +(* definition ::= 'def' prototype expression *) +let parse_definition = parser + | [< 'Token.Def; p=parse_prototype; e=parse_expr >] -> + Ast.Function (p, e) + +(* toplevelexpr ::= expression *) +let parse_toplevel = parser + | [< e=parse_expr >] -> + (* Make an anonymous proto. *) + Ast.Function (Ast.Prototype ("", [||]), e) + +(* external ::= 'extern' prototype *) +let parse_extern = parser + | [< 'Token.Extern; e=parse_prototype >] -> e diff --git a/examples/OCaml-Kaleidoscope/Chapter3/token.ml b/examples/OCaml-Kaleidoscope/Chapter3/token.ml new file mode 100644 index 000000000000..2ca782e14997 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter3/token.ml @@ -0,0 +1,15 @@ +(*===----------------------------------------------------------------------=== + * Lexer Tokens + *===----------------------------------------------------------------------===*) + +(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of + * these others for known things. *) +type token = + (* commands *) + | Def | Extern + + (* primary *) + | Ident of string | Number of float + + (* unknown *) + | Kwd of char diff --git a/examples/OCaml-Kaleidoscope/Chapter3/toplevel.ml b/examples/OCaml-Kaleidoscope/Chapter3/toplevel.ml new file mode 100644 index 000000000000..d1bf5d4c0c65 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter3/toplevel.ml @@ -0,0 +1,39 @@ +(*===----------------------------------------------------------------------=== + * Top-Level parsing and JIT Driver + *===----------------------------------------------------------------------===*) + +open Llvm + +(* top ::= definition | external | expression | ';' *) +let rec main_loop stream = + match Stream.peek stream with + | None -> () + + (* ignore top-level semicolons. *) + | Some (Token.Kwd ';') -> + Stream.junk stream; + main_loop stream + + | Some token -> + begin + try match token with + | Token.Def -> + let e = Parser.parse_definition stream in + print_endline "parsed a function definition."; + dump_value (Codegen.codegen_func e); + | Token.Extern -> + let e = Parser.parse_extern stream in + print_endline "parsed an extern."; + dump_value (Codegen.codegen_proto e); + | _ -> + (* Evaluate a top-level expression into an anonymous function. *) + let e = Parser.parse_toplevel stream in + print_endline "parsed a top-level expr"; + dump_value (Codegen.codegen_func e); + with Stream.Error s | Codegen.Error s -> + (* Skip token for error recovery. *) + Stream.junk stream; + print_endline s; + end; + print_string "ready> "; flush stdout; + main_loop stream diff --git a/examples/OCaml-Kaleidoscope/Chapter3/toy.ml b/examples/OCaml-Kaleidoscope/Chapter3/toy.ml new file mode 100644 index 000000000000..73c1a1ec62a2 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter3/toy.ml @@ -0,0 +1,26 @@ +(*===----------------------------------------------------------------------=== + * Main driver code. + *===----------------------------------------------------------------------===*) + +open Llvm + +let main () = + (* Install standard binary operators. + * 1 is the lowest precedence. *) + Hashtbl.add Parser.binop_precedence '<' 10; + Hashtbl.add Parser.binop_precedence '+' 20; + Hashtbl.add Parser.binop_precedence '-' 20; + Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *) + + (* Prime the first token. *) + print_string "ready> "; flush stdout; + let stream = Lexer.lex (Stream.of_channel stdin) in + + (* Run the main "interpreter loop" now. *) + Toplevel.main_loop stream; + + (* Print out all the generated code. *) + dump_module Codegen.the_module +;; + +main () diff --git a/examples/OCaml-Kaleidoscope/Chapter4/Makefile b/examples/OCaml-Kaleidoscope/Chapter4/Makefile new file mode 100644 index 000000000000..d9c3f49bea6e --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/Makefile @@ -0,0 +1,25 @@ +##===- examples/OCaml-Kaleidoscope/Chapter4/Makefile -------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 4. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../../.. +TOOLNAME := OCaml-Kaleidoscope-Ch4 +EXAMPLE_TOOL := 1 +UsedComponents := core +UsedOcamLibs := llvm llvm_analysis llvm_executionengine llvm_target \ + llvm_scalar_opts + +OCAMLCFLAGS += -pp camlp4of + +ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml + +include $(LEVEL)/bindings/ocaml/Makefile.ocaml diff --git a/examples/OCaml-Kaleidoscope/Chapter4/_tags b/examples/OCaml-Kaleidoscope/Chapter4/_tags new file mode 100644 index 000000000000..7a03dba66723 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/_tags @@ -0,0 +1,4 @@ +<{lexer,parser}.ml>: use_camlp4, pp(camlp4of) +<*.{byte,native}>: g++, use_llvm, use_llvm_analysis +<*.{byte,native}>: use_llvm_executionengine, use_llvm_target +<*.{byte,native}>: use_llvm_scalar_opts, use_bindings diff --git a/examples/OCaml-Kaleidoscope/Chapter4/ast.ml b/examples/OCaml-Kaleidoscope/Chapter4/ast.ml new file mode 100644 index 000000000000..4cc2dea86b78 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/ast.ml @@ -0,0 +1,25 @@ +(*===----------------------------------------------------------------------=== + * Abstract Syntax Tree (aka Parse Tree) + *===----------------------------------------------------------------------===*) + +(* expr - Base type for all expression nodes. *) +type expr = + (* variant for numeric literals like "1.0". *) + | Number of float + + (* variant for referencing a variable, like "a". *) + | Variable of string + + (* variant for a binary operator. *) + | Binary of char * expr * expr + + (* variant for function calls. *) + | Call of string * expr array + +(* proto - This type represents the "prototype" for a function, which captures + * its name, and its argument names (thus implicitly the number of arguments the + * function takes). *) +type proto = Prototype of string * string array + +(* func - This type represents a function definition itself. *) +type func = Function of proto * expr diff --git a/examples/OCaml-Kaleidoscope/Chapter4/bindings.c b/examples/OCaml-Kaleidoscope/Chapter4/bindings.c new file mode 100644 index 000000000000..053513bf0c0c --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/bindings.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +/* putchard - putchar that takes a double and returns 0. */ +extern double putchard(double X) { + putchar((char)X); + return 0; +} diff --git a/examples/OCaml-Kaleidoscope/Chapter4/codegen.ml b/examples/OCaml-Kaleidoscope/Chapter4/codegen.ml new file mode 100644 index 000000000000..69d0928b1bc3 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/codegen.ml @@ -0,0 +1,103 @@ +(*===----------------------------------------------------------------------=== + * Code Generation + *===----------------------------------------------------------------------===*) + +open Llvm + +exception Error of string + +let context = global_context () +let the_module = create_module context "my cool jit" +let builder = builder context +let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10 +let double_type = double_type context + +let rec codegen_expr = function + | Ast.Number n -> const_float double_type n + | Ast.Variable name -> + (try Hashtbl.find named_values name with + | Not_found -> raise (Error "unknown variable name")) + | Ast.Binary (op, lhs, rhs) -> + let lhs_val = codegen_expr lhs in + let rhs_val = codegen_expr rhs in + begin + match op with + | '+' -> build_add lhs_val rhs_val "addtmp" builder + | '-' -> build_sub lhs_val rhs_val "subtmp" builder + | '*' -> build_mul lhs_val rhs_val "multmp" builder + | '<' -> + (* Convert bool 0/1 to double 0.0 or 1.0 *) + let i = build_fcmp Fcmp.Ult lhs_val rhs_val "cmptmp" builder in + build_uitofp i double_type "booltmp" builder + | _ -> raise (Error "invalid binary operator") + end + | Ast.Call (callee, args) -> + (* Look up the name in the module table. *) + let callee = + match lookup_function callee the_module with + | Some callee -> callee + | None -> raise (Error "unknown function referenced") + in + let params = params callee in + + (* If argument mismatch error. *) + if Array.length params == Array.length args then () else + raise (Error "incorrect # arguments passed"); + let args = Array.map codegen_expr args in + build_call callee args "calltmp" builder + +let codegen_proto = function + | Ast.Prototype (name, args) -> + (* Make the function type: double(double,double) etc. *) + let doubles = Array.make (Array.length args) double_type in + let ft = function_type double_type doubles in + let f = + match lookup_function name the_module with + | None -> declare_function name ft the_module + + (* If 'f' conflicted, there was already something named 'name'. If it + * has a body, don't allow redefinition or reextern. *) + | Some f -> + (* If 'f' already has a body, reject this. *) + if block_begin f <> At_end f then + raise (Error "redefinition of function"); + + (* If 'f' took a different number of arguments, reject. *) + if element_type (type_of f) <> ft then + raise (Error "redefinition of function with different # args"); + f + in + + (* Set names for all arguments. *) + Array.iteri (fun i a -> + let n = args.(i) in + set_value_name n a; + Hashtbl.add named_values n a; + ) (params f); + f + +let codegen_func the_fpm = function + | Ast.Function (proto, body) -> + Hashtbl.clear named_values; + let the_function = codegen_proto proto in + + (* Create a new basic block to start insertion into. *) + let bb = append_block context "entry" the_function in + position_at_end bb builder; + + try + let ret_val = codegen_expr body in + + (* Finish off the function. *) + let _ = build_ret ret_val builder in + + (* Validate the generated code, checking for consistency. *) + Llvm_analysis.assert_valid_function the_function; + + (* Optimize the function. *) + let _ = PassManager.run_function the_function the_fpm in + + the_function + with e -> + delete_function the_function; + raise e diff --git a/examples/OCaml-Kaleidoscope/Chapter4/lexer.ml b/examples/OCaml-Kaleidoscope/Chapter4/lexer.ml new file mode 100644 index 000000000000..22a915552f03 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/lexer.ml @@ -0,0 +1,52 @@ +(*===----------------------------------------------------------------------=== + * Lexer + *===----------------------------------------------------------------------===*) + +let rec lex = parser + (* Skip any whitespace. *) + | [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream + + (* identifier: [a-zA-Z][a-zA-Z0-9] *) + | [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_ident buffer stream + + (* number: [0-9.]+ *) + | [< ' ('0' .. '9' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_number buffer stream + + (* Comment until end of line. *) + | [< ' ('#'); stream >] -> + lex_comment stream + + (* Otherwise, just return the character as its ascii value. *) + | [< 'c; stream >] -> + [< 'Token.Kwd c; lex stream >] + + (* end of stream. *) + | [< >] -> [< >] + +and lex_number buffer = parser + | [< ' ('0' .. '9' | '.' as c); stream >] -> + Buffer.add_char buffer c; + lex_number buffer stream + | [< stream=lex >] -> + [< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >] + +and lex_ident buffer = parser + | [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] -> + Buffer.add_char buffer c; + lex_ident buffer stream + | [< stream=lex >] -> + match Buffer.contents buffer with + | "def" -> [< 'Token.Def; stream >] + | "extern" -> [< 'Token.Extern; stream >] + | id -> [< 'Token.Ident id; stream >] + +and lex_comment = parser + | [< ' ('\n'); stream=lex >] -> stream + | [< 'c; e=lex_comment >] -> e + | [< >] -> [< >] diff --git a/examples/OCaml-Kaleidoscope/Chapter4/myocamlbuild.ml b/examples/OCaml-Kaleidoscope/Chapter4/myocamlbuild.ml new file mode 100644 index 000000000000..ff42664c43ba --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/myocamlbuild.ml @@ -0,0 +1,10 @@ +open Ocamlbuild_plugin;; + +ocaml_lib ~extern:true "llvm";; +ocaml_lib ~extern:true "llvm_analysis";; +ocaml_lib ~extern:true "llvm_executionengine";; +ocaml_lib ~extern:true "llvm_target";; +ocaml_lib ~extern:true "llvm_scalar_opts";; + +flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"]);; +dep ["link"; "ocaml"; "use_bindings"] ["bindings.o"];; diff --git a/examples/OCaml-Kaleidoscope/Chapter4/parser.ml b/examples/OCaml-Kaleidoscope/Chapter4/parser.ml new file mode 100644 index 000000000000..83d9874a4ab6 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/parser.ml @@ -0,0 +1,122 @@ +(*===---------------------------------------------------------------------=== + * Parser + *===---------------------------------------------------------------------===*) + +(* binop_precedence - This holds the precedence for each binary operator that is + * defined *) +let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10 + +(* precedence - Get the precedence of the pending binary operator token. *) +let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1 + +(* primary + * ::= identifier + * ::= numberexpr + * ::= parenexpr *) +let rec parse_primary = parser + (* numberexpr ::= number *) + | [< 'Token.Number n >] -> Ast.Number n + + (* parenexpr ::= '(' expression ')' *) + | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e + + (* identifierexpr + * ::= identifier + * ::= identifier '(' argumentexpr ')' *) + | [< 'Token.Ident id; stream >] -> + let rec parse_args accumulator = parser + | [< e=parse_expr; stream >] -> + begin parser + | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e + | [< >] -> e :: accumulator + end stream + | [< >] -> accumulator + in + let rec parse_ident id = parser + (* Call. *) + | [< 'Token.Kwd '('; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')'">] -> + Ast.Call (id, Array.of_list (List.rev args)) + + (* Simple variable ref. *) + | [< >] -> Ast.Variable id + in + parse_ident id stream + + | [< >] -> raise (Stream.Error "unknown token when expecting an expression.") + +(* binoprhs + * ::= ('+' primary)* *) +and parse_bin_rhs expr_prec lhs stream = + match Stream.peek stream with + (* If this is a binop, find its precedence. *) + | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c -> + let token_prec = precedence c in + + (* If this is a binop that binds at least as tightly as the current binop, + * consume it, otherwise we are done. *) + if token_prec < expr_prec then lhs else begin + (* Eat the binop. *) + Stream.junk stream; + + (* Parse the primary expression after the binary operator. *) + let rhs = parse_primary stream in + + (* Okay, we know this is a binop. *) + let rhs = + match Stream.peek stream with + | Some (Token.Kwd c2) -> + (* If BinOp binds less tightly with rhs than the operator after + * rhs, let the pending operator take rhs as its lhs. *) + let next_prec = precedence c2 in + if token_prec < next_prec + then parse_bin_rhs (token_prec + 1) rhs stream + else rhs + | _ -> rhs + in + + (* Merge lhs/rhs. *) + let lhs = Ast.Binary (c, lhs, rhs) in + parse_bin_rhs expr_prec lhs stream + end + | _ -> lhs + +(* expression + * ::= primary binoprhs *) +and parse_expr = parser + | [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream + +(* prototype + * ::= id '(' id* ')' *) +let parse_prototype = + let rec parse_args accumulator = parser + | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e + | [< >] -> accumulator + in + + parser + | [< 'Token.Ident id; + 'Token.Kwd '(' ?? "expected '(' in prototype"; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')' in prototype" >] -> + (* success. *) + Ast.Prototype (id, Array.of_list (List.rev args)) + + | [< >] -> + raise (Stream.Error "expected function name in prototype") + +(* definition ::= 'def' prototype expression *) +let parse_definition = parser + | [< 'Token.Def; p=parse_prototype; e=parse_expr >] -> + Ast.Function (p, e) + +(* toplevelexpr ::= expression *) +let parse_toplevel = parser + | [< e=parse_expr >] -> + (* Make an anonymous proto. *) + Ast.Function (Ast.Prototype ("", [||]), e) + +(* external ::= 'extern' prototype *) +let parse_extern = parser + | [< 'Token.Extern; e=parse_prototype >] -> e diff --git a/examples/OCaml-Kaleidoscope/Chapter4/token.ml b/examples/OCaml-Kaleidoscope/Chapter4/token.ml new file mode 100644 index 000000000000..2ca782e14997 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/token.ml @@ -0,0 +1,15 @@ +(*===----------------------------------------------------------------------=== + * Lexer Tokens + *===----------------------------------------------------------------------===*) + +(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of + * these others for known things. *) +type token = + (* commands *) + | Def | Extern + + (* primary *) + | Ident of string | Number of float + + (* unknown *) + | Kwd of char diff --git a/examples/OCaml-Kaleidoscope/Chapter4/toplevel.ml b/examples/OCaml-Kaleidoscope/Chapter4/toplevel.ml new file mode 100644 index 000000000000..01d24ede1492 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/toplevel.ml @@ -0,0 +1,49 @@ +(*===----------------------------------------------------------------------=== + * Top-Level parsing and JIT Driver + *===----------------------------------------------------------------------===*) + +open Llvm +open Llvm_executionengine + +(* top ::= definition | external | expression | ';' *) +let rec main_loop the_fpm the_execution_engine stream = + match Stream.peek stream with + | None -> () + + (* ignore top-level semicolons. *) + | Some (Token.Kwd ';') -> + Stream.junk stream; + main_loop the_fpm the_execution_engine stream + + | Some token -> + begin + try match token with + | Token.Def -> + let e = Parser.parse_definition stream in + print_endline "parsed a function definition."; + dump_value (Codegen.codegen_func the_fpm e); + | Token.Extern -> + let e = Parser.parse_extern stream in + print_endline "parsed an extern."; + dump_value (Codegen.codegen_proto e); + | _ -> + (* Evaluate a top-level expression into an anonymous function. *) + let e = Parser.parse_toplevel stream in + print_endline "parsed a top-level expr"; + let the_function = Codegen.codegen_func the_fpm e in + dump_value the_function; + + (* JIT the function, returning a function pointer. *) + let result = ExecutionEngine.run_function the_function [||] + the_execution_engine in + + print_string "Evaluated to "; + print_float (GenericValue.as_float Codegen.double_type result); + print_newline (); + with Stream.Error s | Codegen.Error s -> + (* Skip token for error recovery. *) + Stream.junk stream; + print_endline s; + end; + print_string "ready> "; flush stdout; + main_loop the_fpm the_execution_engine stream diff --git a/examples/OCaml-Kaleidoscope/Chapter4/toy.ml b/examples/OCaml-Kaleidoscope/Chapter4/toy.ml new file mode 100644 index 000000000000..5f9d912499c9 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter4/toy.ml @@ -0,0 +1,53 @@ +(*===----------------------------------------------------------------------=== + * Main driver code. + *===----------------------------------------------------------------------===*) + +open Llvm +open Llvm_executionengine +open Llvm_target +open Llvm_scalar_opts + +let main () = + ignore (initialize_native_target ()); + + (* Install standard binary operators. + * 1 is the lowest precedence. *) + Hashtbl.add Parser.binop_precedence '<' 10; + Hashtbl.add Parser.binop_precedence '+' 20; + Hashtbl.add Parser.binop_precedence '-' 20; + Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *) + + (* Prime the first token. *) + print_string "ready> "; flush stdout; + let stream = Lexer.lex (Stream.of_channel stdin) in + + (* Create the JIT. *) + let the_execution_engine = ExecutionEngine.create Codegen.the_module in + let the_fpm = PassManager.create_function Codegen.the_module in + + (* Set up the optimizer pipeline. Start with registering info about how the + * target lays out data structures. *) + TargetData.add (ExecutionEngine.target_data the_execution_engine) the_fpm; + + (* Do simple "peephole" optimizations and bit-twiddling optzn. *) + add_instruction_combination the_fpm; + + (* reassociate expressions. *) + add_reassociation the_fpm; + + (* Eliminate Common SubExpressions. *) + add_gvn the_fpm; + + (* Simplify the control flow graph (deleting unreachable blocks, etc). *) + add_cfg_simplification the_fpm; + + ignore (PassManager.initialize the_fpm); + + (* Run the main "interpreter loop" now. *) + Toplevel.main_loop the_fpm the_execution_engine stream; + + (* Print out all the generated code. *) + dump_module Codegen.the_module +;; + +main () diff --git a/examples/OCaml-Kaleidoscope/Chapter5/Makefile b/examples/OCaml-Kaleidoscope/Chapter5/Makefile new file mode 100644 index 000000000000..f31c10d3c2fb --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/Makefile @@ -0,0 +1,25 @@ +##===- examples/OCaml-Kaleidoscope/Chapter5/Makefile -------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 5. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../../.. +TOOLNAME := OCaml-Kaleidoscope-Ch5 +EXAMPLE_TOOL := 1 +UsedComponents := core +UsedOcamLibs := llvm llvm_analysis llvm_executionengine llvm_target \ + llvm_scalar_opts + +OCAMLCFLAGS += -pp camlp4of + +ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml + +include $(LEVEL)/bindings/ocaml/Makefile.ocaml diff --git a/examples/OCaml-Kaleidoscope/Chapter5/_tags b/examples/OCaml-Kaleidoscope/Chapter5/_tags new file mode 100644 index 000000000000..7a03dba66723 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/_tags @@ -0,0 +1,4 @@ +<{lexer,parser}.ml>: use_camlp4, pp(camlp4of) +<*.{byte,native}>: g++, use_llvm, use_llvm_analysis +<*.{byte,native}>: use_llvm_executionengine, use_llvm_target +<*.{byte,native}>: use_llvm_scalar_opts, use_bindings diff --git a/examples/OCaml-Kaleidoscope/Chapter5/ast.ml b/examples/OCaml-Kaleidoscope/Chapter5/ast.ml new file mode 100644 index 000000000000..8a6703db837e --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/ast.ml @@ -0,0 +1,31 @@ +(*===----------------------------------------------------------------------=== + * Abstract Syntax Tree (aka Parse Tree) + *===----------------------------------------------------------------------===*) + +(* expr - Base type for all expression nodes. *) +type expr = + (* variant for numeric literals like "1.0". *) + | Number of float + + (* variant for referencing a variable, like "a". *) + | Variable of string + + (* variant for a binary operator. *) + | Binary of char * expr * expr + + (* variant for function calls. *) + | Call of string * expr array + + (* variant for if/then/else. *) + | If of expr * expr * expr + + (* variant for for/in. *) + | For of string * expr * expr * expr option * expr + +(* proto - This type represents the "prototype" for a function, which captures + * its name, and its argument names (thus implicitly the number of arguments the + * function takes). *) +type proto = Prototype of string * string array + +(* func - This type represents a function definition itself. *) +type func = Function of proto * expr diff --git a/examples/OCaml-Kaleidoscope/Chapter5/bindings.c b/examples/OCaml-Kaleidoscope/Chapter5/bindings.c new file mode 100644 index 000000000000..053513bf0c0c --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/bindings.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +/* putchard - putchar that takes a double and returns 0. */ +extern double putchard(double X) { + putchar((char)X); + return 0; +} diff --git a/examples/OCaml-Kaleidoscope/Chapter5/codegen.ml b/examples/OCaml-Kaleidoscope/Chapter5/codegen.ml new file mode 100644 index 000000000000..e0db2d2c8627 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/codegen.ml @@ -0,0 +1,225 @@ +(*===----------------------------------------------------------------------=== + * Code Generation + *===----------------------------------------------------------------------===*) + +open Llvm + +exception Error of string + +let context = global_context () +let the_module = create_module context "my cool jit" +let builder = builder context +let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10 +let double_type = double_type context + +let rec codegen_expr = function + | Ast.Number n -> const_float double_type n + | Ast.Variable name -> + (try Hashtbl.find named_values name with + | Not_found -> raise (Error "unknown variable name")) + | Ast.Binary (op, lhs, rhs) -> + let lhs_val = codegen_expr lhs in + let rhs_val = codegen_expr rhs in + begin + match op with + | '+' -> build_add lhs_val rhs_val "addtmp" builder + | '-' -> build_sub lhs_val rhs_val "subtmp" builder + | '*' -> build_mul lhs_val rhs_val "multmp" builder + | '<' -> + (* Convert bool 0/1 to double 0.0 or 1.0 *) + let i = build_fcmp Fcmp.Ult lhs_val rhs_val "cmptmp" builder in + build_uitofp i double_type "booltmp" builder + | _ -> raise (Error "invalid binary operator") + end + | Ast.Call (callee, args) -> + (* Look up the name in the module table. *) + let callee = + match lookup_function callee the_module with + | Some callee -> callee + | None -> raise (Error "unknown function referenced") + in + let params = params callee in + + (* If argument mismatch error. *) + if Array.length params == Array.length args then () else + raise (Error "incorrect # arguments passed"); + let args = Array.map codegen_expr args in + build_call callee args "calltmp" builder + | Ast.If (cond, then_, else_) -> + let cond = codegen_expr cond in + + (* Convert condition to a bool by comparing equal to 0.0 *) + let zero = const_float double_type 0.0 in + let cond_val = build_fcmp Fcmp.One cond zero "ifcond" builder in + + (* Grab the first block so that we might later add the conditional branch + * to it at the end of the function. *) + let start_bb = insertion_block builder in + let the_function = block_parent start_bb in + + let then_bb = append_block context "then" the_function in + + (* Emit 'then' value. *) + position_at_end then_bb builder; + let then_val = codegen_expr then_ in + + (* Codegen of 'then' can change the current block, update then_bb for the + * phi. We create a new name because one is used for the phi node, and the + * other is used for the conditional branch. *) + let new_then_bb = insertion_block builder in + + (* Emit 'else' value. *) + let else_bb = append_block context "else" the_function in + position_at_end else_bb builder; + let else_val = codegen_expr else_ in + + (* Codegen of 'else' can change the current block, update else_bb for the + * phi. *) + let new_else_bb = insertion_block builder in + + (* Emit merge block. *) + let merge_bb = append_block context "ifcont" the_function in + position_at_end merge_bb builder; + let incoming = [(then_val, new_then_bb); (else_val, new_else_bb)] in + let phi = build_phi incoming "iftmp" builder in + + (* Return to the start block to add the conditional branch. *) + position_at_end start_bb builder; + ignore (build_cond_br cond_val then_bb else_bb builder); + + (* Set a unconditional branch at the end of the 'then' block and the + * 'else' block to the 'merge' block. *) + position_at_end new_then_bb builder; ignore (build_br merge_bb builder); + position_at_end new_else_bb builder; ignore (build_br merge_bb builder); + + (* Finally, set the builder to the end of the merge block. *) + position_at_end merge_bb builder; + + phi + | Ast.For (var_name, start, end_, step, body) -> + (* Emit the start code first, without 'variable' in scope. *) + let start_val = codegen_expr start in + + (* Make the new basic block for the loop header, inserting after current + * block. *) + let preheader_bb = insertion_block builder in + let the_function = block_parent preheader_bb in + let loop_bb = append_block context "loop" the_function in + + (* Insert an explicit fall through from the current block to the + * loop_bb. *) + ignore (build_br loop_bb builder); + + (* Start insertion in loop_bb. *) + position_at_end loop_bb builder; + + (* Start the PHI node with an entry for start. *) + let variable = build_phi [(start_val, preheader_bb)] var_name builder in + + (* Within the loop, the variable is defined equal to the PHI node. If it + * shadows an existing variable, we have to restore it, so save it + * now. *) + let old_val = + try Some (Hashtbl.find named_values var_name) with Not_found -> None + in + Hashtbl.add named_values var_name variable; + + (* Emit the body of the loop. This, like any other expr, can change the + * current BB. Note that we ignore the value computed by the body, but + * don't allow an error *) + ignore (codegen_expr body); + + (* Emit the step value. *) + let step_val = + match step with + | Some step -> codegen_expr step + (* If not specified, use 1.0. *) + | None -> const_float double_type 1.0 + in + + let next_var = build_add variable step_val "nextvar" builder in + + (* Compute the end condition. *) + let end_cond = codegen_expr end_ in + + (* Convert condition to a bool by comparing equal to 0.0. *) + let zero = const_float double_type 0.0 in + let end_cond = build_fcmp Fcmp.One end_cond zero "loopcond" builder in + + (* Create the "after loop" block and insert it. *) + let loop_end_bb = insertion_block builder in + let after_bb = append_block context "afterloop" the_function in + + (* Insert the conditional branch into the end of loop_end_bb. *) + ignore (build_cond_br end_cond loop_bb after_bb builder); + + (* Any new code will be inserted in after_bb. *) + position_at_end after_bb builder; + + (* Add a new entry to the PHI node for the backedge. *) + add_incoming (next_var, loop_end_bb) variable; + + (* Restore the unshadowed variable. *) + begin match old_val with + | Some old_val -> Hashtbl.add named_values var_name old_val + | None -> () + end; + + (* for expr always returns 0.0. *) + const_null double_type + +let codegen_proto = function + | Ast.Prototype (name, args) -> + (* Make the function type: double(double,double) etc. *) + let doubles = Array.make (Array.length args) double_type in + let ft = function_type double_type doubles in + let f = + match lookup_function name the_module with + | None -> declare_function name ft the_module + + (* If 'f' conflicted, there was already something named 'name'. If it + * has a body, don't allow redefinition or reextern. *) + | Some f -> + (* If 'f' already has a body, reject this. *) + if block_begin f <> At_end f then + raise (Error "redefinition of function"); + + (* If 'f' took a different number of arguments, reject. *) + if element_type (type_of f) <> ft then + raise (Error "redefinition of function with different # args"); + f + in + + (* Set names for all arguments. *) + Array.iteri (fun i a -> + let n = args.(i) in + set_value_name n a; + Hashtbl.add named_values n a; + ) (params f); + f + +let codegen_func the_fpm = function + | Ast.Function (proto, body) -> + Hashtbl.clear named_values; + let the_function = codegen_proto proto in + + (* Create a new basic block to start insertion into. *) + let bb = append_block context "entry" the_function in + position_at_end bb builder; + + try + let ret_val = codegen_expr body in + + (* Finish off the function. *) + let _ = build_ret ret_val builder in + + (* Validate the generated code, checking for consistency. *) + Llvm_analysis.assert_valid_function the_function; + + (* Optimize the function. *) + let _ = PassManager.run_function the_function the_fpm in + + the_function + with e -> + delete_function the_function; + raise e diff --git a/examples/OCaml-Kaleidoscope/Chapter5/lexer.ml b/examples/OCaml-Kaleidoscope/Chapter5/lexer.ml new file mode 100644 index 000000000000..d8c1d563010f --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/lexer.ml @@ -0,0 +1,57 @@ +(*===----------------------------------------------------------------------=== + * Lexer + *===----------------------------------------------------------------------===*) + +let rec lex = parser + (* Skip any whitespace. *) + | [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream + + (* identifier: [a-zA-Z][a-zA-Z0-9] *) + | [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_ident buffer stream + + (* number: [0-9.]+ *) + | [< ' ('0' .. '9' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_number buffer stream + + (* Comment until end of line. *) + | [< ' ('#'); stream >] -> + lex_comment stream + + (* Otherwise, just return the character as its ascii value. *) + | [< 'c; stream >] -> + [< 'Token.Kwd c; lex stream >] + + (* end of stream. *) + | [< >] -> [< >] + +and lex_number buffer = parser + | [< ' ('0' .. '9' | '.' as c); stream >] -> + Buffer.add_char buffer c; + lex_number buffer stream + | [< stream=lex >] -> + [< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >] + +and lex_ident buffer = parser + | [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] -> + Buffer.add_char buffer c; + lex_ident buffer stream + | [< stream=lex >] -> + match Buffer.contents buffer with + | "def" -> [< 'Token.Def; stream >] + | "extern" -> [< 'Token.Extern; stream >] + | "if" -> [< 'Token.If; stream >] + | "then" -> [< 'Token.Then; stream >] + | "else" -> [< 'Token.Else; stream >] + | "for" -> [< 'Token.For; stream >] + | "in" -> [< 'Token.In; stream >] + | id -> [< 'Token.Ident id; stream >] + +and lex_comment = parser + | [< ' ('\n'); stream=lex >] -> stream + | [< 'c; e=lex_comment >] -> e + | [< >] -> [< >] diff --git a/examples/OCaml-Kaleidoscope/Chapter5/myocamlbuild.ml b/examples/OCaml-Kaleidoscope/Chapter5/myocamlbuild.ml new file mode 100644 index 000000000000..ff42664c43ba --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/myocamlbuild.ml @@ -0,0 +1,10 @@ +open Ocamlbuild_plugin;; + +ocaml_lib ~extern:true "llvm";; +ocaml_lib ~extern:true "llvm_analysis";; +ocaml_lib ~extern:true "llvm_executionengine";; +ocaml_lib ~extern:true "llvm_target";; +ocaml_lib ~extern:true "llvm_scalar_opts";; + +flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"]);; +dep ["link"; "ocaml"; "use_bindings"] ["bindings.o"];; diff --git a/examples/OCaml-Kaleidoscope/Chapter5/parser.ml b/examples/OCaml-Kaleidoscope/Chapter5/parser.ml new file mode 100644 index 000000000000..bfb4f1684583 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/parser.ml @@ -0,0 +1,158 @@ +(*===---------------------------------------------------------------------=== + * Parser + *===---------------------------------------------------------------------===*) + +(* binop_precedence - This holds the precedence for each binary operator that is + * defined *) +let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10 + +(* precedence - Get the precedence of the pending binary operator token. *) +let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1 + +(* primary + * ::= identifier + * ::= numberexpr + * ::= parenexpr + * ::= ifexpr + * ::= forexpr *) +let rec parse_primary = parser + (* numberexpr ::= number *) + | [< 'Token.Number n >] -> Ast.Number n + + (* parenexpr ::= '(' expression ')' *) + | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e + + (* identifierexpr + * ::= identifier + * ::= identifier '(' argumentexpr ')' *) + | [< 'Token.Ident id; stream >] -> + let rec parse_args accumulator = parser + | [< e=parse_expr; stream >] -> + begin parser + | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e + | [< >] -> e :: accumulator + end stream + | [< >] -> accumulator + in + let rec parse_ident id = parser + (* Call. *) + | [< 'Token.Kwd '('; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')'">] -> + Ast.Call (id, Array.of_list (List.rev args)) + + (* Simple variable ref. *) + | [< >] -> Ast.Variable id + in + parse_ident id stream + + (* ifexpr ::= 'if' expr 'then' expr 'else' expr *) + | [< 'Token.If; c=parse_expr; + 'Token.Then ?? "expected 'then'"; t=parse_expr; + 'Token.Else ?? "expected 'else'"; e=parse_expr >] -> + Ast.If (c, t, e) + + (* forexpr + ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *) + | [< 'Token.For; + 'Token.Ident id ?? "expected identifier after for"; + 'Token.Kwd '=' ?? "expected '=' after for"; + stream >] -> + begin parser + | [< + start=parse_expr; + 'Token.Kwd ',' ?? "expected ',' after for"; + end_=parse_expr; + stream >] -> + let step = + begin parser + | [< 'Token.Kwd ','; step=parse_expr >] -> Some step + | [< >] -> None + end stream + in + begin parser + | [< 'Token.In; body=parse_expr >] -> + Ast.For (id, start, end_, step, body) + | [< >] -> + raise (Stream.Error "expected 'in' after for") + end stream + | [< >] -> + raise (Stream.Error "expected '=' after for") + end stream + + | [< >] -> raise (Stream.Error "unknown token when expecting an expression.") + +(* binoprhs + * ::= ('+' primary)* *) +and parse_bin_rhs expr_prec lhs stream = + match Stream.peek stream with + (* If this is a binop, find its precedence. *) + | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c -> + let token_prec = precedence c in + + (* If this is a binop that binds at least as tightly as the current binop, + * consume it, otherwise we are done. *) + if token_prec < expr_prec then lhs else begin + (* Eat the binop. *) + Stream.junk stream; + + (* Parse the primary expression after the binary operator. *) + let rhs = parse_primary stream in + + (* Okay, we know this is a binop. *) + let rhs = + match Stream.peek stream with + | Some (Token.Kwd c2) -> + (* If BinOp binds less tightly with rhs than the operator after + * rhs, let the pending operator take rhs as its lhs. *) + let next_prec = precedence c2 in + if token_prec < next_prec + then parse_bin_rhs (token_prec + 1) rhs stream + else rhs + | _ -> rhs + in + + (* Merge lhs/rhs. *) + let lhs = Ast.Binary (c, lhs, rhs) in + parse_bin_rhs expr_prec lhs stream + end + | _ -> lhs + +(* expression + * ::= primary binoprhs *) +and parse_expr = parser + | [< lhs=parse_primary; stream >] -> parse_bin_rhs 0 lhs stream + +(* prototype + * ::= id '(' id* ')' *) +let parse_prototype = + let rec parse_args accumulator = parser + | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e + | [< >] -> accumulator + in + + parser + | [< 'Token.Ident id; + 'Token.Kwd '(' ?? "expected '(' in prototype"; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')' in prototype" >] -> + (* success. *) + Ast.Prototype (id, Array.of_list (List.rev args)) + + | [< >] -> + raise (Stream.Error "expected function name in prototype") + +(* definition ::= 'def' prototype expression *) +let parse_definition = parser + | [< 'Token.Def; p=parse_prototype; e=parse_expr >] -> + Ast.Function (p, e) + +(* toplevelexpr ::= expression *) +let parse_toplevel = parser + | [< e=parse_expr >] -> + (* Make an anonymous proto. *) + Ast.Function (Ast.Prototype ("", [||]), e) + +(* external ::= 'extern' prototype *) +let parse_extern = parser + | [< 'Token.Extern; e=parse_prototype >] -> e diff --git a/examples/OCaml-Kaleidoscope/Chapter5/token.ml b/examples/OCaml-Kaleidoscope/Chapter5/token.ml new file mode 100644 index 000000000000..5eb502fb8942 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/token.ml @@ -0,0 +1,19 @@ +(*===----------------------------------------------------------------------=== + * Lexer Tokens + *===----------------------------------------------------------------------===*) + +(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of + * these others for known things. *) +type token = + (* commands *) + | Def | Extern + + (* primary *) + | Ident of string | Number of float + + (* unknown *) + | Kwd of char + + (* control *) + | If | Then | Else + | For | In diff --git a/examples/OCaml-Kaleidoscope/Chapter5/toplevel.ml b/examples/OCaml-Kaleidoscope/Chapter5/toplevel.ml new file mode 100644 index 000000000000..01d24ede1492 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/toplevel.ml @@ -0,0 +1,49 @@ +(*===----------------------------------------------------------------------=== + * Top-Level parsing and JIT Driver + *===----------------------------------------------------------------------===*) + +open Llvm +open Llvm_executionengine + +(* top ::= definition | external | expression | ';' *) +let rec main_loop the_fpm the_execution_engine stream = + match Stream.peek stream with + | None -> () + + (* ignore top-level semicolons. *) + | Some (Token.Kwd ';') -> + Stream.junk stream; + main_loop the_fpm the_execution_engine stream + + | Some token -> + begin + try match token with + | Token.Def -> + let e = Parser.parse_definition stream in + print_endline "parsed a function definition."; + dump_value (Codegen.codegen_func the_fpm e); + | Token.Extern -> + let e = Parser.parse_extern stream in + print_endline "parsed an extern."; + dump_value (Codegen.codegen_proto e); + | _ -> + (* Evaluate a top-level expression into an anonymous function. *) + let e = Parser.parse_toplevel stream in + print_endline "parsed a top-level expr"; + let the_function = Codegen.codegen_func the_fpm e in + dump_value the_function; + + (* JIT the function, returning a function pointer. *) + let result = ExecutionEngine.run_function the_function [||] + the_execution_engine in + + print_string "Evaluated to "; + print_float (GenericValue.as_float Codegen.double_type result); + print_newline (); + with Stream.Error s | Codegen.Error s -> + (* Skip token for error recovery. *) + Stream.junk stream; + print_endline s; + end; + print_string "ready> "; flush stdout; + main_loop the_fpm the_execution_engine stream diff --git a/examples/OCaml-Kaleidoscope/Chapter5/toy.ml b/examples/OCaml-Kaleidoscope/Chapter5/toy.ml new file mode 100644 index 000000000000..5f9d912499c9 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter5/toy.ml @@ -0,0 +1,53 @@ +(*===----------------------------------------------------------------------=== + * Main driver code. + *===----------------------------------------------------------------------===*) + +open Llvm +open Llvm_executionengine +open Llvm_target +open Llvm_scalar_opts + +let main () = + ignore (initialize_native_target ()); + + (* Install standard binary operators. + * 1 is the lowest precedence. *) + Hashtbl.add Parser.binop_precedence '<' 10; + Hashtbl.add Parser.binop_precedence '+' 20; + Hashtbl.add Parser.binop_precedence '-' 20; + Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *) + + (* Prime the first token. *) + print_string "ready> "; flush stdout; + let stream = Lexer.lex (Stream.of_channel stdin) in + + (* Create the JIT. *) + let the_execution_engine = ExecutionEngine.create Codegen.the_module in + let the_fpm = PassManager.create_function Codegen.the_module in + + (* Set up the optimizer pipeline. Start with registering info about how the + * target lays out data structures. *) + TargetData.add (ExecutionEngine.target_data the_execution_engine) the_fpm; + + (* Do simple "peephole" optimizations and bit-twiddling optzn. *) + add_instruction_combination the_fpm; + + (* reassociate expressions. *) + add_reassociation the_fpm; + + (* Eliminate Common SubExpressions. *) + add_gvn the_fpm; + + (* Simplify the control flow graph (deleting unreachable blocks, etc). *) + add_cfg_simplification the_fpm; + + ignore (PassManager.initialize the_fpm); + + (* Run the main "interpreter loop" now. *) + Toplevel.main_loop the_fpm the_execution_engine stream; + + (* Print out all the generated code. *) + dump_module Codegen.the_module +;; + +main () diff --git a/examples/OCaml-Kaleidoscope/Chapter6/Makefile b/examples/OCaml-Kaleidoscope/Chapter6/Makefile new file mode 100644 index 000000000000..831213863a6e --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/Makefile @@ -0,0 +1,25 @@ +##===- examples/OCaml-Kaleidoscope/Chapter6/Makefile -------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 6. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../../.. +TOOLNAME := OCaml-Kaleidoscope-Ch6 +EXAMPLE_TOOL := 1 +UsedComponents := core +UsedOcamLibs := llvm llvm_analysis llvm_executionengine llvm_target \ + llvm_scalar_opts + +OCAMLCFLAGS += -pp camlp4of + +ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml + +include $(LEVEL)/bindings/ocaml/Makefile.ocaml diff --git a/examples/OCaml-Kaleidoscope/Chapter6/_tags b/examples/OCaml-Kaleidoscope/Chapter6/_tags new file mode 100644 index 000000000000..7a03dba66723 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/_tags @@ -0,0 +1,4 @@ +<{lexer,parser}.ml>: use_camlp4, pp(camlp4of) +<*.{byte,native}>: g++, use_llvm, use_llvm_analysis +<*.{byte,native}>: use_llvm_executionengine, use_llvm_target +<*.{byte,native}>: use_llvm_scalar_opts, use_bindings diff --git a/examples/OCaml-Kaleidoscope/Chapter6/ast.ml b/examples/OCaml-Kaleidoscope/Chapter6/ast.ml new file mode 100644 index 000000000000..99088cfd2f51 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/ast.ml @@ -0,0 +1,36 @@ +(*===----------------------------------------------------------------------=== + * Abstract Syntax Tree (aka Parse Tree) + *===----------------------------------------------------------------------===*) + +(* expr - Base type for all expression nodes. *) +type expr = + (* variant for numeric literals like "1.0". *) + | Number of float + + (* variant for referencing a variable, like "a". *) + | Variable of string + + (* variant for a unary operator. *) + | Unary of char * expr + + (* variant for a binary operator. *) + | Binary of char * expr * expr + + (* variant for function calls. *) + | Call of string * expr array + + (* variant for if/then/else. *) + | If of expr * expr * expr + + (* variant for for/in. *) + | For of string * expr * expr * expr option * expr + +(* proto - This type represents the "prototype" for a function, which captures + * its name, and its argument names (thus implicitly the number of arguments the + * function takes). *) +type proto = + | Prototype of string * string array + | BinOpPrototype of string * string array * int + +(* func - This type represents a function definition itself. *) +type func = Function of proto * expr diff --git a/examples/OCaml-Kaleidoscope/Chapter6/bindings.c b/examples/OCaml-Kaleidoscope/Chapter6/bindings.c new file mode 100644 index 000000000000..90faed15813d --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/bindings.c @@ -0,0 +1,13 @@ +#include <stdio.h> + +/* putchard - putchar that takes a double and returns 0. */ +extern double putchard(double X) { + putchar((char)X); + return 0; +} + +/* printd - printf that takes a double prints it as "%f\n", returning 0. */ +extern double printd(double X) { + printf("%f\n", X); + return 0; +} diff --git a/examples/OCaml-Kaleidoscope/Chapter6/codegen.ml b/examples/OCaml-Kaleidoscope/Chapter6/codegen.ml new file mode 100644 index 000000000000..e00edf294f8f --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/codegen.ml @@ -0,0 +1,251 @@ +(*===----------------------------------------------------------------------=== + * Code Generation + *===----------------------------------------------------------------------===*) + +open Llvm + +exception Error of string + +let context = global_context () +let the_module = create_module context "my cool jit" +let builder = builder context +let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10 +let double_type = double_type context + +let rec codegen_expr = function + | Ast.Number n -> const_float double_type n + | Ast.Variable name -> + (try Hashtbl.find named_values name with + | Not_found -> raise (Error "unknown variable name")) + | Ast.Unary (op, operand) -> + let operand = codegen_expr operand in + let callee = "unary" ^ (String.make 1 op) in + let callee = + match lookup_function callee the_module with + | Some callee -> callee + | None -> raise (Error "unknown unary operator") + in + build_call callee [|operand|] "unop" builder + | Ast.Binary (op, lhs, rhs) -> + let lhs_val = codegen_expr lhs in + let rhs_val = codegen_expr rhs in + begin + match op with + | '+' -> build_add lhs_val rhs_val "addtmp" builder + | '-' -> build_sub lhs_val rhs_val "subtmp" builder + | '*' -> build_mul lhs_val rhs_val "multmp" builder + | '<' -> + (* Convert bool 0/1 to double 0.0 or 1.0 *) + let i = build_fcmp Fcmp.Ult lhs_val rhs_val "cmptmp" builder in + build_uitofp i double_type "booltmp" builder + | _ -> + (* If it wasn't a builtin binary operator, it must be a user defined + * one. Emit a call to it. *) + let callee = "binary" ^ (String.make 1 op) in + let callee = + match lookup_function callee the_module with + | Some callee -> callee + | None -> raise (Error "binary operator not found!") + in + build_call callee [|lhs_val; rhs_val|] "binop" builder + end + | Ast.Call (callee, args) -> + (* Look up the name in the module table. *) + let callee = + match lookup_function callee the_module with + | Some callee -> callee + | None -> raise (Error "unknown function referenced") + in + let params = params callee in + + (* If argument mismatch error. *) + if Array.length params == Array.length args then () else + raise (Error "incorrect # arguments passed"); + let args = Array.map codegen_expr args in + build_call callee args "calltmp" builder + | Ast.If (cond, then_, else_) -> + let cond = codegen_expr cond in + + (* Convert condition to a bool by comparing equal to 0.0 *) + let zero = const_float double_type 0.0 in + let cond_val = build_fcmp Fcmp.One cond zero "ifcond" builder in + + (* Grab the first block so that we might later add the conditional branch + * to it at the end of the function. *) + let start_bb = insertion_block builder in + let the_function = block_parent start_bb in + + let then_bb = append_block context "then" the_function in + + (* Emit 'then' value. *) + position_at_end then_bb builder; + let then_val = codegen_expr then_ in + + (* Codegen of 'then' can change the current block, update then_bb for the + * phi. We create a new name because one is used for the phi node, and the + * other is used for the conditional branch. *) + let new_then_bb = insertion_block builder in + + (* Emit 'else' value. *) + let else_bb = append_block context "else" the_function in + position_at_end else_bb builder; + let else_val = codegen_expr else_ in + + (* Codegen of 'else' can change the current block, update else_bb for the + * phi. *) + let new_else_bb = insertion_block builder in + + (* Emit merge block. *) + let merge_bb = append_block context "ifcont" the_function in + position_at_end merge_bb builder; + let incoming = [(then_val, new_then_bb); (else_val, new_else_bb)] in + let phi = build_phi incoming "iftmp" builder in + + (* Return to the start block to add the conditional branch. *) + position_at_end start_bb builder; + ignore (build_cond_br cond_val then_bb else_bb builder); + + (* Set a unconditional branch at the end of the 'then' block and the + * 'else' block to the 'merge' block. *) + position_at_end new_then_bb builder; ignore (build_br merge_bb builder); + position_at_end new_else_bb builder; ignore (build_br merge_bb builder); + + (* Finally, set the builder to the end of the merge block. *) + position_at_end merge_bb builder; + + phi + | Ast.For (var_name, start, end_, step, body) -> + (* Emit the start code first, without 'variable' in scope. *) + let start_val = codegen_expr start in + + (* Make the new basic block for the loop header, inserting after current + * block. *) + let preheader_bb = insertion_block builder in + let the_function = block_parent preheader_bb in + let loop_bb = append_block context "loop" the_function in + + (* Insert an explicit fall through from the current block to the + * loop_bb. *) + ignore (build_br loop_bb builder); + + (* Start insertion in loop_bb. *) + position_at_end loop_bb builder; + + (* Start the PHI node with an entry for start. *) + let variable = build_phi [(start_val, preheader_bb)] var_name builder in + + (* Within the loop, the variable is defined equal to the PHI node. If it + * shadows an existing variable, we have to restore it, so save it + * now. *) + let old_val = + try Some (Hashtbl.find named_values var_name) with Not_found -> None + in + Hashtbl.add named_values var_name variable; + + (* Emit the body of the loop. This, like any other expr, can change the + * current BB. Note that we ignore the value computed by the body, but + * don't allow an error *) + ignore (codegen_expr body); + + (* Emit the step value. *) + let step_val = + match step with + | Some step -> codegen_expr step + (* If not specified, use 1.0. *) + | None -> const_float double_type 1.0 + in + + let next_var = build_add variable step_val "nextvar" builder in + + (* Compute the end condition. *) + let end_cond = codegen_expr end_ in + + (* Convert condition to a bool by comparing equal to 0.0. *) + let zero = const_float double_type 0.0 in + let end_cond = build_fcmp Fcmp.One end_cond zero "loopcond" builder in + + (* Create the "after loop" block and insert it. *) + let loop_end_bb = insertion_block builder in + let after_bb = append_block context "afterloop" the_function in + + (* Insert the conditional branch into the end of loop_end_bb. *) + ignore (build_cond_br end_cond loop_bb after_bb builder); + + (* Any new code will be inserted in after_bb. *) + position_at_end after_bb builder; + + (* Add a new entry to the PHI node for the backedge. *) + add_incoming (next_var, loop_end_bb) variable; + + (* Restore the unshadowed variable. *) + begin match old_val with + | Some old_val -> Hashtbl.add named_values var_name old_val + | None -> () + end; + + (* for expr always returns 0.0. *) + const_null double_type + +let codegen_proto = function + | Ast.Prototype (name, args) | Ast.BinOpPrototype (name, args, _) -> + (* Make the function type: double(double,double) etc. *) + let doubles = Array.make (Array.length args) double_type in + let ft = function_type double_type doubles in + let f = + match lookup_function name the_module with + | None -> declare_function name ft the_module + + (* If 'f' conflicted, there was already something named 'name'. If it + * has a body, don't allow redefinition or reextern. *) + | Some f -> + (* If 'f' already has a body, reject this. *) + if block_begin f <> At_end f then + raise (Error "redefinition of function"); + + (* If 'f' took a different number of arguments, reject. *) + if element_type (type_of f) <> ft then + raise (Error "redefinition of function with different # args"); + f + in + + (* Set names for all arguments. *) + Array.iteri (fun i a -> + let n = args.(i) in + set_value_name n a; + Hashtbl.add named_values n a; + ) (params f); + f + +let codegen_func the_fpm = function + | Ast.Function (proto, body) -> + Hashtbl.clear named_values; + let the_function = codegen_proto proto in + + (* If this is an operator, install it. *) + begin match proto with + | Ast.BinOpPrototype (name, args, prec) -> + let op = name.[String.length name - 1] in + Hashtbl.add Parser.binop_precedence op prec; + | _ -> () + end; + + (* Create a new basic block to start insertion into. *) + let bb = append_block context "entry" the_function in + position_at_end bb builder; + + try + let ret_val = codegen_expr body in + + (* Finish off the function. *) + let _ = build_ret ret_val builder in + + (* Validate the generated code, checking for consistency. *) + Llvm_analysis.assert_valid_function the_function; + + (* Optimize the function. *) + let _ = PassManager.run_function the_function the_fpm in + + the_function + with e -> + delete_function the_function; + raise e diff --git a/examples/OCaml-Kaleidoscope/Chapter6/lexer.ml b/examples/OCaml-Kaleidoscope/Chapter6/lexer.ml new file mode 100644 index 000000000000..5fe9da4f16c7 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/lexer.ml @@ -0,0 +1,59 @@ +(*===----------------------------------------------------------------------=== + * Lexer + *===----------------------------------------------------------------------===*) + +let rec lex = parser + (* Skip any whitespace. *) + | [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream + + (* identifier: [a-zA-Z][a-zA-Z0-9] *) + | [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_ident buffer stream + + (* number: [0-9.]+ *) + | [< ' ('0' .. '9' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_number buffer stream + + (* Comment until end of line. *) + | [< ' ('#'); stream >] -> + lex_comment stream + + (* Otherwise, just return the character as its ascii value. *) + | [< 'c; stream >] -> + [< 'Token.Kwd c; lex stream >] + + (* end of stream. *) + | [< >] -> [< >] + +and lex_number buffer = parser + | [< ' ('0' .. '9' | '.' as c); stream >] -> + Buffer.add_char buffer c; + lex_number buffer stream + | [< stream=lex >] -> + [< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >] + +and lex_ident buffer = parser + | [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] -> + Buffer.add_char buffer c; + lex_ident buffer stream + | [< stream=lex >] -> + match Buffer.contents buffer with + | "def" -> [< 'Token.Def; stream >] + | "extern" -> [< 'Token.Extern; stream >] + | "if" -> [< 'Token.If; stream >] + | "then" -> [< 'Token.Then; stream >] + | "else" -> [< 'Token.Else; stream >] + | "for" -> [< 'Token.For; stream >] + | "in" -> [< 'Token.In; stream >] + | "binary" -> [< 'Token.Binary; stream >] + | "unary" -> [< 'Token.Unary; stream >] + | id -> [< 'Token.Ident id; stream >] + +and lex_comment = parser + | [< ' ('\n'); stream=lex >] -> stream + | [< 'c; e=lex_comment >] -> e + | [< >] -> [< >] diff --git a/examples/OCaml-Kaleidoscope/Chapter6/myocamlbuild.ml b/examples/OCaml-Kaleidoscope/Chapter6/myocamlbuild.ml new file mode 100644 index 000000000000..ff42664c43ba --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/myocamlbuild.ml @@ -0,0 +1,10 @@ +open Ocamlbuild_plugin;; + +ocaml_lib ~extern:true "llvm";; +ocaml_lib ~extern:true "llvm_analysis";; +ocaml_lib ~extern:true "llvm_executionengine";; +ocaml_lib ~extern:true "llvm_target";; +ocaml_lib ~extern:true "llvm_scalar_opts";; + +flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"]);; +dep ["link"; "ocaml"; "use_bindings"] ["bindings.o"];; diff --git a/examples/OCaml-Kaleidoscope/Chapter6/parser.ml b/examples/OCaml-Kaleidoscope/Chapter6/parser.ml new file mode 100644 index 000000000000..da443c5bb687 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/parser.ml @@ -0,0 +1,195 @@ +(*===---------------------------------------------------------------------=== + * Parser + *===---------------------------------------------------------------------===*) + +(* binop_precedence - This holds the precedence for each binary operator that is + * defined *) +let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10 + +(* precedence - Get the precedence of the pending binary operator token. *) +let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1 + +(* primary + * ::= identifier + * ::= numberexpr + * ::= parenexpr + * ::= ifexpr + * ::= forexpr *) +let rec parse_primary = parser + (* numberexpr ::= number *) + | [< 'Token.Number n >] -> Ast.Number n + + (* parenexpr ::= '(' expression ')' *) + | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e + + (* identifierexpr + * ::= identifier + * ::= identifier '(' argumentexpr ')' *) + | [< 'Token.Ident id; stream >] -> + let rec parse_args accumulator = parser + | [< e=parse_expr; stream >] -> + begin parser + | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e + | [< >] -> e :: accumulator + end stream + | [< >] -> accumulator + in + let rec parse_ident id = parser + (* Call. *) + | [< 'Token.Kwd '('; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')'">] -> + Ast.Call (id, Array.of_list (List.rev args)) + + (* Simple variable ref. *) + | [< >] -> Ast.Variable id + in + parse_ident id stream + + (* ifexpr ::= 'if' expr 'then' expr 'else' expr *) + | [< 'Token.If; c=parse_expr; + 'Token.Then ?? "expected 'then'"; t=parse_expr; + 'Token.Else ?? "expected 'else'"; e=parse_expr >] -> + Ast.If (c, t, e) + + (* forexpr + ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *) + | [< 'Token.For; + 'Token.Ident id ?? "expected identifier after for"; + 'Token.Kwd '=' ?? "expected '=' after for"; + stream >] -> + begin parser + | [< + start=parse_expr; + 'Token.Kwd ',' ?? "expected ',' after for"; + end_=parse_expr; + stream >] -> + let step = + begin parser + | [< 'Token.Kwd ','; step=parse_expr >] -> Some step + | [< >] -> None + end stream + in + begin parser + | [< 'Token.In; body=parse_expr >] -> + Ast.For (id, start, end_, step, body) + | [< >] -> + raise (Stream.Error "expected 'in' after for") + end stream + | [< >] -> + raise (Stream.Error "expected '=' after for") + end stream + + | [< >] -> raise (Stream.Error "unknown token when expecting an expression.") + +(* unary + * ::= primary + * ::= '!' unary *) +and parse_unary = parser + (* If this is a unary operator, read it. *) + | [< 'Token.Kwd op when op != '(' && op != ')'; operand=parse_expr >] -> + Ast.Unary (op, operand) + + (* If the current token is not an operator, it must be a primary expr. *) + | [< stream >] -> parse_primary stream + +(* binoprhs + * ::= ('+' primary)* *) +and parse_bin_rhs expr_prec lhs stream = + match Stream.peek stream with + (* If this is a binop, find its precedence. *) + | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c -> + let token_prec = precedence c in + + (* If this is a binop that binds at least as tightly as the current binop, + * consume it, otherwise we are done. *) + if token_prec < expr_prec then lhs else begin + (* Eat the binop. *) + Stream.junk stream; + + (* Parse the unary expression after the binary operator. *) + let rhs = parse_unary stream in + + (* Okay, we know this is a binop. *) + let rhs = + match Stream.peek stream with + | Some (Token.Kwd c2) -> + (* If BinOp binds less tightly with rhs than the operator after + * rhs, let the pending operator take rhs as its lhs. *) + let next_prec = precedence c2 in + if token_prec < next_prec + then parse_bin_rhs (token_prec + 1) rhs stream + else rhs + | _ -> rhs + in + + (* Merge lhs/rhs. *) + let lhs = Ast.Binary (c, lhs, rhs) in + parse_bin_rhs expr_prec lhs stream + end + | _ -> lhs + +(* expression + * ::= primary binoprhs *) +and parse_expr = parser + | [< lhs=parse_unary; stream >] -> parse_bin_rhs 0 lhs stream + +(* prototype + * ::= id '(' id* ')' + * ::= binary LETTER number? (id, id) + * ::= unary LETTER number? (id) *) +let parse_prototype = + let rec parse_args accumulator = parser + | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e + | [< >] -> accumulator + in + let parse_operator = parser + | [< 'Token.Unary >] -> "unary", 1 + | [< 'Token.Binary >] -> "binary", 2 + in + let parse_binary_precedence = parser + | [< 'Token.Number n >] -> int_of_float n + | [< >] -> 30 + in + parser + | [< 'Token.Ident id; + 'Token.Kwd '(' ?? "expected '(' in prototype"; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')' in prototype" >] -> + (* success. *) + Ast.Prototype (id, Array.of_list (List.rev args)) + | [< (prefix, kind)=parse_operator; + 'Token.Kwd op ?? "expected an operator"; + (* Read the precedence if present. *) + binary_precedence=parse_binary_precedence; + 'Token.Kwd '(' ?? "expected '(' in prototype"; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')' in prototype" >] -> + let name = prefix ^ (String.make 1 op) in + let args = Array.of_list (List.rev args) in + + (* Verify right number of arguments for operator. *) + if Array.length args != kind + then raise (Stream.Error "invalid number of operands for operator") + else + if kind == 1 then + Ast.Prototype (name, args) + else + Ast.BinOpPrototype (name, args, binary_precedence) + | [< >] -> + raise (Stream.Error "expected function name in prototype") + +(* definition ::= 'def' prototype expression *) +let parse_definition = parser + | [< 'Token.Def; p=parse_prototype; e=parse_expr >] -> + Ast.Function (p, e) + +(* toplevelexpr ::= expression *) +let parse_toplevel = parser + | [< e=parse_expr >] -> + (* Make an anonymous proto. *) + Ast.Function (Ast.Prototype ("", [||]), e) + +(* external ::= 'extern' prototype *) +let parse_extern = parser + | [< 'Token.Extern; e=parse_prototype >] -> e diff --git a/examples/OCaml-Kaleidoscope/Chapter6/token.ml b/examples/OCaml-Kaleidoscope/Chapter6/token.ml new file mode 100644 index 000000000000..c7a5f95092d1 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/token.ml @@ -0,0 +1,22 @@ +(*===----------------------------------------------------------------------=== + * Lexer Tokens + *===----------------------------------------------------------------------===*) + +(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of + * these others for known things. *) +type token = + (* commands *) + | Def | Extern + + (* primary *) + | Ident of string | Number of float + + (* unknown *) + | Kwd of char + + (* control *) + | If | Then | Else + | For | In + + (* operators *) + | Binary | Unary diff --git a/examples/OCaml-Kaleidoscope/Chapter6/toplevel.ml b/examples/OCaml-Kaleidoscope/Chapter6/toplevel.ml new file mode 100644 index 000000000000..01d24ede1492 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/toplevel.ml @@ -0,0 +1,49 @@ +(*===----------------------------------------------------------------------=== + * Top-Level parsing and JIT Driver + *===----------------------------------------------------------------------===*) + +open Llvm +open Llvm_executionengine + +(* top ::= definition | external | expression | ';' *) +let rec main_loop the_fpm the_execution_engine stream = + match Stream.peek stream with + | None -> () + + (* ignore top-level semicolons. *) + | Some (Token.Kwd ';') -> + Stream.junk stream; + main_loop the_fpm the_execution_engine stream + + | Some token -> + begin + try match token with + | Token.Def -> + let e = Parser.parse_definition stream in + print_endline "parsed a function definition."; + dump_value (Codegen.codegen_func the_fpm e); + | Token.Extern -> + let e = Parser.parse_extern stream in + print_endline "parsed an extern."; + dump_value (Codegen.codegen_proto e); + | _ -> + (* Evaluate a top-level expression into an anonymous function. *) + let e = Parser.parse_toplevel stream in + print_endline "parsed a top-level expr"; + let the_function = Codegen.codegen_func the_fpm e in + dump_value the_function; + + (* JIT the function, returning a function pointer. *) + let result = ExecutionEngine.run_function the_function [||] + the_execution_engine in + + print_string "Evaluated to "; + print_float (GenericValue.as_float Codegen.double_type result); + print_newline (); + with Stream.Error s | Codegen.Error s -> + (* Skip token for error recovery. *) + Stream.junk stream; + print_endline s; + end; + print_string "ready> "; flush stdout; + main_loop the_fpm the_execution_engine stream diff --git a/examples/OCaml-Kaleidoscope/Chapter6/toy.ml b/examples/OCaml-Kaleidoscope/Chapter6/toy.ml new file mode 100644 index 000000000000..5f9d912499c9 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter6/toy.ml @@ -0,0 +1,53 @@ +(*===----------------------------------------------------------------------=== + * Main driver code. + *===----------------------------------------------------------------------===*) + +open Llvm +open Llvm_executionengine +open Llvm_target +open Llvm_scalar_opts + +let main () = + ignore (initialize_native_target ()); + + (* Install standard binary operators. + * 1 is the lowest precedence. *) + Hashtbl.add Parser.binop_precedence '<' 10; + Hashtbl.add Parser.binop_precedence '+' 20; + Hashtbl.add Parser.binop_precedence '-' 20; + Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *) + + (* Prime the first token. *) + print_string "ready> "; flush stdout; + let stream = Lexer.lex (Stream.of_channel stdin) in + + (* Create the JIT. *) + let the_execution_engine = ExecutionEngine.create Codegen.the_module in + let the_fpm = PassManager.create_function Codegen.the_module in + + (* Set up the optimizer pipeline. Start with registering info about how the + * target lays out data structures. *) + TargetData.add (ExecutionEngine.target_data the_execution_engine) the_fpm; + + (* Do simple "peephole" optimizations and bit-twiddling optzn. *) + add_instruction_combination the_fpm; + + (* reassociate expressions. *) + add_reassociation the_fpm; + + (* Eliminate Common SubExpressions. *) + add_gvn the_fpm; + + (* Simplify the control flow graph (deleting unreachable blocks, etc). *) + add_cfg_simplification the_fpm; + + ignore (PassManager.initialize the_fpm); + + (* Run the main "interpreter loop" now. *) + Toplevel.main_loop the_fpm the_execution_engine stream; + + (* Print out all the generated code. *) + dump_module Codegen.the_module +;; + +main () diff --git a/examples/OCaml-Kaleidoscope/Chapter7/Makefile b/examples/OCaml-Kaleidoscope/Chapter7/Makefile new file mode 100644 index 000000000000..ddf667b0e123 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/Makefile @@ -0,0 +1,25 @@ +##===- examples/OCaml-Kaleidoscope/Chapter7/Makefile -------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This is the makefile for the Objective Caml kaleidoscope tutorial, chapter 7. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../../.. +TOOLNAME := OCaml-Kaleidoscope-Ch7 +EXAMPLE_TOOL := 1 +UsedComponents := core +UsedOcamLibs := llvm llvm_analysis llvm_executionengine llvm_target \ + llvm_scalar_opts + +OCAMLCFLAGS += -pp camlp4of + +ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml + +include $(LEVEL)/bindings/ocaml/Makefile.ocaml diff --git a/examples/OCaml-Kaleidoscope/Chapter7/_tags b/examples/OCaml-Kaleidoscope/Chapter7/_tags new file mode 100644 index 000000000000..7a03dba66723 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/_tags @@ -0,0 +1,4 @@ +<{lexer,parser}.ml>: use_camlp4, pp(camlp4of) +<*.{byte,native}>: g++, use_llvm, use_llvm_analysis +<*.{byte,native}>: use_llvm_executionengine, use_llvm_target +<*.{byte,native}>: use_llvm_scalar_opts, use_bindings diff --git a/examples/OCaml-Kaleidoscope/Chapter7/ast.ml b/examples/OCaml-Kaleidoscope/Chapter7/ast.ml new file mode 100644 index 000000000000..c699e8074a4a --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/ast.ml @@ -0,0 +1,39 @@ +(*===----------------------------------------------------------------------=== + * Abstract Syntax Tree (aka Parse Tree) + *===----------------------------------------------------------------------===*) + +(* expr - Base type for all expression nodes. *) +type expr = + (* variant for numeric literals like "1.0". *) + | Number of float + + (* variant for referencing a variable, like "a". *) + | Variable of string + + (* variant for a unary operator. *) + | Unary of char * expr + + (* variant for a binary operator. *) + | Binary of char * expr * expr + + (* variant for function calls. *) + | Call of string * expr array + + (* variant for if/then/else. *) + | If of expr * expr * expr + + (* variant for for/in. *) + | For of string * expr * expr * expr option * expr + + (* variant for var/in. *) + | Var of (string * expr option) array * expr + +(* proto - This type represents the "prototype" for a function, which captures + * its name, and its argument names (thus implicitly the number of arguments the + * function takes). *) +type proto = + | Prototype of string * string array + | BinOpPrototype of string * string array * int + +(* func - This type represents a function definition itself. *) +type func = Function of proto * expr diff --git a/examples/OCaml-Kaleidoscope/Chapter7/bindings.c b/examples/OCaml-Kaleidoscope/Chapter7/bindings.c new file mode 100644 index 000000000000..90faed15813d --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/bindings.c @@ -0,0 +1,13 @@ +#include <stdio.h> + +/* putchard - putchar that takes a double and returns 0. */ +extern double putchard(double X) { + putchar((char)X); + return 0; +} + +/* printd - printf that takes a double prints it as "%f\n", returning 0. */ +extern double printd(double X) { + printf("%f\n", X); + return 0; +} diff --git a/examples/OCaml-Kaleidoscope/Chapter7/codegen.ml b/examples/OCaml-Kaleidoscope/Chapter7/codegen.ml new file mode 100644 index 000000000000..e8fac32f5b25 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/codegen.ml @@ -0,0 +1,370 @@ +(*===----------------------------------------------------------------------=== + * Code Generation + *===----------------------------------------------------------------------===*) + +open Llvm + +exception Error of string + +let context = global_context () +let the_module = create_module context "my cool jit" +let builder = builder context +let named_values:(string, llvalue) Hashtbl.t = Hashtbl.create 10 +let double_type = double_type context + +(* Create an alloca instruction in the entry block of the function. This + * is used for mutable variables etc. *) +let create_entry_block_alloca the_function var_name = + let builder = builder_at context (instr_begin (entry_block the_function)) in + build_alloca double_type var_name builder + +let rec codegen_expr = function + | Ast.Number n -> const_float double_type n + | Ast.Variable name -> + let v = try Hashtbl.find named_values name with + | Not_found -> raise (Error "unknown variable name") + in + (* Load the value. *) + build_load v name builder + | Ast.Unary (op, operand) -> + let operand = codegen_expr operand in + let callee = "unary" ^ (String.make 1 op) in + let callee = + match lookup_function callee the_module with + | Some callee -> callee + | None -> raise (Error "unknown unary operator") + in + build_call callee [|operand|] "unop" builder + | Ast.Binary (op, lhs, rhs) -> + begin match op with + | '=' -> + (* Special case '=' because we don't want to emit the LHS as an + * expression. *) + let name = + match lhs with + | Ast.Variable name -> name + | _ -> raise (Error "destination of '=' must be a variable") + in + + (* Codegen the rhs. *) + let val_ = codegen_expr rhs in + + (* Lookup the name. *) + let variable = try Hashtbl.find named_values name with + | Not_found -> raise (Error "unknown variable name") + in + ignore(build_store val_ variable builder); + val_ + | _ -> + let lhs_val = codegen_expr lhs in + let rhs_val = codegen_expr rhs in + begin + match op with + | '+' -> build_add lhs_val rhs_val "addtmp" builder + | '-' -> build_sub lhs_val rhs_val "subtmp" builder + | '*' -> build_mul lhs_val rhs_val "multmp" builder + | '<' -> + (* Convert bool 0/1 to double 0.0 or 1.0 *) + let i = build_fcmp Fcmp.Ult lhs_val rhs_val "cmptmp" builder in + build_uitofp i double_type "booltmp" builder + | _ -> + (* If it wasn't a builtin binary operator, it must be a user defined + * one. Emit a call to it. *) + let callee = "binary" ^ (String.make 1 op) in + let callee = + match lookup_function callee the_module with + | Some callee -> callee + | None -> raise (Error "binary operator not found!") + in + build_call callee [|lhs_val; rhs_val|] "binop" builder + end + end + | Ast.Call (callee, args) -> + (* Look up the name in the module table. *) + let callee = + match lookup_function callee the_module with + | Some callee -> callee + | None -> raise (Error "unknown function referenced") + in + let params = params callee in + + (* If argument mismatch error. *) + if Array.length params == Array.length args then () else + raise (Error "incorrect # arguments passed"); + let args = Array.map codegen_expr args in + build_call callee args "calltmp" builder + | Ast.If (cond, then_, else_) -> + let cond = codegen_expr cond in + + (* Convert condition to a bool by comparing equal to 0.0 *) + let zero = const_float double_type 0.0 in + let cond_val = build_fcmp Fcmp.One cond zero "ifcond" builder in + + (* Grab the first block so that we might later add the conditional branch + * to it at the end of the function. *) + let start_bb = insertion_block builder in + let the_function = block_parent start_bb in + + let then_bb = append_block context "then" the_function in + + (* Emit 'then' value. *) + position_at_end then_bb builder; + let then_val = codegen_expr then_ in + + (* Codegen of 'then' can change the current block, update then_bb for the + * phi. We create a new name because one is used for the phi node, and the + * other is used for the conditional branch. *) + let new_then_bb = insertion_block builder in + + (* Emit 'else' value. *) + let else_bb = append_block context "else" the_function in + position_at_end else_bb builder; + let else_val = codegen_expr else_ in + + (* Codegen of 'else' can change the current block, update else_bb for the + * phi. *) + let new_else_bb = insertion_block builder in + + (* Emit merge block. *) + let merge_bb = append_block context "ifcont" the_function in + position_at_end merge_bb builder; + let incoming = [(then_val, new_then_bb); (else_val, new_else_bb)] in + let phi = build_phi incoming "iftmp" builder in + + (* Return to the start block to add the conditional branch. *) + position_at_end start_bb builder; + ignore (build_cond_br cond_val then_bb else_bb builder); + + (* Set a unconditional branch at the end of the 'then' block and the + * 'else' block to the 'merge' block. *) + position_at_end new_then_bb builder; ignore (build_br merge_bb builder); + position_at_end new_else_bb builder; ignore (build_br merge_bb builder); + + (* Finally, set the builder to the end of the merge block. *) + position_at_end merge_bb builder; + + phi + | Ast.For (var_name, start, end_, step, body) -> + (* Output this as: + * var = alloca double + * ... + * start = startexpr + * store start -> var + * goto loop + * loop: + * ... + * bodyexpr + * ... + * loopend: + * step = stepexpr + * endcond = endexpr + * + * curvar = load var + * nextvar = curvar + step + * store nextvar -> var + * br endcond, loop, endloop + * outloop: *) + + let the_function = block_parent (insertion_block builder) in + + (* Create an alloca for the variable in the entry block. *) + let alloca = create_entry_block_alloca the_function var_name in + + (* Emit the start code first, without 'variable' in scope. *) + let start_val = codegen_expr start in + + (* Store the value into the alloca. *) + ignore(build_store start_val alloca builder); + + (* Make the new basic block for the loop header, inserting after current + * block. *) + let loop_bb = append_block context "loop" the_function in + + (* Insert an explicit fall through from the current block to the + * loop_bb. *) + ignore (build_br loop_bb builder); + + (* Start insertion in loop_bb. *) + position_at_end loop_bb builder; + + (* Within the loop, the variable is defined equal to the PHI node. If it + * shadows an existing variable, we have to restore it, so save it + * now. *) + let old_val = + try Some (Hashtbl.find named_values var_name) with Not_found -> None + in + Hashtbl.add named_values var_name alloca; + + (* Emit the body of the loop. This, like any other expr, can change the + * current BB. Note that we ignore the value computed by the body, but + * don't allow an error *) + ignore (codegen_expr body); + + (* Emit the step value. *) + let step_val = + match step with + | Some step -> codegen_expr step + (* If not specified, use 1.0. *) + | None -> const_float double_type 1.0 + in + + (* Compute the end condition. *) + let end_cond = codegen_expr end_ in + + (* Reload, increment, and restore the alloca. This handles the case where + * the body of the loop mutates the variable. *) + let cur_var = build_load alloca var_name builder in + let next_var = build_add cur_var step_val "nextvar" builder in + ignore(build_store next_var alloca builder); + + (* Convert condition to a bool by comparing equal to 0.0. *) + let zero = const_float double_type 0.0 in + let end_cond = build_fcmp Fcmp.One end_cond zero "loopcond" builder in + + (* Create the "after loop" block and insert it. *) + let after_bb = append_block context "afterloop" the_function in + + (* Insert the conditional branch into the end of loop_end_bb. *) + ignore (build_cond_br end_cond loop_bb after_bb builder); + + (* Any new code will be inserted in after_bb. *) + position_at_end after_bb builder; + + (* Restore the unshadowed variable. *) + begin match old_val with + | Some old_val -> Hashtbl.add named_values var_name old_val + | None -> () + end; + + (* for expr always returns 0.0. *) + const_null double_type + | Ast.Var (var_names, body) -> + let old_bindings = ref [] in + + let the_function = block_parent (insertion_block builder) in + + (* Register all variables and emit their initializer. *) + Array.iter (fun (var_name, init) -> + (* Emit the initializer before adding the variable to scope, this + * prevents the initializer from referencing the variable itself, and + * permits stuff like this: + * var a = 1 in + * var a = a in ... # refers to outer 'a'. *) + let init_val = + match init with + | Some init -> codegen_expr init + (* If not specified, use 0.0. *) + | None -> const_float double_type 0.0 + in + + let alloca = create_entry_block_alloca the_function var_name in + ignore(build_store init_val alloca builder); + + (* Remember the old variable binding so that we can restore the binding + * when we unrecurse. *) + begin + try + let old_value = Hashtbl.find named_values var_name in + old_bindings := (var_name, old_value) :: !old_bindings; + with Not_found -> () + end; + + (* Remember this binding. *) + Hashtbl.add named_values var_name alloca; + ) var_names; + + (* Codegen the body, now that all vars are in scope. *) + let body_val = codegen_expr body in + + (* Pop all our variables from scope. *) + List.iter (fun (var_name, old_value) -> + Hashtbl.add named_values var_name old_value + ) !old_bindings; + + (* Return the body computation. *) + body_val + +let codegen_proto = function + | Ast.Prototype (name, args) | Ast.BinOpPrototype (name, args, _) -> + (* Make the function type: double(double,double) etc. *) + let doubles = Array.make (Array.length args) double_type in + let ft = function_type double_type doubles in + let f = + match lookup_function name the_module with + | None -> declare_function name ft the_module + + (* If 'f' conflicted, there was already something named 'name'. If it + * has a body, don't allow redefinition or reextern. *) + | Some f -> + (* If 'f' already has a body, reject this. *) + if block_begin f <> At_end f then + raise (Error "redefinition of function"); + + (* If 'f' took a different number of arguments, reject. *) + if element_type (type_of f) <> ft then + raise (Error "redefinition of function with different # args"); + f + in + + (* Set names for all arguments. *) + Array.iteri (fun i a -> + let n = args.(i) in + set_value_name n a; + Hashtbl.add named_values n a; + ) (params f); + f + +(* Create an alloca for each argument and register the argument in the symbol + * table so that references to it will succeed. *) +let create_argument_allocas the_function proto = + let args = match proto with + | Ast.Prototype (_, args) | Ast.BinOpPrototype (_, args, _) -> args + in + Array.iteri (fun i ai -> + let var_name = args.(i) in + (* Create an alloca for this variable. *) + let alloca = create_entry_block_alloca the_function var_name in + + (* Store the initial value into the alloca. *) + ignore(build_store ai alloca builder); + + (* Add arguments to variable symbol table. *) + Hashtbl.add named_values var_name alloca; + ) (params the_function) + +let codegen_func the_fpm = function + | Ast.Function (proto, body) -> + Hashtbl.clear named_values; + let the_function = codegen_proto proto in + + (* If this is an operator, install it. *) + begin match proto with + | Ast.BinOpPrototype (name, args, prec) -> + let op = name.[String.length name - 1] in + Hashtbl.add Parser.binop_precedence op prec; + | _ -> () + end; + + (* Create a new basic block to start insertion into. *) + let bb = append_block context "entry" the_function in + position_at_end bb builder; + + try + (* Add all arguments to the symbol table and create their allocas. *) + create_argument_allocas the_function proto; + + let ret_val = codegen_expr body in + + (* Finish off the function. *) + let _ = build_ret ret_val builder in + + (* Validate the generated code, checking for consistency. *) + Llvm_analysis.assert_valid_function the_function; + + (* Optimize the function. *) + let _ = PassManager.run_function the_function the_fpm in + + the_function + with e -> + delete_function the_function; + raise e diff --git a/examples/OCaml-Kaleidoscope/Chapter7/lexer.ml b/examples/OCaml-Kaleidoscope/Chapter7/lexer.ml new file mode 100644 index 000000000000..922cabf04281 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/lexer.ml @@ -0,0 +1,60 @@ +(*===----------------------------------------------------------------------=== + * Lexer + *===----------------------------------------------------------------------===*) + +let rec lex = parser + (* Skip any whitespace. *) + | [< ' (' ' | '\n' | '\r' | '\t'); stream >] -> lex stream + + (* identifier: [a-zA-Z][a-zA-Z0-9] *) + | [< ' ('A' .. 'Z' | 'a' .. 'z' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_ident buffer stream + + (* number: [0-9.]+ *) + | [< ' ('0' .. '9' as c); stream >] -> + let buffer = Buffer.create 1 in + Buffer.add_char buffer c; + lex_number buffer stream + + (* Comment until end of line. *) + | [< ' ('#'); stream >] -> + lex_comment stream + + (* Otherwise, just return the character as its ascii value. *) + | [< 'c; stream >] -> + [< 'Token.Kwd c; lex stream >] + + (* end of stream. *) + | [< >] -> [< >] + +and lex_number buffer = parser + | [< ' ('0' .. '9' | '.' as c); stream >] -> + Buffer.add_char buffer c; + lex_number buffer stream + | [< stream=lex >] -> + [< 'Token.Number (float_of_string (Buffer.contents buffer)); stream >] + +and lex_ident buffer = parser + | [< ' ('A' .. 'Z' | 'a' .. 'z' | '0' .. '9' as c); stream >] -> + Buffer.add_char buffer c; + lex_ident buffer stream + | [< stream=lex >] -> + match Buffer.contents buffer with + | "def" -> [< 'Token.Def; stream >] + | "extern" -> [< 'Token.Extern; stream >] + | "if" -> [< 'Token.If; stream >] + | "then" -> [< 'Token.Then; stream >] + | "else" -> [< 'Token.Else; stream >] + | "for" -> [< 'Token.For; stream >] + | "in" -> [< 'Token.In; stream >] + | "binary" -> [< 'Token.Binary; stream >] + | "unary" -> [< 'Token.Unary; stream >] + | "var" -> [< 'Token.Var; stream >] + | id -> [< 'Token.Ident id; stream >] + +and lex_comment = parser + | [< ' ('\n'); stream=lex >] -> stream + | [< 'c; e=lex_comment >] -> e + | [< >] -> [< >] diff --git a/examples/OCaml-Kaleidoscope/Chapter7/myocamlbuild.ml b/examples/OCaml-Kaleidoscope/Chapter7/myocamlbuild.ml new file mode 100644 index 000000000000..ff42664c43ba --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/myocamlbuild.ml @@ -0,0 +1,10 @@ +open Ocamlbuild_plugin;; + +ocaml_lib ~extern:true "llvm";; +ocaml_lib ~extern:true "llvm_analysis";; +ocaml_lib ~extern:true "llvm_executionengine";; +ocaml_lib ~extern:true "llvm_target";; +ocaml_lib ~extern:true "llvm_scalar_opts";; + +flag ["link"; "ocaml"; "g++"] (S[A"-cc"; A"g++"]);; +dep ["link"; "ocaml"; "use_bindings"] ["bindings.o"];; diff --git a/examples/OCaml-Kaleidoscope/Chapter7/parser.ml b/examples/OCaml-Kaleidoscope/Chapter7/parser.ml new file mode 100644 index 000000000000..c0e7db8349a5 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/parser.ml @@ -0,0 +1,221 @@ +(*===---------------------------------------------------------------------=== + * Parser + *===---------------------------------------------------------------------===*) + +(* binop_precedence - This holds the precedence for each binary operator that is + * defined *) +let binop_precedence:(char, int) Hashtbl.t = Hashtbl.create 10 + +(* precedence - Get the precedence of the pending binary operator token. *) +let precedence c = try Hashtbl.find binop_precedence c with Not_found -> -1 + +(* primary + * ::= identifier + * ::= numberexpr + * ::= parenexpr + * ::= ifexpr + * ::= forexpr + * ::= varexpr *) +let rec parse_primary = parser + (* numberexpr ::= number *) + | [< 'Token.Number n >] -> Ast.Number n + + (* parenexpr ::= '(' expression ')' *) + | [< 'Token.Kwd '('; e=parse_expr; 'Token.Kwd ')' ?? "expected ')'" >] -> e + + (* identifierexpr + * ::= identifier + * ::= identifier '(' argumentexpr ')' *) + | [< 'Token.Ident id; stream >] -> + let rec parse_args accumulator = parser + | [< e=parse_expr; stream >] -> + begin parser + | [< 'Token.Kwd ','; e=parse_args (e :: accumulator) >] -> e + | [< >] -> e :: accumulator + end stream + | [< >] -> accumulator + in + let rec parse_ident id = parser + (* Call. *) + | [< 'Token.Kwd '('; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')'">] -> + Ast.Call (id, Array.of_list (List.rev args)) + + (* Simple variable ref. *) + | [< >] -> Ast.Variable id + in + parse_ident id stream + + (* ifexpr ::= 'if' expr 'then' expr 'else' expr *) + | [< 'Token.If; c=parse_expr; + 'Token.Then ?? "expected 'then'"; t=parse_expr; + 'Token.Else ?? "expected 'else'"; e=parse_expr >] -> + Ast.If (c, t, e) + + (* forexpr + ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression *) + | [< 'Token.For; + 'Token.Ident id ?? "expected identifier after for"; + 'Token.Kwd '=' ?? "expected '=' after for"; + stream >] -> + begin parser + | [< + start=parse_expr; + 'Token.Kwd ',' ?? "expected ',' after for"; + end_=parse_expr; + stream >] -> + let step = + begin parser + | [< 'Token.Kwd ','; step=parse_expr >] -> Some step + | [< >] -> None + end stream + in + begin parser + | [< 'Token.In; body=parse_expr >] -> + Ast.For (id, start, end_, step, body) + | [< >] -> + raise (Stream.Error "expected 'in' after for") + end stream + | [< >] -> + raise (Stream.Error "expected '=' after for") + end stream + + (* varexpr + * ::= 'var' identifier ('=' expression? + * (',' identifier ('=' expression)?)* 'in' expression *) + | [< 'Token.Var; + (* At least one variable name is required. *) + 'Token.Ident id ?? "expected identifier after var"; + init=parse_var_init; + var_names=parse_var_names [(id, init)]; + (* At this point, we have to have 'in'. *) + 'Token.In ?? "expected 'in' keyword after 'var'"; + body=parse_expr >] -> + Ast.Var (Array.of_list (List.rev var_names), body) + + | [< >] -> raise (Stream.Error "unknown token when expecting an expression.") + +(* unary + * ::= primary + * ::= '!' unary *) +and parse_unary = parser + (* If this is a unary operator, read it. *) + | [< 'Token.Kwd op when op != '(' && op != ')'; operand=parse_expr >] -> + Ast.Unary (op, operand) + + (* If the current token is not an operator, it must be a primary expr. *) + | [< stream >] -> parse_primary stream + +(* binoprhs + * ::= ('+' primary)* *) +and parse_bin_rhs expr_prec lhs stream = + match Stream.peek stream with + (* If this is a binop, find its precedence. *) + | Some (Token.Kwd c) when Hashtbl.mem binop_precedence c -> + let token_prec = precedence c in + + (* If this is a binop that binds at least as tightly as the current binop, + * consume it, otherwise we are done. *) + if token_prec < expr_prec then lhs else begin + (* Eat the binop. *) + Stream.junk stream; + + (* Parse the primary expression after the binary operator. *) + let rhs = parse_unary stream in + + (* Okay, we know this is a binop. *) + let rhs = + match Stream.peek stream with + | Some (Token.Kwd c2) -> + (* If BinOp binds less tightly with rhs than the operator after + * rhs, let the pending operator take rhs as its lhs. *) + let next_prec = precedence c2 in + if token_prec < next_prec + then parse_bin_rhs (token_prec + 1) rhs stream + else rhs + | _ -> rhs + in + + (* Merge lhs/rhs. *) + let lhs = Ast.Binary (c, lhs, rhs) in + parse_bin_rhs expr_prec lhs stream + end + | _ -> lhs + +and parse_var_init = parser + (* read in the optional initializer. *) + | [< 'Token.Kwd '='; e=parse_expr >] -> Some e + | [< >] -> None + +and parse_var_names accumulator = parser + | [< 'Token.Kwd ','; + 'Token.Ident id ?? "expected identifier list after var"; + init=parse_var_init; + e=parse_var_names ((id, init) :: accumulator) >] -> e + | [< >] -> accumulator + +(* expression + * ::= primary binoprhs *) +and parse_expr = parser + | [< lhs=parse_unary; stream >] -> parse_bin_rhs 0 lhs stream + +(* prototype + * ::= id '(' id* ')' + * ::= binary LETTER number? (id, id) + * ::= unary LETTER number? (id) *) +let parse_prototype = + let rec parse_args accumulator = parser + | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e + | [< >] -> accumulator + in + let parse_operator = parser + | [< 'Token.Unary >] -> "unary", 1 + | [< 'Token.Binary >] -> "binary", 2 + in + let parse_binary_precedence = parser + | [< 'Token.Number n >] -> int_of_float n + | [< >] -> 30 + in + parser + | [< 'Token.Ident id; + 'Token.Kwd '(' ?? "expected '(' in prototype"; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')' in prototype" >] -> + (* success. *) + Ast.Prototype (id, Array.of_list (List.rev args)) + | [< (prefix, kind)=parse_operator; + 'Token.Kwd op ?? "expected an operator"; + (* Read the precedence if present. *) + binary_precedence=parse_binary_precedence; + 'Token.Kwd '(' ?? "expected '(' in prototype"; + args=parse_args []; + 'Token.Kwd ')' ?? "expected ')' in prototype" >] -> + let name = prefix ^ (String.make 1 op) in + let args = Array.of_list (List.rev args) in + + (* Verify right number of arguments for operator. *) + if Array.length args != kind + then raise (Stream.Error "invalid number of operands for operator") + else + if kind == 1 then + Ast.Prototype (name, args) + else + Ast.BinOpPrototype (name, args, binary_precedence) + | [< >] -> + raise (Stream.Error "expected function name in prototype") + +(* definition ::= 'def' prototype expression *) +let parse_definition = parser + | [< 'Token.Def; p=parse_prototype; e=parse_expr >] -> + Ast.Function (p, e) + +(* toplevelexpr ::= expression *) +let parse_toplevel = parser + | [< e=parse_expr >] -> + (* Make an anonymous proto. *) + Ast.Function (Ast.Prototype ("", [||]), e) + +(* external ::= 'extern' prototype *) +let parse_extern = parser + | [< 'Token.Extern; e=parse_prototype >] -> e diff --git a/examples/OCaml-Kaleidoscope/Chapter7/token.ml b/examples/OCaml-Kaleidoscope/Chapter7/token.ml new file mode 100644 index 000000000000..1489f0b9e79d --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/token.ml @@ -0,0 +1,25 @@ +(*===----------------------------------------------------------------------=== + * Lexer Tokens + *===----------------------------------------------------------------------===*) + +(* The lexer returns these 'Kwd' if it is an unknown character, otherwise one of + * these others for known things. *) +type token = + (* commands *) + | Def | Extern + + (* primary *) + | Ident of string | Number of float + + (* unknown *) + | Kwd of char + + (* control *) + | If | Then | Else + | For | In + + (* operators *) + | Binary | Unary + + (* var definition *) + | Var diff --git a/examples/OCaml-Kaleidoscope/Chapter7/toplevel.ml b/examples/OCaml-Kaleidoscope/Chapter7/toplevel.ml new file mode 100644 index 000000000000..01d24ede1492 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/toplevel.ml @@ -0,0 +1,49 @@ +(*===----------------------------------------------------------------------=== + * Top-Level parsing and JIT Driver + *===----------------------------------------------------------------------===*) + +open Llvm +open Llvm_executionengine + +(* top ::= definition | external | expression | ';' *) +let rec main_loop the_fpm the_execution_engine stream = + match Stream.peek stream with + | None -> () + + (* ignore top-level semicolons. *) + | Some (Token.Kwd ';') -> + Stream.junk stream; + main_loop the_fpm the_execution_engine stream + + | Some token -> + begin + try match token with + | Token.Def -> + let e = Parser.parse_definition stream in + print_endline "parsed a function definition."; + dump_value (Codegen.codegen_func the_fpm e); + | Token.Extern -> + let e = Parser.parse_extern stream in + print_endline "parsed an extern."; + dump_value (Codegen.codegen_proto e); + | _ -> + (* Evaluate a top-level expression into an anonymous function. *) + let e = Parser.parse_toplevel stream in + print_endline "parsed a top-level expr"; + let the_function = Codegen.codegen_func the_fpm e in + dump_value the_function; + + (* JIT the function, returning a function pointer. *) + let result = ExecutionEngine.run_function the_function [||] + the_execution_engine in + + print_string "Evaluated to "; + print_float (GenericValue.as_float Codegen.double_type result); + print_newline (); + with Stream.Error s | Codegen.Error s -> + (* Skip token for error recovery. *) + Stream.junk stream; + print_endline s; + end; + print_string "ready> "; flush stdout; + main_loop the_fpm the_execution_engine stream diff --git a/examples/OCaml-Kaleidoscope/Chapter7/toy.ml b/examples/OCaml-Kaleidoscope/Chapter7/toy.ml new file mode 100644 index 000000000000..babab28601dd --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Chapter7/toy.ml @@ -0,0 +1,57 @@ +(*===----------------------------------------------------------------------=== + * Main driver code. + *===----------------------------------------------------------------------===*) + +open Llvm +open Llvm_executionengine +open Llvm_target +open Llvm_scalar_opts + +let main () = + ignore (initialize_native_target ()); + + (* Install standard binary operators. + * 1 is the lowest precedence. *) + Hashtbl.add Parser.binop_precedence '=' 2; + Hashtbl.add Parser.binop_precedence '<' 10; + Hashtbl.add Parser.binop_precedence '+' 20; + Hashtbl.add Parser.binop_precedence '-' 20; + Hashtbl.add Parser.binop_precedence '*' 40; (* highest. *) + + (* Prime the first token. *) + print_string "ready> "; flush stdout; + let stream = Lexer.lex (Stream.of_channel stdin) in + + (* Create the JIT. *) + let the_execution_engine = ExecutionEngine.create Codegen.the_module in + let the_fpm = PassManager.create_function Codegen.the_module in + + (* Set up the optimizer pipeline. Start with registering info about how the + * target lays out data structures. *) + TargetData.add (ExecutionEngine.target_data the_execution_engine) the_fpm; + + (* Promote allocas to registers. *) + add_memory_to_register_promotion the_fpm; + + (* Do simple "peephole" optimizations and bit-twiddling optzn. *) + add_instruction_combination the_fpm; + + (* reassociate expressions. *) + add_reassociation the_fpm; + + (* Eliminate Common SubExpressions. *) + add_gvn the_fpm; + + (* Simplify the control flow graph (deleting unreachable blocks, etc). *) + add_cfg_simplification the_fpm; + + ignore (PassManager.initialize the_fpm); + + (* Run the main "interpreter loop" now. *) + Toplevel.main_loop the_fpm the_execution_engine stream; + + (* Print out all the generated code. *) + dump_module Codegen.the_module +;; + +main () diff --git a/examples/OCaml-Kaleidoscope/Makefile b/examples/OCaml-Kaleidoscope/Makefile new file mode 100644 index 000000000000..5342b94022a9 --- /dev/null +++ b/examples/OCaml-Kaleidoscope/Makefile @@ -0,0 +1,15 @@ +##===- examples/OCaml-Kaleidoscope/Makefile ----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL=../.. + +include $(LEVEL)/Makefile.config + +PARALLEL_DIRS:= Chapter2 Chapter3 Chapter4 Chapter5 Chapter6 Chapter7 + +include $(LEVEL)/Makefile.common diff --git a/include/llvm-c/Transforms/Scalar.h b/include/llvm-c/Transforms/Scalar.h index 2c5a3714d4d1..c94019ac98b0 100644 --- a/include/llvm-c/Transforms/Scalar.h +++ b/include/llvm-c/Transforms/Scalar.h @@ -79,6 +79,10 @@ void LLVMAddSCCPPass(LLVMPassManagerRef PM); /** See llvm::createScalarReplAggregatesPass function. */ void LLVMAddScalarReplAggregatesPass(LLVMPassManagerRef PM); +/** See llvm::createScalarReplAggregatesPass function. */ +void LLVMAddScalarReplAggregatesPassWithThreshold(LLVMPassManagerRef PM, + int Threshold); + /** See llvm::createSimplifyLibCallsPass function. */ void LLVMAddSimplifyLibCallsPass(LLVMPassManagerRef PM); @@ -91,6 +95,9 @@ void LLVMAddConstantPropagationPass(LLVMPassManagerRef PM); /** See llvm::demotePromoteMemoryToRegisterPass function. */ void LLVMAddDemoteMemoryToRegisterPass(LLVMPassManagerRef PM); +/** See llvm::createVerifierPass function. */ +void LLVMAddVerifierPass(LLVMPassManagerRef PM); + #ifdef __cplusplus } #endif /* defined(__cplusplus) */ diff --git a/include/llvm/ADT/STLExtras.h b/include/llvm/ADT/STLExtras.h index 32cf4590e993..8dbf79031c35 100644 --- a/include/llvm/ADT/STLExtras.h +++ b/include/llvm/ADT/STLExtras.h @@ -279,6 +279,28 @@ static inline void array_pod_sort(IteratorTy Start, IteratorTy End, qsort(&*Start, End-Start, sizeof(*Start), Compare); } +//===----------------------------------------------------------------------===// +// Extra additions to <algorithm> +//===----------------------------------------------------------------------===// + +/// For a container of pointers, deletes the pointers and then clears the +/// container. +template<typename Container> +void DeleteContainerPointers(Container &C) { + for (typename Container::iterator I = C.begin(), E = C.end(); I != E; ++I) + delete *I; + C.clear(); +} + +/// In a container of pairs (usually a map) whose second element is a pointer, +/// deletes the second elements and then clears the container. +template<typename Container> +void DeleteContainerSeconds(Container &C) { + for (typename Container::iterator I = C.begin(), E = C.end(); I != E; ++I) + delete I->second; + C.clear(); +} + } // End llvm namespace #endif diff --git a/include/llvm/Analysis/InlineCost.h b/include/llvm/Analysis/InlineCost.h index f0e97d7a181b..a0c521d7ed3b 100644 --- a/include/llvm/Analysis/InlineCost.h +++ b/include/llvm/Analysis/InlineCost.h @@ -18,6 +18,7 @@ #include <climits> #include <map> #include <vector> +#include "llvm/ADT/DenseMap.h" namespace llvm { @@ -42,6 +43,9 @@ namespace llvm { /// is used to estimate the code size cost of inlining it. unsigned NumInsts, NumBlocks; + /// NumBBInsts - Keeps track of basic block code size estimates. + DenseMap<const BasicBlock *, unsigned> NumBBInsts; + /// NumCalls - Keep track of the number of calls to 'big' functions. unsigned NumCalls; diff --git a/include/llvm/Analysis/LoopInfo.h b/include/llvm/Analysis/LoopInfo.h index f792a7fae3ee..2babc25cb140 100644 --- a/include/llvm/Analysis/LoopInfo.h +++ b/include/llvm/Analysis/LoopInfo.h @@ -571,7 +571,7 @@ public: unsigned getSmallConstantTripMultiple() const; /// isLCSSAForm - Return true if the Loop is in LCSSA form - bool isLCSSAForm() const; + bool isLCSSAForm(DominatorTree &DT) const; /// isLoopSimplifyForm - Return true if the Loop is in the form that /// the LoopSimplify form transforms loops to, which is sometimes called diff --git a/include/llvm/CallingConv.h b/include/llvm/CallingConv.h index c54527c21877..624390d1cd84 100644 --- a/include/llvm/CallingConv.h +++ b/include/llvm/CallingConv.h @@ -44,6 +44,9 @@ namespace CallingConv { // call does not break any live ranges in the caller side. Cold = 9, + // GHC - Calling convention used by the Glasgow Haskell Compiler (GHC). + GHC = 10, + // Target - This is the start of the target-specific calling conventions, // e.g. fastcall and thiscall on X86. FirstTargetCC = 64, diff --git a/include/llvm/CodeGen/AsmPrinter.h b/include/llvm/CodeGen/AsmPrinter.h index 6187447597c9..2cd477e8065c 100644 --- a/include/llvm/CodeGen/AsmPrinter.h +++ b/include/llvm/CodeGen/AsmPrinter.h @@ -143,8 +143,7 @@ namespace llvm { protected: explicit AsmPrinter(formatted_raw_ostream &o, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T); + MCStreamer &Streamer); public: virtual ~AsmPrinter(); @@ -306,18 +305,10 @@ namespace llvm { unsigned ForcedAlignBits = 0, bool UseFillExpr = true) const; - /// printLabel - This method prints a local label used by debug and - /// exception handling tables. - void printLabel(unsigned Id) const; - /// printDeclare - This method prints a local variable declaration used by /// debug tables. void printDeclare(const MachineInstr *MI) const; - /// GetGlobalValueSymbol - Return the MCSymbol for the specified global - /// value. - virtual MCSymbol *GetGlobalValueSymbol(const GlobalValue *GV) const; - /// GetSymbolWithGlobalValueBase - Return the MCSymbol for a symbol with /// global value name as its base, with the specified suffix, and where the /// symbol is forced to have private linkage if ForcePrivate is true. @@ -342,8 +333,7 @@ namespace llvm { /// GetBlockAddressSymbol - Return the MCSymbol used to satisfy BlockAddress /// uses of the specified basic block. MCSymbol *GetBlockAddressSymbol(const BlockAddress *BA) const; - MCSymbol *GetBlockAddressSymbol(const Function *F, - const BasicBlock *BB) const; + MCSymbol *GetBlockAddressSymbol(const BasicBlock *BB) const; /// EmitBasicBlockStart - This method prints the label for the specified /// MachineBasicBlock, an alignment (if present) and a comment describing diff --git a/include/llvm/CodeGen/GCMetadata.h b/include/llvm/CodeGen/GCMetadata.h index 04fd8bed9724..783f636740c2 100644 --- a/include/llvm/CodeGen/GCMetadata.h +++ b/include/llvm/CodeGen/GCMetadata.h @@ -38,12 +38,10 @@ #include "llvm/ADT/StringMap.h" namespace llvm { - class AsmPrinter; class GCStrategy; class Constant; - class MCAsmInfo; - + class MCSymbol; namespace GC { /// PointKind - The type of a collector-safe point. @@ -60,9 +58,9 @@ namespace llvm { /// struct GCPoint { GC::PointKind Kind; //< The kind of the safe point. - unsigned Num; //< Usually a label. + MCSymbol *Label; //< A label. - GCPoint(GC::PointKind K, unsigned N) : Kind(K), Num(N) {} + GCPoint(GC::PointKind K, MCSymbol *L) : Kind(K), Label(L) {} }; /// GCRoot - Metadata for a pointer to an object managed by the garbage @@ -123,8 +121,8 @@ namespace llvm { /// addSafePoint - Notes the existence of a safe point. Num is the ID of the /// label just prior to the safe point (if the code generator is using /// MachineModuleInfo). - void addSafePoint(GC::PointKind Kind, unsigned Num) { - SafePoints.push_back(GCPoint(Kind, Num)); + void addSafePoint(GC::PointKind Kind, MCSymbol *Label) { + SafePoints.push_back(GCPoint(Kind, Label)); } /// getFrameSize/setFrameSize - Records the function's frame size. diff --git a/include/llvm/CodeGen/GCMetadataPrinter.h b/include/llvm/CodeGen/GCMetadataPrinter.h index ff1a205adbfd..62875c398b89 100644 --- a/include/llvm/CodeGen/GCMetadataPrinter.h +++ b/include/llvm/CodeGen/GCMetadataPrinter.h @@ -28,6 +28,7 @@ namespace llvm { class GCMetadataPrinter; class raw_ostream; + class MCAsmInfo; /// GCMetadataPrinterRegistry - The GC assembly printer registry uses all the /// defaults from Registry. diff --git a/include/llvm/CodeGen/JITCodeEmitter.h b/include/llvm/CodeGen/JITCodeEmitter.h index 0a1d4f47e980..5da4961dbd39 100644 --- a/include/llvm/CodeGen/JITCodeEmitter.h +++ b/include/llvm/CodeGen/JITCodeEmitter.h @@ -35,7 +35,7 @@ class MachineRelocation; class Value; class GlobalValue; class Function; - + /// JITCodeEmitter - This class defines two sorts of methods: those for /// emitting the actual bytes of machine code, and those for emitting auxillary /// structures, such as jump tables, relocations, etc. @@ -242,7 +242,7 @@ public: /// emitLabel - Emits a label - virtual void emitLabel(uint64_t LabelID) = 0; + virtual void emitLabel(MCSymbol *Label) = 0; /// allocateSpace - Allocate a block of space in the current output buffer, /// returning null (and setting conditions to indicate buffer overflow) on @@ -316,10 +316,10 @@ public: /// virtual uintptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) const= 0; - /// getLabelAddress - Return the address of the specified LabelID, only usable - /// after the LabelID has been emitted. + /// getLabelAddress - Return the address of the specified Label, only usable + /// after the Label has been emitted. /// - virtual uintptr_t getLabelAddress(uint64_t LabelID) const = 0; + virtual uintptr_t getLabelAddress(MCSymbol *Label) const = 0; /// Specifies the MachineModuleInfo object. This is used for exception handling /// purposes. diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h index e8856ac10377..1a2cc25ba490 100644 --- a/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -127,11 +127,11 @@ namespace llvm { bool conflictsWithPhysReg(const LiveInterval &li, VirtRegMap &vrm, unsigned reg); - /// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except - /// it can check use as well. - bool conflictsWithPhysRegRef(LiveInterval &li, unsigned Reg, - bool CheckUse, - SmallPtrSet<MachineInstr*,32> &JoinedCopies); + /// conflictsWithSubPhysRegRef - Similar to conflictsWithPhysRegRef except + /// it checks for sub-register reference and it can check use as well. + bool conflictsWithSubPhysRegRef(LiveInterval &li, unsigned Reg, + bool CheckUse, + SmallPtrSet<MachineInstr*,32> &JoinedCopies); // Interval creation LiveInterval &getOrCreateInterval(unsigned reg) { diff --git a/include/llvm/CodeGen/MachineBasicBlock.h b/include/llvm/CodeGen/MachineBasicBlock.h index d92650b42c9c..2995bea9df07 100644 --- a/include/llvm/CodeGen/MachineBasicBlock.h +++ b/include/llvm/CodeGen/MachineBasicBlock.h @@ -21,7 +21,6 @@ namespace llvm { class BasicBlock; class MachineFunction; -class MCContext; class MCSymbol; class StringRef; class raw_ostream; @@ -352,7 +351,7 @@ public: /// getSymbol - Return the MCSymbol for this basic block. /// - MCSymbol *getSymbol(MCContext &Ctx) const; + MCSymbol *getSymbol() const; private: // Methods used to maintain doubly linked list of blocks... friend struct ilist_traits<MachineBasicBlock>; diff --git a/include/llvm/CodeGen/MachineCodeEmitter.h b/include/llvm/CodeGen/MachineCodeEmitter.h index 48b4082ef9a5..7abb49a219ef 100644 --- a/include/llvm/CodeGen/MachineCodeEmitter.h +++ b/include/llvm/CodeGen/MachineCodeEmitter.h @@ -31,6 +31,7 @@ class MachineRelocation; class Value; class GlobalValue; class Function; +class MCSymbol; /// MachineCodeEmitter - This class defines two sorts of methods: those for /// emitting the actual bytes of machine code, and those for emitting auxillary @@ -247,7 +248,7 @@ public: virtual void processDebugLoc(DebugLoc DL, bool BeforePrintintInsn) {} /// emitLabel - Emits a label - virtual void emitLabel(uint64_t LabelID) = 0; + virtual void emitLabel(MCSymbol *Label) = 0; /// allocateSpace - Allocate a block of space in the current output buffer, /// returning null (and setting conditions to indicate buffer overflow) on @@ -316,10 +317,10 @@ public: /// virtual uintptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) const= 0; - /// getLabelAddress - Return the address of the specified LabelID, only usable + /// getLabelAddress - Return the address of the specified Label, only usable /// after the LabelID has been emitted. /// - virtual uintptr_t getLabelAddress(uint64_t LabelID) const = 0; + virtual uintptr_t getLabelAddress(MCSymbol *Label) const = 0; /// Specifies the MachineModuleInfo object. This is used for exception handling /// purposes. diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h index 3c5b466da7bd..76ec9db5510d 100644 --- a/include/llvm/CodeGen/MachineFunction.h +++ b/include/llvm/CodeGen/MachineFunction.h @@ -33,6 +33,7 @@ class MachineRegisterInfo; class MachineFrameInfo; class MachineConstantPool; class MachineJumpTableInfo; +class MCContext; class Pass; class TargetMachine; class TargetRegisterClass; @@ -71,6 +72,7 @@ struct MachineFunctionInfo { class MachineFunction { Function *Fn; const TargetMachine &Target; + MCContext &Ctx; // RegInfo - Information about each register in use in the function. MachineRegisterInfo *RegInfo; @@ -121,13 +123,16 @@ class MachineFunction { // The alignment of the function. unsigned Alignment; - MachineFunction(const MachineFunction &); // intentionally unimplemented - void operator=(const MachineFunction&); // intentionally unimplemented + MachineFunction(const MachineFunction &); // DO NOT IMPLEMENT + void operator=(const MachineFunction&); // DO NOT IMPLEMENT public: - MachineFunction(Function *Fn, const TargetMachine &TM, unsigned FunctionNum); + MachineFunction(Function *Fn, const TargetMachine &TM, unsigned FunctionNum, + MCContext &Ctx); ~MachineFunction(); + MCContext &getContext() const { return Ctx; } + /// getFunction - Return the LLVM function that this machine code represents /// Function *getFunction() const { return Fn; } diff --git a/include/llvm/CodeGen/MachineInstrBuilder.h b/include/llvm/CodeGen/MachineInstrBuilder.h index 47f7cf7b3f4f..9baa592f96e0 100644 --- a/include/llvm/CodeGen/MachineInstrBuilder.h +++ b/include/llvm/CodeGen/MachineInstrBuilder.h @@ -131,6 +131,11 @@ public: MI->addOperand(MachineOperand::CreateMetadata(MD)); return *this; } + + const MachineInstrBuilder &addSym(MCSymbol *Sym) const { + MI->addOperand(MachineOperand::CreateMCSymbol(Sym)); + return *this; + } }; /// BuildMI - Builder interface. Specify how to create the initial instruction diff --git a/include/llvm/CodeGen/MachineJumpTableInfo.h b/include/llvm/CodeGen/MachineJumpTableInfo.h index 5a4c9a9fb761..b8d04bf2132e 100644 --- a/include/llvm/CodeGen/MachineJumpTableInfo.h +++ b/include/llvm/CodeGen/MachineJumpTableInfo.h @@ -61,7 +61,11 @@ public: /// .set L4_5_set_123, LBB123 - LJTI1_2 /// .word L4_5_set_123 EK_LabelDifference32, - + + /// EK_Inline - Jump table entries are emitted inline at their point of + /// use. It is the responsibility of the target to emit the entries. + EK_Inline, + /// EK_Custom32 - Each entry is a 32-bit value that is custom lowered by the /// TargetLowering::LowerCustomJumpTableEntry hook. EK_Custom32 diff --git a/include/llvm/CodeGen/MachineLocation.h b/include/llvm/CodeGen/MachineLocation.h index 2db4e5571ecd..a1fcb9fe7576 100644 --- a/include/llvm/CodeGen/MachineLocation.h +++ b/include/llvm/CodeGen/MachineLocation.h @@ -22,13 +22,13 @@ #define LLVM_CODEGEN_MACHINELOCATION_H namespace llvm { - + class MCSymbol; + class MachineLocation { private: bool IsRegister; // True if location is a register. unsigned Register; // gcc/gdb register number. int Offset; // Displacement if not register. - public: enum { // The target register number for an abstract frame pointer. The value is @@ -36,20 +36,11 @@ public: VirtualFP = ~0U }; MachineLocation() - : IsRegister(false) - , Register(0) - , Offset(0) - {} + : IsRegister(false), Register(0), Offset(0) {} explicit MachineLocation(unsigned R) - : IsRegister(true) - , Register(R) - , Offset(0) - {} + : IsRegister(true), Register(R), Offset(0) {} MachineLocation(unsigned R, int O) - : IsRegister(false) - , Register(R) - , Offset(O) - {} + : IsRegister(false), Register(R), Offset(O) {} // Accessors bool isReg() const { return IsRegister; } @@ -74,29 +65,25 @@ public: #endif }; +/// MachineMove - This class represents the save or restore of a callee saved +/// register that exception or debug info needs to know about. class MachineMove { private: - unsigned LabelID; // Label ID number for post-instruction - // address when result of move takes - // effect. - MachineLocation Destination; // Move to location. - MachineLocation Source; // Move from location. + /// Label - Symbol for post-instruction address when result of move takes + /// effect. + MCSymbol *Label; + // Move to & from location. + MachineLocation Destination, Source; public: - MachineMove() - : LabelID(0) - , Destination() - , Source() - {} + MachineMove() : Label(0) {} - MachineMove(unsigned ID, MachineLocation &D, MachineLocation &S) - : LabelID(ID) - , Destination(D) - , Source(S) - {} + MachineMove(MCSymbol *label, const MachineLocation &D, + const MachineLocation &S) + : Label(label), Destination(D), Source(S) {} // Accessors - unsigned getLabelID() const { return LabelID; } + MCSymbol *getLabel() const { return Label; } const MachineLocation &getDestination() const { return Destination; } const MachineLocation &getSource() const { return Source; } }; diff --git a/include/llvm/CodeGen/MachineModuleInfo.h b/include/llvm/CodeGen/MachineModuleInfo.h index fff8e83354c0..d446eaeb7f49 100644 --- a/include/llvm/CodeGen/MachineModuleInfo.h +++ b/include/llvm/CodeGen/MachineModuleInfo.h @@ -31,48 +31,43 @@ #ifndef LLVM_CODEGEN_MACHINEMODULEINFO_H #define LLVM_CODEGEN_MACHINEMODULEINFO_H +#include "llvm/Pass.h" +#include "llvm/GlobalValue.h" +#include "llvm/Metadata.h" +#include "llvm/CodeGen/MachineLocation.h" +#include "llvm/MC/MCContext.h" #include "llvm/Support/Dwarf.h" +#include "llvm/Support/ValueHandle.h" #include "llvm/System/DataTypes.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/UniqueVector.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/CodeGen/MachineLocation.h" -#include "llvm/GlobalValue.h" -#include "llvm/Pass.h" -#include "llvm/Metadata.h" -#include "llvm/Support/ValueHandle.h" +#include "llvm/ADT/SmallVector.h" namespace llvm { //===----------------------------------------------------------------------===// // Forward declarations. class Constant; -class MCSymbol; -class MDNode; class GlobalVariable; +class MDNode; class MachineBasicBlock; class MachineFunction; class Module; class PointerType; class StructType; - /// MachineModuleInfoImpl - This class can be derived from and used by targets /// to hold private target-specific information for each Module. Objects of /// type are accessed/created with MMI::getInfo and destroyed when the /// MachineModuleInfo is destroyed. class MachineModuleInfoImpl { public: + typedef PointerIntPair<MCSymbol*, 1, bool> StubValueTy; virtual ~MachineModuleInfoImpl(); - - typedef std::vector<std::pair<MCSymbol*, MCSymbol*> > - SymbolListTy; + typedef std::vector<std::pair<MCSymbol*, StubValueTy> > SymbolListTy; protected: - static SymbolListTy - GetSortedStubs(const DenseMap<MCSymbol*, MCSymbol*> &Map); + static SymbolListTy GetSortedStubs(const DenseMap<MCSymbol*, StubValueTy>&); }; @@ -82,37 +77,33 @@ protected: /// the current function. /// struct LandingPadInfo { - MachineBasicBlock *LandingPadBlock; // Landing pad block. - SmallVector<unsigned, 1> BeginLabels; // Labels prior to invoke. - SmallVector<unsigned, 1> EndLabels; // Labels after invoke. - unsigned LandingPadLabel; // Label at beginning of landing pad. - Function *Personality; // Personality function. - std::vector<int> TypeIds; // List of type ids (filters negative) + MachineBasicBlock *LandingPadBlock; // Landing pad block. + SmallVector<MCSymbol*, 1> BeginLabels; // Labels prior to invoke. + SmallVector<MCSymbol*, 1> EndLabels; // Labels after invoke. + MCSymbol *LandingPadLabel; // Label at beginning of landing pad. + Function *Personality; // Personality function. + std::vector<int> TypeIds; // List of type ids (filters negative) explicit LandingPadInfo(MachineBasicBlock *MBB) - : LandingPadBlock(MBB) - , LandingPadLabel(0) - , Personality(NULL) - {} + : LandingPadBlock(MBB), LandingPadLabel(0), Personality(0) {} }; +class MMIAddrLabelMap; + //===----------------------------------------------------------------------===// /// MachineModuleInfo - This class contains meta information specific to a /// module. Queries can be made by different debugging and exception handling /// schemes and reformated for specific use. /// class MachineModuleInfo : public ImmutablePass { + /// Context - This is the MCContext used for the entire code generator. + MCContext Context; + /// ObjFileMMI - This is the object-file-format-specific implementation of /// MachineModuleInfoImpl, which lets targets accumulate whatever info they /// want. MachineModuleInfoImpl *ObjFileMMI; - // LabelIDList - One entry per assigned label. Normally the entry is equal to - // the list index(+1). If the entry is zero then the label has been deleted. - // Any other value indicates the label has been deleted by is mapped to - // another label. - std::vector<unsigned> LabelIDList; - // FrameMoves - List of moves done by a function's prolog. Used to construct // frame maps by debug and exception handling consumers. std::vector<MachineMove> FrameMoves; @@ -123,7 +114,7 @@ class MachineModuleInfo : public ImmutablePass { // Map of invoke call site index values to associated begin EH_LABEL for // the current function. - DenseMap<unsigned, unsigned> CallSiteMap; + DenseMap<MCSymbol*, unsigned> CallSiteMap; // The current call site index being processed, if any. 0 if none. unsigned CurCallSite; @@ -150,6 +141,11 @@ class MachineModuleInfo : public ImmutablePass { /// llvm.compiler.used. SmallPtrSet<const Function *, 32> UsedFunctions; + + /// AddrLabelSymbols - This map keeps track of which symbol is being used for + /// the specified basic block's address of label. + MMIAddrLabelMap *AddrLabelSymbols; + bool CallsEHReturn; bool CallsUnwindInit; @@ -165,7 +161,8 @@ public: VariableDbgInfoMapTy; VariableDbgInfoMapTy VariableDbgInfo; - MachineModuleInfo(); + MachineModuleInfo(); // DUMMY CONSTRUCTOR, DO NOT CALL. + MachineModuleInfo(const MCAsmInfo &MAI); // Real constructor. ~MachineModuleInfo(); bool doInitialization(); @@ -174,6 +171,9 @@ public: /// EndFunction - Discard function meta information. /// void EndFunction(); + + const MCContext &getContext() const { return Context; } + MCContext &getContext() { return Context; } /// getInfo - Keep track of various per-function pieces of information for /// backends that would like to do so. @@ -205,37 +205,30 @@ public: bool callsUnwindInit() const { return CallsUnwindInit; } void setCallsUnwindInit(bool b) { CallsUnwindInit = b; } - /// NextLabelID - Return the next unique label id. - /// - unsigned NextLabelID() { - unsigned ID = (unsigned)LabelIDList.size() + 1; - LabelIDList.push_back(ID); - return ID; - } - - /// InvalidateLabel - Inhibit use of the specified label # from - /// MachineModuleInfo, for example because the code was deleted. - void InvalidateLabel(unsigned LabelID) { - // Remap to zero to indicate deletion. - assert(0 < LabelID && LabelID <= LabelIDList.size() && - "Old label ID out of range."); - LabelIDList[LabelID - 1] = 0; - } - - /// isLabelDeleted - Return true if the label was deleted. - /// FIXME: This should eventually be eliminated and use the 'is emitted' bit - /// on MCSymbol. - bool isLabelDeleted(unsigned LabelID) const { - assert(LabelID <= LabelIDList.size() && "Debug label ID out of range."); - return LabelID == 0 || LabelIDList[LabelID - 1] == 0; - } - /// getFrameMoves - Returns a reference to a list of moves done in the current /// function's prologue. Used to construct frame maps for debug and exception /// handling comsumers. std::vector<MachineMove> &getFrameMoves() { return FrameMoves; } - //===-EH-----------------------------------------------------------------===// + /// getAddrLabelSymbol - Return the symbol to be used for the specified basic + /// block when its address is taken. This cannot be its normal LBB label + /// because the block may be accessed outside its containing function. + MCSymbol *getAddrLabelSymbol(const BasicBlock *BB); + + /// getAddrLabelSymbolToEmit - Return the symbol to be used for the specified + /// basic block when its address is taken. If other blocks were RAUW'd to + /// this one, we may have to emit them as well, return the whole set. + std::vector<MCSymbol*> getAddrLabelSymbolToEmit(const BasicBlock *BB); + + /// takeDeletedSymbolsForFunction - If the specified function has had any + /// references to address-taken blocks generated, but the block got deleted, + /// return the symbol now so we can emit it. This prevents emitting a + /// reference to a symbol that has no definition. + void takeDeletedSymbolsForFunction(const Function *F, + std::vector<MCSymbol*> &Result); + + + //===- EH ---------------------------------------------------------------===// /// getOrCreateLandingPadInfo - Find or create an LandingPadInfo for the /// specified MachineBasicBlock. @@ -243,12 +236,12 @@ public: /// addInvoke - Provide the begin and end labels of an invoke style call and /// associate it with a try landing pad block. - void addInvoke(MachineBasicBlock *LandingPad, unsigned BeginLabel, - unsigned EndLabel); + void addInvoke(MachineBasicBlock *LandingPad, + MCSymbol *BeginLabel, MCSymbol *EndLabel); /// addLandingPad - Add a new panding pad. Returns the label ID for the /// landing pad entry. - unsigned addLandingPad(MachineBasicBlock *LandingPad); + MCSymbol *addLandingPad(MachineBasicBlock *LandingPad); /// addPersonality - Provide the personality function for the exception /// information. @@ -303,12 +296,12 @@ public: } /// setCallSiteBeginLabel - Map the begin label for a call site - void setCallSiteBeginLabel(unsigned BeginLabel, unsigned Site) { + void setCallSiteBeginLabel(MCSymbol *BeginLabel, unsigned Site) { CallSiteMap[BeginLabel] = Site; } /// getCallSiteBeginLabel - Get the call site number for a begin label - unsigned getCallSiteBeginLabel(unsigned BeginLabel) { + unsigned getCallSiteBeginLabel(MCSymbol *BeginLabel) { assert(CallSiteMap.count(BeginLabel) && "Missing call site number for EH_LABEL!"); return CallSiteMap[BeginLabel]; diff --git a/include/llvm/CodeGen/MachineModuleInfoImpls.h b/include/llvm/CodeGen/MachineModuleInfoImpls.h index 89b820740a82..9401ffd199d4 100644 --- a/include/llvm/CodeGen/MachineModuleInfoImpls.h +++ b/include/llvm/CodeGen/MachineModuleInfoImpls.h @@ -25,32 +25,34 @@ namespace llvm { class MachineModuleInfoMachO : public MachineModuleInfoImpl { /// FnStubs - Darwin '$stub' stubs. The key is something like "Lfoo$stub", /// the value is something like "_foo". - DenseMap<MCSymbol*, MCSymbol*> FnStubs; + DenseMap<MCSymbol*, StubValueTy> FnStubs; /// GVStubs - Darwin '$non_lazy_ptr' stubs. The key is something like - /// "Lfoo$non_lazy_ptr", the value is something like "_foo". - DenseMap<MCSymbol*, MCSymbol*> GVStubs; + /// "Lfoo$non_lazy_ptr", the value is something like "_foo". The extra bit + /// is true if this GV is external. + DenseMap<MCSymbol*, StubValueTy> GVStubs; /// HiddenGVStubs - Darwin '$non_lazy_ptr' stubs. The key is something like /// "Lfoo$non_lazy_ptr", the value is something like "_foo". Unlike GVStubs - /// these are for things with hidden visibility. - DenseMap<MCSymbol*, MCSymbol*> HiddenGVStubs; + /// these are for things with hidden visibility. The extra bit is true if + /// this GV is external. + DenseMap<MCSymbol*, StubValueTy> HiddenGVStubs; virtual void Anchor(); // Out of line virtual method. public: MachineModuleInfoMachO(const MachineModuleInfo &) {} - MCSymbol *&getFnStubEntry(MCSymbol *Sym) { + StubValueTy &getFnStubEntry(MCSymbol *Sym) { assert(Sym && "Key cannot be null"); return FnStubs[Sym]; } - MCSymbol *&getGVStubEntry(MCSymbol *Sym) { + StubValueTy &getGVStubEntry(MCSymbol *Sym) { assert(Sym && "Key cannot be null"); return GVStubs[Sym]; } - MCSymbol *&getHiddenGVStubEntry(MCSymbol *Sym) { + StubValueTy &getHiddenGVStubEntry(MCSymbol *Sym) { assert(Sym && "Key cannot be null"); return HiddenGVStubs[Sym]; } @@ -72,13 +74,13 @@ namespace llvm { class MachineModuleInfoELF : public MachineModuleInfoImpl { /// GVStubs - These stubs are used to materialize global addresses in PIC /// mode. - DenseMap<MCSymbol*, MCSymbol*> GVStubs; + DenseMap<MCSymbol*, StubValueTy> GVStubs; virtual void Anchor(); // Out of line virtual method. public: MachineModuleInfoELF(const MachineModuleInfo &) {} - MCSymbol *&getGVStubEntry(MCSymbol *Sym) { + StubValueTy &getGVStubEntry(MCSymbol *Sym) { assert(Sym && "Key cannot be null"); return GVStubs[Sym]; } diff --git a/include/llvm/CodeGen/MachineOperand.h b/include/llvm/CodeGen/MachineOperand.h index 0978057c2090..e5229479f1e2 100644 --- a/include/llvm/CodeGen/MachineOperand.h +++ b/include/llvm/CodeGen/MachineOperand.h @@ -28,6 +28,7 @@ class MachineRegisterInfo; class MDNode; class TargetMachine; class raw_ostream; +class MCSymbol; /// MachineOperand class - Representation of each machine instruction operand. /// @@ -44,7 +45,8 @@ public: MO_ExternalSymbol, ///< Name of external global symbol MO_GlobalAddress, ///< Address of a global value MO_BlockAddress, ///< Address of a basic block - MO_Metadata ///< Metadata reference (for debug info) + MO_Metadata, ///< Metadata reference (for debug info) + MO_MCSymbol ///< MCSymbol reference (for debug/eh info) }; private: @@ -101,6 +103,7 @@ private: const ConstantFP *CFP; // For MO_FPImmediate. int64_t ImmVal; // For MO_Immediate. const MDNode *MD; // For MO_Metadata. + MCSymbol *Sym; // For MO_MCSymbol struct { // For MO_Register. unsigned RegNo; @@ -167,6 +170,7 @@ public: bool isBlockAddress() const { return OpKind == MO_BlockAddress; } /// isMetadata - Tests if this is a MO_Metadata operand. bool isMetadata() const { return OpKind == MO_Metadata; } + bool isMCSymbol() const { return OpKind == MO_MCSymbol; } //===--------------------------------------------------------------------===// // Accessors for Register Operands @@ -315,6 +319,11 @@ public: assert(isBlockAddress() && "Wrong MachineOperand accessor"); return Contents.OffsetedInfo.Val.BA; } + + MCSymbol *getMCSymbol() const { + assert(isMCSymbol() && "Wrong MachineOperand accessor"); + return Contents.Sym; + } /// getOffset - Return the offset from the symbol in this operand. This always /// returns 0 for ExternalSymbol operands. @@ -473,6 +482,12 @@ public: return Op; } + static MachineOperand CreateMCSymbol(MCSymbol *Sym) { + MachineOperand Op(MachineOperand::MO_MCSymbol); + Op.Contents.Sym = Sym; + return Op; + } + friend class MachineInstr; friend class MachineRegisterInfo; private: diff --git a/include/llvm/CodeGen/ObjectCodeEmitter.h b/include/llvm/CodeGen/ObjectCodeEmitter.h index 170c0c8ed3be..d46628caae79 100644 --- a/include/llvm/CodeGen/ObjectCodeEmitter.h +++ b/include/llvm/CodeGen/ObjectCodeEmitter.h @@ -137,13 +137,6 @@ public: /// emitted. virtual uintptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) const; - /// emitLabel - Emits a label - virtual void emitLabel(uint64_t LabelID) = 0; - - /// getLabelAddress - Return the address of the specified LabelID, only usable - /// after the LabelID has been emitted. - virtual uintptr_t getLabelAddress(uint64_t LabelID) const = 0; - /// emitJumpTables - Emit all the jump tables for a given jump table info /// record to the appropriate section. virtual void emitJumpTables(MachineJumpTableInfo *MJTI) = 0; diff --git a/include/llvm/CodeGen/RuntimeLibcalls.h b/include/llvm/CodeGen/RuntimeLibcalls.h index c404ab6ea3f5..4ac316084c52 100644 --- a/include/llvm/CodeGen/RuntimeLibcalls.h +++ b/include/llvm/CodeGen/RuntimeLibcalls.h @@ -150,9 +150,15 @@ namespace RTLIB { FLOOR_F64, FLOOR_F80, FLOOR_PPCF128, + COPYSIGN_F32, + COPYSIGN_F64, + COPYSIGN_F80, + COPYSIGN_PPCF128, // CONVERSION FPEXT_F32_F64, + FPEXT_F16_F32, + FPROUND_F32_F16, FPROUND_F64_F32, FPROUND_F80_F32, FPROUND_PPCF128_F32, diff --git a/include/llvm/CodeGen/ScheduleDAG.h b/include/llvm/CodeGen/ScheduleDAG.h index 955965bccfa9..81e9ab31529e 100644 --- a/include/llvm/CodeGen/ScheduleDAG.h +++ b/include/llvm/CodeGen/ScheduleDAG.h @@ -227,6 +227,7 @@ namespace llvm { private: SDNode *Node; // Representative node. MachineInstr *Instr; // Alternatively, a MachineInstr. + MachineInstr *DbgInstr; // A dbg_value referencing this. public: SUnit *OrigNode; // If not this, the node from which // this node was cloned. @@ -269,10 +270,10 @@ namespace llvm { /// SUnit - Construct an SUnit for pre-regalloc scheduling to represent /// an SDNode and any nodes flagged to it. SUnit(SDNode *node, unsigned nodenum) - : Node(node), Instr(0), OrigNode(0), NodeNum(nodenum), NodeQueueId(0), - Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0), - isTwoAddress(false), isCommutable(false), hasPhysRegDefs(false), - hasPhysRegClobbers(false), + : Node(node), Instr(0), DbgInstr(0), OrigNode(0), NodeNum(nodenum), + NodeQueueId(0), Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), + NumSuccsLeft(0), isTwoAddress(false), isCommutable(false), + hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false), isAvailable(false), isScheduled(false), isScheduleHigh(false), isCloned(false), isDepthCurrent(false), isHeightCurrent(false), Depth(0), Height(0), @@ -281,10 +282,10 @@ namespace llvm { /// SUnit - Construct an SUnit for post-regalloc scheduling to represent /// a MachineInstr. SUnit(MachineInstr *instr, unsigned nodenum) - : Node(0), Instr(instr), OrigNode(0), NodeNum(nodenum), NodeQueueId(0), - Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0), - isTwoAddress(false), isCommutable(false), hasPhysRegDefs(false), - hasPhysRegClobbers(false), + : Node(0), Instr(instr), DbgInstr(0), OrigNode(0), NodeNum(nodenum), + NodeQueueId(0), Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), + NumSuccsLeft(0), isTwoAddress(false), isCommutable(false), + hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false), isAvailable(false), isScheduled(false), isScheduleHigh(false), isCloned(false), isDepthCurrent(false), isHeightCurrent(false), Depth(0), Height(0), @@ -292,10 +293,10 @@ namespace llvm { /// SUnit - Construct a placeholder SUnit. SUnit() - : Node(0), Instr(0), OrigNode(0), NodeNum(~0u), NodeQueueId(0), - Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0), - isTwoAddress(false), isCommutable(false), hasPhysRegDefs(false), - hasPhysRegClobbers(false), + : Node(0), Instr(0), DbgInstr(0), OrigNode(0), NodeNum(~0u), + NodeQueueId(0), Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), + NumSuccsLeft(0), isTwoAddress(false), isCommutable(false), + hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false), isAvailable(false), isScheduled(false), isScheduleHigh(false), isCloned(false), isDepthCurrent(false), isHeightCurrent(false), Depth(0), Height(0), @@ -329,6 +330,20 @@ namespace llvm { return Instr; } + /// setDbgInstr - Assign the debug instruction for the SUnit. + /// This may be used during post-regalloc scheduling. + void setDbgInstr(MachineInstr *MI) { + assert(!Node && "Setting debug MachineInstr of SUnit with SDNode!"); + DbgInstr = MI; + } + + /// getDbgInstr - Return the debug MachineInstr for this SUnit. + /// This may be used during post-regalloc scheduling. + MachineInstr *getDbgInstr() const { + assert(!Node && "Reading debug MachineInstr of SUnit with SDNode!"); + return DbgInstr; + } + /// addPred - This adds the specified edge as a pred of the current node if /// not already. It also adds the current node as a successor of the /// specified node. diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h index ad01e89b3c6c..c8d29aa0c7d1 100644 --- a/include/llvm/CodeGen/SelectionDAG.h +++ b/include/llvm/CodeGen/SelectionDAG.h @@ -35,6 +35,7 @@ class MachineConstantPoolValue; class MachineFunction; class MachineModuleInfo; class SDNodeOrdering; +class SDDbgValue; class TargetLowering; template<> struct ilist_traits<SDNode> : public ilist_default_traits<SDNode> { @@ -57,6 +58,46 @@ private: static void createNode(const SDNode &); }; +/// SDDbgInfo - Keeps track of dbg_value information through SDISel. We do +/// not build SDNodes for these so as not to perturb the generated code; +/// instead the info is kept off to the side in this structure. SDNodes may +/// have an associated dbg_value entry in DbgValMap. Debug info that is not +/// associated with any SDNode is held in DbgConstMap. It is possible for +/// optimizations to change a variable to a constant, in which case the +/// corresponding debug info is moved from the variable to the constant table +/// (NYI). +class SDDbgInfo { + DenseMap<const SDNode*, SDDbgValue*> DbgVblMap; + SmallVector<SDDbgValue*, 4> DbgConstMap; + + void operator=(const SDDbgInfo&); // Do not implement. + SDDbgInfo(const SDDbgInfo&); // Do not implement. +public: + SDDbgInfo() {} + + void add(const SDNode *Node, SDDbgValue *V) { + DbgVblMap[Node] = V; + } + void add(SDDbgValue *V) { DbgConstMap.push_back(V); } + void remove(const SDNode *Node) { + DenseMap<const SDNode*, SDDbgValue*>::iterator Itr = + DbgVblMap.find(Node); + if (Itr != DbgVblMap.end()) + DbgVblMap.erase(Itr); + } + // No need to remove a constant. + void clear() { + DbgVblMap.clear(); + DbgConstMap.clear(); + } + SDDbgValue *getSDDbgValue(const SDNode *Node) { + return DbgVblMap[Node]; + } + typedef SmallVector<SDDbgValue*, 4>::iterator ConstDbgIterator; + ConstDbgIterator DbgConstBegin() { return DbgConstMap.begin(); } + ConstDbgIterator DbgConstEnd() { return DbgConstMap.end(); } +}; + enum CombineLevel { Unrestricted, // Combine may create illegal operations and illegal types. NoIllegalTypes, // Combine may create illegal operations but no illegal types. @@ -119,6 +160,9 @@ class SelectionDAG { /// the ordering of the original LLVM instructions. SDNodeOrdering *Ordering; + /// DbgInfo - Tracks dbg_value information through SDISel. + SDDbgInfo *DbgInfo; + /// VerifyNode - Sanity check the given node. Aborts if it is invalid. void VerifyNode(SDNode *N); @@ -339,8 +383,7 @@ public: unsigned char TargetFlags = 0); SDValue getValueType(EVT); SDValue getRegister(unsigned Reg, EVT VT); - SDValue getLabel(unsigned Opcode, DebugLoc dl, SDValue Root, - unsigned LabelID); + SDValue getEHLabel(DebugLoc dl, SDValue Root, MCSymbol *Label); SDValue getBlockAddress(BlockAddress *BA, EVT VT, bool isTarget = false, unsigned char TargetFlags = 0); @@ -828,6 +871,20 @@ public: /// GetOrdering - Get the order for the SDNode. unsigned GetOrdering(const SDNode *SD) const; + /// AssignDbgInfo - Assign debug info to the SDNode. + void AssignDbgInfo(SDNode *SD, SDDbgValue *db); + + /// RememberDbgInfo - Remember debug info with no associated SDNode. + void RememberDbgInfo(SDDbgValue *db); + + /// GetDbgInfo - Get the debug info for the SDNode. + SDDbgValue *GetDbgInfo(const SDNode* SD); + + SDDbgInfo::ConstDbgIterator DbgConstBegin() { + return DbgInfo->DbgConstBegin(); + } + SDDbgInfo::ConstDbgIterator DbgConstEnd() { return DbgInfo->DbgConstEnd(); } + void dump() const; /// CreateStackTemporary - Create a stack temporary, suitable for holding the diff --git a/include/llvm/CodeGen/SelectionDAGISel.h b/include/llvm/CodeGen/SelectionDAGISel.h index d9c1374a01d3..a1576be90b78 100644 --- a/include/llvm/CodeGen/SelectionDAGISel.h +++ b/include/llvm/CodeGen/SelectionDAGISel.h @@ -274,7 +274,6 @@ private: // Calls to these functions are generated by tblgen. SDNode *Select_INLINEASM(SDNode *N); SDNode *Select_UNDEF(SDNode *N); - SDNode *Select_EH_LABEL(SDNode *N); void CannotYetSelect(SDNode *N); private: diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index 21a0b984b64c..c16a48aea2a9 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -40,6 +40,7 @@ class MachineBasicBlock; class MachineConstantPoolValue; class SDNode; class Value; +class MCSymbol; template <typename T> struct DenseMapInfo; template <typename T> struct simplify_type; template <typename T> struct ilist_traits; @@ -438,6 +439,12 @@ namespace ISD { // 5) ISD::CvtCode indicating the type of conversion to do CONVERT_RNDSAT, + // FP16_TO_FP32, FP32_TO_FP16 - These operators are used to perform + // promotions and truncation for half-precision (16 bit) floating + // numbers. We need special nodes since FP16 is a storage-only type with + // special semantics of operations. + FP16_TO_FP32, FP32_TO_FP16, + // FNEG, FABS, FSQRT, FSIN, FCOS, FPOWI, FPOW, // FLOG, FLOG2, FLOG10, FEXP, FEXP2, // FCEIL, FTRUNC, FRINT, FNEARBYINT, FFLOOR - Perform various unary floating @@ -1383,9 +1390,9 @@ protected: /// This constructor adds no operands itself; operands can be /// set later with InitOperands. SDNode(unsigned Opc, const DebugLoc dl, SDVTList VTs) - : NodeType(Opc), OperandsNeedDelete(false), SubclassData(0), - NodeId(-1), OperandList(0), ValueList(VTs.VTs), UseList(NULL), - NumOperands(0), NumValues(VTs.NumVTs), + : NodeType(Opc), OperandsNeedDelete(false), HasDebugValue(false), + SubclassData(0), NodeId(-1), OperandList(0), ValueList(VTs.VTs), + UseList(NULL), NumOperands(0), NumValues(VTs.NumVTs), debugLoc(dl) {} /// InitOperands - Initialize the operands list of this with 1 operand. @@ -2088,18 +2095,18 @@ public: } }; -class LabelSDNode : public SDNode { +class EHLabelSDNode : public SDNode { SDUse Chain; - unsigned LabelID; + MCSymbol *Label; friend class SelectionDAG; - LabelSDNode(unsigned NodeTy, DebugLoc dl, SDValue ch, unsigned id) - : SDNode(NodeTy, dl, getSDVTList(MVT::Other)), LabelID(id) { + EHLabelSDNode(DebugLoc dl, SDValue ch, MCSymbol *L) + : SDNode(ISD::EH_LABEL, dl, getSDVTList(MVT::Other)), Label(L) { InitOperands(&Chain, ch); } public: - unsigned getLabelID() const { return LabelID; } + MCSymbol *getLabel() const { return Label; } - static bool classof(const LabelSDNode *) { return true; } + static bool classof(const EHLabelSDNode *) { return true; } static bool classof(const SDNode *N) { return N->getOpcode() == ISD::EH_LABEL; } diff --git a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index 3d99fa76e0bd..b34ac21cf1ee 100644 --- a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -78,12 +78,13 @@ public: SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const; - /// getSymbolForDwarfGlobalReference - Return an MCExpr to use for a reference + /// getExprForDwarfGlobalReference - Return an MCExpr to use for a reference /// to the specified global variable from exception handling information. /// virtual const MCExpr * - getSymbolForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, - MachineModuleInfo *MMI, unsigned Encoding) const; + getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const; }; @@ -166,11 +167,12 @@ public: return NonLazySymbolPointerSection; } - /// getSymbolForDwarfGlobalReference - The mach-o version of this method + /// getExprForDwarfGlobalReference - The mach-o version of this method /// defaults to returning a stub reference. virtual const MCExpr * - getSymbolForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, - MachineModuleInfo *MMI, unsigned Encoding) const; + getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const; virtual unsigned getPersonalityEncoding() const; virtual unsigned getLSDAEncoding() const; diff --git a/include/llvm/Config/config.h.cmake b/include/llvm/Config/config.h.cmake index 1f48ae96878b..adbcc1132fb5 100644 --- a/include/llvm/Config/config.h.cmake +++ b/include/llvm/Config/config.h.cmake @@ -452,6 +452,9 @@ /* Define to 1 if the system has the type `u_int64_t'. */ #undef HAVE_U_INT64_T +/* Define to 1 if you have the <valgrind/valgrind.h> header file. */ +#cmakedefine HAVE_VALGRIND_VALGRIND_H ${HAVE_VALGRIND_VALGRIND_H} + /* Define to 1 if you have the <windows.h> header file. */ #cmakedefine HAVE_WINDOWS_H ${HAVE_WINDOWS_H} diff --git a/include/llvm/Config/config.h.in b/include/llvm/Config/config.h.in index ce4f37487eb8..5caf778a2d7a 100644 --- a/include/llvm/Config/config.h.in +++ b/include/llvm/Config/config.h.in @@ -440,6 +440,9 @@ /* Define to 1 if the system has the type `u_int64_t'. */ #undef HAVE_U_INT64_T +/* Define to 1 if you have the <valgrind/valgrind.h> header file. */ +#undef HAVE_VALGRIND_VALGRIND_H + /* Define to 1 if you have the <windows.h> header file. */ #undef HAVE_WINDOWS_H diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index f07291cc62c4..80b7ca4f82df 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -1984,7 +1984,7 @@ public: }; template <> -struct OperandTraits<ReturnInst> : public OptionalOperandTraits<> { +struct OperandTraits<ReturnInst> : public VariadicOperandTraits<> { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ReturnInst, Value) diff --git a/include/llvm/Intrinsics.td b/include/llvm/Intrinsics.td index 3a0da9cabdae..54c7b1f102b3 100644 --- a/include/llvm/Intrinsics.td +++ b/include/llvm/Intrinsics.td @@ -450,6 +450,14 @@ def int_flt_rounds : Intrinsic<[llvm_i32_ty]>, def int_trap : Intrinsic<[llvm_void_ty]>, GCCBuiltin<"__builtin_trap">; +// Intrisics to support half precision floating point format +let Properties = [IntrNoMem] in { +def int_convert_to_fp16 : Intrinsic<[llvm_i16_ty], [llvm_float_ty]>, + GCCBuiltin<"__gnu_f2h_ieee">; +def int_convert_from_fp16 : Intrinsic<[llvm_float_ty], [llvm_i16_ty]>, + GCCBuiltin<"__gnu_h2f_ieee">; +} + // These convert intrinsics are to support various conversions between // various types with rounding and saturation. NOTE: avoid using these // intrinsics as they might be removed sometime in the future and diff --git a/include/llvm/MC/MCAsmInfo.h b/include/llvm/MC/MCAsmInfo.h index 7e0c8a54319f..4dfe9f0e52eb 100644 --- a/include/llvm/MC/MCAsmInfo.h +++ b/include/llvm/MC/MCAsmInfo.h @@ -145,6 +145,11 @@ namespace llvm { /// which doesn't support the '.bss' directive only. bool UsesELFSectionDirectiveForBSS; // Defaults to false. + /// HasMicrosoftFastStdCallMangling - True if this target uses microsoft + /// style mangling for functions with X86_StdCall/X86_FastCall calling + /// convention. + bool HasMicrosoftFastStdCallMangling; // Defaults to false. + //===--- Alignment Information ----------------------------------------===// /// AlignDirective - The directive used to emit round up to an alignment @@ -295,6 +300,10 @@ namespace llvm { return UsesELFSectionDirectiveForBSS; } + bool hasMicrosoftFastStdCallMangling() const { + return HasMicrosoftFastStdCallMangling; + } + // Accessors. // bool hasMachoZeroFillDirective() const { return HasMachoZeroFillDirective; } diff --git a/include/llvm/MC/MCAsmLayout.h b/include/llvm/MC/MCAsmLayout.h new file mode 100644 index 000000000000..27bdbe9cbf59 --- /dev/null +++ b/include/llvm/MC/MCAsmLayout.h @@ -0,0 +1,36 @@ +//===- MCAsmLayout.h - Assembly Layout Object -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCASMLAYOUT_H +#define LLVM_MC_MCASMLAYOUT_H + +namespace llvm { +class MCAssembler; + +/// Encapsulates the layout of an assembly file at a particular point in time. +/// +/// Assembly may requiring compute multiple layouts for a particular assembly +/// file as part of the relaxation process. This class encapsulates the layout +/// at a single point in time in such a way that it is always possible to +/// efficiently compute the exact addresses of any symbol in the assembly file, +/// even during the relaxation process. +class MCAsmLayout { +private: + MCAssembler &Assembler; + +public: + MCAsmLayout(MCAssembler &_Assembler) : Assembler(_Assembler) {} + + /// Get the assembler object this is a layout for. + MCAssembler &getAssembler() const { return Assembler; } +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 882929f2eeef..1d8051fdb060 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -10,6 +10,7 @@ #ifndef LLVM_MC_MCASSEMBLER_H #define LLVM_MC_MCASSEMBLER_H +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" @@ -20,6 +21,7 @@ namespace llvm { class raw_ostream; +class MCAsmLayout; class MCAssembler; class MCContext; class MCExpr; @@ -27,6 +29,8 @@ class MCFragment; class MCSection; class MCSectionData; class MCSymbol; +class MCValue; +class TargetAsmBackend; /// MCAsmFixup - Represent a fixed size region of bytes inside some fragment /// which needs to be rewritten. This region will either be rewritten by the @@ -160,6 +164,13 @@ public: /// @name Fixup Access /// @{ + void addFixup(MCAsmFixup Fixup) { + // Enforce invariant that fixups are in offset order. + assert((Fixups.empty() || Fixup.Offset > Fixups.back().Offset) && + "Fixups must be added in order!"); + Fixups.push_back(Fixup); + } + std::vector<MCAsmFixup> &getFixups() { return Fixups; } const std::vector<MCAsmFixup> &getFixups() const { return Fixups; } @@ -195,7 +206,8 @@ class MCAlignFragment : public MCFragment { /// cannot be satisfied in this width then this fragment is ignored. unsigned MaxBytesToEmit; - /// EmitNops - true when aligning code and optimal nops to be used for filling + /// EmitNops - true when aligning code and optimal nops to be used for + /// filling. bool EmitNops; public: @@ -505,6 +517,11 @@ public: uint64_t getOffset() const { return Offset; } void setOffset(uint64_t Value) { Offset = Value; } + uint64_t getAddress() const { + assert(getFragment() && "Invalid getAddress() on undefined symbol!"); + return getFragment()->getAddress() + getOffset(); + } + /// @} /// @name Symbol Attributes /// @{ @@ -581,22 +598,61 @@ private: MCContext &Context; + TargetAsmBackend &Backend; + raw_ostream &OS; iplist<MCSectionData> Sections; iplist<MCSymbolData> Symbols; + /// The map of sections to their associated assembler backend data. + // + // FIXME: Avoid this indirection? + DenseMap<const MCSection*, MCSectionData*> SectionMap; + + /// The map of symbols to their associated assembler backend data. + // + // FIXME: Avoid this indirection? + DenseMap<const MCSymbol*, MCSymbolData*> SymbolMap; + std::vector<IndirectSymbolData> IndirectSymbols; unsigned SubsectionsViaSymbols : 1; private: + /// Check whether a fixup can be satisfied, or whether it needs to be relaxed + /// (increased in size, in order to hold its value correctly). + bool FixupNeedsRelaxation(MCAsmFixup &Fixup, MCDataFragment *DF); + /// LayoutSection - Assign offsets and sizes to the fragments in the section /// \arg SD, and update the section size. The section file offset should /// already have been computed. void LayoutSection(MCSectionData &SD); + /// LayoutOnce - Perform one layout iteration and return true if any offsets + /// were adjusted. + bool LayoutOnce(); + + // FIXME: Make protected once we factor out object writer classes. +public: + /// Evaluate a fixup to a relocatable expression and the value which should be + /// placed into the fixup. + /// + /// \param Layout The layout to use for evaluation. + /// \param Fixup The fixup to evaluate. + /// \param DF The fragment the fixup is inside. + /// \param Target [out] On return, the relocatable expression the fixup + /// evaluates to. + /// \param Value [out] On return, the value of the fixup as currently layed + /// out. + /// \return Whether the fixup value was fully resolved. This is true if the + /// \arg Value result is fixed, otherwise the value may change due to + /// relocation. + bool EvaluateFixup(const MCAsmLayout &Layout, + MCAsmFixup &Fixup, MCDataFragment *DF, + MCValue &Target, uint64_t &Value) const; + public: /// Construct a new assembler instance. /// @@ -606,11 +662,13 @@ public: // concrete and require clients to pass in a target like object. The other // option is to make this abstract, and have targets provide concrete // implementations as we do with AsmParser. - MCAssembler(MCContext &_Context, raw_ostream &OS); + MCAssembler(MCContext &_Context, TargetAsmBackend &_Backend, raw_ostream &OS); ~MCAssembler(); MCContext &getContext() const { return Context; } + TargetAsmBackend &getBackend() const { return Backend; } + /// Finish - Do final processing and write the object to the output stream. void Finish(); @@ -673,6 +731,44 @@ public: size_t indirect_symbol_size() const { return IndirectSymbols.size(); } /// @} + /// @name Backend Data Access + /// @{ + + MCSectionData &getSectionData(const MCSection &Section) const { + MCSectionData *Entry = SectionMap.lookup(&Section); + assert(Entry && "Missing section data!"); + return *Entry; + } + + MCSectionData &getOrCreateSectionData(const MCSection &Section, + bool *Created = 0) { + MCSectionData *&Entry = SectionMap[&Section]; + + if (Created) *Created = !Entry; + if (!Entry) + Entry = new MCSectionData(Section, this); + + return *Entry; + } + + MCSymbolData &getSymbolData(const MCSymbol &Symbol) const { + MCSymbolData *Entry = SymbolMap.lookup(&Symbol); + assert(Entry && "Missing symbol data!"); + return *Entry; + } + + MCSymbolData &getOrCreateSymbolData(const MCSymbol &Symbol, + bool *Created = 0) { + MCSymbolData *&Entry = SymbolMap[&Symbol]; + + if (Created) *Created = !Entry; + if (!Entry) + Entry = new MCSymbolData(Symbol, 0, 0, this); + + return *Entry; + } + + /// @} void dump(); }; diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index f2f1456c4a9a..85114e30995e 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -15,6 +15,7 @@ #include "llvm/Support/Allocator.h" namespace llvm { + class MCAsmInfo; class MCExpr; class MCSection; class MCSymbol; @@ -28,31 +29,44 @@ namespace llvm { MCContext(const MCContext&); // DO NOT IMPLEMENT MCContext &operator=(const MCContext&); // DO NOT IMPLEMENT + /// The MCAsmInfo for this target. + const MCAsmInfo &MAI; + /// Sections - Bindings of names to allocated sections. StringMap<MCSection*> Sections; /// Symbols - Bindings of names to symbols. StringMap<MCSymbol*> Symbols; + /// NextUniqueID - The next ID to dole out to an unnamed assembler temporary + /// symbol. + unsigned NextUniqueID; + /// Allocator - Allocator object used for creating machine code objects. /// /// We use a bump pointer allocator to avoid the need to track all allocated /// objects. BumpPtrAllocator Allocator; public: - MCContext(); + explicit MCContext(const MCAsmInfo &MAI); ~MCContext(); + + const MCAsmInfo &getAsmInfo() const { return MAI; } /// @name Symbol Managment /// @{ + + /// CreateTempSymbol - Create and return a new assembler temporary symbol + /// with a unique but unspecified name. + MCSymbol *CreateTempSymbol(); /// GetOrCreateSymbol - Lookup the symbol inside with the specified /// @p Name. If it exists, return it. If not, create a forward /// reference and return it. /// /// @param Name - The symbol name, which must be unique across all symbols. - MCSymbol *GetOrCreateSymbol(StringRef Name); - MCSymbol *GetOrCreateSymbol(const Twine &Name); + MCSymbol *GetOrCreateSymbol(StringRef Name, bool isTemporary = false); + MCSymbol *GetOrCreateSymbol(const Twine &Name, bool isTemporary = false); /// GetOrCreateTemporarySymbol - Create a new assembler temporary symbol /// with the specified @p Name if it doesn't exist or return the existing diff --git a/include/llvm/MC/MCExpr.h b/include/llvm/MC/MCExpr.h index 3f17492c6b47..6efec52751c0 100644 --- a/include/llvm/MC/MCExpr.h +++ b/include/llvm/MC/MCExpr.h @@ -15,6 +15,7 @@ namespace llvm { class MCAsmInfo; +class MCAsmLayout; class MCContext; class MCSymbol; class MCValue; @@ -62,21 +63,25 @@ public: /// EvaluateAsAbsolute - Try to evaluate the expression to an absolute value. /// /// @param Res - The absolute value, if evaluation succeeds. + /// @param Layout - The assembler layout object to use for evaluating symbol + /// values. If not given, then only non-symbolic expressions will be + /// evaluated. /// @result - True on success. - bool EvaluateAsAbsolute(int64_t &Res) const; + bool EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout = 0) const; /// EvaluateAsRelocatable - Try to evaluate the expression to a relocatable /// value, i.e. an expression of the fixed form (a - b + constant). /// /// @param Res - The relocatable value, if evaluation succeeds. + /// @param Layout - The assembler layout object to use for evaluating values. /// @result - True on success. - bool EvaluateAsRelocatable(MCValue &Res) const; + bool EvaluateAsRelocatable(MCValue &Res, const MCAsmLayout *Layout = 0) const; /// @} static bool classof(const MCExpr *) { return true; } }; - + inline raw_ostream &operator<<(raw_ostream &OS, const MCExpr &E) { E.print(OS); return OS; @@ -116,21 +121,49 @@ public: /// assembler variable (defined constant), or constitute an implicit definition /// of the symbol as external. class MCSymbolRefExpr : public MCExpr { +public: + enum VariantKind { + VK_None, + VK_Invalid, + + VK_GOT, + VK_GOTOFF, + VK_GOTPCREL, + VK_GOTTPOFF, + VK_INDNTPOFF, + VK_NTPOFF, + VK_PLT, + VK_TLSGD, + VK_TPOFF + }; + +private: + /// The symbol being referenced. const MCSymbol *Symbol; - explicit MCSymbolRefExpr(const MCSymbol *_Symbol) - : MCExpr(MCExpr::SymbolRef), Symbol(_Symbol) {} + /// The symbol reference modifier. + const VariantKind Kind; + + explicit MCSymbolRefExpr(const MCSymbol *_Symbol, VariantKind _Kind) + : MCExpr(MCExpr::SymbolRef), Symbol(_Symbol), Kind(_Kind) {} public: /// @name Construction /// @{ - static const MCSymbolRefExpr *Create(const MCSymbol *Symbol, MCContext &Ctx); - static const MCSymbolRefExpr *Create(StringRef Name, MCContext &Ctx); + static const MCSymbolRefExpr *Create(const MCSymbol *Symbol, MCContext &Ctx) { + return MCSymbolRefExpr::Create(Symbol, VK_None, Ctx); + } + + static const MCSymbolRefExpr *Create(const MCSymbol *Symbol, VariantKind Kind, + MCContext &Ctx); + static const MCSymbolRefExpr *Create(StringRef Name, VariantKind Kind, + MCContext &Ctx); /// CreateTemp - Create a reference to an assembler temporary label with the /// specified name. - static const MCSymbolRefExpr *CreateTemp(StringRef Name, MCContext &Ctx); + static const MCSymbolRefExpr *CreateTemp(StringRef Name, VariantKind Kind, + MCContext &Ctx); /// @} /// @name Accessors @@ -138,6 +171,16 @@ public: const MCSymbol &getSymbol() const { return *Symbol; } + VariantKind getKind() const { return Kind; } + + /// @} + /// @name Static Utility Functions + /// @{ + + static StringRef getVariantKindName(VariantKind Kind); + + static VariantKind getVariantKindForName(StringRef Name); + /// @} static bool classof(const MCExpr *E) { @@ -346,11 +389,12 @@ protected: MCTargetExpr() : MCExpr(Target) {} virtual ~MCTargetExpr() {} public: - + virtual void PrintImpl(raw_ostream &OS) const = 0; - virtual bool EvaluateAsRelocatableImpl(MCValue &Res) const = 0; + virtual bool EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const = 0; + - static bool classof(const MCExpr *E) { return E->getKind() == MCExpr::Target; } diff --git a/include/llvm/MC/MCParser/AsmParser.h b/include/llvm/MC/MCParser/AsmParser.h index 829604c81f7c..06e0920950d4 100644 --- a/include/llvm/MC/MCParser/AsmParser.h +++ b/include/llvm/MC/MCParser/AsmParser.h @@ -31,7 +31,6 @@ class MCExpr; class MCInst; class MCStreamer; class MCAsmInfo; -class MCValue; class SourceMgr; class TargetAsmParser; class Twine; @@ -65,7 +64,7 @@ public: const MCAsmInfo &MAI); ~AsmParser(); - bool Run(); + bool Run(bool NoInitialTextSection); void AddDirectiveHandler(StringRef Directive, diff --git a/include/llvm/MC/MCParser/MCAsmParser.h b/include/llvm/MC/MCParser/MCAsmParser.h index 843c692148bf..7f7f1b60f67d 100644 --- a/include/llvm/MC/MCParser/MCAsmParser.h +++ b/include/llvm/MC/MCParser/MCAsmParser.h @@ -18,7 +18,6 @@ class MCAsmLexer; class MCContext; class MCExpr; class MCStreamer; -class MCValue; class SMLoc; class Twine; diff --git a/include/llvm/MC/MCSection.h b/include/llvm/MC/MCSection.h index ceb6d278c9c0..3d8815a7783f 100644 --- a/include/llvm/MC/MCSection.h +++ b/include/llvm/MC/MCSection.h @@ -42,6 +42,8 @@ namespace llvm { }; class MCSectionCOFF : public MCSection { + // FIXME: This memory is leaked because MCSectionCOFF is bump pointer + // allocated and this never gets freed. std::string Name; /// IsDirective - This is true if the section name is a directive, not diff --git a/include/llvm/MC/MCSectionELF.h b/include/llvm/MC/MCSectionELF.h index 2dccf5c57286..cdd2f73b3484 100644 --- a/include/llvm/MC/MCSectionELF.h +++ b/include/llvm/MC/MCSectionELF.h @@ -21,7 +21,9 @@ namespace llvm { /// MCSectionELF - This represents a section on linux, lots of unix variants /// and some bare metal systems. class MCSectionELF : public MCSection { - std::string SectionName; + /// SectionName - This is the name of the section. The referenced memory is + /// owned by TargetLoweringObjectFileELF's ELFUniqueMap. + StringRef SectionName; /// Type - This is the sh_type field of a section, drawn from the enums below. unsigned Type; @@ -37,7 +39,7 @@ class MCSectionELF : public MCSection { protected: MCSectionELF(StringRef Section, unsigned type, unsigned flags, SectionKind K, bool isExplicit) - : MCSection(K), SectionName(Section.str()), Type(type), Flags(flags), + : MCSection(K), SectionName(Section), Type(type), Flags(flags), IsExplicit(isExplicit) {} public: @@ -163,10 +165,7 @@ public: TARGET_INDEP_SHF = FIRST_TARGET_DEP_FLAG-1U }; - StringRef getSectionName() const { - return StringRef(SectionName); - } - + StringRef getSectionName() const { return SectionName; } unsigned getType() const { return Type; } unsigned getFlags() const { return Flags; } diff --git a/include/llvm/MC/MCSectionMachO.h b/include/llvm/MC/MCSectionMachO.h index 61568194d700..5839c281ed6f 100644 --- a/include/llvm/MC/MCSectionMachO.h +++ b/include/llvm/MC/MCSectionMachO.h @@ -151,10 +151,12 @@ public: return StringRef(SectionName, 16); return StringRef(SectionName); } - + unsigned getTypeAndAttributes() const { return TypeAndAttributes; } unsigned getStubSize() const { return Reserved2; } - + + unsigned getType() const { return TypeAndAttributes & SECTION_TYPE; } + /// ParseSectionSpecifier - Parse the section specifier indicated by "Spec". /// This is a string that can appear after a .section directive in a mach-o /// flavored .s file. If successful, this fills in the specified Out @@ -165,7 +167,7 @@ public: StringRef &Section, // Out. unsigned &TAA, // Out. unsigned &StubSize); // Out. - + virtual void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const; }; diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 6359ccefe63a..47befcaf6b0d 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -27,6 +27,7 @@ namespace llvm { class MCSection; class MCSymbol; class StringRef; +class TargetAsmBackend; class Twine; class raw_ostream; class formatted_raw_ostream; @@ -298,24 +299,15 @@ namespace llvm { /// \param ShowInst - Whether to show the MCInst representation inline with /// the assembly. MCStreamer *createAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, - const MCAsmInfo &MAI, bool isLittleEndian, - bool isVerboseAsm, + bool isLittleEndian, bool isVerboseAsm, MCInstPrinter *InstPrint = 0, MCCodeEmitter *CE = 0, bool ShowInst = false); - // FIXME: These two may end up getting rolled into a single - // createObjectStreamer interface, which implements the assembler backend, and - // is parameterized on an output object file writer. - /// createMachOStream - Create a machine code streamer which will generative /// Mach-O format object files. - MCStreamer *createMachOStreamer(MCContext &Ctx, raw_ostream &OS, - MCCodeEmitter *CE); - - /// createELFStreamer - Create a machine code streamer which will generative - /// ELF format object files. - MCStreamer *createELFStreamer(MCContext &Ctx, raw_ostream &OS); + MCStreamer *createMachOStreamer(MCContext &Ctx, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *CE); } // end namespace llvm diff --git a/include/llvm/MC/MCSymbol.h b/include/llvm/MC/MCSymbol.h index d5c4d95c183c..e41eb2ab8859 100644 --- a/include/llvm/MC/MCSymbol.h +++ b/include/llvm/MC/MCSymbol.h @@ -14,9 +14,7 @@ #ifndef LLVM_MC_MCSYMBOL_H #define LLVM_MC_MCSYMBOL_H -#include <string> #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" namespace llvm { class MCExpr; @@ -38,8 +36,9 @@ namespace llvm { // FIXME: Use a PointerInt wrapper for this? static const MCSection *AbsolutePseudoSection; - /// Name - The name of the symbol. - std::string Name; + /// Name - The name of the symbol. The referred-to string data is actually + /// held by the StringMap that lives in MCContext. + StringRef Name; /// Section - The section the symbol is defined in. This is null for /// undefined symbols, and the special AbsolutePseudoSection value for @@ -56,14 +55,14 @@ namespace llvm { private: // MCContext creates and uniques these. friend class MCContext; - MCSymbol(StringRef _Name, bool _IsTemporary) - : Name(_Name), Section(0), Value(0), IsTemporary(_IsTemporary) {} + MCSymbol(StringRef name, bool isTemporary) + : Name(name), Section(0), Value(0), IsTemporary(isTemporary) {} MCSymbol(const MCSymbol&); // DO NOT IMPLEMENT void operator=(const MCSymbol&); // DO NOT IMPLEMENT public: /// getName - Get the symbol name. - const std::string &getName() const { return Name; } + StringRef getName() const { return Name; } /// @name Symbol Type /// @{ diff --git a/include/llvm/Metadata.h b/include/llvm/Metadata.h index cf87989062a8..ff3e03e96fd8 100644 --- a/include/llvm/Metadata.h +++ b/include/llvm/Metadata.h @@ -110,9 +110,6 @@ class MDNode : public Value, public FoldingSetNode { /// node with T. void replaceOperand(MDNodeOperand *Op, Value *NewVal); ~MDNode(); - /// replaceAllOperandsWithNull - This is used while destroying llvm context to - /// gracefully delete all nodes. This method replaces all operands with null. - void replaceAllOperandsWithNull(); protected: explicit MDNode(LLVMContext &C, Value *const *Vals, unsigned NumVals, @@ -168,9 +165,7 @@ private: bool isNotUniqued() const { return (getSubclassDataFromValue() & NotUniquedBit) != 0; } - void setIsNotUniqued() { - setValueSubclassData(getSubclassDataFromValue() | NotUniquedBit); - } + void setIsNotUniqued(); // Shadow Value::setValueSubclassData with a private forwarding method so that // any future subclasses cannot accidentally use it. diff --git a/include/llvm/OperandTraits.h b/include/llvm/OperandTraits.h index 7c879c88f13b..b614ccbc3777 100644 --- a/include/llvm/OperandTraits.h +++ b/include/llvm/OperandTraits.h @@ -20,7 +20,7 @@ namespace llvm { //===----------------------------------------------------------------------===// -// FixedNumOperands Trait Class +// FixedNumOperand Trait Class //===----------------------------------------------------------------------===// /// FixedNumOperandTraits - determine the allocation regime of the Use array @@ -51,9 +51,12 @@ struct FixedNumOperandTraits { }; //===----------------------------------------------------------------------===// -// OptionalOperands Trait Class +// OptionalOperand Trait Class //===----------------------------------------------------------------------===// +/// OptionalOperandTraits - when the number of operands may change at runtime. +/// Naturally it may only decrease, because the allocations may not change. + template <unsigned ARITY = 1> struct OptionalOperandTraits : public FixedNumOperandTraits<ARITY> { static unsigned operands(const User *U) { diff --git a/include/llvm/Support/MemoryBuffer.h b/include/llvm/Support/MemoryBuffer.h index 65c7167318a9..fcea5d20de4b 100644 --- a/include/llvm/Support/MemoryBuffer.h +++ b/include/llvm/Support/MemoryBuffer.h @@ -17,6 +17,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/System/DataTypes.h" #include <string> +#include <sys/stat.h> namespace llvm { @@ -59,7 +60,8 @@ public: /// it has the specified size. static MemoryBuffer *getFile(StringRef Filename, std::string *ErrStr = 0, - int64_t FileSize = -1); + int64_t FileSize = -1, + struct stat *FileInfo = 0); /// getMemBuffer - Open the specified memory range as a MemoryBuffer. Note /// that EndPtr[0] must be a null byte and be accessible! @@ -95,7 +97,8 @@ public: /// in *ErrStr with a reason. static MemoryBuffer *getFileOrSTDIN(StringRef Filename, std::string *ErrStr = 0, - int64_t FileSize = -1); + int64_t FileSize = -1, + struct stat *FileInfo = 0); }; } // end namespace llvm diff --git a/include/llvm/System/Valgrind.h b/include/llvm/System/Valgrind.h new file mode 100644 index 000000000000..5ec79c3c5573 --- /dev/null +++ b/include/llvm/System/Valgrind.h @@ -0,0 +1,32 @@ +//===- llvm/System/Valgrind.h - Communication with Valgrind -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Methods for communicating with a valgrind instance this program is running +// under. These are all no-ops unless LLVM was configured on a system with the +// valgrind headers installed and valgrind is controlling this process. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_VALGRIND_H +#define LLVM_SYSTEM_VALGRIND_H + +#include <stddef.h> + +namespace llvm { +namespace sys { + // True if Valgrind is controlling this process. + bool RunningOnValgrind(); + + // Discard valgrind's translation of code in the range [Addr .. Addr + Len). + // Otherwise valgrind may continue to execute the old version of the code. + void ValgrindDiscardTranslations(const void *Addr, size_t Len); +} +} + +#endif diff --git a/include/llvm/Target/Mangler.h b/include/llvm/Target/Mangler.h index 45cbf9da1e4e..a9f3576559d4 100644 --- a/include/llvm/Target/Mangler.h +++ b/include/llvm/Target/Mangler.h @@ -1,4 +1,4 @@ -//===-- llvm/Target/Mangler.h - Self-contained name mangler ----*- C++ -*-===// +//===-- llvm/Target/Mangler.h - Self-contained name mangler -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -23,7 +23,9 @@ class Twine; class Value; class GlobalValue; template <typename T> class SmallVectorImpl; -class MCAsmInfo; +class MCContext; +class MCSymbol; +class TargetData; class Mangler { public: @@ -34,7 +36,8 @@ public: }; private: - const MCAsmInfo &MAI; + MCContext &Context; + const TargetData &TD; /// AnonGlobalIDs - We need to give global values the same name every time /// they are mangled. This keeps track of the number we give to anonymous @@ -47,10 +50,14 @@ private: unsigned NextAnonGlobalID; public: - // Mangler ctor - if a prefix is specified, it will be prepended onto all - // symbols. - Mangler(const MCAsmInfo &mai) : MAI(mai), NextAnonGlobalID(1) {} + Mangler(MCContext &context, const TargetData &td) + : Context(context), TD(td), NextAnonGlobalID(1) {} + /// getSymbol - Return the MCSymbol for the specified global value. This + /// symbol is the main label that is the address of the global. + MCSymbol *getSymbol(const GlobalValue *GV); + + /// getNameWithPrefix - Fill OutName with the name of the appropriate prefix /// and the specified global variable's name. If the global variable doesn't /// have a name, this fills in a unique name for the global. diff --git a/include/llvm/Target/TargetAsmBackend.h b/include/llvm/Target/TargetAsmBackend.h index dfdabdb7fa3b..35a995f541e2 100644 --- a/include/llvm/Target/TargetAsmBackend.h +++ b/include/llvm/Target/TargetAsmBackend.h @@ -11,6 +11,7 @@ #define LLVM_TARGET_TARGETASMBACKEND_H namespace llvm { +class MCSection; class Target; /// TargetAsmBackend - Generic interface to target specific assembler backends. @@ -28,6 +29,34 @@ public: const Target &getTarget() const { return TheTarget; } + /// hasAbsolutizedSet - Check whether this target "absolutizes" + /// assignments. That is, given code like: + /// a: + /// ... + /// b: + /// tmp = a - b + /// .long tmp + /// will the value of 'tmp' be a relocatable expression, or the assembly time + /// value of L0 - L1. This distinction is only relevant for platforms that + /// support scattered symbols, since in the absence of scattered symbols (a - + /// b) cannot change after assembly. + virtual bool hasAbsolutizedSet() const { return false; } + + /// hasScatteredSymbols - Check whether this target supports scattered + /// symbols. If so, the assembler should assume that atoms can be scattered by + /// the linker. In particular, this means that the offsets between symbols + /// which are in distinct atoms is not known at link time, and the assembler + /// must generate fixups and relocations appropriately. + /// + /// Note that the assembler currently does not reason about atoms, instead it + /// assumes all temporary symbols reside in the "current atom". + virtual bool hasScatteredSymbols() const { return false; } + + /// doesSectionRequireSymbols - Check whether the given section requires that + /// all symbols (even temporaries) have symbol table entries. + virtual bool doesSectionRequireSymbols(const MCSection &Section) const { + return false; + } }; } // End llvm namespace diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 5bc1c0e60927..b19c20af346f 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -323,13 +323,6 @@ public: return false; } - /// getWidenVectorType: given a vector type, returns the type to widen to - /// (e.g., v7i8 to v8i8). If the vector type is legal, it returns itself. - /// If there is no vector type that we want to widen to, returns MVT::Other - /// When and were to widen is target dependent based on the cost of - /// scalarizing vs using the wider vector type. - virtual EVT getWidenVectorType(EVT VT) const; - /// isFPImmLegal - Returns true if the target can instruction select the /// specified FP immediate natively. If false, the legalizer will materialize /// the FP immediate as a load from a constant pool. diff --git a/include/llvm/Target/TargetLoweringObjectFile.h b/include/llvm/Target/TargetLoweringObjectFile.h index 056efea30caa..6c99598ea6ee 100644 --- a/include/llvm/Target/TargetLoweringObjectFile.h +++ b/include/llvm/Target/TargetLoweringObjectFile.h @@ -22,11 +22,12 @@ namespace llvm { class MachineModuleInfo; class Mangler; class MCAsmInfo; + class MCContext; class MCExpr; class MCSection; class MCSectionMachO; class MCSymbol; - class MCContext; + class MCStreamer; class GlobalValue; class TargetMachine; @@ -197,17 +198,20 @@ public: return 0; } - /// getSymbolForDwarfGlobalReference - Return an MCExpr to use for a reference + /// getExprForDwarfGlobalReference - Return an MCExpr to use for a reference /// to the specified global variable from exception handling information. /// virtual const MCExpr * - getSymbolForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, - MachineModuleInfo *MMI, unsigned Encoding) const; - - virtual const MCExpr * - getSymbolForDwarfReference(const MCSymbol *Sym, MachineModuleInfo *MMI, - unsigned Encoding) const; + getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const; + /// + const MCExpr * + getExprForDwarfReference(const MCSymbol *Sym, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const; + virtual unsigned getPersonalityEncoding() const; virtual unsigned getLSDAEncoding() const; virtual unsigned getFDEEncoding() const; diff --git a/include/llvm/Target/TargetMachine.h b/include/llvm/Target/TargetMachine.h index a7062ac94f35..b239a306761f 100644 --- a/include/llvm/Target/TargetMachine.h +++ b/include/llvm/Target/TargetMachine.h @@ -30,6 +30,7 @@ class TargetJITInfo; class TargetLowering; class TargetFrameInfo; class JITCodeEmitter; +class MCContext; class TargetRegisterInfo; class PassManagerBase; class PassManager; @@ -224,16 +225,18 @@ public: /// implemented with the LLVM target-independent code generator. /// class LLVMTargetMachine : public TargetMachine { + std::string TargetTriple; + protected: // Can only create subclasses. LLVMTargetMachine(const Target &T, const std::string &TargetTriple); +private: /// addCommonCodeGenPasses - Add standard LLVM codegen passes used for /// both emitting to assembly files or machine code output. /// bool addCommonCodeGenPasses(PassManagerBase &, CodeGenOpt::Level, - bool DisableVerify); + bool DisableVerify, MCContext *&OutCtx); -private: virtual void setCodeModelForJIT(); virtual void setCodeModelForStatic(); diff --git a/include/llvm/Target/TargetRegistry.h b/include/llvm/Target/TargetRegistry.h index a409b621af2b..43738638cf8e 100644 --- a/include/llvm/Target/TargetRegistry.h +++ b/include/llvm/Target/TargetRegistry.h @@ -62,11 +62,9 @@ namespace llvm { const std::string &Features); typedef AsmPrinter *(*AsmPrinterCtorTy)(formatted_raw_ostream &OS, TargetMachine &TM, - MCContext &Ctx, - MCStreamer &Streamer, - const MCAsmInfo *MAI); + MCStreamer &Streamer); typedef TargetAsmBackend *(*AsmBackendCtorTy)(const Target &T, - MCAssembler &A); + const std::string &TT); typedef TargetAsmLexer *(*AsmLexerCtorTy)(const Target &T, const MCAsmInfo &MAI); typedef TargetAsmParser *(*AsmParserCtorTy)(const Target &T,MCAsmParser &P); @@ -208,11 +206,12 @@ namespace llvm { /// createAsmBackend - Create a target specific assembly parser. /// + /// \arg Triple - The target triple string. /// \arg Backend - The target independent assembler object. - TargetAsmBackend *createAsmBackend(MCAssembler &Backend) const { + TargetAsmBackend *createAsmBackend(const std::string &Triple) const { if (!AsmBackendCtorFn) return 0; - return AsmBackendCtorFn(*this, Backend); + return AsmBackendCtorFn(*this, Triple); } /// createAsmLexer - Create a target specific assembly lexer. @@ -234,13 +233,12 @@ namespace llvm { } /// createAsmPrinter - Create a target specific assembly printer pass. This - /// takes ownership of the MCContext and MCStreamer objects but not the MAI. + /// takes ownership of the MCStreamer object. AsmPrinter *createAsmPrinter(formatted_raw_ostream &OS, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *MAI) const { + MCStreamer &Streamer) const { if (!AsmPrinterCtorFn) return 0; - return AsmPrinterCtorFn(OS, TM, Ctx, Streamer, MAI); + return AsmPrinterCtorFn(OS, TM, Streamer); } const MCDisassembler *createMCDisassembler() const { @@ -587,8 +585,9 @@ namespace llvm { } private: - static TargetAsmBackend *Allocator(const Target &T, MCAssembler &Backend) { - return new AsmBackendImpl(T, Backend); + static TargetAsmBackend *Allocator(const Target &T, + const std::string &Triple) { + return new AsmBackendImpl(T, Triple); } }; @@ -648,9 +647,8 @@ namespace llvm { private: static AsmPrinter *Allocator(formatted_raw_ostream &OS, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *MAI) { - return new AsmPrinterImpl(OS, TM, Ctx, Streamer, MAI); + MCStreamer &Streamer) { + return new AsmPrinterImpl(OS, TM, Streamer); } }; diff --git a/include/llvm/Target/TargetSelectionDAG.td b/include/llvm/Target/TargetSelectionDAG.td index 4365d332c044..c718c86e60ad 100644 --- a/include/llvm/Target/TargetSelectionDAG.td +++ b/include/llvm/Target/TargetSelectionDAG.td @@ -345,6 +345,8 @@ def sint_to_fp : SDNode<"ISD::SINT_TO_FP" , SDTIntToFPOp>; def uint_to_fp : SDNode<"ISD::UINT_TO_FP" , SDTIntToFPOp>; def fp_to_sint : SDNode<"ISD::FP_TO_SINT" , SDTFPToIntOp>; def fp_to_uint : SDNode<"ISD::FP_TO_UINT" , SDTFPToIntOp>; +def f16_to_f32 : SDNode<"ISD::FP16_TO_FP32", SDTIntToFPOp>; +def f32_to_f16 : SDNode<"ISD::FP32_TO_FP16", SDTFPToIntOp>; def setcc : SDNode<"ISD::SETCC" , SDTSetCC>; def select : SDNode<"ISD::SELECT" , SDTSelect>; diff --git a/include/llvm/Transforms/Utils/BuildLibCalls.h b/include/llvm/Transforms/Utils/BuildLibCalls.h index 03716a8eed73..ac5f07e2d384 100644 --- a/include/llvm/Transforms/Utils/BuildLibCalls.h +++ b/include/llvm/Transforms/Utils/BuildLibCalls.h @@ -37,6 +37,11 @@ namespace llvm { /// EmitStrCpy - Emit a call to the strcpy function to the builder, for the /// specified pointer arguments. Value *EmitStrCpy(Value *Dst, Value *Src, IRBuilder<> &B, + const TargetData *TD, StringRef Name = "strcpy"); + + /// EmitStrNCpy - Emit a call to the strncpy function to the builder, for the + /// specified pointer arguments and length. + Value *EmitStrNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B, const TargetData *TD); /// EmitMemCpy - Emit a call to the memcpy function to the builder. This @@ -91,6 +96,19 @@ namespace llvm { /// a pointer, Size is an 'intptr_t', and File is a pointer to FILE. void EmitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B, const TargetData *TD); + + /// SimplifyFortifiedLibCalls - Helper class for folding checked library + /// calls (e.g. __strcpy_chk) into their unchecked counterparts. + class SimplifyFortifiedLibCalls { + protected: + CallInst *CI; + virtual void replaceCall(Value *With) = 0; + virtual bool isFoldable(unsigned SizeCIOp, unsigned SizeArgOp, + bool isString) const = 0; + public: + virtual ~SimplifyFortifiedLibCalls(); + bool fold(CallInst *CI, const TargetData *TD); + }; } #endif diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp index 114db2d37050..96bb02714a03 100644 --- a/lib/Analysis/ConstantFolding.cpp +++ b/lib/Analysis/ConstantFolding.cpp @@ -589,6 +589,30 @@ static Constant *SymbolicallyEvaluateGEP(Constant *const *Ops, unsigned NumOps, APInt Offset = APInt(BitWidth, TD->getIndexedOffset(Ptr->getType(), (Value**)Ops+1, NumOps-1)); + Ptr = cast<Constant>(Ptr->stripPointerCasts()); + + // If this is a GEP of a GEP, fold it all into a single GEP. + while (GEPOperator *GEP = dyn_cast<GEPOperator>(Ptr)) { + SmallVector<Value *, 4> NestedOps(GEP->op_begin()+1, GEP->op_end()); + + // Do not try the incorporate the sub-GEP if some index is not a number. + bool AllConstantInt = true; + for (unsigned i = 0, e = NestedOps.size(); i != e; ++i) + if (!isa<ConstantInt>(NestedOps[i])) { + AllConstantInt = false; + break; + } + if (!AllConstantInt) + break; + + Ptr = cast<Constant>(GEP->getOperand(0)); + Offset += APInt(BitWidth, + TD->getIndexedOffset(Ptr->getType(), + (Value**)NestedOps.data(), + NestedOps.size())); + Ptr = cast<Constant>(Ptr->stripPointerCasts()); + } + // If the base value for this address is a literal integer value, fold the // getelementptr to the resulting integer value casted to the pointer type. if (BaseIsInt) { @@ -600,7 +624,6 @@ static Constant *SymbolicallyEvaluateGEP(Constant *const *Ops, unsigned NumOps, // we eliminate over-indexing of the notional static type array bounds. // This makes it easy to determine if the getelementptr is "inbounds". // Also, this helps GlobalOpt do SROA on GlobalVariables. - Ptr = cast<Constant>(Ptr->stripPointerCasts()); const Type *Ty = Ptr->getType(); SmallVector<Constant*, 32> NewIdxs; do { diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp index 0f1f93b66b0e..5b8b53495c40 100644 --- a/lib/Analysis/InlineCost.cpp +++ b/lib/Analysis/InlineCost.cpp @@ -22,7 +22,7 @@ using namespace llvm; // instructions will be constant folded if the specified value is constant. // unsigned InlineCostAnalyzer::FunctionInfo:: - CountCodeReductionForConstant(Value *V) { +CountCodeReductionForConstant(Value *V) { unsigned Reduction = 0; for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI) if (isa<BranchInst>(*UI) || isa<SwitchInst>(*UI)) { @@ -31,7 +31,7 @@ unsigned InlineCostAnalyzer::FunctionInfo:: const unsigned NumSucc = TI.getNumSuccessors(); unsigned Instrs = 0; for (unsigned I = 0; I != NumSucc; ++I) - Instrs += TI.getSuccessor(I)->size(); + Instrs += Metrics.NumBBInsts[TI.getSuccessor(I)]; // We don't know which blocks will be eliminated, so use the average size. Reduction += InlineConstants::InstrCost*Instrs*(NumSucc-1)/NumSucc; } else if (CallInst *CI = dyn_cast<CallInst>(*UI)) { @@ -120,7 +120,7 @@ static bool callIsSmall(const Function *F) { StringRef Name = F->getName(); // These will all likely lower to a single selection DAG node. - if (Name == "copysign" || Name == "copysignf" || + if (Name == "copysign" || Name == "copysignf" || Name == "copysignl" || Name == "fabs" || Name == "fabsf" || Name == "fabsl" || Name == "sin" || Name == "sinf" || Name == "sinl" || Name == "cos" || Name == "cosf" || Name == "cosl" || @@ -142,7 +142,7 @@ static bool callIsSmall(const Function *F) { /// from the specified block. void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) { ++NumBlocks; - + unsigned NumInstsBeforeThisBB = NumInsts; for (BasicBlock::const_iterator II = BB->begin(), E = BB->end(); II != E; ++II) { if (isa<PHINode>(II)) continue; // PHI nodes don't count. @@ -208,6 +208,9 @@ void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) { // function which is extremely undefined behavior. if (isa<IndirectBrInst>(BB->getTerminator())) NeverInline = true; + + // Remember NumInsts for this BB. + NumBBInsts[BB] = NumInsts - NumInstsBeforeThisBB; } /// analyzeFunction - Fill in the current structure with information gleaned diff --git a/lib/Analysis/LoopInfo.cpp b/lib/Analysis/LoopInfo.cpp index 2139c29cc1f8..1001d2b54603 100644 --- a/lib/Analysis/LoopInfo.cpp +++ b/lib/Analysis/LoopInfo.cpp @@ -263,14 +263,7 @@ unsigned Loop::getSmallConstantTripMultiple() const { } /// isLCSSAForm - Return true if the Loop is in LCSSA form -bool Loop::isLCSSAForm() const { - // Collect all the reachable blocks in the function, for fast lookups. - SmallPtrSet<BasicBlock *, 32> ReachableBBs; - BasicBlock *EntryBB = getHeader()->getParent()->begin(); - for (df_iterator<BasicBlock *> NI = df_begin(EntryBB), - NE = df_end(EntryBB); NI != NE; ++NI) - ReachableBBs.insert(*NI); - +bool Loop::isLCSSAForm(DominatorTree &DT) const { // Sort the blocks vector so that we can use binary search to do quick // lookups. SmallPtrSet<BasicBlock *, 16> LoopBBs(block_begin(), block_end()); @@ -290,7 +283,7 @@ bool Loop::isLCSSAForm() const { // entry are special; uses in them don't need to go through PHIs. if (UserBB != BB && !LoopBBs.count(UserBB) && - ReachableBBs.count(UserBB)) + DT.isReachableFromEntry(UserBB)) return false; } } diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 92cbb7c95c03..5ae72f7aba9a 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -779,7 +779,7 @@ unsigned llvm::ComputeNumSignBits(Value *V, const TargetData *TD, for (unsigned i = 1, e = PN->getNumIncomingValues(); i != e; ++i) { if (Tmp == 1) return Tmp; Tmp = std::min(Tmp, - ComputeNumSignBits(PN->getIncomingValue(1), TD, Depth+1)); + ComputeNumSignBits(PN->getIncomingValue(i), TD, Depth+1)); } return Tmp; } diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 4978fba44cdc..2636e2c4017f 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -55,12 +55,13 @@ using namespace llvm; STATISTIC(EmittedInsts, "Number of machine instrs printed"); char AsmPrinter::ID = 0; + AsmPrinter::AsmPrinter(formatted_raw_ostream &o, TargetMachine &tm, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) + MCStreamer &Streamer) : MachineFunctionPass(&ID), O(o), - TM(tm), MAI(T), TRI(tm.getRegisterInfo()), - OutContext(Ctx), OutStreamer(Streamer), + TM(tm), MAI(tm.getMCAsmInfo()), TRI(tm.getRegisterInfo()), + OutContext(Streamer.getContext()), + OutStreamer(Streamer), LastMI(0), LastFn(0), Counter(~0U), SetCounter(0), PrevDLT(NULL) { DW = 0; MMI = 0; VerboseAsm = Streamer.isVerboseAsm(); @@ -72,7 +73,6 @@ AsmPrinter::~AsmPrinter() { delete I->second; delete &OutStreamer; - delete &OutContext; } /// getFunctionNumber - Return a unique ID for the current function. @@ -94,17 +94,21 @@ const MCSection *AsmPrinter::getCurrentSection() const { void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); MachineFunctionPass::getAnalysisUsage(AU); + AU.addRequired<MachineModuleInfo>(); AU.addRequired<GCModuleInfo>(); if (VerboseAsm) AU.addRequired<MachineLoopInfo>(); } bool AsmPrinter::doInitialization(Module &M) { + MMI = getAnalysisIfAvailable<MachineModuleInfo>(); + MMI->AnalyzeModule(M); + // Initialize TargetLoweringObjectFile. const_cast<TargetLoweringObjectFile&>(getObjFileLowering()) .Initialize(OutContext, TM); - Mang = new Mangler(*MAI); + Mang = new Mangler(OutContext, *TM.getTargetData()); // Allow the target to emit any magic that it wants at the start of the file. EmitStartOfAsmFile(M); @@ -128,9 +132,6 @@ bool AsmPrinter::doInitialization(Module &M) { << '\n' << MAI->getCommentString() << " End of file scope inline assembly\n"; - MMI = getAnalysisIfAvailable<MachineModuleInfo>(); - if (MMI) - MMI->AnalyzeModule(M); DW = getAnalysisIfAvailable<DwarfWriter>(); if (DW) DW->BeginModule(&M, MMI, O, this, MAI); @@ -193,7 +194,7 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { if (EmitSpecialLLVMGlobal(GV)) return; - MCSymbol *GVSym = GetGlobalValueSymbol(GV); + MCSymbol *GVSym = Mang->getSymbol(GV); EmitVisibility(GVSym, GV->getVisibility()); if (MAI->hasDotTypeDotSizeDirective()) @@ -306,6 +307,16 @@ void AsmPrinter::EmitFunctionHeader() { // do their wild and crazy things as required. EmitFunctionEntryLabel(); + // If the function had address-taken blocks that got deleted, then we have + // references to the dangling symbols. Emit them at the start of the function + // so that we don't get references to undefined symbols. + std::vector<MCSymbol*> DeadBlockSyms; + MMI->takeDeletedSymbolsForFunction(F, DeadBlockSyms); + for (unsigned i = 0, e = DeadBlockSyms.size(); i != e; ++i) { + OutStreamer.AddComment("Address taken block that was later removed"); + OutStreamer.EmitLabel(DeadBlockSyms[i]); + } + // Add some workaround for linkonce linkage on Cygwin\MinGW. if (MAI->getLinkOnceDirective() != 0 && (F->hasLinkOnceLinkage() || F->hasWeakLinkage())) @@ -477,14 +488,12 @@ bool AsmPrinter::doFinalization(Module &M) { for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) { if (!I->hasExternalWeakLinkage()) continue; - OutStreamer.EmitSymbolAttribute(GetGlobalValueSymbol(I), - MCSA_WeakReference); + OutStreamer.EmitSymbolAttribute(Mang->getSymbol(I), MCSA_WeakReference); } for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) { if (!I->hasExternalWeakLinkage()) continue; - OutStreamer.EmitSymbolAttribute(GetGlobalValueSymbol(I), - MCSA_WeakReference); + OutStreamer.EmitSymbolAttribute(Mang->getSymbol(I), MCSA_WeakReference); } } @@ -492,10 +501,10 @@ bool AsmPrinter::doFinalization(Module &M) { OutStreamer.AddBlankLine(); for (Module::const_alias_iterator I = M.alias_begin(), E = M.alias_end(); I != E; ++I) { - MCSymbol *Name = GetGlobalValueSymbol(I); + MCSymbol *Name = Mang->getSymbol(I); const GlobalValue *GV = cast<GlobalValue>(I->getAliasedGlobal()); - MCSymbol *Target = GetGlobalValueSymbol(GV); + MCSymbol *Target = Mang->getSymbol(GV); if (I->hasExternalLinkage() || !MAI->getWeakRefDirective()) OutStreamer.EmitSymbolAttribute(Name, MCSA_Global); @@ -539,7 +548,7 @@ bool AsmPrinter::doFinalization(Module &M) { void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { this->MF = &MF; // Get the function symbol. - CurrentFnSym = GetGlobalValueSymbol(MF.getFunction()); + CurrentFnSym = Mang->getSymbol(MF.getFunction()); if (VerboseAsm) LI = &getAnalysis<MachineLoopInfo>(); @@ -651,6 +660,7 @@ void AsmPrinter::EmitConstantPool() { void AsmPrinter::EmitJumpTableInfo() { const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); if (MJTI == 0) return; + if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_Inline) return; const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); if (JT.empty()) return; @@ -698,7 +708,7 @@ void AsmPrinter::EmitJumpTableInfo() { // .set LJTSet, LBB32-base const MCExpr *LHS = - MCSymbolRefExpr::Create(MBB->getSymbol(OutContext), OutContext); + MCSymbolRefExpr::Create(MBB->getSymbol(), OutContext); OutStreamer.EmitAssignment(GetJTSetSymbol(JTI, MBB->getNumber()), MCBinaryExpr::CreateSub(LHS, Base, OutContext)); } @@ -727,6 +737,8 @@ void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, unsigned UID) const { const MCExpr *Value = 0; switch (MJTI->getEntryKind()) { + case MachineJumpTableInfo::EK_Inline: + llvm_unreachable("Cannot emit EK_Inline jump table entry"); break; case MachineJumpTableInfo::EK_Custom32: Value = TM.getTargetLowering()->LowerCustomJumpTableEntry(MJTI, MBB, UID, OutContext); @@ -734,13 +746,13 @@ void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, case MachineJumpTableInfo::EK_BlockAddress: // EK_BlockAddress - Each entry is a plain address of block, e.g.: // .word LBB123 - Value = MCSymbolRefExpr::Create(MBB->getSymbol(OutContext), OutContext); + Value = MCSymbolRefExpr::Create(MBB->getSymbol(), OutContext); break; case MachineJumpTableInfo::EK_GPRel32BlockAddress: { // EK_GPRel32BlockAddress - Each entry is an address of block, encoded // with a relocation as gp-relative, e.g.: // .gprel32 LBB123 - MCSymbol *MBBSym = MBB->getSymbol(OutContext); + MCSymbol *MBBSym = MBB->getSymbol(); OutStreamer.EmitGPRel32Value(MCSymbolRefExpr::Create(MBBSym, OutContext)); return; } @@ -764,7 +776,7 @@ void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, break; } // Otherwise, use the difference as the jump table entry. - Value = MCSymbolRefExpr::Create(MBB->getSymbol(OutContext), OutContext); + Value = MCSymbolRefExpr::Create(MBB->getSymbol(), OutContext); const MCExpr *JTI = MCSymbolRefExpr::Create(GetJTISymbol(UID), OutContext); Value = MCBinaryExpr::CreateSub(Value, JTI, OutContext); break; @@ -842,8 +854,7 @@ void AsmPrinter::EmitLLVMUsedList(Constant *List) { const GlobalValue *GV = dyn_cast<GlobalValue>(InitList->getOperand(i)->stripPointerCasts()); if (GV && getObjFileLowering().shouldEmitUsedDirectiveFor(GV, Mang)) - OutStreamer.EmitSymbolAttribute(GetGlobalValueSymbol(GV), - MCSA_NoDeadStrip); + OutStreamer.EmitSymbolAttribute(Mang->getSymbol(GV), MCSA_NoDeadStrip); } } @@ -960,7 +971,7 @@ static const MCExpr *LowerConstant(const Constant *CV, AsmPrinter &AP) { return MCConstantExpr::Create(CI->getZExtValue(), Ctx); if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) - return MCSymbolRefExpr::Create(AP.GetGlobalValueSymbol(GV), Ctx); + return MCSymbolRefExpr::Create(AP.Mang->getSymbol(GV), Ctx); if (const BlockAddress *BA = dyn_cast<BlockAddress>(CV)) return MCSymbolRefExpr::Create(AP.GetBlockAddressSymbol(BA), Ctx); @@ -1308,6 +1319,8 @@ void AsmPrinter::processDebugLoc(const MachineInstr *MI, if (!MAI || !DW || !MAI->doesSupportDebugInformation() || !DW->ShouldEmitDwarfDebug()) return; + if (MI->getOpcode() == TargetOpcode::DBG_VALUE) + return; DebugLoc DL = MI->getDebugLoc(); if (DL.isUnknown()) return; @@ -1499,7 +1512,7 @@ void AsmPrinter::printInlineAsm(const MachineInstr *MI) const { ++OpNo; // Skip over the ID number. if (Modifier[0] == 'l') // labels are target independent - O << *MI->getOperand(OpNo).getMBB()->getSymbol(OutContext); + O << *MI->getOperand(OpNo).getMBB()->getSymbol(); else { AsmPrinter *AP = const_cast<AsmPrinter*>(this); if ((OpFlags & 7) == 4) { @@ -1552,17 +1565,7 @@ void AsmPrinter::printKill(const MachineInstr *MI) const { /// printLabel - This method prints a local label used by debug and /// exception handling tables. void AsmPrinter::printLabelInst(const MachineInstr *MI) const { - MCSymbol *Sym = - OutContext.GetOrCreateTemporarySymbol(Twine(MAI->getPrivateGlobalPrefix()) + - "label" + Twine(MI->getOperand(0).getImm())); - OutStreamer.EmitLabel(Sym); -} - -void AsmPrinter::printLabel(unsigned Id) const { - MCSymbol *Sym = - OutContext.GetOrCreateTemporarySymbol(Twine(MAI->getPrivateGlobalPrefix()) + - "label" + Twine(Id)); - OutStreamer.EmitLabel(Sym); + OutStreamer.EmitLabel(MI->getOperand(0).getMCSymbol()); } /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM @@ -1582,28 +1585,11 @@ bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, } MCSymbol *AsmPrinter::GetBlockAddressSymbol(const BlockAddress *BA) const { - return GetBlockAddressSymbol(BA->getFunction(), BA->getBasicBlock()); + return MMI->getAddrLabelSymbol(BA->getBasicBlock()); } -MCSymbol *AsmPrinter::GetBlockAddressSymbol(const Function *F, - const BasicBlock *BB) const { - assert(BB->hasName() && - "Address of anonymous basic block not supported yet!"); - - // This code must use the function name itself, and not the function number, - // since it must be possible to generate the label name from within other - // functions. - SmallString<60> FnName; - Mang->getNameWithPrefix(FnName, F, false); - - // FIXME: THIS IS BROKEN IF THE LLVM BASIC BLOCK DOESN'T HAVE A NAME! - SmallString<60> NameResult; - Mang->getNameWithPrefix(NameResult, - StringRef("BA") + Twine((unsigned)FnName.size()) + - "_" + FnName.str() + "_" + BB->getName(), - Mangler::Private); - - return OutContext.GetOrCreateTemporarySymbol(NameResult.str()); +MCSymbol *AsmPrinter::GetBlockAddressSymbol(const BasicBlock *BB) const { + return MMI->getAddrLabelSymbol(BB); } /// GetCPISymbol - Return the symbol for the specified constant pool entry. @@ -1626,17 +1612,6 @@ MCSymbol *AsmPrinter::GetJTSetSymbol(unsigned UID, unsigned MBBID) const { Twine(UID) + "_set_" + Twine(MBBID)); } -/// GetGlobalValueSymbol - Return the MCSymbol for the specified global -/// value. -MCSymbol *AsmPrinter::GetGlobalValueSymbol(const GlobalValue *GV) const { - SmallString<60> NameStr; - Mang->getNameWithPrefix(NameStr, GV, false); - - if (!GV->hasPrivateLinkage()) - return OutContext.GetOrCreateSymbol(NameStr.str()); - return OutContext.GetOrCreateTemporarySymbol(NameStr.str()); -} - /// GetSymbolWithGlobalValueBase - Return the MCSymbol for a symbol with /// global value name as its base, with the specified suffix, and where the /// symbol is forced to have private linkage if ForcePrivate is true. @@ -1734,16 +1709,19 @@ void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock *MBB) const { if (unsigned Align = MBB->getAlignment()) EmitAlignment(Log2_32(Align)); - // If the block has its address taken, emit a special label to satisfy - // references to the block. This is done so that we don't need to - // remember the number of this label, and so that we can make - // forward references to labels without knowing what their numbers - // will be. + // If the block has its address taken, emit any labels that were used to + // reference the block. It is possible that there is more than one label + // here, because multiple LLVM BB's may have been RAUW'd to this block after + // the references were generated. if (MBB->hasAddressTaken()) { const BasicBlock *BB = MBB->getBasicBlock(); if (VerboseAsm) - OutStreamer.AddComment("Address Taken"); - OutStreamer.EmitLabel(GetBlockAddressSymbol(BB->getParent(), BB)); + OutStreamer.AddComment("Block address taken"); + + std::vector<MCSymbol*> Syms = MMI->getAddrLabelSymbolToEmit(BB); + + for (unsigned i = 0, e = Syms.size(); i != e; ++i) + OutStreamer.EmitLabel(Syms[i]); } // Print the main label for the block. @@ -1766,7 +1744,7 @@ void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock *MBB) const { PrintBasicBlockLoopComments(*MBB, LI, *this); } - OutStreamer.EmitLabel(MBB->getSymbol(OutContext)); + OutStreamer.EmitLabel(MBB->getSymbol()); } } diff --git a/lib/CodeGen/AsmPrinter/DIE.h b/lib/CodeGen/AsmPrinter/DIE.h index e08d748dc108..c5909faab7e1 100644 --- a/lib/CodeGen/AsmPrinter/DIE.h +++ b/lib/CodeGen/AsmPrinter/DIE.h @@ -112,7 +112,6 @@ namespace llvm { //===--------------------------------------------------------------------===// /// DIE - A structured debug information entry. Has an abbreviation which /// describes it's organization. - class CompileUnit; class DIEValue; class DIE { @@ -159,7 +158,6 @@ namespace llvm { void setTag(unsigned Tag) { Abbrev.setTag(Tag); } void setOffset(unsigned O) { Offset = O; } void setSize(unsigned S) { Size = S; } - void setParent(DIE *P) { Parent = P; } /// addValue - Add a value and attributes to a DIE. /// @@ -185,7 +183,7 @@ namespace llvm { } Abbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes); Children.push_back(Child); - Child->setParent(this); + Child->Parent = this; } #ifndef NDEBUG @@ -393,12 +391,11 @@ namespace llvm { /// this class can also be used as a proxy for a debug information entry not /// yet defined (ie. types.) class DIEEntry : public DIEValue { - DIE *Entry; + DIE *const Entry; public: explicit DIEEntry(DIE *E) : DIEValue(isEntry), Entry(E) {} DIE *getEntry() const { return Entry; } - void setEntry(DIE *E) { Entry = E; } /// EmitValue - Emit debug information entry offset. /// diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 36be5b99b946..866f457139ae 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -25,6 +25,7 @@ #include "llvm/Target/TargetFrameInfo.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -52,9 +53,9 @@ class CompileUnit { /// Die - Compile unit debug information entry. /// - DIE *CUDie; + const OwningPtr<DIE> CUDie; - /// IndexTyDie - An anonymous type for index type. + /// IndexTyDie - An anonymous type for index type. Owned by CUDie. DIE *IndexTyDie; /// GVToDieMap - Tracks the mapping of unit level debug informaton @@ -78,11 +79,10 @@ class CompileUnit { public: CompileUnit(unsigned I, DIE *D) : ID(I), CUDie(D), IndexTyDie(0) {} - ~CompileUnit() { delete CUDie; delete IndexTyDie; } // Accessors. unsigned getID() const { return ID; } - DIE* getCUDie() const { return CUDie; } + DIE* getCUDie() const { return CUDie.get(); } const StringMap<DIE*> &getGlobals() const { return Globals; } const StringMap<DIE*> &getGlobalTypes() const { return GlobalTypes; } @@ -148,16 +148,21 @@ public: class DbgVariable { DIVariable Var; // Variable Descriptor. unsigned FrameIndex; // Variable frame index. - DbgVariable *AbstractVar; // Abstract variable for this variable. + const MachineInstr *DbgValueMInsn; // DBG_VALUE + DbgVariable *const AbstractVar; // Abstract variable for this variable. DIE *TheDIE; public: - DbgVariable(DIVariable V, unsigned I) - : Var(V), FrameIndex(I), AbstractVar(0), TheDIE(0) {} + // AbsVar may be NULL. + DbgVariable(DIVariable V, unsigned I, DbgVariable *AbsVar) + : Var(V), FrameIndex(I), DbgValueMInsn(0), AbstractVar(AbsVar), TheDIE(0) {} + DbgVariable(DIVariable V, const MachineInstr *MI, DbgVariable *AbsVar) + : Var(V), FrameIndex(0), DbgValueMInsn(MI), AbstractVar(AbsVar), TheDIE(0) + {} // Accessors. DIVariable getVariable() const { return Var; } unsigned getFrameIndex() const { return FrameIndex; } - void setAbstractVariable(DbgVariable *V) { AbstractVar = V; } + const MachineInstr *getDbgValue() const { return DbgValueMInsn; } DbgVariable *getAbstractVariable() const { return AbstractVar; } void setDIE(DIE *D) { TheDIE = D; } DIE *getDIE() const { return TheDIE; } @@ -176,8 +181,10 @@ class DbgScope { MCSymbol *EndLabel; // Label ID of the end of scope. const MachineInstr *LastInsn; // Last instruction of this scope. const MachineInstr *FirstInsn; // First instruction of this scope. - SmallVector<DbgScope *, 4> Scopes; // Scopes defined in scope. - SmallVector<DbgVariable *, 8> Variables;// Variables declared in scope. + // Scopes defined in scope. Contents not owned. + SmallVector<DbgScope *, 4> Scopes; + // Variables declared in scope. Contents owned. + SmallVector<DbgVariable *, 8> Variables; // Private state for dump() mutable unsigned IndentLevel; @@ -192,14 +199,12 @@ public: DbgScope *getParent() const { return Parent; } void setParent(DbgScope *P) { Parent = P; } DIDescriptor getDesc() const { return Desc; } - MDNode *getInlinedAt() const { - return InlinedAtLocation; - } + MDNode *getInlinedAt() const { return InlinedAtLocation; } MDNode *getScopeNode() const { return Desc.getNode(); } MCSymbol *getStartLabel() const { return StartLabel; } MCSymbol *getEndLabel() const { return EndLabel; } - SmallVector<DbgScope *, 4> &getScopes() { return Scopes; } - SmallVector<DbgVariable *, 8> &getVariables() { return Variables; } + const SmallVector<DbgScope *, 4> &getScopes() { return Scopes; } + const SmallVector<DbgVariable *, 8> &getVariables() { return Variables; } void setStartLabel(MCSymbol *S) { StartLabel = S; } void setEndLabel(MCSymbol *E) { EndLabel = E; } void setLastInsn(const MachineInstr *MI) { LastInsn = MI; } @@ -222,14 +227,14 @@ public: assert (getFirstInsn() && "First instruction is missing!"); // Use the end of last child scope as end of this scope. - SmallVector<DbgScope *, 4> &Scopes = getScopes(); + const SmallVector<DbgScope *, 4> &Scopes = getScopes(); const MachineInstr *LastInsn = getFirstInsn(); unsigned LIndex = 0; if (Scopes.empty()) { assert (getLastInsn() && "Inner most scope does not have last insn!"); return; } - for (SmallVector<DbgScope *, 4>::iterator SI = Scopes.begin(), + for (SmallVector<DbgScope *, 4>::const_iterator SI = Scopes.begin(), SE = Scopes.end(); SI != SE; ++SI) { DbgScope *DS = *SI; DS->fixInstructionMarkers(MIIndexMap); @@ -281,8 +286,6 @@ void DbgScope::dump() const { #endif DbgScope::~DbgScope() { - for (unsigned i = 0, N = Scopes.size(); i < N; ++i) - delete Scopes[i]; for (unsigned j = 0, M = Variables.size(); j < M; ++j) delete Variables[j]; } @@ -292,9 +295,9 @@ DbgScope::~DbgScope() { DwarfDebug::DwarfDebug(raw_ostream &OS, AsmPrinter *A, const MCAsmInfo *T) : DwarfPrinter(OS, A, T), ModuleCU(0), AbbreviationsSet(InitAbbreviationsSetSize), Abbreviations(), - DIEValues(), StringPool(), - SectionSourceLines(), didInitial(false), shouldEmit(false), + DIEValues(), SectionSourceLines(), didInitial(false), shouldEmit(false), CurrentFnDbgScope(0), DebugTimer(0) { + NextStringPoolNumber = 0; if (TimePassesIsEnabled) DebugTimer = new Timer("Dwarf Debug Writer"); } @@ -305,6 +308,15 @@ DwarfDebug::~DwarfDebug() { delete DebugTimer; } +MCSymbol *DwarfDebug::getStringPoolEntry(StringRef Str) { + std::pair<MCSymbol*, unsigned> &Entry = StringPool[Str]; + if (Entry.first) return Entry.first; + + Entry.second = NextStringPoolNumber++; + return Entry.first = getDWLabel("string", Entry.second); +} + + /// assignAbbrevNumber - Define a unique number for the abbreviation. /// void DwarfDebug::assignAbbrevNumber(DIEAbbrev &Abbrev) { @@ -820,14 +832,13 @@ void DwarfDebug::addType(DIE *Entity, DIType Ty) { return; } - // Set up proxy. - Entry = createDIEEntry(); - ModuleCU->insertDIEEntry(Ty.getNode(), Entry); - // Construct type. DIE *Buffer = getOrCreateTypeDIE(Ty); - Entry->setEntry(Buffer); + // Set up proxy. + Entry = createDIEEntry(Buffer); + ModuleCU->insertDIEEntry(Ty.getNode(), Entry); + Entity->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, Entry); } @@ -1315,24 +1326,25 @@ DbgScope *DwarfDebug::getOrCreateAbstractScope(MDNode *N) { /// If there are global variables in this scope then create and insert /// DIEs for these variables. DIE *DwarfDebug::updateSubprogramScopeDIE(MDNode *SPNode) { - DIE *SPDie = ModuleCU->getDIE(SPNode); - assert (SPDie && "Unable to find subprogram DIE!"); + assert(SPDie && "Unable to find subprogram DIE!"); DISubprogram SP(SPNode); + // There is not any need to generate specification DIE for a function // defined at compile unit level. If a function is defined inside another // function then gdb prefers the definition at top level and but does not // expect specification DIE in parent function. So avoid creating // specification DIE for a function defined inside a function. - if (SP.isDefinition() && !SP.getContext().isCompileUnit() - && !SP.getContext().isSubprogram()) { + if (SP.isDefinition() && !SP.getContext().isCompileUnit() && + !SP.getContext().isFile() && !SP.getContext().isSubprogram()) { addUInt(SPDie, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); - // Add arguments. + + // Add arguments. DICompositeType SPTy = SP.getType(); DIArray Args = SPTy.getTypeArray(); unsigned SPTag = SPTy.getTag(); if (SPTag == dwarf::DW_TAG_subroutine_type) - for (unsigned i = 1, N = Args.getNumElements(); i < N; ++i) { + for (unsigned i = 1, N = Args.getNumElements(); i < N; ++i) { DIE *Arg = new DIE(dwarf::DW_TAG_formal_parameter); DIType ATy = DIType(DIType(Args.getElement(i).getNode())); addType(Arg, ATy); @@ -1421,9 +1433,6 @@ DIE *DwarfDebug::constructInlinedScopeDIE(DbgScope *Scope) { } else I->second.push_back(std::make_pair(StartLabel, ScopeDIE)); - StringPool.insert(InlinedSP.getName()); - StringPool.insert(getRealLinkageName(InlinedSP.getLinkageName())); - DILocation DL(Scope->getInlinedAt()); addUInt(ScopeDIE, dwarf::DW_AT_call_file, 0, ModuleCU->getID()); addUInt(ScopeDIE, dwarf::DW_AT_call_line, 0, DL.getLineNumber()); @@ -1489,17 +1498,41 @@ DIE *DwarfDebug::constructVariableDIE(DbgVariable *DV, DbgScope *Scope) { // Add variable address. if (!Scope->isAbstractScope()) { - MachineLocation Location; - unsigned FrameReg; - int Offset = RI->getFrameIndexReference(*MF, DV->getFrameIndex(), FrameReg); - Location.set(FrameReg, Offset); - - if (VD.hasComplexAddress()) - addComplexAddress(DV, VariableDie, dwarf::DW_AT_location, Location); - else if (VD.isBlockByrefVariable()) - addBlockByrefAddress(DV, VariableDie, dwarf::DW_AT_location, Location); - else - addAddress(VariableDie, dwarf::DW_AT_location, Location); + // Check if variable is described by DBG_VALUE instruction. + if (const MachineInstr *DbgValueInsn = DV->getDbgValue()) { + if (DbgValueInsn->getNumOperands() == 3) { + // FIXME : Handle getNumOperands != 3 + if (DbgValueInsn->getOperand(0).getType() + == MachineOperand::MO_Register + && DbgValueInsn->getOperand(0).getReg()) { + MachineLocation Location; + Location.set(DbgValueInsn->getOperand(0).getReg()); + addAddress(VariableDie, dwarf::DW_AT_location, Location); + } else if (DbgValueInsn->getOperand(0).getType() == + MachineOperand::MO_Immediate) { + DIEBlock *Block = new DIEBlock(); + unsigned Imm = DbgValueInsn->getOperand(0).getImm(); + addUInt(Block, 0, dwarf::DW_FORM_udata, Imm); + addBlock(VariableDie, dwarf::DW_AT_const_value, 0, Block); + } else { + //FIXME : Handle other operand types. + delete VariableDie; + return NULL; + } + } + } else { + MachineLocation Location; + unsigned FrameReg; + int Offset = RI->getFrameIndexReference(*MF, DV->getFrameIndex(), FrameReg); + Location.set(FrameReg, Offset); + + if (VD.hasComplexAddress()) + addComplexAddress(DV, VariableDie, dwarf::DW_AT_location, Location); + else if (VD.isBlockByrefVariable()) + addBlockByrefAddress(DV, VariableDie, dwarf::DW_AT_location, Location); + else + addAddress(VariableDie, dwarf::DW_AT_location, Location); + } } if (Tag == dwarf::DW_TAG_formal_parameter && VD.getType().isArtificial()) @@ -1549,7 +1582,7 @@ DIE *DwarfDebug::constructScopeDIE(DbgScope *Scope) { } // Add variables to scope. - SmallVector<DbgVariable *, 8> &Variables = Scope->getVariables(); + const SmallVector<DbgVariable *, 8> &Variables = Scope->getVariables(); for (unsigned i = 0, N = Variables.size(); i < N; ++i) { DIE *VariableDIE = constructVariableDIE(Variables[i], Scope); if (VariableDIE) @@ -1557,7 +1590,7 @@ DIE *DwarfDebug::constructScopeDIE(DbgScope *Scope) { } // Add nested scopes. - SmallVector<DbgScope *, 4> &Scopes = Scope->getScopes(); + const SmallVector<DbgScope *, 4> &Scopes = Scope->getScopes(); for (unsigned j = 0, M = Scopes.size(); j < M; ++j) { // Define the Scope debug information entry. DIE *NestedDIE = constructScopeDIE(Scopes[j]); @@ -1622,8 +1655,12 @@ DIE *DwarfDebug::getOrCreateNameSpace(DINameSpace NS) { return NDie; } -CompileUnit *DwarfDebug::constructCompileUnit(MDNode *N) { +void DwarfDebug::constructCompileUnit(MDNode *N) { DICompileUnit DIUnit(N); + // Use first compile unit marked as isMain as the compile unit for this + // module. + if (ModuleCU || !DIUnit.isMain()) + return; StringRef FN = DIUnit.getFilename(); StringRef Dir = DIUnit.getDirectory(); unsigned ID = GetOrCreateSourceID(Dir, FN); @@ -1653,14 +1690,9 @@ CompileUnit *DwarfDebug::constructCompileUnit(MDNode *N) { addUInt(Die, dwarf::DW_AT_APPLE_major_runtime_vers, dwarf::DW_FORM_data1, RVer); - CompileUnit *Unit = new CompileUnit(ID, Die); - if (!ModuleCU && DIUnit.isMain()) { - // Use first compile unit marked as isMain as the compile unit - // for this module. - ModuleCU = Unit; - } - - return Unit; + assert(!ModuleCU && + "ModuleCU assigned since the top of constructCompileUnit"); + ModuleCU = new CompileUnit(ID, Die); } void DwarfDebug::constructGlobalVariableDIE(MDNode *N) { @@ -1686,7 +1718,7 @@ void DwarfDebug::constructGlobalVariableDIE(MDNode *N) { // Do not create specification DIE if context is either compile unit // or a subprogram. if (DI_GV.isDefinition() && !GVContext.isCompileUnit() - && !GVContext.isSubprogram()) { + && !GVContext.isFile() && !GVContext.isSubprogram()) { // Create specification DIE. DIE *VariableSpecDIE = new DIE(dwarf::DW_TAG_variable); addDIEEntry(VariableSpecDIE, dwarf::DW_AT_specification, @@ -1694,7 +1726,7 @@ void DwarfDebug::constructGlobalVariableDIE(MDNode *N) { DIEBlock *Block = new DIEBlock(); addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_addr); addLabel(Block, 0, dwarf::DW_FORM_udata, - Asm->GetGlobalValueSymbol(DI_GV.getGlobal())); + Asm->Mang->getSymbol(DI_GV.getGlobal())); addBlock(VariableSpecDIE, dwarf::DW_AT_location, 0, Block); addUInt(VariableDie, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); ModuleCU->addDie(VariableSpecDIE); @@ -1702,7 +1734,7 @@ void DwarfDebug::constructGlobalVariableDIE(MDNode *N) { DIEBlock *Block = new DIEBlock(); addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_addr); addLabel(Block, 0, dwarf::DW_FORM_udata, - Asm->GetGlobalValueSymbol(DI_GV.getGlobal())); + Asm->Mang->getSymbol(DI_GV.getGlobal())); addBlock(VariableDie, dwarf::DW_AT_location, 0, Block); } addToContextOwner(VariableDie, GVContext); @@ -1880,9 +1912,6 @@ void DwarfDebug::endModule() { // Emit info into a debug pubtypes section. emitDebugPubTypes(); - // Emit info into a debug str section. - emitDebugStr(); - // Emit info into a debug loc section. emitDebugLoc(); @@ -1898,6 +1927,12 @@ void DwarfDebug::endModule() { // Emit inline info. emitDebugInlineInfo(); + // Emit info into a debug str section. + emitDebugStr(); + + delete ModuleCU; + ModuleCU = NULL; // Reset for the next Module, if any. + if (TimePassesIsEnabled) DebugTimer->stopTimer(); } @@ -1915,7 +1950,29 @@ DbgVariable *DwarfDebug::findAbstractVariable(DIVariable &Var, if (!Scope) return NULL; - AbsDbgVariable = new DbgVariable(Var, FrameIdx); + AbsDbgVariable = new DbgVariable(Var, FrameIdx, + NULL /* No more-abstract variable*/); + Scope->addVariable(AbsDbgVariable); + AbstractVariables[Var.getNode()] = AbsDbgVariable; + return AbsDbgVariable; +} + +/// findAbstractVariable - Find abstract variable, if any, associated with Var. +/// FIXME : Refactor findAbstractVariable. +DbgVariable *DwarfDebug::findAbstractVariable(DIVariable &Var, + const MachineInstr *MI, + DILocation &ScopeLoc) { + + DbgVariable *AbsDbgVariable = AbstractVariables.lookup(Var.getNode()); + if (AbsDbgVariable) + return AbsDbgVariable; + + DbgScope *Scope = AbstractScopes.lookup(ScopeLoc.getScope().getNode()); + if (!Scope) + return NULL; + + AbsDbgVariable = new DbgVariable(Var, MI, + NULL /* No more-abstract variable*/); Scope->addVariable(AbsDbgVariable); AbstractVariables[Var.getNode()] = AbsDbgVariable; return AbsDbgVariable; @@ -1942,11 +1999,46 @@ void DwarfDebug::collectVariableInfo() { if (!Scope) continue; - DbgVariable *RegVar = new DbgVariable(DV, VP.first); + DbgVariable *AbsDbgVariable = findAbstractVariable(DV, VP.first, ScopeLoc); + DbgVariable *RegVar = new DbgVariable(DV, VP.first, AbsDbgVariable); Scope->addVariable(RegVar); - if (DbgVariable *AbsDbgVariable = findAbstractVariable(DV, VP.first, - ScopeLoc)) - RegVar->setAbstractVariable(AbsDbgVariable); + } + + // Collect variable information from DBG_VALUE machine instructions; + for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); + I != E; ++I) { + for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end(); + II != IE; ++II) { + const MachineInstr *MInsn = II; + if (MInsn->getOpcode() != TargetOpcode::DBG_VALUE) + continue; + // FIXME : Lift this restriction. + if (MInsn->getNumOperands() != 3) + continue; + DIVariable DV((MDNode*)(MInsn->getOperand(MInsn->getNumOperands() - 1).getMetadata())); + if (DV.getTag() == dwarf::DW_TAG_arg_variable) { + // FIXME Handle inlined subroutine arguments. + DbgVariable *ArgVar = new DbgVariable(DV, MInsn, NULL); + CurrentFnDbgScope->addVariable(ArgVar); + continue; + } + + DebugLoc DL = MInsn->getDebugLoc(); + if (DL.isUnknown()) continue; + DILocation ScopeLoc = MF->getDILocation(DL); + DbgScope *Scope = + ConcreteScopes.lookup(ScopeLoc.getOrigLocation().getNode()); + if (!Scope) + Scope = DbgScopeMap.lookup(ScopeLoc.getScope().getNode()); + // If variable scope is not found then skip this variable. + if (!Scope) + continue; + + DbgVariable *AbsDbgVariable = findAbstractVariable(DV, MInsn, + ScopeLoc); + DbgVariable *RegVar = new DbgVariable(DV, MInsn, AbsDbgVariable); + Scope->addVariable(RegVar); + } } } @@ -1967,7 +2059,7 @@ void DwarfDebug::endScope(const MachineInstr *MI) { if (I == DbgScopeEndMap.end()) return; - MCSymbol *Label = getDWLabel("label", MMI->NextLabelID()); + MCSymbol *Label = MMI->getContext().CreateTempSymbol(); Asm->OutStreamer.EmitLabel(Label); SmallVector<DbgScope*, 2> &SD = I->second; @@ -2017,6 +2109,8 @@ bool DwarfDebug::extractScopeInformation() { for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end(); II != IE; ++II) { const MachineInstr *MInsn = II; + // FIXME : Remove DBG_VALUE check. + if (MInsn->getOpcode() == TargetOpcode::DBG_VALUE) continue; MIIndexMap[MInsn] = MIIndex++; DebugLoc DL = MInsn->getDebugLoc(); if (DL.isUnknown()) continue; @@ -2037,6 +2131,8 @@ bool DwarfDebug::extractScopeInformation() { for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end(); II != IE; ++II) { const MachineInstr *MInsn = II; + // FIXME : Remove DBG_VALUE check. + if (MInsn->getOpcode() == TargetOpcode::DBG_VALUE) continue; DebugLoc DL = MInsn->getDebugLoc(); if (DL.isUnknown()) continue; DILocation DLT = MF->getDILocation(DL); @@ -2065,9 +2161,9 @@ bool DwarfDebug::extractScopeInformation() { while (!WorkList.empty()) { DbgScope *S = WorkList.back(); WorkList.pop_back(); - SmallVector<DbgScope *, 4> &Children = S->getScopes(); + const SmallVector<DbgScope *, 4> &Children = S->getScopes(); if (!Children.empty()) - for (SmallVector<DbgScope *, 4>::iterator SI = Children.begin(), + for (SmallVector<DbgScope *, 4>::const_iterator SI = Children.begin(), SE = Children.end(); SI != SE; ++SI) WorkList.push_back(*SI); @@ -2172,11 +2268,13 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { // Clear debug info CurrentFnDbgScope = NULL; - DbgScopeMap.clear(); + DeleteContainerSeconds(DbgScopeMap); DbgScopeBeginMap.clear(); DbgScopeEndMap.clear(); ConcreteScopes.clear(); + DeleteContainerSeconds(AbstractScopes); AbstractScopesList.clear(); + AbstractVariables.clear(); Lines.clear(); if (TimePassesIsEnabled) @@ -2210,16 +2308,15 @@ MCSymbol *DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, MDNode *S) { Dir = DB.getDirectory(); Fn = DB.getFilename(); } else - assert (0 && "Unexpected scope info"); + assert(0 && "Unexpected scope info"); unsigned Src = GetOrCreateSourceID(Dir, Fn); - unsigned ID = MMI->NextLabelID(); - Lines.push_back(SrcLineInfo(Line, Col, Src, ID)); + MCSymbol *Label = MMI->getContext().CreateTempSymbol(); + Lines.push_back(SrcLineInfo(Line, Col, Src, Label)); if (TimePassesIsEnabled) DebugTimer->stopTimer(); - MCSymbol *Label = getDWLabel("label", ID); Asm->OutStreamer.EmitLabel(Label); return Label; } @@ -2607,8 +2704,8 @@ void DwarfDebug::emitDebugLines() { // Construct rows of the address, source, line, column matrix. for (unsigned i = 0, N = LineInfos.size(); i < N; ++i) { const SrcLineInfo &LineInfo = LineInfos[i]; - unsigned LabelID = LineInfo.getLabelID(); - if (MMI->isLabelDeleted(LabelID)) continue; + MCSymbol *Label = LineInfo.getLabel(); + if (!Label->isDefined()) continue; // Not emitted, in dead code. if (LineInfo.getLine() == 0) continue; @@ -2631,8 +2728,8 @@ void DwarfDebug::emitDebugLines() { Asm->EmitInt8(dwarf::DW_LNE_set_address); Asm->OutStreamer.AddComment("Location label"); - Asm->OutStreamer.EmitSymbolValue(getDWLabel("label", LabelID), - TD->getPointerSize(), 0/*AddrSpace*/); + Asm->OutStreamer.EmitSymbolValue(Label, TD->getPointerSize(), + 0/*AddrSpace*/); // If change of source, then switch to the new source. if (Source != LineInfo.getSourceID()) { @@ -2718,7 +2815,7 @@ void DwarfDebug::emitCommonDebugFrame() { std::vector<MachineMove> Moves; RI->getInitialFrameState(Moves); - EmitFrameMoves(NULL, 0, Moves, false); + EmitFrameMoves(0, Moves, false); Asm->EmitAlignment(2, 0, 0, false); Asm->OutStreamer.EmitLabel(getTempLabel("debug_frame_common_end")); @@ -2726,8 +2823,8 @@ void DwarfDebug::emitCommonDebugFrame() { /// emitFunctionDebugFrame - Emit per function frame info into a debug frame /// section. -void -DwarfDebug::emitFunctionDebugFrame(const FunctionDebugFrameInfo&DebugFrameInfo){ +void DwarfDebug:: +emitFunctionDebugFrame(const FunctionDebugFrameInfo &DebugFrameInfo) { if (!MAI->doesDwarfRequireFrameSection()) return; @@ -2736,33 +2833,31 @@ DwarfDebug::emitFunctionDebugFrame(const FunctionDebugFrameInfo&DebugFrameInfo){ Asm->getObjFileLowering().getDwarfFrameSection()); Asm->OutStreamer.AddComment("Length of Frame Information Entry"); - EmitDifference(getDWLabel("debug_frame_end", DebugFrameInfo.Number), - getDWLabel("debug_frame_begin", DebugFrameInfo.Number), true); + MCSymbol *DebugFrameBegin = + getDWLabel("debug_frame_begin", DebugFrameInfo.Number); + MCSymbol *DebugFrameEnd = + getDWLabel("debug_frame_end", DebugFrameInfo.Number); + EmitDifference(DebugFrameEnd, DebugFrameBegin, true); - Asm->OutStreamer.EmitLabel(getDWLabel("debug_frame_begin", - DebugFrameInfo.Number)); + Asm->OutStreamer.EmitLabel(DebugFrameBegin); Asm->OutStreamer.AddComment("FDE CIE offset"); EmitSectionOffset(getTempLabel("debug_frame_common"), getTempLabel("section_debug_frame"), true, false); Asm->OutStreamer.AddComment("FDE initial location"); - Asm->OutStreamer.EmitSymbolValue(getDWLabel("func_begin", - DebugFrameInfo.Number), + MCSymbol *FuncBeginSym = getDWLabel("func_begin", DebugFrameInfo.Number); + Asm->OutStreamer.EmitSymbolValue(FuncBeginSym, TD->getPointerSize(), 0/*AddrSpace*/); - Asm->OutStreamer.AddComment("FDE address range"); - EmitDifference(getDWLabel("func_end", DebugFrameInfo.Number), - getDWLabel("func_begin", DebugFrameInfo.Number)); + EmitDifference(getDWLabel("func_end", DebugFrameInfo.Number), FuncBeginSym); - EmitFrameMoves("func_begin", DebugFrameInfo.Number, DebugFrameInfo.Moves, - false); + EmitFrameMoves(FuncBeginSym, DebugFrameInfo.Moves, false); Asm->EmitAlignment(2, 0, 0, false); - Asm->OutStreamer.EmitLabel(getDWLabel("debug_frame_end", - DebugFrameInfo.Number)); + Asm->OutStreamer.EmitLabel(DebugFrameEnd); } /// emitDebugPubNames - Emit visible names into a debug pubnames section. @@ -2860,14 +2955,23 @@ void DwarfDebug::emitDebugStr() { Asm->OutStreamer.SwitchSection( Asm->getObjFileLowering().getDwarfStrSection()); - // For each of strings in the string pool. - for (unsigned StringID = 1, N = StringPool.size(); StringID <= N; ++StringID){ + // Get all of the string pool entries and put them in an array by their ID so + // we can sort them. + SmallVector<std::pair<unsigned, + StringMapEntry<std::pair<MCSymbol*, unsigned> >*>, 64> Entries; + + for (StringMap<std::pair<MCSymbol*, unsigned> >::iterator + I = StringPool.begin(), E = StringPool.end(); I != E; ++I) + Entries.push_back(std::make_pair(I->second.second, &*I)); + + array_pod_sort(Entries.begin(), Entries.end()); + + for (unsigned i = 0, e = Entries.size(); i != e; ++i) { // Emit a label for reference from debug information entries. - Asm->OutStreamer.EmitLabel(getDWLabel("string", StringID)); + Asm->OutStreamer.EmitLabel(Entries[i].second->getValue().first); // Emit the string itself. - const std::string &String = StringPool[StringID]; - Asm->OutStreamer.EmitBytes(StringRef(String.c_str(), String.size()+1), 0); + Asm->OutStreamer.EmitBytes(Entries[i].second->getKey(), 0/*addrspace*/); } } @@ -2960,13 +3064,12 @@ void DwarfDebug::emitDebugInlineInfo() { Asm->OutStreamer.EmitBytes(Name, 0); Asm->OutStreamer.EmitIntValue(0, 1, 0); // nul terminator. } else - EmitSectionOffset(getDWLabel("string", - StringPool.idFor(getRealLinkageName(LName))), + EmitSectionOffset(getStringPoolEntry(getRealLinkageName(LName)), getTempLabel("section_str"), true); Asm->OutStreamer.AddComment("Function name"); - EmitSectionOffset(getDWLabel("string", StringPool.idFor(Name)), - getTempLabel("section_str"), false, true); + EmitSectionOffset(getStringPoolEntry(Name), getTempLabel("section_str"), + false, true); EmitULEB128(Labels.size(), "Inline count"); for (SmallVector<InlineInfoLabels, 4>::iterator LI = Labels.begin(), diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 40d1d646761a..d6634e1f5d10 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -45,16 +45,16 @@ class SrcLineInfo { unsigned Line; // Source line number. unsigned Column; // Source column. unsigned SourceID; // Source ID number. - unsigned LabelID; // Label in code ID number. + MCSymbol *Label; // Label in code ID number. public: - SrcLineInfo(unsigned L, unsigned C, unsigned S, unsigned I) - : Line(L), Column(C), SourceID(S), LabelID(I) {} + SrcLineInfo(unsigned L, unsigned C, unsigned S, MCSymbol *label) + : Line(L), Column(C), SourceID(S), Label(label) {} // Accessors unsigned getLine() const { return Line; } unsigned getColumn() const { return Column; } unsigned getSourceID() const { return SourceID; } - unsigned getLabelID() const { return LabelID; } + MCSymbol *getLabel() const { return Label; } }; class DwarfDebug : public DwarfPrinter { @@ -102,9 +102,12 @@ class DwarfDebug : public DwarfPrinter { /// std::vector<DIEValue *> DIEValues; - /// StringPool - A UniqueVector of strings used by indirect references. - /// - UniqueVector<std::string> StringPool; + /// StringPool - A String->Symbol mapping of strings used by indirect + /// references. + StringMap<std::pair<MCSymbol*, unsigned> > StringPool; + unsigned NextStringPoolNumber; + + MCSymbol *getStringPoolEntry(StringRef Str); /// SectionMap - Provides a unique id per text section. /// @@ -126,7 +129,8 @@ class DwarfDebug : public DwarfPrinter { // DbgScope *CurrentFnDbgScope; - /// DbgScopeMap - Tracks the scopes in the current function. + /// DbgScopeMap - Tracks the scopes in the current function. Owns the + /// contained DbgScope*s. /// DenseMap<MDNode *, DbgScope *> DbgScopeMap; @@ -135,11 +139,12 @@ class DwarfDebug : public DwarfPrinter { DenseMap<MDNode *, DbgScope *> ConcreteScopes; /// AbstractScopes - Tracks the abstract scopes a module. These scopes are - /// not included DbgScopeMap. + /// not included DbgScopeMap. AbstractScopes owns its DbgScope*s. DenseMap<MDNode *, DbgScope *> AbstractScopes; SmallVector<DbgScope *, 4>AbstractScopesList; - /// AbstractVariables - Collection on abstract variables. + /// AbstractVariables - Collection on abstract variables. Owned by the + /// DbgScopes in AbstractScopes. DenseMap<MDNode *, DbgVariable *> AbstractVariables; /// InliendSubprogramDIEs - Collection of subprgram DIEs that are marked @@ -225,7 +230,7 @@ class DwarfDebug : public DwarfPrinter { /// createDIEEntry - Creates a new DIEEntry to be a proxy for a debug /// information entry. - DIEEntry *createDIEEntry(DIE *Entry = NULL); + DIEEntry *createDIEEntry(DIE *Entry); /// addUInt - Add an unsigned integer attribute data and value. /// @@ -356,6 +361,8 @@ class DwarfDebug : public DwarfPrinter { /// findAbstractVariable - Find abstract variable associated with Var. DbgVariable *findAbstractVariable(DIVariable &Var, unsigned FrameIdx, DILocation &Loc); + DbgVariable *findAbstractVariable(DIVariable &Var, const MachineInstr *MI, + DILocation &Loc); /// updateSubprogramScopeDIE - Find DIE for the given subprogram and /// attach appropriate DW_AT_low_pc and DW_AT_high_pc attributes. @@ -473,7 +480,7 @@ class DwarfDebug : public DwarfPrinter { /// as well. unsigned GetOrCreateSourceID(StringRef DirName, StringRef FileName); - CompileUnit *constructCompileUnit(MDNode *N); + void constructCompileUnit(MDNode *N); void constructGlobalVariableDIE(MDNode *N); diff --git a/lib/CodeGen/AsmPrinter/DwarfException.cpp b/lib/CodeGen/AsmPrinter/DwarfException.cpp index 11a01fe51ea6..4946b4c3c25e 100644 --- a/lib/CodeGen/AsmPrinter/DwarfException.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfException.cpp @@ -50,25 +50,6 @@ DwarfException::~DwarfException() { delete ExceptionTimer; } -/// CreateLabelDiff - Emit a label and subtract it from the expression we -/// already have. This is equivalent to emitting "foo - .", but we have to emit -/// the label for "." directly. -const MCExpr *DwarfException::CreateLabelDiff(const MCExpr *ExprRef, - const char *LabelName, - unsigned Index) { - SmallString<64> Name; - raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() - << LabelName << Asm->getFunctionNumber() - << "_" << Index; - MCSymbol *DotSym = Asm->OutContext.GetOrCreateTemporarySymbol(Name.str()); - Asm->OutStreamer.EmitLabel(DotSym); - - return MCBinaryExpr::CreateSub(ExprRef, - MCSymbolRefExpr::Create(DotSym, - Asm->OutContext), - Asm->OutContext); -} - /// EmitCIE - Emit a Common Information Entry (CIE). This holds information that /// is shared among many Frame Description Entries. There is at least one CIE /// in every non-empty .debug_frame section. @@ -169,7 +150,7 @@ void DwarfException::EmitCIE(const Function *PersonalityFn, unsigned Index) { // Indicate locations of general callee saved registers in frame. std::vector<MachineMove> Moves; RI->getInitialFrameState(Moves); - EmitFrameMoves(NULL, 0, Moves, true); + EmitFrameMoves(0, Moves, true); // On Darwin the linker honors the alignment of eh_frame, which means it must // be 8-byte on 64-bit targets to match what gcc does. Otherwise you get @@ -240,12 +221,13 @@ void DwarfException::EmitFDE(const FunctionEHFrameInfo &EHFrameInfo) { EHFrameInfo.PersonalityIndex), true, true); + MCSymbol *EHFuncBeginSym = getDWLabel("eh_func_begin", EHFrameInfo.Number); Asm->OutStreamer.AddComment("FDE initial location"); - EmitReference(getDWLabel("eh_func_begin", EHFrameInfo.Number), FDEEncoding); + EmitReference(EHFuncBeginSym, FDEEncoding); + Asm->OutStreamer.AddComment("FDE address range"); - EmitDifference(getDWLabel("eh_func_end", EHFrameInfo.Number), - getDWLabel("eh_func_begin", EHFrameInfo.Number), + EmitDifference(getDWLabel("eh_func_end", EHFrameInfo.Number),EHFuncBeginSym, SizeOfEncodedValue(FDEEncoding) == 4); // If there is a personality and landing pads then point to the language @@ -265,8 +247,7 @@ void DwarfException::EmitFDE(const FunctionEHFrameInfo &EHFrameInfo) { } // Indicate locations of function specific callee saved registers in frame. - EmitFrameMoves("eh_func_begin", EHFrameInfo.Number, EHFrameInfo.Moves, - true); + EmitFrameMoves(EHFuncBeginSym, EHFrameInfo.Moves, true); // On Darwin the linker honors the alignment of eh_frame, which means it // must be 8-byte on 64-bit targets to match what gcc does. Otherwise you @@ -473,7 +454,7 @@ ComputeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, const SmallVectorImpl<const LandingPadInfo *> &LandingPads, const SmallVectorImpl<unsigned> &FirstActions) { // The end label of the previous invoke or nounwind try-range. - unsigned LastLabel = 0; + MCSymbol *LastLabel = 0; // Whether there is a potentially throwing instruction (currently this means // an ordinary call) between the end of the previous try-range and now. @@ -490,14 +471,11 @@ ComputeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites, if (!MI->isLabel()) { if (MI->getDesc().isCall()) SawPotentiallyThrowing |= !CallToNoUnwindFunction(MI); - continue; } - unsigned BeginLabel = MI->getOperand(0).getImm(); - assert(BeginLabel && "Invalid label!"); - // End of the previous try-range? + MCSymbol *BeginLabel = MI->getOperand(0).getMCSymbol(); if (BeginLabel == LastLabel) SawPotentiallyThrowing = false; @@ -599,7 +577,6 @@ void DwarfException::EmitExceptionTable() { const std::vector<GlobalVariable *> &TypeInfos = MMI->getTypeInfos(); const std::vector<unsigned> &FilterIds = MMI->getFilterIds(); const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads(); - if (PadInfos.empty()) return; // Sort the landing pads in order of their type ids. This is used to fold // duplicate actions. @@ -624,7 +601,7 @@ void DwarfException::EmitExceptionTable() { for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { const LandingPadInfo *LandingPad = LandingPads[i]; for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) { - unsigned BeginLabel = LandingPad->BeginLabels[j]; + MCSymbol *BeginLabel = LandingPad->BeginLabels[j]; assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); PadRange P = { i, j }; PadMap[BeginLabel] = P; @@ -809,45 +786,33 @@ void DwarfException::EmitExceptionTable() { for (SmallVectorImpl<CallSiteEntry>::const_iterator I = CallSites.begin(), E = CallSites.end(); I != E; ++I) { const CallSiteEntry &S = *I; - const char *BeginTag; - unsigned BeginNumber; - - if (!S.BeginLabel) { - BeginTag = "eh_func_begin"; - BeginNumber = SubprogramCount; - } else { - BeginTag = "label"; - BeginNumber = S.BeginLabel; - } - + + MCSymbol *EHFuncBeginSym = getDWLabel("eh_func_begin", SubprogramCount); + + MCSymbol *BeginLabel = S.BeginLabel; + if (BeginLabel == 0) + BeginLabel = EHFuncBeginSym; + MCSymbol *EndLabel = S.EndLabel; + if (EndLabel == 0) + EndLabel = getDWLabel("eh_func_end", SubprogramCount); + // Offset of the call site relative to the previous call site, counted in // number of 16-byte bundles. The first call site is counted relative to // the start of the procedure fragment. Asm->OutStreamer.AddComment("Region start"); - EmitSectionOffset(getDWLabel(BeginTag, BeginNumber), - getDWLabel("eh_func_begin", SubprogramCount), - true, true); - + EmitSectionOffset(BeginLabel, EHFuncBeginSym, true, true); + Asm->OutStreamer.AddComment("Region length"); - if (!S.EndLabel) - EmitDifference(getDWLabel("eh_func_end", SubprogramCount), - getDWLabel(BeginTag, BeginNumber), - true); - else - EmitDifference(getDWLabel("label", S.EndLabel), - getDWLabel(BeginTag, BeginNumber), true); + EmitDifference(EndLabel, BeginLabel, true); // Offset of the landing pad, counted in 16-byte bundles relative to the // @LPStart address. Asm->OutStreamer.AddComment("Landing pad"); - if (!S.PadLabel) { + if (!S.PadLabel) Asm->OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); - } else { - EmitSectionOffset(getDWLabel("label", S.PadLabel), - getDWLabel("eh_func_begin", SubprogramCount), - true, true); - } + else + EmitSectionOffset(S.PadLabel, EHFuncBeginSym, true, true); // Offset of the first associated action record, relative to the start of // the action table. This value is biased by 1 (1 indicates the start of @@ -947,16 +912,11 @@ void DwarfException::BeginFunction(const MachineFunction *MF) { this->MF = MF; shouldEmitTable = shouldEmitMoves = false; - // Map all labels and get rid of any dead landing pads. - MMI->TidyLandingPads(); - // If any landing pads survive, we need an EH table. - if (!MMI->getLandingPads().empty()) - shouldEmitTable = true; + shouldEmitTable = !MMI->getLandingPads().empty(); // See if we need frame move info. - if (!MF->getFunction()->doesNotThrow() || UnwindTablesMandatory) - shouldEmitMoves = true; + shouldEmitMoves = !MF->getFunction()->doesNotThrow() || UnwindTablesMandatory; if (shouldEmitMoves || shouldEmitTable) // Assumes in correct section after the entry point. @@ -978,7 +938,16 @@ void DwarfException::EndFunction() { ExceptionTimer->startTimer(); Asm->OutStreamer.EmitLabel(getDWLabel("eh_func_end", SubprogramCount)); - EmitExceptionTable(); + + // Record if this personality index uses a landing pad. + bool HasLandingPad = !MMI->getLandingPads().empty(); + UsesLSDA[MMI->getPersonalityIndex()] |= HasLandingPad; + + // Map all labels and get rid of any dead landing pads. + MMI->TidyLandingPads(); + + if (HasLandingPad) + EmitExceptionTable(); const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); MCSymbol *FunctionEHSym = @@ -993,9 +962,6 @@ void DwarfException::EndFunction() { MMI->getFrameMoves(), MF->getFunction())); - // Record if this personality index uses a landing pad. - UsesLSDA[MMI->getPersonalityIndex()] |= !MMI->getLandingPads().empty(); - if (TimePassesIsEnabled) ExceptionTimer->stopTimer(); } diff --git a/lib/CodeGen/AsmPrinter/DwarfException.h b/lib/CodeGen/AsmPrinter/DwarfException.h index 3db1a00802d6..4bc4a458c04e 100644 --- a/lib/CodeGen/AsmPrinter/DwarfException.h +++ b/lib/CodeGen/AsmPrinter/DwarfException.h @@ -111,13 +111,6 @@ class DwarfException : public DwarfPrinter { /// PadLT - Order landing pads lexicographically by type id. static bool PadLT(const LandingPadInfo *L, const LandingPadInfo *R); - struct KeyInfo { - static inline unsigned getEmptyKey() { return -1U; } - static inline unsigned getTombstoneKey() { return -2U; } - static unsigned getHashValue(const unsigned &Key) { return Key; } - static bool isEqual(unsigned LHS, unsigned RHS) { return LHS == RHS; } - }; - /// PadRange - Structure holding a try-range and the associated landing pad. struct PadRange { // The index of the landing pad. @@ -126,7 +119,7 @@ class DwarfException : public DwarfPrinter { unsigned RangeIndex; }; - typedef DenseMap<unsigned, PadRange, KeyInfo> RangeMapType; + typedef DenseMap<MCSymbol *, PadRange> RangeMapType; /// ActionEntry - Structure describing an entry in the actions table. struct ActionEntry { @@ -138,11 +131,11 @@ class DwarfException : public DwarfPrinter { /// CallSiteEntry - Structure describing an entry in the call-site table. struct CallSiteEntry { // The 'try-range' is BeginLabel .. EndLabel. - unsigned BeginLabel; // zero indicates the start of the function. - unsigned EndLabel; // zero indicates the end of the function. + MCSymbol *BeginLabel; // zero indicates the start of the function. + MCSymbol *EndLabel; // zero indicates the end of the function. // The landing pad starts at PadLabel. - unsigned PadLabel; // zero indicates that there is no landing pad. + MCSymbol *PadLabel; // zero indicates that there is no landing pad. unsigned Action; }; @@ -169,11 +162,6 @@ class DwarfException : public DwarfPrinter { const SmallVectorImpl<unsigned> &FirstActions); void EmitExceptionTable(); - /// CreateLabelDiff - Emit a label and subtract it from the expression we - /// already have. This is equivalent to emitting "foo - .", but we have to - /// emit the label for "." directly. - const MCExpr *CreateLabelDiff(const MCExpr *ExprRef, const char *LabelName, - unsigned Index); public: //===--------------------------------------------------------------------===// // Main entry points. diff --git a/lib/CodeGen/AsmPrinter/DwarfPrinter.cpp b/lib/CodeGen/AsmPrinter/DwarfPrinter.cpp index 7890e5cc1798..e21269604e24 100644 --- a/lib/CodeGen/AsmPrinter/DwarfPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfPrinter.cpp @@ -189,7 +189,9 @@ void DwarfPrinter::EmitULEB128(unsigned Value, const char *Desc, void DwarfPrinter::EmitReference(const MCSymbol *Sym, unsigned Encoding) const { const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); - const MCExpr *Exp = TLOF.getSymbolForDwarfReference(Sym, Asm->MMI, Encoding); + const MCExpr *Exp = TLOF.getExprForDwarfReference(Sym, Asm->Mang, + Asm->MMI, Encoding, + Asm->OutStreamer); Asm->OutStreamer.EmitValue(Exp, SizeOfEncodedValue(Encoding), /*addrspace*/0); } @@ -197,7 +199,8 @@ void DwarfPrinter::EmitReference(const GlobalValue *GV, unsigned Encoding)const{ const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); const MCExpr *Exp = - TLOF.getSymbolForDwarfGlobalReference(GV, Asm->Mang, Asm->MMI, Encoding); + TLOF.getExprForDwarfGlobalReference(GV, Asm->Mang, Asm->MMI, Encoding, + Asm->OutStreamer); Asm->OutStreamer.EmitValue(Exp, SizeOfEncodedValue(Encoding), /*addrspace*/0); } @@ -222,10 +225,11 @@ void DwarfPrinter::EmitSectionOffset(const MCSymbol *Label, return EmitDifference(Label, Section, IsSmall); // On COFF targets, we have to emit the weird .secrel32 directive. - if (const char *SecOffDir = MAI->getDwarfSectionOffsetDirective()) + if (const char *SecOffDir = MAI->getDwarfSectionOffsetDirective()) { // FIXME: MCize. Asm->O << SecOffDir << Label->getName(); - else { + Asm->OutStreamer.AddBlankLine(); + } else { unsigned Size = IsSmall ? 4 : TD->getPointerSize(); Asm->OutStreamer.EmitSymbolValue(Label, Size, 0/*AddrSpace*/); } @@ -233,34 +237,31 @@ void DwarfPrinter::EmitSectionOffset(const MCSymbol *Label, /// EmitFrameMoves - Emit frame instructions to describe the layout of the /// frame. -void DwarfPrinter::EmitFrameMoves(const char *BaseLabel, unsigned BaseLabelID, +void DwarfPrinter::EmitFrameMoves(MCSymbol *BaseLabel, const std::vector<MachineMove> &Moves, bool isEH) { - int stackGrowth = - Asm->TM.getFrameInfo()->getStackGrowthDirection() == - TargetFrameInfo::StackGrowsUp ? - TD->getPointerSize() : -TD->getPointerSize(); - bool IsLocal = BaseLabel && strcmp(BaseLabel, "label") == 0; - + int stackGrowth = TD->getPointerSize(); + if (Asm->TM.getFrameInfo()->getStackGrowthDirection() != + TargetFrameInfo::StackGrowsUp) + stackGrowth *= -1; + for (unsigned i = 0, N = Moves.size(); i < N; ++i) { const MachineMove &Move = Moves[i]; - unsigned LabelID = Move.getLabelID(); - + MCSymbol *Label = Move.getLabel(); // Throw out move if the label is invalid. - if (LabelID && MMI->isLabelDeleted(LabelID)) - continue; + if (Label && !Label->isDefined()) continue; // Not emitted, in dead code. const MachineLocation &Dst = Move.getDestination(); const MachineLocation &Src = Move.getSource(); // Advance row if new location. - if (BaseLabel && LabelID && (BaseLabelID != LabelID || !IsLocal)) { - EmitCFAByte(dwarf::DW_CFA_advance_loc4); - EmitDifference(getDWLabel("label", LabelID), - getDWLabel(BaseLabel, BaseLabelID), true); - BaseLabelID = LabelID; - BaseLabel = "label"; - IsLocal = true; + if (BaseLabel && Label) { + MCSymbol *ThisSym = Label; + if (ThisSym != BaseLabel) { + EmitCFAByte(dwarf::DW_CFA_advance_loc4); + EmitDifference(ThisSym, BaseLabel, true); + BaseLabel = ThisSym; + } } // If advancing cfa. diff --git a/lib/CodeGen/AsmPrinter/DwarfPrinter.h b/lib/CodeGen/AsmPrinter/DwarfPrinter.h index 5e2d806a66a5..0b94645a8c7b 100644 --- a/lib/CodeGen/AsmPrinter/DwarfPrinter.h +++ b/lib/CodeGen/AsmPrinter/DwarfPrinter.h @@ -122,7 +122,7 @@ public: /// EmitFrameMoves - Emit frame instructions to describe the layout of the /// frame. - void EmitFrameMoves(const char *BaseLabel, unsigned BaseLabelID, + void EmitFrameMoves(MCSymbol *BaseLabel, const std::vector<MachineMove> &Moves, bool isEH); }; diff --git a/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp b/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp index 3531ed603933..fa840e133a5e 100644 --- a/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp @@ -15,8 +15,9 @@ #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/GCMetadataPrinter.h" #include "llvm/Module.h" -#include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCStreamer.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" @@ -138,8 +139,7 @@ void OcamlGCMetadataPrinter::finishAssembly(raw_ostream &OS, AsmPrinter &AP, llvm_report_error(Msg.str()); // Very rude! } - OS << AddressDirective - << MAI.getPrivateGlobalPrefix() << "label" << J->Num << '\n'; + OS << AddressDirective << J->Label->getName() << '\n'; AP.EmitInt16(FrameSize); diff --git a/lib/CodeGen/BranchFolding.cpp b/lib/CodeGen/BranchFolding.cpp index 889763ac1c8e..13ae43daf6dd 100644 --- a/lib/CodeGen/BranchFolding.cpp +++ b/lib/CodeGen/BranchFolding.cpp @@ -105,17 +105,6 @@ void BranchFolder::RemoveDeadBlock(MachineBasicBlock *MBB) { while (!MBB->succ_empty()) MBB->removeSuccessor(MBB->succ_end()-1); - // If there are any labels in the basic block, unregister them from - // MachineModuleInfo. - if (MMI && !MBB->empty()) { - for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); - I != E; ++I) { - if (I->isLabel()) - // The label ID # is always operand #0, an immediate. - MMI->InvalidateLabel(I->getOperand(0).getImm()); - } - } - // Remove the block. MF->erase(MBB); } @@ -984,6 +973,17 @@ static bool IsEmptyBlock(MachineBasicBlock *MBB) { return true; } +// Blocks with only debug info and branches should be considered the same +// as blocks with only branches. +static bool IsBranchOnlyBlock(MachineBasicBlock *MBB) { + MachineBasicBlock::iterator MBBI, MBBE; + for (MBBI = MBB->begin(), MBBE = MBB->end(); MBBI!=MBBE; ++MBBI) { + if (!MBBI->isDebugValue()) + break; + } + return (MBBI->getDesc().isBranch()); +} + /// IsBetterFallthrough - Return true if it would be clearly better to /// fall-through to MBB1 than to fall through into MBB2. This has to return /// a strict ordering, returning true for both (MBB1,MBB2) and (MBB2,MBB1) will @@ -1206,7 +1206,7 @@ ReoptimizeBlock: // If this branch is the only thing in its block, see if we can forward // other blocks across it. if (CurTBB && CurCond.empty() && CurFBB == 0 && - MBB->begin()->getDesc().isBranch() && CurTBB != MBB && + IsBranchOnlyBlock(MBB) && CurTBB != MBB && !MBB->hasAddressTaken()) { // This block may contain just an unconditional branch. Because there can // be 'non-branch terminators' in the block, try removing the branch and diff --git a/lib/CodeGen/ELFCodeEmitter.h b/lib/CodeGen/ELFCodeEmitter.h index b5e9c844ec69..2ec1f6e873d6 100644 --- a/lib/CodeGen/ELFCodeEmitter.h +++ b/lib/CodeGen/ELFCodeEmitter.h @@ -57,13 +57,13 @@ namespace llvm { bool finishFunction(MachineFunction &F); /// emitLabel - Emits a label - virtual void emitLabel(uint64_t LabelID) { + virtual void emitLabel(MCSymbol *Label) { assert("emitLabel not implemented"); } /// getLabelAddress - Return the address of the specified LabelID, /// only usable after the LabelID has been emitted. - virtual uintptr_t getLabelAddress(uint64_t Label) const { + virtual uintptr_t getLabelAddress(MCSymbol *Label) const { assert("getLabelAddress not implemented"); return 0; } diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index 0979c04ea8aa..eda167cb54a5 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -64,7 +64,7 @@ char ELFWriter::ID = 0; ELFWriter::ELFWriter(raw_ostream &o, TargetMachine &tm) : MachineFunctionPass(&ID), O(o), TM(tm), - OutContext(*new MCContext()), + OutContext(*new MCContext(*TM.getMCAsmInfo())), TLOF(TM.getTargetLowering()->getObjFileLowering()), is64Bit(TM.getTargetData()->getPointerSizeInBits() == 64), isLittleEndian(TM.getTargetData()->isLittleEndian()), @@ -109,7 +109,7 @@ bool ELFWriter::doInitialization(Module &M) { // Initialize TargetLoweringObjectFile. const_cast<TargetLoweringObjectFile&>(TLOF).Initialize(OutContext, TM); - Mang = new Mangler(*MAI); + Mang = new Mangler(OutContext, *TM.getTargetData()); // ELF Header // ---------- diff --git a/lib/CodeGen/GCMetadata.cpp b/lib/CodeGen/GCMetadata.cpp index 055172b4e0e9..ab0a80022531 100644 --- a/lib/CodeGen/GCMetadata.cpp +++ b/lib/CodeGen/GCMetadata.cpp @@ -17,6 +17,7 @@ #include "llvm/Pass.h" #include "llvm/CodeGen/Passes.h" #include "llvm/Function.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -150,30 +151,31 @@ static const char *DescKind(GC::PointKind Kind) { } bool Printer::runOnFunction(Function &F) { - if (!F.hasGC()) { - GCFunctionInfo *FD = &getAnalysis<GCModuleInfo>().getFunctionInfo(F); + if (F.hasGC()) return false; + + GCFunctionInfo *FD = &getAnalysis<GCModuleInfo>().getFunctionInfo(F); + + OS << "GC roots for " << FD->getFunction().getNameStr() << ":\n"; + for (GCFunctionInfo::roots_iterator RI = FD->roots_begin(), + RE = FD->roots_end(); RI != RE; ++RI) + OS << "\t" << RI->Num << "\t" << RI->StackOffset << "[sp]\n"; + + OS << "GC safe points for " << FD->getFunction().getNameStr() << ":\n"; + for (GCFunctionInfo::iterator PI = FD->begin(), + PE = FD->end(); PI != PE; ++PI) { - OS << "GC roots for " << FD->getFunction().getNameStr() << ":\n"; - for (GCFunctionInfo::roots_iterator RI = FD->roots_begin(), - RE = FD->roots_end(); RI != RE; ++RI) - OS << "\t" << RI->Num << "\t" << RI->StackOffset << "[sp]\n"; + OS << "\t" << PI->Label->getName() << ": " + << DescKind(PI->Kind) << ", live = {"; - OS << "GC safe points for " << FD->getFunction().getNameStr() << ":\n"; - for (GCFunctionInfo::iterator PI = FD->begin(), - PE = FD->end(); PI != PE; ++PI) { - - OS << "\tlabel " << PI->Num << ": " << DescKind(PI->Kind) << ", live = {"; - - for (GCFunctionInfo::live_iterator RI = FD->live_begin(PI), - RE = FD->live_end(PI);;) { - OS << " " << RI->Num; - if (++RI == RE) - break; - OS << ","; - } - - OS << " }\n"; + for (GCFunctionInfo::live_iterator RI = FD->live_begin(PI), + RE = FD->live_end(PI);;) { + OS << " " << RI->Num; + if (++RI == RE) + break; + OS << ","; } + + OS << " }\n"; } return false; diff --git a/lib/CodeGen/GCMetadataPrinter.cpp b/lib/CodeGen/GCMetadataPrinter.cpp index 9cd2925e2d28..752752f71ba3 100644 --- a/lib/CodeGen/GCMetadataPrinter.cpp +++ b/lib/CodeGen/GCMetadataPrinter.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/GCMetadataPrinter.h" - using namespace llvm; GCMetadataPrinter::GCMetadataPrinter() { } diff --git a/lib/CodeGen/GCStrategy.cpp b/lib/CodeGen/GCStrategy.cpp index b5006fdbb4ee..1a23be0c7d11 100644 --- a/lib/CodeGen/GCStrategy.cpp +++ b/lib/CodeGen/GCStrategy.cpp @@ -71,9 +71,9 @@ namespace { void FindSafePoints(MachineFunction &MF); void VisitCallPoint(MachineBasicBlock::iterator MI); - unsigned InsertLabel(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - DebugLoc DL) const; + MCSymbol *InsertLabel(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + DebugLoc DL) const; void FindStackOffsets(MachineFunction &MF); @@ -329,14 +329,11 @@ void MachineCodeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<GCModuleInfo>(); } -unsigned MachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - DebugLoc DL) const { - unsigned Label = MMI->NextLabelID(); - - BuildMI(MBB, MI, DL, - TII->get(TargetOpcode::GC_LABEL)).addImm(Label); - +MCSymbol *MachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + DebugLoc DL) const { + MCSymbol *Label = MBB.getParent()->getContext().GetOrCreateTemporarySymbol(); + BuildMI(MBB, MI, DL, TII->get(TargetOpcode::GC_LABEL)).addSym(Label); return Label; } diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp index 9bc0b7121d72..75e45efe4de1 100644 --- a/lib/CodeGen/LLVMTargetMachine.cpp +++ b/lib/CodeGen/LLVMTargetMachine.cpp @@ -13,16 +13,15 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/PassManager.h" -#include "llvm/Pass.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Assembly/PrintModulePass.h" #include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/Passes.h" -#include "llvm/CodeGen/GCStrategy.h" #include "llvm/CodeGen/MachineFunctionAnalysis.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/GCStrategy.h" +#include "llvm/CodeGen/Passes.h" #include "llvm/Target/TargetOptions.h" #include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetRegistry.h" @@ -94,21 +93,19 @@ static cl::opt<bool> EnableSplitGEPGVN("split-gep-gvn", cl::Hidden, cl::desc("Split GEPs and run no-load GVN")); LLVMTargetMachine::LLVMTargetMachine(const Target &T, - const std::string &TargetTriple) - : TargetMachine(T) { + const std::string &Triple) + : TargetMachine(T), TargetTriple(Triple) { AsmInfo = T.createAsmInfo(TargetTriple); } // Set the default code model for the JIT for a generic target. // FIXME: Is small right here? or .is64Bit() ? Large : Small? -void -LLVMTargetMachine::setCodeModelForJIT() { +void LLVMTargetMachine::setCodeModelForJIT() { setCodeModel(CodeModel::Small); } // Set the default code model for static compilation for a generic target. -void -LLVMTargetMachine::setCodeModelForStatic() { +void LLVMTargetMachine::setCodeModelForStatic() { setCodeModel(CodeModel::Small); } @@ -118,20 +115,21 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM, CodeGenOpt::Level OptLevel, bool DisableVerify) { // Add common CodeGen passes. - if (addCommonCodeGenPasses(PM, OptLevel, DisableVerify)) + MCContext *Context = 0; + if (addCommonCodeGenPasses(PM, OptLevel, DisableVerify, Context)) return true; + assert(Context != 0 && "Failed to get MCContext"); - OwningPtr<MCContext> Context(new MCContext()); + const MCAsmInfo &MAI = *getMCAsmInfo(); OwningPtr<MCStreamer> AsmStreamer; formatted_raw_ostream *LegacyOutput; switch (FileType) { default: return true; case CGFT_AssemblyFile: { - const MCAsmInfo &MAI = *getMCAsmInfo(); MCInstPrinter *InstPrinter = getTarget().createMCInstPrinter(MAI.getAssemblerDialect(), MAI, Out); - AsmStreamer.reset(createAsmStreamer(*Context, Out, MAI, + AsmStreamer.reset(createAsmStreamer(*Context, Out, getTargetData()->isLittleEndian(), getVerboseAsm(), InstPrinter, /*codeemitter*/0)); @@ -143,10 +141,11 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM, // Create the code emitter for the target if it exists. If not, .o file // emission fails. MCCodeEmitter *MCE = getTarget().createCodeEmitter(*this, *Context); - if (MCE == 0) + TargetAsmBackend *TAB = getTarget().createAsmBackend(TargetTriple); + if (MCE == 0 || TAB == 0) return true; - AsmStreamer.reset(createMachOStreamer(*Context, Out, MCE)); + AsmStreamer.reset(createMachOStreamer(*Context, *TAB, Out, MCE)); // Any output to the asmprinter's "O" stream is bad and needs to be fixed, // force it to come out stderr. @@ -167,16 +166,14 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM, break; } - // Create the AsmPrinter, which takes ownership of Context and AsmStreamer - // if successful. + // Create the AsmPrinter, which takes ownership of AsmStreamer if successful. FunctionPass *Printer = - getTarget().createAsmPrinter(*LegacyOutput, *this, *Context, *AsmStreamer, - getMCAsmInfo()); + getTarget().createAsmPrinter(*LegacyOutput, *this, *AsmStreamer); if (Printer == 0) return true; - // If successful, createAsmPrinter took ownership of AsmStreamer and Context. - Context.take(); AsmStreamer.take(); + // If successful, createAsmPrinter took ownership of AsmStreamer. + AsmStreamer.take(); PM.add(Printer); @@ -200,7 +197,8 @@ bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM, setCodeModelForJIT(); // Add common CodeGen passes. - if (addCommonCodeGenPasses(PM, OptLevel, DisableVerify)) + MCContext *Ctx = 0; + if (addCommonCodeGenPasses(PM, OptLevel, DisableVerify, Ctx)) return true; addCodeEmitter(PM, OptLevel, JCE); @@ -209,8 +207,7 @@ bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM, return false; // success! } -static void printNoVerify(PassManagerBase &PM, - const char *Banner) { +static void printNoVerify(PassManagerBase &PM, const char *Banner) { if (PrintMachineCode) PM.add(createMachineFunctionPrinterPass(dbgs(), Banner)); } @@ -230,7 +227,8 @@ static void printAndVerify(PassManagerBase &PM, /// bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, CodeGenOpt::Level OptLevel, - bool DisableVerify) { + bool DisableVerify, + MCContext *&OutContext) { // Standard LLVM-Level Passes. // Before running any passes, run the verifier to determine if the input @@ -253,8 +251,7 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, // Turn exception handling constructs into something the code generators can // handle. - switch (getMCAsmInfo()->getExceptionHandlingType()) - { + switch (getMCAsmInfo()->getExceptionHandlingType()) { case ExceptionHandling::SjLj: // SjLj piggy-backs on dwarf for this bit. The cleanups done apply to both // Dwarf EH prepare needs to be run after SjLj prepare. Otherwise, @@ -294,6 +291,13 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, PM.add(createVerifierPass()); // Standard Lower-Level Passes. + + // Install a MachineModuleInfo class, which is an immutable pass that holds + // all the per-module stuff we're generating, including MCContext. + MachineModuleInfo *MMI = new MachineModuleInfo(*getMCAsmInfo()); + PM.add(MMI); + OutContext = &MMI->getContext(); // Return the MCContext specifically by-ref. + // Set up a MachineFunction for the rest of CodeGen to work on. PM.add(new MachineFunctionAnalysis(*this, OptLevel)); diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp index f8b170745959..dbb5e1919177 100644 --- a/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -218,9 +218,9 @@ bool LiveIntervals::conflictsWithPhysReg(const LiveInterval &li, return false; } -/// conflictsWithPhysRegRef - Similar to conflictsWithPhysRegRef except -/// it can check use as well. -bool LiveIntervals::conflictsWithPhysRegRef(LiveInterval &li, +/// conflictsWithSubPhysRegRef - Similar to conflictsWithPhysRegRef except +/// it checks for sub-register reference and it can check use as well. +bool LiveIntervals::conflictsWithSubPhysRegRef(LiveInterval &li, unsigned Reg, bool CheckUse, SmallPtrSet<MachineInstr*,32> &JoinedCopies) { for (LiveInterval::Ranges::const_iterator diff --git a/lib/CodeGen/MachineBasicBlock.cpp b/lib/CodeGen/MachineBasicBlock.cpp index 32b1a7d728e1..fc8ae5f705d6 100644 --- a/lib/CodeGen/MachineBasicBlock.cpp +++ b/lib/CodeGen/MachineBasicBlock.cpp @@ -41,9 +41,10 @@ MachineBasicBlock::~MachineBasicBlock() { /// getSymbol - Return the MCSymbol for this basic block. /// -MCSymbol *MachineBasicBlock::getSymbol(MCContext &Ctx) const { +MCSymbol *MachineBasicBlock::getSymbol() const { const MachineFunction *MF = getParent(); - const char *Prefix = MF->getTarget().getMCAsmInfo()->getPrivateGlobalPrefix(); + MCContext &Ctx = MF->getContext(); + const char *Prefix = Ctx.getAsmInfo().getPrivateGlobalPrefix(); return Ctx.GetOrCreateTemporarySymbol(Twine(Prefix) + "BB" + Twine(MF->getFunctionNumber()) + "_" + Twine(getNumber())); diff --git a/lib/CodeGen/MachineCSE.cpp b/lib/CodeGen/MachineCSE.cpp index ce95d8d05ea6..91d363588295 100644 --- a/lib/CodeGen/MachineCSE.cpp +++ b/lib/CodeGen/MachineCSE.cpp @@ -122,8 +122,12 @@ bool MachineCSE::isPhysDefTriviallyDead(unsigned Reg, // Reached end of block, register is obviously dead. return true; - if (I->isDebugValue()) + if (I->isDebugValue()) { + // These must not count against the limit. + ++LookAheadLeft; + ++I; continue; + } bool SeenDef = false; for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { const MachineOperand &MO = I->getOperand(i); @@ -188,7 +192,7 @@ static bool isCopy(const MachineInstr *MI, const TargetInstrInfo *TII) { bool MachineCSE::isCSECandidate(MachineInstr *MI) { if (MI->isLabel() || MI->isPHI() || MI->isImplicitDef() || - MI->isKill() || MI->isInlineAsm()) + MI->isKill() || MI->isInlineAsm() || MI->isDebugValue()) return false; // Ignore copies. diff --git a/lib/CodeGen/MachineFunction.cpp b/lib/CodeGen/MachineFunction.cpp index 1e3cb1ee5a55..37f3d22630d4 100644 --- a/lib/CodeGen/MachineFunction.cpp +++ b/lib/CodeGen/MachineFunction.cpp @@ -85,8 +85,8 @@ void ilist_traits<MachineBasicBlock>::deleteNode(MachineBasicBlock *MBB) { } MachineFunction::MachineFunction(Function *F, const TargetMachine &TM, - unsigned FunctionNum) - : Fn(F), Target(TM) { + unsigned FunctionNum, MCContext &ctx) + : Fn(F), Target(TM), Ctx(ctx) { if (TM.getRegisterInfo()) RegInfo = new (Allocator.Allocate<MachineRegisterInfo>()) MachineRegisterInfo(*TM.getRegisterInfo()); @@ -574,6 +574,8 @@ unsigned MachineJumpTableInfo::getEntrySize(const TargetData &TD) const { case MachineJumpTableInfo::EK_LabelDifference32: case MachineJumpTableInfo::EK_Custom32: return 4; + case MachineJumpTableInfo::EK_Inline: + return 0; } assert(0 && "Unknown jump table encoding!"); return ~0; @@ -591,6 +593,8 @@ unsigned MachineJumpTableInfo::getEntryAlignment(const TargetData &TD) const { case MachineJumpTableInfo::EK_LabelDifference32: case MachineJumpTableInfo::EK_Custom32: return TD.getABIIntegerTypeAlignment(32); + case MachineJumpTableInfo::EK_Inline: + return 1; } assert(0 && "Unknown jump table encoding!"); return ~0; diff --git a/lib/CodeGen/MachineFunctionAnalysis.cpp b/lib/CodeGen/MachineFunctionAnalysis.cpp index 8d87e3e4b136..d3f1d8296daa 100644 --- a/lib/CodeGen/MachineFunctionAnalysis.cpp +++ b/lib/CodeGen/MachineFunctionAnalysis.cpp @@ -13,6 +13,7 @@ #include "llvm/CodeGen/MachineFunctionAnalysis.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" using namespace llvm; // Register this pass with PassInfo directly to avoid having to define @@ -36,7 +37,8 @@ MachineFunctionAnalysis::~MachineFunctionAnalysis() { bool MachineFunctionAnalysis::runOnFunction(Function &F) { assert(!MF && "MachineFunctionAnalysis already initialized!"); - MF = new MachineFunction(&F, TM, NextFnNum++); + MF = new MachineFunction(&F, TM, NextFnNum++, + getAnalysis<MachineModuleInfo>().getContext()); return false; } @@ -47,4 +49,5 @@ void MachineFunctionAnalysis::releaseMemory() { void MachineFunctionAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); + AU.addRequired<MachineModuleInfo>(); } diff --git a/lib/CodeGen/MachineInstr.cpp b/lib/CodeGen/MachineInstr.cpp index 4c7cb8f3aae4..40d6b2093be7 100644 --- a/lib/CodeGen/MachineInstr.cpp +++ b/lib/CodeGen/MachineInstr.cpp @@ -15,6 +15,7 @@ #include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/InlineAsm.h" +#include "llvm/Metadata.h" #include "llvm/Type.h" #include "llvm/Value.h" #include "llvm/Assembly/Writer.h" @@ -23,6 +24,7 @@ #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetInstrDesc.h" @@ -35,7 +37,6 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/Metadata.h" using namespace llvm; //===----------------------------------------------------------------------===// @@ -189,6 +190,8 @@ bool MachineOperand::isIdenticalTo(const MachineOperand &Other) const { getOffset() == Other.getOffset(); case MachineOperand::MO_BlockAddress: return getBlockAddress() == Other.getBlockAddress(); + case MachineOperand::MO_MCSymbol: + return getMCSymbol() == Other.getMCSymbol(); } } @@ -291,6 +294,9 @@ void MachineOperand::print(raw_ostream &OS, const TargetMachine *TM) const { WriteAsOperand(OS, getMetadata(), /*PrintType=*/false); OS << '>'; break; + case MachineOperand::MO_MCSymbol: + OS << "<MCSym=" << *getMCSymbol() << '>'; + break; default: llvm_unreachable("Unrecognized operand type"); } @@ -1363,30 +1369,33 @@ MachineInstrExpressionTrait::getHashValue(const MachineInstr* const &MI) { const MachineOperand &MO = MI->getOperand(i); uint64_t Key = (uint64_t)MO.getType() << 32; switch (MO.getType()) { - default: break; - case MachineOperand::MO_Register: - if (MO.isDef() && MO.getReg() && - TargetRegisterInfo::isVirtualRegister(MO.getReg())) - continue; // Skip virtual register defs. - Key |= MO.getReg(); - break; - case MachineOperand::MO_Immediate: - Key |= MO.getImm(); - break; - case MachineOperand::MO_FrameIndex: - case MachineOperand::MO_ConstantPoolIndex: - case MachineOperand::MO_JumpTableIndex: - Key |= MO.getIndex(); - break; - case MachineOperand::MO_MachineBasicBlock: - Key |= DenseMapInfo<void*>::getHashValue(MO.getMBB()); - break; - case MachineOperand::MO_GlobalAddress: - Key |= DenseMapInfo<void*>::getHashValue(MO.getGlobal()); - break; - case MachineOperand::MO_BlockAddress: - Key |= DenseMapInfo<void*>::getHashValue(MO.getBlockAddress()); - break; + default: break; + case MachineOperand::MO_Register: + if (MO.isDef() && MO.getReg() && + TargetRegisterInfo::isVirtualRegister(MO.getReg())) + continue; // Skip virtual register defs. + Key |= MO.getReg(); + break; + case MachineOperand::MO_Immediate: + Key |= MO.getImm(); + break; + case MachineOperand::MO_FrameIndex: + case MachineOperand::MO_ConstantPoolIndex: + case MachineOperand::MO_JumpTableIndex: + Key |= MO.getIndex(); + break; + case MachineOperand::MO_MachineBasicBlock: + Key |= DenseMapInfo<void*>::getHashValue(MO.getMBB()); + break; + case MachineOperand::MO_GlobalAddress: + Key |= DenseMapInfo<void*>::getHashValue(MO.getGlobal()); + break; + case MachineOperand::MO_BlockAddress: + Key |= DenseMapInfo<void*>::getHashValue(MO.getBlockAddress()); + break; + case MachineOperand::MO_MCSymbol: + Key |= DenseMapInfo<void*>::getHashValue(MO.getMCSymbol()); + break; } Key += ~(Key << 32); Key ^= (Key >> 22); diff --git a/lib/CodeGen/MachineModuleInfo.cpp b/lib/CodeGen/MachineModuleInfo.cpp index 72fb9fd987d9..af48e9ebb5b3 100644 --- a/lib/CodeGen/MachineModuleInfo.cpp +++ b/lib/CodeGen/MachineModuleInfo.cpp @@ -10,6 +10,11 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Intrinsics.h" +#include "llvm/Instructions.h" +#include "llvm/Module.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineFunction.h" @@ -17,11 +22,8 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/DerivedTypes.h" -#include "llvm/GlobalVariable.h" -#include "llvm/Intrinsics.h" -#include "llvm/Instructions.h" -#include "llvm/Module.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; @@ -29,38 +31,263 @@ using namespace llvm::dwarf; // Handle the Pass registration stuff necessary to use TargetData's. static RegisterPass<MachineModuleInfo> -X("machinemoduleinfo", "Module Information"); +X("machinemoduleinfo", "Machine Module Information"); char MachineModuleInfo::ID = 0; // Out of line virtual method. MachineModuleInfoImpl::~MachineModuleInfoImpl() {} +namespace llvm { +class MMIAddrLabelMapCallbackPtr : CallbackVH { + MMIAddrLabelMap *Map; +public: + MMIAddrLabelMapCallbackPtr() : Map(0) {} + MMIAddrLabelMapCallbackPtr(Value *V) : CallbackVH(V), Map(0) {} + + void setMap(MMIAddrLabelMap *map) { Map = map; } + + virtual void deleted(); + virtual void allUsesReplacedWith(Value *V2); +}; + +class MMIAddrLabelMap { + MCContext &Context; + struct AddrLabelSymEntry { + /// Symbols - The symbols for the label. This is a pointer union that is + /// either one symbol (the common case) or a list of symbols. + PointerUnion<MCSymbol *, std::vector<MCSymbol*>*> Symbols; + + Function *Fn; // The containing function of the BasicBlock. + unsigned Index; // The index in BBCallbacks for the BasicBlock. + }; + + DenseMap<AssertingVH<BasicBlock>, AddrLabelSymEntry> AddrLabelSymbols; + + /// BBCallbacks - Callbacks for the BasicBlock's that we have entries for. We + /// use this so we get notified if a block is deleted or RAUWd. + std::vector<MMIAddrLabelMapCallbackPtr> BBCallbacks; + + /// DeletedAddrLabelsNeedingEmission - This is a per-function list of symbols + /// whose corresponding BasicBlock got deleted. These symbols need to be + /// emitted at some point in the file, so AsmPrinter emits them after the + /// function body. + DenseMap<AssertingVH<Function>, std::vector<MCSymbol*> > + DeletedAddrLabelsNeedingEmission; +public: + + MMIAddrLabelMap(MCContext &context) : Context(context) {} + ~MMIAddrLabelMap() { + assert(DeletedAddrLabelsNeedingEmission.empty() && + "Some labels for deleted blocks never got emitted"); + + // Deallocate any of the 'list of symbols' case. + for (DenseMap<AssertingVH<BasicBlock>, AddrLabelSymEntry>::iterator + I = AddrLabelSymbols.begin(), E = AddrLabelSymbols.end(); I != E; ++I) + if (I->second.Symbols.is<std::vector<MCSymbol*>*>()) + delete I->second.Symbols.get<std::vector<MCSymbol*>*>(); + } + + MCSymbol *getAddrLabelSymbol(BasicBlock *BB); + std::vector<MCSymbol*> getAddrLabelSymbolToEmit(BasicBlock *BB); + + void takeDeletedSymbolsForFunction(Function *F, + std::vector<MCSymbol*> &Result); + + void UpdateForDeletedBlock(BasicBlock *BB); + void UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New); +}; +} + +MCSymbol *MMIAddrLabelMap::getAddrLabelSymbol(BasicBlock *BB) { + assert(BB->hasAddressTaken() && + "Shouldn't get label for block without address taken"); + AddrLabelSymEntry &Entry = AddrLabelSymbols[BB]; + + // If we already had an entry for this block, just return it. + if (!Entry.Symbols.isNull()) { + assert(BB->getParent() == Entry.Fn && "Parent changed"); + if (Entry.Symbols.is<MCSymbol*>()) + return Entry.Symbols.get<MCSymbol*>(); + return (*Entry.Symbols.get<std::vector<MCSymbol*>*>())[0]; + } + + // Otherwise, this is a new entry, create a new symbol for it and add an + // entry to BBCallbacks so we can be notified if the BB is deleted or RAUWd. + BBCallbacks.push_back(BB); + BBCallbacks.back().setMap(this); + Entry.Index = BBCallbacks.size()-1; + Entry.Fn = BB->getParent(); + MCSymbol *Result = Context.CreateTempSymbol(); + Entry.Symbols = Result; + return Result; +} + +std::vector<MCSymbol*> +MMIAddrLabelMap::getAddrLabelSymbolToEmit(BasicBlock *BB) { + assert(BB->hasAddressTaken() && + "Shouldn't get label for block without address taken"); + AddrLabelSymEntry &Entry = AddrLabelSymbols[BB]; + + std::vector<MCSymbol*> Result; + + // If we already had an entry for this block, just return it. + if (Entry.Symbols.isNull()) + Result.push_back(getAddrLabelSymbol(BB)); + else if (MCSymbol *Sym = Entry.Symbols.dyn_cast<MCSymbol*>()) + Result.push_back(Sym); + else + Result = *Entry.Symbols.get<std::vector<MCSymbol*>*>(); + return Result; +} + + +/// takeDeletedSymbolsForFunction - If we have any deleted symbols for F, return +/// them. +void MMIAddrLabelMap:: +takeDeletedSymbolsForFunction(Function *F, std::vector<MCSymbol*> &Result) { + DenseMap<AssertingVH<Function>, std::vector<MCSymbol*> >::iterator I = + DeletedAddrLabelsNeedingEmission.find(F); + + // If there are no entries for the function, just return. + if (I == DeletedAddrLabelsNeedingEmission.end()) return; + + // Otherwise, take the list. + std::swap(Result, I->second); + DeletedAddrLabelsNeedingEmission.erase(I); +} + + +void MMIAddrLabelMap::UpdateForDeletedBlock(BasicBlock *BB) { + // If the block got deleted, there is no need for the symbol. If the symbol + // was already emitted, we can just forget about it, otherwise we need to + // queue it up for later emission when the function is output. + AddrLabelSymEntry Entry = AddrLabelSymbols[BB]; + AddrLabelSymbols.erase(BB); + assert(!Entry.Symbols.isNull() && "Didn't have a symbol, why a callback?"); + BBCallbacks[Entry.Index] = 0; // Clear the callback. + + assert((BB->getParent() == 0 || BB->getParent() == Entry.Fn) && + "Block/parent mismatch"); + + // Handle both the single and the multiple symbols cases. + if (MCSymbol *Sym = Entry.Symbols.dyn_cast<MCSymbol*>()) { + if (Sym->isDefined()) + return; + + // If the block is not yet defined, we need to emit it at the end of the + // function. Add the symbol to the DeletedAddrLabelsNeedingEmission list + // for the containing Function. Since the block is being deleted, its + // parent may already be removed, we have to get the function from 'Entry'. + DeletedAddrLabelsNeedingEmission[Entry.Fn].push_back(Sym); + } else { + std::vector<MCSymbol*> *Syms = Entry.Symbols.get<std::vector<MCSymbol*>*>(); + + for (unsigned i = 0, e = Syms->size(); i != e; ++i) { + MCSymbol *Sym = (*Syms)[i]; + if (Sym->isDefined()) continue; // Ignore already emitted labels. + + // If the block is not yet defined, we need to emit it at the end of the + // function. Add the symbol to the DeletedAddrLabelsNeedingEmission list + // for the containing Function. Since the block is being deleted, its + // parent may already be removed, we have to get the function from + // 'Entry'. + DeletedAddrLabelsNeedingEmission[Entry.Fn].push_back(Sym); + } + + // The entry is deleted, free the memory associated with the symbol list. + delete Syms; + } +} + +void MMIAddrLabelMap::UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New) { + // Get the entry for the RAUW'd block and remove it from our map. + AddrLabelSymEntry OldEntry = AddrLabelSymbols[Old]; + AddrLabelSymbols.erase(Old); + assert(!OldEntry.Symbols.isNull() && "Didn't have a symbol, why a callback?"); + + AddrLabelSymEntry &NewEntry = AddrLabelSymbols[New]; + + // If New is not address taken, just move our symbol over to it. + if (NewEntry.Symbols.isNull()) { + BBCallbacks[OldEntry.Index] = New; // Update the callback. + NewEntry = OldEntry; // Set New's entry. + return; + } + + BBCallbacks[OldEntry.Index] = 0; // Update the callback. + + // Otherwise, we need to add the old symbol to the new block's set. If it is + // just a single entry, upgrade it to a symbol list. + if (MCSymbol *PrevSym = NewEntry.Symbols.dyn_cast<MCSymbol*>()) { + std::vector<MCSymbol*> *SymList = new std::vector<MCSymbol*>(); + SymList->push_back(PrevSym); + NewEntry.Symbols = SymList; + } + + std::vector<MCSymbol*> *SymList = + NewEntry.Symbols.get<std::vector<MCSymbol*>*>(); + + // If the old entry was a single symbol, add it. + if (MCSymbol *Sym = OldEntry.Symbols.dyn_cast<MCSymbol*>()) { + SymList->push_back(Sym); + return; + } + + // Otherwise, concatenate the list. + std::vector<MCSymbol*> *Syms =OldEntry.Symbols.get<std::vector<MCSymbol*>*>(); + SymList->insert(SymList->end(), Syms->begin(), Syms->end()); + delete Syms; +} + + +void MMIAddrLabelMapCallbackPtr::deleted() { + Map->UpdateForDeletedBlock(cast<BasicBlock>(getValPtr())); +} + +void MMIAddrLabelMapCallbackPtr::allUsesReplacedWith(Value *V2) { + Map->UpdateForRAUWBlock(cast<BasicBlock>(getValPtr()), cast<BasicBlock>(V2)); +} + + //===----------------------------------------------------------------------===// -MachineModuleInfo::MachineModuleInfo() -: ImmutablePass(&ID) -, ObjFileMMI(0) -, CurCallSite(0) -, CallsEHReturn(0) -, CallsUnwindInit(0) -, DbgInfoAvailable(false) { +MachineModuleInfo::MachineModuleInfo(const MCAsmInfo &MAI) +: ImmutablePass(&ID), Context(MAI), + ObjFileMMI(0), + CurCallSite(0), CallsEHReturn(0), CallsUnwindInit(0), DbgInfoAvailable(false){ // Always emit some info, by default "no personality" info. Personalities.push_back(NULL); + AddrLabelSymbols = 0; +} + +MachineModuleInfo::MachineModuleInfo() +: ImmutablePass(&ID), Context(*(MCAsmInfo*)0) { + assert(0 && "This MachineModuleInfo constructor should never be called, MMI " + "should always be explicitly constructed by LLVMTargetMachine"); + abort(); } MachineModuleInfo::~MachineModuleInfo() { delete ObjFileMMI; + + // FIXME: Why isn't doFinalization being called?? + //assert(AddrLabelSymbols == 0 && "doFinalization not called"); + delete AddrLabelSymbols; + AddrLabelSymbols = 0; } /// doInitialization - Initialize the state for a new module. /// bool MachineModuleInfo::doInitialization() { + assert(AddrLabelSymbols == 0 && "Improperly initialized"); return false; } /// doFinalization - Tear down the state after completion of a module. /// bool MachineModuleInfo::doFinalization() { + delete AddrLabelSymbols; + AddrLabelSymbols = 0; return false; } @@ -99,7 +326,45 @@ void MachineModuleInfo::AnalyzeModule(Module &M) { UsedFunctions.insert(F); } -//===-EH-------------------------------------------------------------------===// +//===- Address of Block Management ----------------------------------------===// + + +/// getAddrLabelSymbol - Return the symbol to be used for the specified basic +/// block when its address is taken. This cannot be its normal LBB label +/// because the block may be accessed outside its containing function. +MCSymbol *MachineModuleInfo::getAddrLabelSymbol(const BasicBlock *BB) { + // Lazily create AddrLabelSymbols. + if (AddrLabelSymbols == 0) + AddrLabelSymbols = new MMIAddrLabelMap(Context); + return AddrLabelSymbols->getAddrLabelSymbol(const_cast<BasicBlock*>(BB)); +} + +/// getAddrLabelSymbolToEmit - Return the symbol to be used for the specified +/// basic block when its address is taken. If other blocks were RAUW'd to +/// this one, we may have to emit them as well, return the whole set. +std::vector<MCSymbol*> MachineModuleInfo:: +getAddrLabelSymbolToEmit(const BasicBlock *BB) { + // Lazily create AddrLabelSymbols. + if (AddrLabelSymbols == 0) + AddrLabelSymbols = new MMIAddrLabelMap(Context); + return AddrLabelSymbols->getAddrLabelSymbolToEmit(const_cast<BasicBlock*>(BB)); +} + + +/// takeDeletedSymbolsForFunction - If the specified function has had any +/// references to address-taken blocks generated, but the block got deleted, +/// return the symbol now so we can emit it. This prevents emitting a +/// reference to a symbol that has no definition. +void MachineModuleInfo:: +takeDeletedSymbolsForFunction(const Function *F, + std::vector<MCSymbol*> &Result) { + // If no blocks have had their addresses taken, we're done. + if (AddrLabelSymbols == 0) return; + return AddrLabelSymbols-> + takeDeletedSymbolsForFunction(const_cast<Function*>(F), Result); +} + +//===- EH -----------------------------------------------------------------===// /// getOrCreateLandingPadInfo - Find or create an LandingPadInfo for the /// specified MachineBasicBlock. @@ -119,7 +384,7 @@ LandingPadInfo &MachineModuleInfo::getOrCreateLandingPadInfo /// addInvoke - Provide the begin and end labels of an invoke style call and /// associate it with a try landing pad block. void MachineModuleInfo::addInvoke(MachineBasicBlock *LandingPad, - unsigned BeginLabel, unsigned EndLabel) { + MCSymbol *BeginLabel, MCSymbol *EndLabel) { LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad); LP.BeginLabels.push_back(BeginLabel); LP.EndLabels.push_back(EndLabel); @@ -127,8 +392,8 @@ void MachineModuleInfo::addInvoke(MachineBasicBlock *LandingPad, /// addLandingPad - Provide the label of a try LandingPad block. /// -unsigned MachineModuleInfo::addLandingPad(MachineBasicBlock *LandingPad) { - unsigned LandingPadLabel = NextLabelID(); +MCSymbol *MachineModuleInfo::addLandingPad(MachineBasicBlock *LandingPad) { + MCSymbol *LandingPadLabel = Context.CreateTempSymbol(); LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad); LP.LandingPadLabel = LandingPadLabel; return LandingPadLabel; @@ -185,7 +450,7 @@ void MachineModuleInfo::addCleanup(MachineBasicBlock *LandingPad) { void MachineModuleInfo::TidyLandingPads() { for (unsigned i = 0; i != LandingPads.size(); ) { LandingPadInfo &LandingPad = LandingPads[i]; - if (isLabelDeleted(LandingPad.LandingPadLabel)) + if (LandingPad.LandingPadLabel && !LandingPad.LandingPadLabel->isDefined()) LandingPad.LandingPadLabel = 0; // Special case: we *should* emit LPs with null LP MBB. This indicates @@ -195,16 +460,14 @@ void MachineModuleInfo::TidyLandingPads() { continue; } - for (unsigned j=0; j != LandingPads[i].BeginLabels.size(); ) { - unsigned BeginLabel = LandingPad.BeginLabels[j]; - unsigned EndLabel = LandingPad.EndLabels[j]; - if (isLabelDeleted(BeginLabel) || isLabelDeleted(EndLabel)) { - LandingPad.BeginLabels.erase(LandingPad.BeginLabels.begin() + j); - LandingPad.EndLabels.erase(LandingPad.EndLabels.begin() + j); - continue; - } - - ++j; + for (unsigned j = 0, e = LandingPads[i].BeginLabels.size(); j != e; ++j) { + MCSymbol *BeginLabel = LandingPad.BeginLabels[j]; + MCSymbol *EndLabel = LandingPad.EndLabels[j]; + if (BeginLabel->isDefined() && EndLabel->isDefined()) continue; + + LandingPad.BeginLabels.erase(LandingPad.BeginLabels.begin() + j); + LandingPad.EndLabels.erase(LandingPad.EndLabels.begin() + j); + --j, --e; } // Remove landing pads with no try-ranges. @@ -218,7 +481,6 @@ void MachineModuleInfo::TidyLandingPads() { if (!LandingPad.LandingPadBlock || (LandingPad.TypeIds.size() == 1 && !LandingPad.TypeIds[0])) LandingPad.TypeIds.clear(); - ++i; } } diff --git a/lib/CodeGen/MachineModuleInfoImpls.cpp b/lib/CodeGen/MachineModuleInfoImpls.cpp index 39d2c7504f01..5ab56c09f5f6 100644 --- a/lib/CodeGen/MachineModuleInfoImpls.cpp +++ b/lib/CodeGen/MachineModuleInfoImpls.cpp @@ -25,10 +25,9 @@ void MachineModuleInfoMachO::Anchor() {} void MachineModuleInfoELF::Anchor() {} static int SortSymbolPair(const void *LHS, const void *RHS) { - const MCSymbol *LHSS = - ((const std::pair<MCSymbol*, MCSymbol*>*)LHS)->first; - const MCSymbol *RHSS = - ((const std::pair<MCSymbol*, MCSymbol*>*)RHS)->first; + typedef std::pair<MCSymbol*, MachineModuleInfoImpl::StubValueTy> PairTy; + const MCSymbol *LHSS = ((const PairTy *)LHS)->first; + const MCSymbol *RHSS = ((const PairTy *)RHS)->first; return LHSS->getName().compare(RHSS->getName()); } @@ -36,7 +35,7 @@ static int SortSymbolPair(const void *LHS, const void *RHS) { /// sorted orer. MachineModuleInfoImpl::SymbolListTy MachineModuleInfoImpl::GetSortedStubs(const DenseMap<MCSymbol*, - MCSymbol*> &Map) { + MachineModuleInfoImpl::StubValueTy>&Map) { MachineModuleInfoImpl::SymbolListTy List(Map.begin(), Map.end()); if (!List.empty()) diff --git a/lib/CodeGen/RegAllocLocal.cpp b/lib/CodeGen/RegAllocLocal.cpp index 04303cff5bfa..194fc14848bc 100644 --- a/lib/CodeGen/RegAllocLocal.cpp +++ b/lib/CodeGen/RegAllocLocal.cpp @@ -671,8 +671,10 @@ void RALocal::ComputeLocalLiveness(MachineBasicBlock& MBB) { // Live-out (of the function) registers contain return values of the function, // so we need to make sure they are alive at return time. - if (!MBB.empty() && MBB.back().getDesc().isReturn()) { - MachineInstr* Ret = &MBB.back(); + MachineBasicBlock::iterator Ret = MBB.getFirstTerminator(); + bool BBEndsInReturn = (Ret != MBB.end() && Ret->getDesc().isReturn()); + + if (BBEndsInReturn) for (MachineRegisterInfo::liveout_iterator I = MF->getRegInfo().liveout_begin(), E = MF->getRegInfo().liveout_end(); I != E; ++I) @@ -680,7 +682,6 @@ void RALocal::ComputeLocalLiveness(MachineBasicBlock& MBB) { Ret->addOperand(MachineOperand::CreateReg(*I, false, true)); LastUseDef[*I] = std::make_pair(Ret, Ret->getNumOperands()-1); } - } // Finally, loop over the final use/def of each reg // in the block and determine if it is dead. @@ -696,7 +697,10 @@ void RALocal::ComputeLocalLiveness(MachineBasicBlock& MBB) { bool usedOutsideBlock = isPhysReg ? false : UsedInMultipleBlocks.test(MO.getReg() - TargetRegisterInfo::FirstVirtualRegister); - if (!isPhysReg && !usedOutsideBlock) { + + // If the machine BB ends in a return instruction, then the value isn't used + // outside of the BB. + if (!isPhysReg && (!usedOutsideBlock || BBEndsInReturn)) { // DBG_VALUE complicates this: if the only refs of a register outside // this block are DBG_VALUE, we can't keep the reg live just for that, // as it will cause the reg to be spilled at the end of this block when @@ -704,7 +708,7 @@ void RALocal::ComputeLocalLiveness(MachineBasicBlock& MBB) { // happens. bool UsedByDebugValueOnly = false; for (MachineRegisterInfo::reg_iterator UI = MRI.reg_begin(MO.getReg()), - UE = MRI.reg_end(); UI != UE; ++UI) + UE = MRI.reg_end(); UI != UE; ++UI) { // Two cases: // - used in another block // - used in the same block before it is defined (loop) @@ -714,6 +718,7 @@ void RALocal::ComputeLocalLiveness(MachineBasicBlock& MBB) { UsedByDebugValueOnly = true; continue; } + // A non-DBG_VALUE use means we can leave DBG_VALUE uses alone. UsedInMultipleBlocks.set(MO.getReg() - TargetRegisterInfo::FirstVirtualRegister); @@ -721,6 +726,8 @@ void RALocal::ComputeLocalLiveness(MachineBasicBlock& MBB) { UsedByDebugValueOnly = false; break; } + } + if (UsedByDebugValueOnly) for (MachineRegisterInfo::reg_iterator UI = MRI.reg_begin(MO.getReg()), UE = MRI.reg_end(); UI != UE; ++UI) @@ -730,16 +737,16 @@ void RALocal::ComputeLocalLiveness(MachineBasicBlock& MBB) { UI.getOperand().setReg(0U); } - // Physical registers and those that are not live-out of the block - // are killed/dead at their last use/def within this block. - if (isPhysReg || !usedOutsideBlock) { + // Physical registers and those that are not live-out of the block are + // killed/dead at their last use/def within this block. + if (isPhysReg || !usedOutsideBlock || BBEndsInReturn) if (MO.isUse()) { // Don't mark uses that are tied to defs as kills. if (!MI->isRegTiedToDefOperand(idx)) MO.setIsKill(true); - } else + } else { MO.setIsDead(true); - } + } } } diff --git a/lib/CodeGen/ScheduleDAGInstrs.cpp b/lib/CodeGen/ScheduleDAGInstrs.cpp index badf34e66cc7..e532ade5f683 100644 --- a/lib/CodeGen/ScheduleDAGInstrs.cpp +++ b/lib/CodeGen/ScheduleDAGInstrs.cpp @@ -34,6 +34,7 @@ ScheduleDAGInstrs::ScheduleDAGInstrs(MachineFunction &mf, const MachineDominatorTree &mdt) : ScheduleDAG(mf), MLI(mli), MDT(mdt), LoopRegs(MLI, MDT) { MFI = mf.getFrameInfo(); + DbgValueVec.clear(); } /// Run - perform scheduling. @@ -157,6 +158,10 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { std::map<const Value *, SUnit *> AliasMemDefs, NonAliasMemDefs; std::map<const Value *, std::vector<SUnit *> > AliasMemUses, NonAliasMemUses; + // Keep track of dangling debug references to registers. + std::pair<MachineInstr*, unsigned> + DanglingDebugValue[TargetRegisterInfo::FirstVirtualRegister]; + // Check to see if the scheduler cares about latencies. bool UnitLatencies = ForceUnitLatencies(); @@ -164,10 +169,25 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { const TargetSubtarget &ST = TM.getSubtarget<TargetSubtarget>(); unsigned SpecialAddressLatency = ST.getSpecialAddressLatency(); + // Remove any stale debug info; sometimes BuildSchedGraph is called again + // without emitting the info from the previous call. + DbgValueVec.clear(); + std::memset(DanglingDebugValue, 0, sizeof(DanglingDebugValue)); + // Walk the list of instructions, from bottom moving up. for (MachineBasicBlock::iterator MII = InsertPos, MIE = Begin; MII != MIE; --MII) { MachineInstr *MI = prior(MII); + // DBG_VALUE does not have SUnit's built, so just remember these for later + // reinsertion. + if (MI->isDebugValue()) { + if (MI->getNumOperands()==3 && MI->getOperand(0).isReg() && + MI->getOperand(0).getReg()) + DanglingDebugValue[MI->getOperand(0).getReg()] = + std::make_pair(MI, DbgValueVec.size()); + DbgValueVec.push_back(MI); + continue; + } const TargetInstrDesc &TID = MI->getDesc(); assert(!TID.isTerminator() && !MI->isLabel() && "Cannot schedule terminators or labels!"); @@ -188,6 +208,13 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { if (Reg == 0) continue; assert(TRI->isPhysicalRegister(Reg) && "Virtual register encountered!"); + + if (MO.isDef() && DanglingDebugValue[Reg].first!=0) { + SU->setDbgInstr(DanglingDebugValue[Reg].first); + DbgValueVec[DanglingDebugValue[Reg].second] = 0; + DanglingDebugValue[Reg] = std::make_pair((MachineInstr*)0, 0); + } + std::vector<SUnit *> &UseList = Uses[Reg]; std::vector<SUnit *> &DefList = Defs[Reg]; // Optionally add output and anti dependencies. For anti @@ -555,6 +582,14 @@ EmitSchedule(DenseMap<MachineBasicBlock*, MachineBasicBlock*> *EM) { BB->remove(I); } + // First reinsert any remaining debug_values; these are either constants, + // or refer to live-in registers. The beginning of the block is the right + // place for the latter. The former might reasonably be placed elsewhere + // using some kind of ordering algorithm, but right now it doesn't matter. + for (int i = DbgValueVec.size()-1; i>=0; --i) + if (DbgValueVec[i]) + BB->insert(InsertPos, DbgValueVec[i]); + // Then re-insert them according to the given schedule. for (unsigned i = 0, e = Sequence.size(); i != e; i++) { SUnit *SU = Sequence[i]; @@ -565,12 +600,21 @@ EmitSchedule(DenseMap<MachineBasicBlock*, MachineBasicBlock*> *EM) { } BB->insert(InsertPos, SU->getInstr()); + if (SU->getDbgInstr()) + BB->insert(InsertPos, SU->getDbgInstr()); } // Update the Begin iterator, as the first instruction in the block // may have been scheduled later. - if (!Sequence.empty()) + if (!DbgValueVec.empty()) { + for (int i = DbgValueVec.size()-1; i>=0; --i) + if (DbgValueVec[i]!=0) { + Begin = DbgValueVec[DbgValueVec.size()-1]; + break; + } + } else if (!Sequence.empty()) Begin = Sequence[0]->getInstr(); + DbgValueVec.clear(); return BB; } diff --git a/lib/CodeGen/ScheduleDAGInstrs.h b/lib/CodeGen/ScheduleDAGInstrs.h index 366c3a859d64..c9b44de85ec4 100644 --- a/lib/CodeGen/ScheduleDAGInstrs.h +++ b/lib/CodeGen/ScheduleDAGInstrs.h @@ -106,6 +106,10 @@ namespace llvm { /// initialized and destructed for each block. std::vector<SUnit *> Defs[TargetRegisterInfo::FirstVirtualRegister]; std::vector<SUnit *> Uses[TargetRegisterInfo::FirstVirtualRegister]; + + /// DbgValueVec - Remember DBG_VALUEs that refer to a particular + /// register. + std::vector<MachineInstr *>DbgValueVec; /// PendingLoads - Remember where unknown loads are after the most recent /// unknown store, as we iterate. As with Defs and Uses, this is here diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 3be6b431167a..aa283ad894e4 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -4605,7 +4605,7 @@ SDValue DAGCombiner::visitBRCOND(SDNode *N) { SDNode *Trunc = 0; if (N1.getOpcode() == ISD::TRUNCATE && N1.hasOneUse()) { - // Look pass truncate. + // Look past truncate. Trunc = N1.getNode(); N1 = N1.getOperand(0); } @@ -4700,7 +4700,9 @@ SDValue DAGCombiner::visitBRCOND(SDNode *N) { Equal = true; } - EVT SetCCVT = N1.getValueType(); + SDValue NodeToReplace = Trunc ? SDValue(Trunc, 0) : N1; + + EVT SetCCVT = NodeToReplace.getValueType(); if (LegalTypes) SetCCVT = TLI.getSetCCResultType(SetCCVT); SDValue SetCC = DAG.getSetCC(TheXor->getDebugLoc(), @@ -4709,9 +4711,9 @@ SDValue DAGCombiner::visitBRCOND(SDNode *N) { Equal ? ISD::SETEQ : ISD::SETNE); // Replace the uses of XOR with SETCC WorkListRemover DeadNodes(*this); - DAG.ReplaceAllUsesOfValueWith(N1, SetCC, &DeadNodes); - removeFromWorkList(N1.getNode()); - DAG.DeleteNode(N1.getNode()); + DAG.ReplaceAllUsesOfValueWith(NodeToReplace, SetCC, &DeadNodes); + removeFromWorkList(NodeToReplace.getNode()); + DAG.DeleteNode(NodeToReplace.getNode()); return DAG.getNode(ISD::BRCOND, N->getDebugLoc(), MVT::Other, Chain, SetCC, N2); } @@ -5409,7 +5411,7 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { if (SimplifyDemandedBits(Value, APInt::getLowBitsSet( Value.getValueType().getScalarType().getSizeInBits(), - ST->getMemoryVT().getSizeInBits()))) + ST->getMemoryVT().getScalarType().getSizeInBits()))) return SDValue(N, 0); } diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index 1d76c7c39030..3fc30ff90886 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -53,7 +53,6 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetMachine.h" -#include "SelectionDAGBuilder.h" #include "FunctionLoweringInfo.h" using namespace llvm; diff --git a/lib/CodeGen/SelectionDAG/InstrEmitter.cpp b/lib/CodeGen/SelectionDAG/InstrEmitter.cpp index 625de1143296..fda094d393bf 100644 --- a/lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ b/lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -15,7 +15,7 @@ #define DEBUG_TYPE "instr-emitter" #include "InstrEmitter.h" -#include "SDDbgValue.h" +#include "SDNodeDbgValue.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -508,6 +508,7 @@ InstrEmitter::EmitDbgValue(SDNode *Node, return; if (!sd) return; + assert(sd->getKind() == SDDbgValue::SDNODE); unsigned VReg = getVR(SDValue(sd->getSDNode(), sd->getResNo()), VRBaseMap); const TargetInstrDesc &II = TII->get(TargetOpcode::DBG_VALUE); DebugLoc DL = sd->getDebugLoc(); @@ -524,26 +525,46 @@ InstrEmitter::EmitDbgValue(SDNode *Node, MBB->insert(InsertPos, MI); } -/// EmitDbgValue - Generate constant debug info. No SDNode is involved. +/// EmitDbgValue - Generate debug info that does not refer to a SDNode. void -InstrEmitter::EmitDbgValue(SDDbgValue *sd) { +InstrEmitter::EmitDbgValue(SDDbgValue *sd, + DenseMap<MachineBasicBlock*, MachineBasicBlock*> *EM) { if (!sd) return; const TargetInstrDesc &II = TII->get(TargetOpcode::DBG_VALUE); + uint64_t Offset = sd->getOffset(); + MDNode* mdPtr = sd->getMDPtr(); + SDDbgValue::DbgValueKind kind = sd->getKind(); DebugLoc DL = sd->getDebugLoc(); - MachineInstr *MI; - Value *V = sd->getConst(); - if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) { - MI = BuildMI(*MF, DL, II).addImm(CI->getZExtValue()). - addImm(sd->getOffset()). - addMetadata(sd->getMDPtr()); - } else if (ConstantFP *CF = dyn_cast<ConstantFP>(V)) { - MI = BuildMI(*MF, DL, II).addFPImm(CF).addImm(sd->getOffset()). - addMetadata(sd->getMDPtr()); + MachineInstr* MI; + if (kind == SDDbgValue::CONST) { + Value *V = sd->getConst(); + if (ConstantInt *CI = dyn_cast<ConstantInt>(V)) { + MI = BuildMI(*MF, DL, II).addImm(CI->getZExtValue()). + addImm(Offset).addMetadata(mdPtr); + } else if (ConstantFP *CF = dyn_cast<ConstantFP>(V)) { + MI = BuildMI(*MF, DL, II).addFPImm(CF). + addImm(Offset).addMetadata(mdPtr); + } else { + // Could be an Undef. In any case insert an Undef so we can see what we + // dropped. + MI = BuildMI(*MF, DL, II).addReg(0U). + addImm(Offset).addMetadata(mdPtr); + } + } else if (kind == SDDbgValue::FRAMEIX) { + unsigned FrameIx = sd->getFrameIx(); + // Stack address; this needs to be lowered in target-dependent fashion. + // FIXME test that the target supports this somehow; if not emit Undef. + // Create a pseudo for EmitInstrWithCustomInserter's consumption. + MI = BuildMI(*MF, DL, II).addImm(FrameIx). + addImm(Offset).addMetadata(mdPtr); + MBB = TLI->EmitInstrWithCustomInserter(MI, MBB, EM); + InsertPos = MBB->end(); + return; } else { // Insert an Undef so we can see what we dropped. - MI = BuildMI(*MF, DL, II).addReg(0U).addImm(sd->getOffset()). - addMetadata(sd->getMDPtr()); + MI = BuildMI(*MF, DL, II).addReg(0U). + addImm(Offset).addMetadata(mdPtr); } MBB->insert(InsertPos, MI); } @@ -684,6 +705,13 @@ void InstrEmitter::EmitNode(SDNode *Node, bool IsClone, bool IsCloned, EmitCopyFromReg(Node, 0, IsClone, IsCloned, SrcReg, VRBaseMap); break; } + case ISD::EH_LABEL: { + MCSymbol *S = cast<EHLabelSDNode>(Node)->getLabel(); + BuildMI(*MBB, InsertPos, Node->getDebugLoc(), + TII->get(TargetOpcode::EH_LABEL)).addSym(S); + break; + } + case ISD::INLINEASM: { unsigned NumOps = Node->getNumOperands(); if (Node->getOperand(NumOps-1).getValueType() == MVT::Flag) diff --git a/lib/CodeGen/SelectionDAG/InstrEmitter.h b/lib/CodeGen/SelectionDAG/InstrEmitter.h index 4fe9f19cc908..eefcd73e6e94 100644 --- a/lib/CodeGen/SelectionDAG/InstrEmitter.h +++ b/lib/CodeGen/SelectionDAG/InstrEmitter.h @@ -106,7 +106,8 @@ public: /// EmitDbgValue - Generate a constant DBG_VALUE. No node is involved. - void EmitDbgValue(SDDbgValue* sd); + void EmitDbgValue(SDDbgValue* sd, + DenseMap<MachineBasicBlock*, MachineBasicBlock*> *EM); /// EmitNode - Generate machine code for a node and needed dependencies. /// diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index f498263b735f..b5af2c134d3b 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -851,6 +851,8 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { case ISD::MERGE_VALUES: case ISD::EH_RETURN: case ISD::FRAME_TO_ARGS_OFFSET: + case ISD::FP16_TO_FP32: + case ISD::FP32_TO_FP16: // These operations lie about being legal: when they claim to be legal, // they should actually be expanded. Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); @@ -1585,35 +1587,51 @@ SDValue SelectionDAGLegalize::ExpandFCOPYSIGN(SDNode* Node) { DebugLoc dl = Node->getDebugLoc(); SDValue Tmp1 = Node->getOperand(0); SDValue Tmp2 = Node->getOperand(1); - assert((Tmp2.getValueType() == MVT::f32 || - Tmp2.getValueType() == MVT::f64) && - "Ugly special-cased code!"); - // Get the sign bit of the RHS. + + // Get the sign bit of the RHS. First obtain a value that has the same + // sign as the sign bit, i.e. negative if and only if the sign bit is 1. SDValue SignBit; - EVT IVT = Tmp2.getValueType() == MVT::f64 ? MVT::i64 : MVT::i32; + EVT FloatVT = Tmp2.getValueType(); + EVT IVT = EVT::getIntegerVT(*DAG.getContext(), FloatVT.getSizeInBits()); if (isTypeLegal(IVT)) { + // Convert to an integer with the same sign bit. SignBit = DAG.getNode(ISD::BIT_CONVERT, dl, IVT, Tmp2); } else { - assert(isTypeLegal(TLI.getPointerTy()) && - (TLI.getPointerTy() == MVT::i32 || - TLI.getPointerTy() == MVT::i64) && - "Legal type for load?!"); - SDValue StackPtr = DAG.CreateStackTemporary(Tmp2.getValueType()); - SDValue StorePtr = StackPtr, LoadPtr = StackPtr; + // Store the float to memory, then load the sign part out as an integer. + MVT LoadTy = TLI.getPointerTy(); + // First create a temporary that is aligned for both the load and store. + SDValue StackPtr = DAG.CreateStackTemporary(FloatVT, LoadTy); + // Then store the float to it. SDValue Ch = - DAG.getStore(DAG.getEntryNode(), dl, Tmp2, StorePtr, NULL, 0, + DAG.getStore(DAG.getEntryNode(), dl, Tmp2, StackPtr, NULL, 0, false, false, 0); - if (Tmp2.getValueType() == MVT::f64 && TLI.isLittleEndian()) - LoadPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), - LoadPtr, DAG.getIntPtrConstant(4)); - SignBit = DAG.getExtLoad(ISD::SEXTLOAD, dl, TLI.getPointerTy(), - Ch, LoadPtr, NULL, 0, MVT::i32, - false, false, 0); - } - SignBit = - DAG.getSetCC(dl, TLI.getSetCCResultType(SignBit.getValueType()), - SignBit, DAG.getConstant(0, SignBit.getValueType()), - ISD::SETLT); + if (TLI.isBigEndian()) { + assert(FloatVT.isByteSized() && "Unsupported floating point type!"); + // Load out a legal integer with the same sign bit as the float. + SignBit = DAG.getLoad(LoadTy, dl, Ch, StackPtr, NULL, 0, false, false, 0); + } else { // Little endian + SDValue LoadPtr = StackPtr; + // The float may be wider than the integer we are going to load. Advance + // the pointer so that the loaded integer will contain the sign bit. + unsigned Strides = (FloatVT.getSizeInBits()-1)/LoadTy.getSizeInBits(); + unsigned ByteOffset = (Strides * LoadTy.getSizeInBits()) / 8; + LoadPtr = DAG.getNode(ISD::ADD, dl, LoadPtr.getValueType(), + LoadPtr, DAG.getIntPtrConstant(ByteOffset)); + // Load a legal integer containing the sign bit. + SignBit = DAG.getLoad(LoadTy, dl, Ch, LoadPtr, NULL, 0, false, false, 0); + // Move the sign bit to the top bit of the loaded integer. + unsigned BitShift = LoadTy.getSizeInBits() - + (FloatVT.getSizeInBits() - 8 * ByteOffset); + assert(BitShift < LoadTy.getSizeInBits() && "Pointer advanced wrong?"); + if (BitShift) + SignBit = DAG.getNode(ISD::SHL, dl, LoadTy, SignBit, + DAG.getConstant(BitShift,TLI.getShiftAmountTy())); + } + } + // Now get the sign bit proper, by seeing whether the value is negative. + SignBit = DAG.getSetCC(dl, TLI.getSetCCResultType(SignBit.getValueType()), + SignBit, DAG.getConstant(0, SignBit.getValueType()), + ISD::SETLT); // Get the absolute value of the result. SDValue AbsVal = DAG.getNode(ISD::FABS, dl, Tmp1.getValueType(), Tmp1); // Select between the nabs and abs value based on the sign bit of @@ -2620,6 +2638,12 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, Results.push_back(ExpandFPLibCall(Node, RTLIB::REM_F32, RTLIB::REM_F64, RTLIB::REM_F80, RTLIB::REM_PPCF128)); break; + case ISD::FP16_TO_FP32: + Results.push_back(ExpandLibCall(RTLIB::FPEXT_F16_F32, Node, false)); + break; + case ISD::FP32_TO_FP16: + Results.push_back(ExpandLibCall(RTLIB::FPROUND_F32_F16, Node, false)); + break; case ISD::ConstantFP: { ConstantFPSDNode *CFP = cast<ConstantFPSDNode>(Node); // Check to see if this FP immediate is already legal. diff --git a/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp index 35a7c7cedd24..665b21f5a6bc 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -79,6 +79,7 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) { case ISD::FNEG: R = SoftenFloatRes_FNEG(N); break; case ISD::FP_EXTEND: R = SoftenFloatRes_FP_EXTEND(N); break; case ISD::FP_ROUND: R = SoftenFloatRes_FP_ROUND(N); break; + case ISD::FP16_TO_FP32:R = SoftenFloatRes_FP16_TO_FP32(N); break; case ISD::FPOW: R = SoftenFloatRes_FPOW(N); break; case ISD::FPOWI: R = SoftenFloatRes_FPOWI(N); break; case ISD::FREM: R = SoftenFloatRes_FREM(N); break; @@ -332,6 +333,14 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FP_EXTEND(SDNode *N) { return MakeLibCall(LC, NVT, &Op, 1, false, N->getDebugLoc()); } +// FIXME: Should we just use 'normal' FP_EXTEND / FP_TRUNC instead of special +// nodes? +SDValue DAGTypeLegalizer::SoftenFloatRes_FP16_TO_FP32(SDNode *N) { + EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); + SDValue Op = N->getOperand(0); + return MakeLibCall(RTLIB::FPEXT_F16_F32, NVT, &Op, 1, false, N->getDebugLoc()); +} + SDValue DAGTypeLegalizer::SoftenFloatRes_FP_ROUND(SDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Op = N->getOperand(0); @@ -548,6 +557,7 @@ bool DAGTypeLegalizer::SoftenFloatOperand(SDNode *N, unsigned OpNo) { case ISD::FP_ROUND: Res = SoftenFloatOp_FP_ROUND(N); break; case ISD::FP_TO_SINT: Res = SoftenFloatOp_FP_TO_SINT(N); break; case ISD::FP_TO_UINT: Res = SoftenFloatOp_FP_TO_UINT(N); break; + case ISD::FP32_TO_FP16:Res = SoftenFloatOp_FP32_TO_FP16(N); break; case ISD::SELECT_CC: Res = SoftenFloatOp_SELECT_CC(N); break; case ISD::SETCC: Res = SoftenFloatOp_SETCC(N); break; case ISD::STORE: Res = SoftenFloatOp_STORE(N, OpNo); break; @@ -704,6 +714,13 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_FP_TO_UINT(SDNode *N) { return MakeLibCall(LC, RVT, &Op, 1, false, N->getDebugLoc()); } +SDValue DAGTypeLegalizer::SoftenFloatOp_FP32_TO_FP16(SDNode *N) { + EVT RVT = N->getValueType(0); + RTLIB::Libcall LC = RTLIB::FPROUND_F32_F16; + SDValue Op = GetSoftenedFloat(N->getOperand(0)); + return MakeLibCall(LC, RVT, &Op, 1, false, N->getDebugLoc()); +} + SDValue DAGTypeLegalizer::SoftenFloatOp_SELECT_CC(SDNode *N) { SDValue NewLHS = N->getOperand(0), NewRHS = N->getOperand(1); ISD::CondCode CCCode = cast<CondCodeSDNode>(N->getOperand(4))->get(); @@ -800,6 +817,7 @@ void DAGTypeLegalizer::ExpandFloatResult(SDNode *N, unsigned ResNo) { case ISD::FABS: ExpandFloatRes_FABS(N, Lo, Hi); break; case ISD::FADD: ExpandFloatRes_FADD(N, Lo, Hi); break; case ISD::FCEIL: ExpandFloatRes_FCEIL(N, Lo, Hi); break; + case ISD::FCOPYSIGN: ExpandFloatRes_FCOPYSIGN(N, Lo, Hi); break; case ISD::FCOS: ExpandFloatRes_FCOS(N, Lo, Hi); break; case ISD::FDIV: ExpandFloatRes_FDIV(N, Lo, Hi); break; case ISD::FEXP: ExpandFloatRes_FEXP(N, Lo, Hi); break; @@ -873,6 +891,17 @@ void DAGTypeLegalizer::ExpandFloatRes_FCEIL(SDNode *N, GetPairElements(Call, Lo, Hi); } +void DAGTypeLegalizer::ExpandFloatRes_FCOPYSIGN(SDNode *N, + SDValue &Lo, SDValue &Hi) { + SDValue Call = LibCallify(GetFPLibCall(N->getValueType(0), + RTLIB::COPYSIGN_F32, + RTLIB::COPYSIGN_F64, + RTLIB::COPYSIGN_F80, + RTLIB::COPYSIGN_PPCF128), + N, false); + GetPairElements(Call, Lo, Hi); +} + void DAGTypeLegalizer::ExpandFloatRes_FCOS(SDNode *N, SDValue &Lo, SDValue &Hi) { SDValue Call = LibCallify(GetFPLibCall(N->getValueType(0), diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index 81f28adc0d83..48f64c34d6d2 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -80,6 +80,8 @@ void DAGTypeLegalizer::PromoteIntegerResult(SDNode *N, unsigned ResNo) { case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: Res = PromoteIntRes_FP_TO_XINT(N); break; + case ISD::FP32_TO_FP16:Res = PromoteIntRes_FP32_TO_FP16(N); break; + case ISD::AND: case ISD::OR: case ISD::XOR: @@ -324,6 +326,16 @@ SDValue DAGTypeLegalizer::PromoteIntRes_FP_TO_XINT(SDNode *N) { NVT, Res, DAG.getValueType(N->getValueType(0))); } +SDValue DAGTypeLegalizer::PromoteIntRes_FP32_TO_FP16(SDNode *N) { + EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); + DebugLoc dl = N->getDebugLoc(); + + SDValue Res = DAG.getNode(N->getOpcode(), dl, NVT, N->getOperand(0)); + + return DAG.getNode(ISD::AssertZext, dl, + NVT, Res, DAG.getValueType(N->getValueType(0))); +} + SDValue DAGTypeLegalizer::PromoteIntRes_INT_EXTEND(SDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); DebugLoc dl = N->getDebugLoc(); @@ -634,6 +646,7 @@ bool DAGTypeLegalizer::PromoteIntegerOperand(SDNode *N, unsigned OpNo) { case ISD::STORE: Res = PromoteIntOp_STORE(cast<StoreSDNode>(N), OpNo); break; case ISD::TRUNCATE: Res = PromoteIntOp_TRUNCATE(N); break; + case ISD::FP16_TO_FP32: case ISD::UINT_TO_FP: Res = PromoteIntOp_UINT_TO_FP(N); break; case ISD::ZERO_EXTEND: Res = PromoteIntOp_ZERO_EXTEND(N); break; diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index b0af357b17bf..9dd9796d0122 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -257,6 +257,7 @@ private: SDValue PromoteIntRes_CTTZ(SDNode *N); SDValue PromoteIntRes_EXTRACT_VECTOR_ELT(SDNode *N); SDValue PromoteIntRes_FP_TO_XINT(SDNode *N); + SDValue PromoteIntRes_FP32_TO_FP16(SDNode *N); SDValue PromoteIntRes_INT_EXTEND(SDNode *N); SDValue PromoteIntRes_LOAD(LoadSDNode *N); SDValue PromoteIntRes_Overflow(SDNode *N); @@ -406,6 +407,7 @@ private: SDValue SoftenFloatRes_FNEARBYINT(SDNode *N); SDValue SoftenFloatRes_FNEG(SDNode *N); SDValue SoftenFloatRes_FP_EXTEND(SDNode *N); + SDValue SoftenFloatRes_FP16_TO_FP32(SDNode *N); SDValue SoftenFloatRes_FP_ROUND(SDNode *N); SDValue SoftenFloatRes_FPOW(SDNode *N); SDValue SoftenFloatRes_FPOWI(SDNode *N); @@ -429,6 +431,7 @@ private: SDValue SoftenFloatOp_FP_ROUND(SDNode *N); SDValue SoftenFloatOp_FP_TO_SINT(SDNode *N); SDValue SoftenFloatOp_FP_TO_UINT(SDNode *N); + SDValue SoftenFloatOp_FP32_TO_FP16(SDNode *N); SDValue SoftenFloatOp_SELECT_CC(SDNode *N); SDValue SoftenFloatOp_SETCC(SDNode *N); SDValue SoftenFloatOp_STORE(SDNode *N, unsigned OpNo); @@ -455,6 +458,7 @@ private: void ExpandFloatRes_FABS (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_FADD (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_FCEIL (SDNode *N, SDValue &Lo, SDValue &Hi); + void ExpandFloatRes_FCOPYSIGN (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_FCOS (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_FDIV (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_FEXP (SDNode *N, SDValue &Lo, SDValue &Hi); diff --git a/lib/CodeGen/SelectionDAG/SDDbgValue.h b/lib/CodeGen/SelectionDAG/SDDbgValue.h deleted file mode 100644 index d43a0447a6cf..000000000000 --- a/lib/CodeGen/SelectionDAG/SDDbgValue.h +++ /dev/null @@ -1,73 +0,0 @@ -//===-- llvm/CodeGen/SDDbgValue.h - SD dbg_value handling--------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the SDDbgValue class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_SDDBGVALUE_H -#define LLVM_CODEGEN_SDDBGVALUE_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/DebugLoc.h" - -namespace llvm { - -class MDNode; -class SDNode; -class Value; - -/// SDDbgValue - Holds the information from a dbg_value node through SDISel. -/// Either Const or Node is nonzero, but not both. -/// We do not use SDValue here to avoid including its header. - -class SDDbgValue { - SDNode *Node; // valid for non-constants - unsigned ResNo; // valid for non-constants - Value *Const; // valid for constants - MDNode *mdPtr; - uint64_t Offset; - DebugLoc DL; - unsigned Order; -public: - // Constructor for non-constants. - SDDbgValue(MDNode *mdP, SDNode *N, unsigned R, uint64_t off, DebugLoc dl, - unsigned O) : - Node(N), ResNo(R), Const(0), mdPtr(mdP), Offset(off), DL(dl), Order(O) {} - - // Constructor for constants. - SDDbgValue(MDNode *mdP, Value *C, uint64_t off, DebugLoc dl, unsigned O) : - Node(0), ResNo(0), Const(C), mdPtr(mdP), Offset(off), DL(dl), Order(O) {} - - // Returns the MDNode pointer. - MDNode *getMDPtr() { return mdPtr; } - - // Returns the SDNode* (valid for non-constants only). - SDNode *getSDNode() { assert (!Const); return Node; } - - // Returns the ResNo (valid for non-constants only). - unsigned getResNo() { assert (!Const); return ResNo; } - - // Returns the Value* for a constant (invalid for non-constants). - Value *getConst() { assert (!Node); return Const; } - - // Returns the offset. - uint64_t getOffset() { return Offset; } - - // Returns the DebugLoc. - DebugLoc getDebugLoc() { return DL; } - - // Returns the SDNodeOrder. This is the order of the preceding node in the - // input. - unsigned getOrder() { return Order; } -}; - -} // end llvm namespace - -#endif diff --git a/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h b/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h new file mode 100644 index 000000000000..dbbd753c5bb4 --- /dev/null +++ b/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h @@ -0,0 +1,104 @@ +//===-- llvm/CodeGen/SDNodeDbgValue.h - SelectionDAG dbg_value --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the SDDbgValue class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_SDNODEDBGVALUE_H +#define LLVM_CODEGEN_SDNODEDBGVALUE_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DebugLoc.h" + +namespace llvm { + +class MDNode; +class SDNode; +class Value; + +/// SDDbgValue - Holds the information from a dbg_value node through SDISel. +/// We do not use SDValue here to avoid including its header. + +class SDDbgValue { +public: + enum DbgValueKind { + SDNODE = 0, // value is the result of an expression + CONST = 1, // value is a constant + FRAMEIX = 2 // value is contents of a stack location + }; +private: + enum DbgValueKind kind; + union { + struct { + SDNode *Node; // valid for expressions + unsigned ResNo; // valid for expressions + } s; + Value *Const; // valid for constants + unsigned FrameIx; // valid for stack objects + } u; + MDNode *mdPtr; + uint64_t Offset; + DebugLoc DL; + unsigned Order; +public: + // Constructor for non-constants. + SDDbgValue(MDNode *mdP, SDNode *N, unsigned R, uint64_t off, DebugLoc dl, + unsigned O) : mdPtr(mdP), Offset(off), DL(dl), Order(O) { + kind = SDNODE; + u.s.Node = N; + u.s.ResNo = R; + } + + // Constructor for constants. + SDDbgValue(MDNode *mdP, Value *C, uint64_t off, DebugLoc dl, unsigned O) : + mdPtr(mdP), Offset(off), DL(dl), Order(O) { + kind = CONST; + u.Const = C; + } + + // Constructor for frame indices. + SDDbgValue(MDNode *mdP, unsigned FI, uint64_t off, DebugLoc dl, unsigned O) : + mdPtr(mdP), Offset(off), DL(dl), Order(O) { + kind = FRAMEIX; + u.FrameIx = FI; + } + + // Returns the kind. + DbgValueKind getKind() { return kind; } + + // Returns the MDNode pointer. + MDNode *getMDPtr() { return mdPtr; } + + // Returns the SDNode* for a register ref + SDNode *getSDNode() { assert (kind==SDNODE); return u.s.Node; } + + // Returns the ResNo for a register ref + unsigned getResNo() { assert (kind==SDNODE); return u.s.ResNo; } + + // Returns the Value* for a constant + Value *getConst() { assert (kind==CONST); return u.Const; } + + // Returns the FrameIx for a stack object + unsigned getFrameIx() { assert (kind==FRAMEIX); return u.FrameIx; } + + // Returns the offset. + uint64_t getOffset() { return Offset; } + + // Returns the DebugLoc. + DebugLoc getDebugLoc() { return DL; } + + // Returns the SDNodeOrder. This is the order of the preceding node in the + // input. + unsigned getOrder() { return Order; } +}; + +} // end llvm namespace + +#endif diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp index 06e7b8c905a7..c13565a35a45 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "pre-RA-sched" +#include "SDNodeDbgValue.h" #include "ScheduleDAGSDNodes.h" #include "InstrEmitter.h" #include "llvm/CodeGen/SelectionDAG.h" @@ -412,6 +413,14 @@ EmitSchedule(DenseMap<MachineBasicBlock*, MachineBasicBlock*> *EM) { InstrEmitter Emitter(BB, InsertPos); DenseMap<SDValue, unsigned> VRBaseMap; DenseMap<SUnit*, unsigned> CopyVRBaseMap; + + // For now, any constant debug info nodes go at the beginning. + for (SDDbgInfo::ConstDbgIterator I = DAG->DbgConstBegin(), + E = DAG->DbgConstEnd(); I!=E; I++) { + Emitter.EmitDbgValue(*I, EM); + delete *I; + } + for (unsigned i = 0, e = Sequence.size(); i != e; i++) { SUnit *SU = Sequence[i]; if (!SU) { @@ -435,10 +444,20 @@ EmitSchedule(DenseMap<MachineBasicBlock*, MachineBasicBlock*> *EM) { while (!FlaggedNodes.empty()) { Emitter.EmitNode(FlaggedNodes.back(), SU->OrigNode != SU, SU->isCloned, VRBaseMap, EM); + if (FlaggedNodes.back()->getHasDebugValue()) + if (SDDbgValue *sd = DAG->GetDbgInfo(FlaggedNodes.back())) { + Emitter.EmitDbgValue(FlaggedNodes.back(), VRBaseMap, sd); + delete sd; + } FlaggedNodes.pop_back(); } Emitter.EmitNode(SU->getNode(), SU->OrigNode != SU, SU->isCloned, VRBaseMap, EM); + if (SU->getNode()->getHasDebugValue()) + if (SDDbgValue *sd = DAG->GetDbgInfo(SU->getNode())) { + Emitter.EmitDbgValue(SU->getNode(), VRBaseMap, sd); + delete sd; + } } BB = Emitter.getBlock(); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 746d4e2e1a54..480c0680880d 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -13,6 +13,7 @@ #include "llvm/CodeGen/SelectionDAG.h" #include "SDNodeOrdering.h" +#include "SDNodeDbgValue.h" #include "llvm/Constants.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Function.h" @@ -596,6 +597,9 @@ void SelectionDAG::DeallocateNode(SDNode *N) { // Remove the ordering of this node. Ordering->remove(N); + + // And its entry in the debug info table, if any. + DbgInfo->remove(N); } /// RemoveNodeFromCSEMaps - Take the specified node out of the CSE map that @@ -793,6 +797,7 @@ SelectionDAG::SelectionDAG(TargetLowering &tli, FunctionLoweringInfo &fli) Root(getEntryNode()), Ordering(0) { AllNodes.push_back(&EntryNode); Ordering = new SDNodeOrdering(); + DbgInfo = new SDDbgInfo(); } void SelectionDAG::init(MachineFunction &mf, MachineModuleInfo *mmi, @@ -806,6 +811,7 @@ void SelectionDAG::init(MachineFunction &mf, MachineModuleInfo *mmi, SelectionDAG::~SelectionDAG() { allnodes_clear(); delete Ordering; + delete DbgInfo; } void SelectionDAG::allnodes_clear() { @@ -833,6 +839,8 @@ void SelectionDAG::clear() { Root = getEntryNode(); delete Ordering; Ordering = new SDNodeOrdering(); + delete DbgInfo; + DbgInfo = new SDDbgInfo(); } SDValue SelectionDAG::getSExtOrTrunc(SDValue Op, DebugLoc DL, EVT VT) { @@ -1306,24 +1314,23 @@ SDValue SelectionDAG::getRegister(unsigned RegNo, EVT VT) { return SDValue(N, 0); } -SDValue SelectionDAG::getLabel(unsigned Opcode, DebugLoc dl, - SDValue Root, - unsigned LabelID) { +SDValue SelectionDAG::getEHLabel(DebugLoc dl, SDValue Root, MCSymbol *Label) { FoldingSetNodeID ID; SDValue Ops[] = { Root }; - AddNodeIDNode(ID, Opcode, getVTList(MVT::Other), &Ops[0], 1); - ID.AddInteger(LabelID); + AddNodeIDNode(ID, ISD::EH_LABEL, getVTList(MVT::Other), &Ops[0], 1); + ID.AddPointer(Label); void *IP = 0; if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP)) return SDValue(E, 0); - - SDNode *N = NodeAllocator.Allocate<LabelSDNode>(); - new (N) LabelSDNode(Opcode, dl, Root, LabelID); + + SDNode *N = NodeAllocator.Allocate<EHLabelSDNode>(); + new (N) EHLabelSDNode(dl, Root, Label); CSEMap.InsertNode(N, IP); AllNodes.push_back(N); return SDValue(N, 0); } + SDValue SelectionDAG::getBlockAddress(BlockAddress *BA, EVT VT, bool isTarget, unsigned char TargetFlags) { @@ -2322,22 +2329,20 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, // Constant fold unary operations with an integer constant operand. if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Operand.getNode())) { const APInt &Val = C->getAPIntValue(); - unsigned BitWidth = VT.getSizeInBits(); switch (Opcode) { default: break; case ISD::SIGN_EXTEND: - return getConstant(APInt(Val).sextOrTrunc(BitWidth), VT); + return getConstant(APInt(Val).sextOrTrunc(VT.getSizeInBits()), VT); case ISD::ANY_EXTEND: case ISD::ZERO_EXTEND: case ISD::TRUNCATE: - return getConstant(APInt(Val).zextOrTrunc(BitWidth), VT); + return getConstant(APInt(Val).zextOrTrunc(VT.getSizeInBits()), VT); case ISD::UINT_TO_FP: case ISD::SINT_TO_FP: { const uint64_t zero[] = {0, 0}; - // No compile time operations on this type. - if (VT==MVT::ppcf128) - break; - APFloat apf = APFloat(APInt(BitWidth, 2, zero)); + // No compile time operations on ppcf128. + if (VT == MVT::ppcf128) break; + APFloat apf = APFloat(APInt(VT.getSizeInBits(), 2, zero)); (void)apf.convertFromAPInt(Val, Opcode==ISD::SINT_TO_FP, APFloat::rmNearestTiesToEven); @@ -5264,6 +5269,25 @@ unsigned SelectionDAG::GetOrdering(const SDNode *SD) const { return Ordering->getOrder(SD); } +/// AssignDbgInfo - Assign debug info to the SDNode. +void SelectionDAG::AssignDbgInfo(SDNode* SD, SDDbgValue* db) { + assert(SD && "Trying to assign dbg info to a null node!"); + DbgInfo->add(SD, db); + SD->setHasDebugValue(true); +} + +/// RememberDbgInfo - Remember debug info which is not assigned to an SDNode. +void SelectionDAG::RememberDbgInfo(SDDbgValue* db) { + DbgInfo->add(db); +} + +/// GetDbgInfo - Get the debug info, if any, for the SDNode. +SDDbgValue* SelectionDAG::GetDbgInfo(const SDNode *SD) { + assert(SD && "Trying to get the order of a null node!"); + if (SD->getHasDebugValue()) + return DbgInfo->getSDDbgValue(SD); + return 0; +} //===----------------------------------------------------------------------===// // SDNode Class @@ -5639,6 +5663,8 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::FP_TO_SINT: return "fp_to_sint"; case ISD::FP_TO_UINT: return "fp_to_uint"; case ISD::BIT_CONVERT: return "bit_convert"; + case ISD::FP16_TO_FP32: return "fp16_to_fp32"; + case ISD::FP32_TO_FP16: return "fp32_to_fp16"; case ISD::CONVERT_RNDSAT: { switch (cast<CvtRndSatSDNode>(this)->getCvtCode()) { @@ -5911,7 +5937,7 @@ void SDNode::print_details(raw_ostream &OS, const SelectionDAG *G) const { if (G) if (unsigned Order = G->GetOrdering(this)) OS << " [ORD=" << Order << ']'; - + if (getNodeId() != -1) OS << " [ID=" << getNodeId() << ']'; } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 308742b76a51..3d9a4d523b61 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "isel" +#include "SDNodeDbgValue.h" #include "SelectionDAGBuilder.h" #include "FunctionLoweringInfo.h" #include "llvm/ADT/BitVector.h" @@ -2185,7 +2186,8 @@ void SelectionDAGBuilder::visitSelect(User &I) { for (unsigned i = 0; i != NumValues; ++i) Values[i] = DAG.getNode(ISD::SELECT, getCurDebugLoc(), - TrueVal.getNode()->getValueType(i), Cond, + TrueVal.getNode()->getValueType(TrueVal.getResNo()+i), + Cond, SDValue(TrueVal.getNode(), TrueVal.getResNo() + i), SDValue(FalseVal.getNode(), @@ -3799,11 +3801,6 @@ SelectionDAGBuilder::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) { return 0; } case Intrinsic::dbg_value: { - // FIXME: currently, we get here only if OptLevel != CodeGenOpt::None. - // The real handling of this intrinsic is in FastISel. - if (OptLevel != CodeGenOpt::None) - // FIXME: Variable debug info is not supported here. - return 0; DwarfWriter *DW = DAG.getDwarfWriter(); if (!DW) return 0; @@ -3812,9 +3809,36 @@ SelectionDAGBuilder::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) { return 0; MDNode *Variable = DI.getVariable(); + uint64_t Offset = DI.getOffset(); Value *V = DI.getValue(); if (!V) return 0; + + // Build an entry in DbgOrdering. Debug info input nodes get an SDNodeOrder + // but do not always have a corresponding SDNode built. The SDNodeOrder + // absolute, but not relative, values are different depending on whether + // debug info exists. + ++SDNodeOrder; + if (isa<ConstantInt>(V) || isa<ConstantFP>(V)) { + SDDbgValue* dv = new SDDbgValue(Variable, V, Offset, dl, SDNodeOrder); + DAG.RememberDbgInfo(dv); + } else { + SDValue &N = NodeMap[V]; + if (N.getNode()) { + SDDbgValue *dv = new SDDbgValue(Variable, N.getNode(), + N.getResNo(), Offset, dl, SDNodeOrder); + DAG.AssignDbgInfo(N.getNode(), dv); + } else { + // We may expand this to cover more cases. One case where we have no + // data available is an unreferenced parameter; we need this fallback. + SDDbgValue* dv = new SDDbgValue(Variable, + UndefValue::get(V->getType()), + Offset, dl, SDNodeOrder); + DAG.RememberDbgInfo(dv); + } + } + + // Build a debug info table entry. if (BitCastInst *BCI = dyn_cast<BitCastInst>(V)) V = BCI->getOperand(0); AllocaInst *AI = dyn_cast<AllocaInst>(V); @@ -3999,6 +4023,14 @@ SelectionDAGBuilder::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) { case Intrinsic::pow: visitPow(I); return 0; + case Intrinsic::convert_to_fp16: + setValue(&I, DAG.getNode(ISD::FP32_TO_FP16, dl, + MVT::i16, getValue(I.getOperand(1)))); + return 0; + case Intrinsic::convert_from_fp16: + setValue(&I, DAG.getNode(ISD::FP16_TO_FP32, dl, + MVT::f32, getValue(I.getOperand(1)))); + return 0; case Intrinsic::pcmarker: { SDValue Tmp = getValue(I.getOperand(1)); DAG.setRoot(DAG.getNode(ISD::PCMARKER, dl, MVT::Other, getRoot(), Tmp)); @@ -4301,7 +4333,7 @@ void SelectionDAGBuilder::LowerCallTo(CallSite CS, SDValue Callee, const FunctionType *FTy = cast<FunctionType>(PT->getElementType()); const Type *RetTy = FTy->getReturnType(); MachineModuleInfo *MMI = DAG.getMachineModuleInfo(); - unsigned BeginLabel = 0, EndLabel = 0; + MCSymbol *BeginLabel = 0; TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; @@ -4361,7 +4393,7 @@ void SelectionDAGBuilder::LowerCallTo(CallSite CS, SDValue Callee, if (LandingPad && MMI) { // Insert a label before the invoke call to mark the try range. This can be // used to detect deletion of the invoke via the MachineModuleInfo. - BeginLabel = MMI->NextLabelID(); + BeginLabel = MMI->getContext().CreateTempSymbol(); // For SjLj, keep track of which landing pads go with which invokes // so as to maintain the ordering of pads in the LSDA. @@ -4375,8 +4407,7 @@ void SelectionDAGBuilder::LowerCallTo(CallSite CS, SDValue Callee, // Both PendingLoads and PendingExports must be flushed here; // this call might not return. (void)getRoot(); - DAG.setRoot(DAG.getLabel(ISD::EH_LABEL, getCurDebugLoc(), - getControlRoot(), BeginLabel)); + DAG.setRoot(DAG.getEHLabel(getCurDebugLoc(), getControlRoot(), BeginLabel)); } // Check if target-independent constraints permit a tail call here. @@ -4464,9 +4495,8 @@ void SelectionDAGBuilder::LowerCallTo(CallSite CS, SDValue Callee, if (LandingPad && MMI) { // Insert a label at the end of the invoke call to mark the try range. This // can be used to detect deletion of the invoke via the MachineModuleInfo. - EndLabel = MMI->NextLabelID(); - DAG.setRoot(DAG.getLabel(ISD::EH_LABEL, getCurDebugLoc(), - getRoot(), EndLabel)); + MCSymbol *EndLabel = MMI->getContext().CreateTempSymbol(); + DAG.setRoot(DAG.getEHLabel(getCurDebugLoc(), getRoot(), EndLabel)); // Inform MachineModuleInfo of range. MMI->addInvoke(LandingPad, BeginLabel, EndLabel); @@ -4632,7 +4662,7 @@ void SelectionDAGBuilder::visitCall(CallInst &I) { // can't be a library call. if (!F->hasLocalLinkage() && F->hasName()) { StringRef Name = F->getName(); - if (Name == "copysign" || Name == "copysignf") { + if (Name == "copysign" || Name == "copysignf" || Name == "copysignl") { if (I.getNumOperands() == 3 && // Basic sanity checks. I.getOperand(1)->getType()->isFloatingPointTy() && I.getType() == I.getOperand(1)->getType() && @@ -5777,12 +5807,6 @@ TargetLowering::LowerCallTo(SDValue Chain, const Type *RetTy, "LowerCall emitted a return value for a tail call!"); assert((isTailCall || InVals.size() == Ins.size()) && "LowerCall didn't emit the correct number of values!"); - DEBUG(for (unsigned i = 0, e = Ins.size(); i != e; ++i) { - assert(InVals[i].getNode() && - "LowerCall emitted a null value!"); - assert(Ins[i].VT == InVals[i].getValueType() && - "LowerCall emitted a value with the wrong type!"); - }); // For a tail call, the return value is merely live-out and there aren't // any nodes in the DAG representing it. Return a special value to @@ -5793,6 +5817,13 @@ TargetLowering::LowerCallTo(SDValue Chain, const Type *RetTy, return std::make_pair(SDValue(), SDValue()); } + DEBUG(for (unsigned i = 0, e = Ins.size(); i != e; ++i) { + assert(InVals[i].getNode() && + "LowerCall emitted a null value!"); + assert(Ins[i].VT == InVals[i].getValueType() && + "LowerCall emitted a value with the wrong type!"); + }); + // Collect the legal value parts into potentially illegal values // that correspond to the original function's return values. ISD::NodeType AssertOp = ISD::DELETED_NODE; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index a82f0f71fea5..cbbe4311756e 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -368,8 +368,6 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { static void SetDebugLoc(unsigned MDDbgKind, Instruction *I, SelectionDAGBuilder *SDB, FastISel *FastIS, MachineFunction *MF) { - if (isa<DbgInfoIntrinsic>(I)) return; - if (MDNode *Dbg = I->getMetadata(MDDbgKind)) { DILocation DILoc(Dbg); DebugLoc Loc = ExtractDebugLocation(DILoc, MF->getDebugLocInfo()); @@ -446,12 +444,25 @@ namespace { /// nodes from the worklist. class SDOPsWorkListRemover : public SelectionDAG::DAGUpdateListener { SmallVector<SDNode*, 128> &Worklist; + SmallPtrSet<SDNode*, 128> &InWorklist; public: - SDOPsWorkListRemover(SmallVector<SDNode*, 128> &wl) : Worklist(wl) {} + SDOPsWorkListRemover(SmallVector<SDNode*, 128> &wl, + SmallPtrSet<SDNode*, 128> &inwl) + : Worklist(wl), InWorklist(inwl) {} + void RemoveFromWorklist(SDNode *N) { + if (!InWorklist.erase(N)) return; + + SmallVector<SDNode*, 128>::iterator I = + std::find(Worklist.begin(), Worklist.end(), N); + assert(I != Worklist.end() && "Not in worklist"); + + *I = Worklist.back(); + Worklist.pop_back(); + } + virtual void NodeDeleted(SDNode *N, SDNode *E) { - Worklist.erase(std::remove(Worklist.begin(), Worklist.end(), N), - Worklist.end()); + RemoveFromWorklist(N); } virtual void NodeUpdated(SDNode *N) { @@ -480,70 +491,79 @@ static bool TrivialTruncElim(SDValue Op, /// x+y to (VT)((SmallVT)x+(SmallVT)y) if the casts are free. void SelectionDAGISel::ShrinkDemandedOps() { SmallVector<SDNode*, 128> Worklist; + SmallPtrSet<SDNode*, 128> InWorklist; // Add all the dag nodes to the worklist. Worklist.reserve(CurDAG->allnodes_size()); for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(), - E = CurDAG->allnodes_end(); I != E; ++I) + E = CurDAG->allnodes_end(); I != E; ++I) { Worklist.push_back(I); - - APInt Mask; - APInt KnownZero; - APInt KnownOne; + InWorklist.insert(I); + } TargetLowering::TargetLoweringOpt TLO(*CurDAG, true); while (!Worklist.empty()) { SDNode *N = Worklist.pop_back_val(); + InWorklist.erase(N); if (N->use_empty() && N != CurDAG->getRoot().getNode()) { + // Deleting this node may make its operands dead, add them to the worklist + // if they aren't already there. + for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) + if (InWorklist.insert(N->getOperand(i).getNode())) + Worklist.push_back(N->getOperand(i).getNode()); + CurDAG->DeleteNode(N); continue; } // Run ShrinkDemandedOp on scalar binary operations. - if (N->getNumValues() == 1 && - N->getValueType(0).isSimple() && N->getValueType(0).isInteger()) { - unsigned BitWidth = N->getValueType(0).getScalarType().getSizeInBits(); - APInt Demanded = APInt::getAllOnesValue(BitWidth); - APInt KnownZero, KnownOne; - if (TLI.SimplifyDemandedBits(SDValue(N, 0), Demanded, - KnownZero, KnownOne, TLO) || - (N->getOpcode() == ISD::TRUNCATE && - TrivialTruncElim(SDValue(N, 0), TLO))) { - // Revisit the node. - Worklist.erase(std::remove(Worklist.begin(), Worklist.end(), N), - Worklist.end()); - Worklist.push_back(N); - - // Replace the old value with the new one. - DEBUG(errs() << "\nReplacing "; - TLO.Old.getNode()->dump(CurDAG); - errs() << "\nWith: "; - TLO.New.getNode()->dump(CurDAG); - errs() << '\n'); - - Worklist.push_back(TLO.New.getNode()); - - SDOPsWorkListRemover DeadNodes(Worklist); - CurDAG->ReplaceAllUsesOfValueWith(TLO.Old, TLO.New, &DeadNodes); - - if (TLO.Old.getNode()->use_empty()) { - for (unsigned i = 0, e = TLO.Old.getNode()->getNumOperands(); - i != e; ++i) { - SDNode *OpNode = TLO.Old.getNode()->getOperand(i).getNode(); - if (OpNode->hasOneUse()) { - Worklist.erase(std::remove(Worklist.begin(), Worklist.end(), - OpNode), Worklist.end()); - Worklist.push_back(OpNode); - } - } + if (N->getNumValues() != 1 || + !N->getValueType(0).isSimple() || !N->getValueType(0).isInteger()) + continue; + + unsigned BitWidth = N->getValueType(0).getScalarType().getSizeInBits(); + APInt Demanded = APInt::getAllOnesValue(BitWidth); + APInt KnownZero, KnownOne; + if (!TLI.SimplifyDemandedBits(SDValue(N, 0), Demanded, + KnownZero, KnownOne, TLO) && + (N->getOpcode() != ISD::TRUNCATE || + !TrivialTruncElim(SDValue(N, 0), TLO))) + continue; + + // Revisit the node. + assert(!InWorklist.count(N) && "Already in worklist"); + Worklist.push_back(N); + InWorklist.insert(N); - Worklist.erase(std::remove(Worklist.begin(), Worklist.end(), - TLO.Old.getNode()), Worklist.end()); - CurDAG->DeleteNode(TLO.Old.getNode()); - } + // Replace the old value with the new one. + DEBUG(errs() << "\nShrinkDemandedOps replacing "; + TLO.Old.getNode()->dump(CurDAG); + errs() << "\nWith: "; + TLO.New.getNode()->dump(CurDAG); + errs() << '\n'); + + if (InWorklist.insert(TLO.New.getNode())) + Worklist.push_back(TLO.New.getNode()); + + SDOPsWorkListRemover DeadNodes(Worklist, InWorklist); + CurDAG->ReplaceAllUsesOfValueWith(TLO.Old, TLO.New, &DeadNodes); + + if (!TLO.Old.getNode()->use_empty()) continue; + + for (unsigned i = 0, e = TLO.Old.getNode()->getNumOperands(); + i != e; ++i) { + SDNode *OpNode = TLO.Old.getNode()->getOperand(i).getNode(); + if (OpNode->hasOneUse()) { + // Add OpNode to the end of the list to revisit. + DeadNodes.RemoveFromWorklist(OpNode); + Worklist.push_back(OpNode); + InWorklist.insert(OpNode); } } + + DeadNodes.RemoveFromWorklist(TLO.Old.getNode()); + CurDAG->DeleteNode(TLO.Old.getNode()); } } @@ -715,13 +735,13 @@ void SelectionDAGISel::CodeGenAndEmitDAG() { DEBUG(dbgs() << "Optimized legalized selection DAG:\n"); DEBUG(CurDAG->dump()); - if (ViewISelDAGs) CurDAG->viewGraph("isel input for " + BlockName); - if (OptLevel != CodeGenOpt::None) { ShrinkDemandedOps(); ComputeLiveOutVRegInfo(); } + if (ViewISelDAGs) CurDAG->viewGraph("isel input for " + BlockName); + // Third, instruction select all of the operations to machine code, adding the // code to the MachineBasicBlock. if (TimePassesIsEnabled) { @@ -879,10 +899,10 @@ void SelectionDAGISel::SelectAllBasicBlocks(Function &Fn, if (MMI && BB->isLandingPad()) { // Add a label to mark the beginning of the landing pad. Deletion of the // landing pad can thus be detected via the MachineModuleInfo. - unsigned LabelID = MMI->addLandingPad(BB); + MCSymbol *Label = MMI->addLandingPad(BB); const TargetInstrDesc &II = TII.get(TargetOpcode::EH_LABEL); - BuildMI(BB, SDB->getCurDebugLoc(), II).addImm(LabelID); + BuildMI(BB, SDB->getCurDebugLoc(), II).addSym(Label); // Mark exception register as live in. unsigned Reg = TLI.getExceptionAddressRegister(); @@ -1517,14 +1537,6 @@ SDNode *SelectionDAGISel::Select_UNDEF(SDNode *N) { return CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF,N->getValueType(0)); } -SDNode *SelectionDAGISel::Select_EH_LABEL(SDNode *N) { - SDValue Chain = N->getOperand(0); - unsigned C = cast<LabelSDNode>(N)->getLabelID(); - SDValue Tmp = CurDAG->getTargetConstant(C, MVT::i32); - return CurDAG->SelectNodeTo(N, TargetOpcode::EH_LABEL, - MVT::Other, Tmp, Chain); -} - /// GetVBR - decode a vbr encoding whose top bit is set. ALWAYS_INLINE static uint64_t GetVBR(uint64_t Val, const unsigned char *MatcherTable, unsigned &Idx) { @@ -1651,7 +1663,8 @@ WalkChainUsers(SDNode *ChainedNode, if (User->getOpcode() == ISD::CopyToReg || User->getOpcode() == ISD::CopyFromReg || - User->getOpcode() == ISD::INLINEASM) { + User->getOpcode() == ISD::INLINEASM || + User->getOpcode() == ISD::EH_LABEL) { // If their node ID got reset to -1 then they've already been selected. // Treat them like a MachineOpcode. if (User->getNodeId() == -1) @@ -2042,6 +2055,8 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, case ISD::EntryToken: // These nodes remain the same. case ISD::BasicBlock: case ISD::Register: + //case ISD::VALUETYPE: + //case ISD::CONDCODE: case ISD::HANDLENODE: case ISD::TargetConstant: case ISD::TargetConstantFP: @@ -2055,6 +2070,7 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, case ISD::TokenFactor: case ISD::CopyFromReg: case ISD::CopyToReg: + case ISD::EH_LABEL: NodeToMatch->setNodeId(-1); // Mark selected. return 0; case ISD::AssertSext: @@ -2063,7 +2079,6 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, NodeToMatch->getOperand(0)); return 0; case ISD::INLINEASM: return Select_INLINEASM(NodeToMatch); - case ISD::EH_LABEL: return Select_EH_LABEL(NodeToMatch); case ISD::UNDEF: return Select_UNDEF(NodeToMatch); } diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 0e54ca44aa5e..f7ef2d640b44 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -174,7 +174,13 @@ static void InitLibcallNames(const char **Names) { Names[RTLIB::FLOOR_F64] = "floor"; Names[RTLIB::FLOOR_F80] = "floorl"; Names[RTLIB::FLOOR_PPCF128] = "floorl"; + Names[RTLIB::COPYSIGN_F32] = "copysignf"; + Names[RTLIB::COPYSIGN_F64] = "copysign"; + Names[RTLIB::COPYSIGN_F80] = "copysignl"; + Names[RTLIB::COPYSIGN_PPCF128] = "copysignl"; Names[RTLIB::FPEXT_F32_F64] = "__extendsfdf2"; + Names[RTLIB::FPEXT_F16_F32] = "__gnu_h2f_ieee"; + Names[RTLIB::FPROUND_F32_F16] = "__gnu_f2h_ieee"; Names[RTLIB::FPROUND_F64_F32] = "__truncdfsf2"; Names[RTLIB::FPROUND_F80_F32] = "__truncxfsf2"; Names[RTLIB::FPROUND_PPCF128_F32] = "__trunctfsf2"; @@ -269,6 +275,7 @@ RTLIB::Libcall RTLIB::getFPEXT(EVT OpVT, EVT RetVT) { if (RetVT == MVT::f64) return FPEXT_F32_F64; } + return UNKNOWN_LIBCALL; } @@ -288,6 +295,7 @@ RTLIB::Libcall RTLIB::getFPROUND(EVT OpVT, EVT RetVT) { if (OpVT == MVT::ppcf128) return FPROUND_PPCF128_F64; } + return UNKNOWN_LIBCALL; } @@ -792,20 +800,6 @@ unsigned TargetLowering::getVectorTypeBreakdown(LLVMContext &Context, EVT VT, return 1; } -/// getWidenVectorType: given a vector type, returns the type to widen to -/// (e.g., v7i8 to v8i8). If the vector type is legal, it returns itself. -/// If there is no vector type that we want to widen to, returns MVT::Other -/// When and where to widen is target dependent based on the cost of -/// scalarizing vs using the wider vector type. -EVT TargetLowering::getWidenVectorType(EVT VT) const { - assert(VT.isVector()); - if (isTypeLegal(VT)) - return VT; - - // Default is not to widen until moved to LegalizeTypes - return MVT::Other; -} - /// getByValTypeAlignment - Return the desired alignment for ByVal aggregate /// function arguments in the caller parameter area. This is the actual /// alignment, not its logarithm. diff --git a/lib/CodeGen/SimpleRegisterCoalescing.cpp b/lib/CodeGen/SimpleRegisterCoalescing.cpp index d25df1d2ad8c..5c621181cd93 100644 --- a/lib/CodeGen/SimpleRegisterCoalescing.cpp +++ b/lib/CodeGen/SimpleRegisterCoalescing.cpp @@ -1260,10 +1260,10 @@ SimpleRegisterCoalescing::CanJoinExtractSubRegToPhysReg(unsigned DstReg, RealDstReg = tri_->getMatchingSuperReg(DstReg, SubIdx, RC); assert(RealDstReg && "Invalid extract_subreg instruction!"); + LiveInterval &RHS = li_->getInterval(SrcReg); // For this type of EXTRACT_SUBREG, conservatively // check if the live interval of the source register interfere with the // actual super physical register we are trying to coalesce with. - LiveInterval &RHS = li_->getInterval(SrcReg); if (li_->hasInterval(RealDstReg) && RHS.overlaps(li_->getInterval(RealDstReg))) { DEBUG({ @@ -1273,7 +1273,11 @@ SimpleRegisterCoalescing::CanJoinExtractSubRegToPhysReg(unsigned DstReg, return false; // Not coalescable } for (const unsigned* SR = tri_->getSubRegisters(RealDstReg); *SR; ++SR) - if (li_->hasInterval(*SR) && RHS.overlaps(li_->getInterval(*SR))) { + // Do not check DstReg or its sub-register. JoinIntervals() will take care + // of that. + if (*SR != DstReg && + !tri_->isSubRegister(DstReg, *SR) && + li_->hasInterval(*SR) && RHS.overlaps(li_->getInterval(*SR))) { DEBUG({ dbgs() << "Interfere with sub-register "; li_->getInterval(*SR).print(dbgs(), tri_); @@ -1294,9 +1298,9 @@ SimpleRegisterCoalescing::CanJoinInsertSubRegToPhysReg(unsigned DstReg, RealSrcReg = tri_->getMatchingSuperReg(SrcReg, SubIdx, RC); assert(RealSrcReg && "Invalid extract_subreg instruction!"); - LiveInterval &RHS = li_->getInterval(DstReg); + LiveInterval &LHS = li_->getInterval(DstReg); if (li_->hasInterval(RealSrcReg) && - RHS.overlaps(li_->getInterval(RealSrcReg))) { + LHS.overlaps(li_->getInterval(RealSrcReg))) { DEBUG({ dbgs() << "Interfere with register "; li_->getInterval(RealSrcReg).print(dbgs(), tri_); @@ -1304,7 +1308,11 @@ SimpleRegisterCoalescing::CanJoinInsertSubRegToPhysReg(unsigned DstReg, return false; // Not coalescable } for (const unsigned* SR = tri_->getSubRegisters(RealSrcReg); *SR; ++SR) - if (li_->hasInterval(*SR) && RHS.overlaps(li_->getInterval(*SR))) { + // Do not check SrcReg or its sub-register. JoinIntervals() will take care + // of that. + if (*SR != SrcReg && + !tri_->isSubRegister(SrcReg, *SR) && + li_->hasInterval(*SR) && LHS.overlaps(li_->getInterval(*SR))) { DEBUG({ dbgs() << "Interfere with sub-register "; li_->getInterval(*SR).print(dbgs(), tri_); @@ -1476,6 +1484,9 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) { return false; // Not coalescable. } + // FIXME: The following checks are somewhat conservative. Perhaps a better + // way to implement this is to treat this as coalescing a vr with the + // super physical register. if (isExtSubReg) { if (!CanJoinExtractSubRegToPhysReg(DstReg, SrcReg, SubIdx, RealDstReg)) return false; // Not coalescable @@ -2205,7 +2216,7 @@ SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS, LiveInterval &RHS, li_->intervalIsInOneMBB(RHS) && li_->getApproximateInstructionCount(RHS) <= 10) { // Perform a more exhaustive check for some common cases. - if (li_->conflictsWithPhysRegRef(RHS, LHS.reg, true, JoinedCopies)) + if (li_->conflictsWithSubPhysRegRef(RHS, LHS.reg, true, JoinedCopies)) return false; } else { for (const unsigned* SR = tri_->getSubRegisters(LHS.reg); *SR; ++SR) @@ -2222,7 +2233,7 @@ SimpleRegisterCoalescing::JoinIntervals(LiveInterval &LHS, LiveInterval &RHS, if (LHS.containsOneValue() && li_->getApproximateInstructionCount(LHS) <= 10) { // Perform a more exhaustive check for some common cases. - if (li_->conflictsWithPhysRegRef(LHS, RHS.reg, false, JoinedCopies)) + if (li_->conflictsWithSubPhysRegRef(LHS, RHS.reg, false, JoinedCopies)) return false; } else { for (const unsigned* SR = tri_->getSubRegisters(RHS.reg); *SR; ++SR) diff --git a/lib/CodeGen/TailDuplication.cpp b/lib/CodeGen/TailDuplication.cpp index 3223e53d5dac..fa3785dc0795 100644 --- a/lib/CodeGen/TailDuplication.cpp +++ b/lib/CodeGen/TailDuplication.cpp @@ -648,17 +648,6 @@ void TailDuplicatePass::RemoveDeadBlock(MachineBasicBlock *MBB) { while (!MBB->succ_empty()) MBB->removeSuccessor(MBB->succ_end()-1); - // If there are any labels in the basic block, unregister them from - // MachineModuleInfo. - if (MMI && !MBB->empty()) { - for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); - I != E; ++I) { - if (I->isLabel()) - // The label ID # is always operand #0, an immediate. - MMI->InvalidateLabel(I->getOperand(0).getImm()); - } - } - // Remove the block. MBB->eraseFromParent(); } diff --git a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 2014b429bd98..b62cca3073d2 100644 --- a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -53,11 +53,13 @@ getELFSection(StringRef Section, unsigned Type, unsigned Flags, ELFUniqueMapTy &Map = *(ELFUniqueMapTy*)UniquingMap; // Do the lookup, if we have a hit, return it. - const MCSectionELF *&Entry = Map[Section]; - if (Entry) return Entry; + StringMapEntry<const MCSectionELF*> &Entry = Map.GetOrCreateValue(Section); + if (Entry.getValue()) return Entry.getValue(); - return Entry = MCSectionELF::Create(Section, Type, Flags, Kind, IsExplicit, - getContext()); + MCSectionELF *Result = MCSectionELF::Create(Entry.getKey(), Type, Flags, Kind, + IsExplicit, getContext()); + Entry.setValue(Result); + return Result; } void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx, @@ -306,9 +308,9 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, // into a 'uniqued' section name, create and return the section now. if (GV->isWeakForLinker() && !Kind.isCommon() && !Kind.isBSS()) { const char *Prefix = getSectionPrefixForUniqueGlobal(Kind); - SmallString<128> Name; - Name.append(Prefix, Prefix+strlen(Prefix)); - Mang->getNameWithPrefix(Name, GV, false); + SmallString<128> Name(Prefix, Prefix+strlen(Prefix)); + MCSymbol *Sym = Mang->getSymbol(GV); + Name.append(Sym->getName().begin(), Sym->getName().end()); return getELFSection(Name.str(), getELFSectionType(Name.str(), Kind), getELFSectionFlags(Kind), Kind); } @@ -391,8 +393,9 @@ getSectionForConstant(SectionKind Kind) const { } const MCExpr *TargetLoweringObjectFileELF:: -getSymbolForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, - MachineModuleInfo *MMI, unsigned Encoding) const { +getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, + MachineModuleInfo *MMI, + unsigned Encoding, MCStreamer &Streamer) const { if (Encoding & dwarf::DW_EH_PE_indirect) { MachineModuleInfoELF &ELFMMI = MMI->getObjFileInfo<MachineModuleInfoELF>(); @@ -403,24 +406,20 @@ getSymbolForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, // Add information about the stub reference to ELFMMI so that the stub // gets emitted by the asmprinter. - MCSymbol *Sym = getContext().GetOrCreateTemporarySymbol(Name.str()); - MCSymbol *&StubSym = ELFMMI.getGVStubEntry(Sym); - if (StubSym == 0) { - Name.clear(); - Mang->getNameWithPrefix(Name, GV, false); - if (GV->hasPrivateLinkage()) - StubSym = getContext().GetOrCreateTemporarySymbol(Name.str()); - else - StubSym = getContext().GetOrCreateSymbol(Name.str()); + MCSymbol *SSym = getContext().GetOrCreateTemporarySymbol(Name.str()); + MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(SSym); + if (StubSym.getPointer() == 0) { + MCSymbol *Sym = Mang->getSymbol(GV); + StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); } return TargetLoweringObjectFile:: - getSymbolForDwarfReference(Sym, MMI, - Encoding & ~dwarf::DW_EH_PE_indirect); + getExprForDwarfReference(SSym, Mang, MMI, + Encoding & ~dwarf::DW_EH_PE_indirect, Streamer); } return TargetLoweringObjectFile:: - getSymbolForDwarfGlobalReference(GV, Mang, MMI, Encoding); + getExprForDwarfGlobalReference(GV, Mang, MMI, Encoding, Streamer); } //===----------------------------------------------------------------------===// @@ -561,8 +560,8 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, } // Exception Handling. - LSDASection = getMachOSection("__DATA", "__gcc_except_tab", 0, - SectionKind::getDataRel()); + LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, + SectionKind::getReadOnlyWithRel()); EHFrameSection = getMachOSection("__TEXT", "__eh_frame", MCSectionMachO::S_COALESCED | @@ -736,9 +735,8 @@ shouldEmitUsedDirectiveFor(const GlobalValue *GV, Mangler *Mang) const { // FIXME: ObjC metadata is currently emitted as internal symbols that have // \1L and \0l prefixes on them. Fix them to be Private/LinkerPrivate and // this horrible hack can go away. - SmallString<64> Name; - Mang->getNameWithPrefix(Name, GV, false); - if (Name[0] == 'L' || Name[0] == 'l') + MCSymbol *Sym = Mang->getSymbol(GV); + if (Sym->getName()[0] == 'L' || Sym->getName()[0] == 'l') return false; } @@ -746,8 +744,9 @@ shouldEmitUsedDirectiveFor(const GlobalValue *GV, Mangler *Mang) const { } const MCExpr *TargetLoweringObjectFileMachO:: -getSymbolForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, - MachineModuleInfo *MMI, unsigned Encoding) const { +getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const { // The mach-o version of this method defaults to returning a stub reference. if (Encoding & DW_EH_PE_indirect) { @@ -760,24 +759,20 @@ getSymbolForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, // Add information about the stub reference to MachOMMI so that the stub // gets emitted by the asmprinter. - MCSymbol *Sym = getContext().GetOrCreateTemporarySymbol(Name.str()); - MCSymbol *&StubSym = MachOMMI.getGVStubEntry(Sym); - if (StubSym == 0) { - Name.clear(); - Mang->getNameWithPrefix(Name, GV, false); - if (GV->hasPrivateLinkage()) - StubSym = getContext().GetOrCreateTemporarySymbol(Name.str()); - else - StubSym = getContext().GetOrCreateSymbol(Name.str()); + MCSymbol *SSym = getContext().GetOrCreateTemporarySymbol(Name.str()); + MachineModuleInfoImpl::StubValueTy &StubSym = MachOMMI.getGVStubEntry(SSym); + if (StubSym.getPointer() == 0) { + MCSymbol *Sym = Mang->getSymbol(GV); + StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); } return TargetLoweringObjectFile:: - getSymbolForDwarfReference(Sym, MMI, - Encoding & ~dwarf::DW_EH_PE_indirect); + getExprForDwarfReference(SSym, Mang, MMI, + Encoding & ~dwarf::DW_EH_PE_indirect, Streamer); } return TargetLoweringObjectFile:: - getSymbolForDwarfGlobalReference(GV, Mang, MMI, Encoding); + getExprForDwarfGlobalReference(GV, Mang, MMI, Encoding, Streamer); } unsigned TargetLoweringObjectFileMachO::getPersonalityEncoding() const { @@ -793,7 +788,7 @@ unsigned TargetLoweringObjectFileMachO::getFDEEncoding() const { } unsigned TargetLoweringObjectFileMachO::getTTypeEncoding() const { - return DW_EH_PE_absptr; + return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; } //===----------------------------------------------------------------------===// @@ -904,7 +899,8 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, if (GV->isWeakForLinker()) { const char *Prefix = getCOFFSectionPrefixForUniqueGlobal(Kind); SmallString<128> Name(Prefix, Prefix+strlen(Prefix)); - Mang->getNameWithPrefix(Name, GV, false); + MCSymbol *Sym = Mang->getSymbol(GV); + Name.append(Sym->getName().begin(), Sym->getName().end()); return getCOFFSection(Name.str(), false, Kind); } diff --git a/lib/CodeGen/UnreachableBlockElim.cpp b/lib/CodeGen/UnreachableBlockElim.cpp index b0f0a07420c3..7b338126d475 100644 --- a/lib/CodeGen/UnreachableBlockElim.cpp +++ b/lib/CodeGen/UnreachableBlockElim.cpp @@ -165,20 +165,8 @@ bool UnreachableMachineBlockElim::runOnMachineFunction(MachineFunction &F) { } // Actually remove the blocks now. - for (unsigned i = 0, e = DeadBlocks.size(); i != e; ++i) { - MachineBasicBlock *MBB = DeadBlocks[i]; - // If there are any labels in the basic block, unregister them from - // MachineModuleInfo. - if (MMI && !MBB->empty()) { - for (MachineBasicBlock::iterator I = MBB->begin(), - E = MBB->end(); I != E; ++I) { - if (I->isLabel()) - // The label ID # is always operand #0, an immediate. - MMI->InvalidateLabel(I->getOperand(0).getImm()); - } - } - MBB->eraseFromParent(); - } + for (unsigned i = 0, e = DeadBlocks.size(); i != e; ++i) + DeadBlocks[i]->eraseFromParent(); // Cleanup PHI nodes. for (MachineFunction::iterator I = F.begin(), E = F.end(); I != E; ++I) { diff --git a/lib/CodeGen/VirtRegRewriter.cpp b/lib/CodeGen/VirtRegRewriter.cpp index 7aa0a9153524..44d5311afd44 100644 --- a/lib/CodeGen/VirtRegRewriter.cpp +++ b/lib/CodeGen/VirtRegRewriter.cpp @@ -98,7 +98,7 @@ struct TrivialRewriter : public VirtRegRewriter { bool runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM, LiveIntervals* LIs) { DEBUG(dbgs() << "********** REWRITE MACHINE CODE **********\n"); - DEBUG(dbgs() << "********** Function: " + DEBUG(dbgs() << "********** Function: " << MF.getFunction()->getName() << '\n'); DEBUG(dbgs() << "**** Machine Instrs" << "(NOTE! Does not include spills and reloads!) ****\n"); @@ -135,10 +135,10 @@ struct TrivialRewriter : public VirtRegRewriter { changed |= !reglist.empty(); } } - + DEBUG(dbgs() << "**** Post Machine Instrs ****\n"); DEBUG(MF.dump()); - + return changed; } @@ -208,7 +208,7 @@ public: /// in the specified physreg. If CanClobber is true, the physreg can be /// modified at any time without changing the semantics of the program. void addAvailable(int SlotOrReMat, unsigned Reg, bool CanClobber = true) { - // If this stack slot is thought to be available in some other physreg, + // If this stack slot is thought to be available in some other physreg, // remove its record. ModifyStackSlotOrReMat(SlotOrReMat); @@ -364,7 +364,7 @@ struct ReusedOp { // AssignedPhysReg - The physreg that was assigned for use by the reload. unsigned AssignedPhysReg; - + // VirtReg - The virtual register itself. unsigned VirtReg; @@ -384,11 +384,11 @@ public: ReuseInfo(MachineInstr &mi, const TargetRegisterInfo *tri) : MI(mi) { PhysRegsClobbered.resize(tri->getNumRegs()); } - + bool hasReuses() const { return !Reuses.empty(); } - + /// addReuse - If we choose to reuse a virtual register that is already /// available instead of reloading it, remember that we did so. void addReuse(unsigned OpNo, unsigned StackSlotOrReMat, @@ -397,9 +397,9 @@ public: // If the reload is to the assigned register anyway, no undo will be // required. if (PhysRegReused == AssignedPhysReg) return; - + // Otherwise, remember this. - Reuses.push_back(ReusedOp(OpNo, StackSlotOrReMat, PhysRegReused, + Reuses.push_back(ReusedOp(OpNo, StackSlotOrReMat, PhysRegReused, AssignedPhysReg, VirtReg)); } @@ -410,10 +410,10 @@ public: bool isClobbered(unsigned PhysReg) const { return PhysRegsClobbered.test(PhysReg); } - + /// GetRegForReload - We are about to emit a reload into PhysReg. If there /// is some other operand that is using the specified register, either pick - /// a new register to use, or evict the previous reload and use this reg. + /// a new register to use, or evict the previous reload and use this reg. unsigned GetRegForReload(const TargetRegisterClass *RC, unsigned PhysReg, MachineFunction &MF, MachineInstr *MI, AvailableSpills &Spills, @@ -525,7 +525,7 @@ static void InvalidateKills(MachineInstr &MI, /// reference. static bool InvalidateRegDef(MachineBasicBlock::iterator I, MachineInstr &NewDef, unsigned Reg, - bool &HasLiveDef, + bool &HasLiveDef, const TargetRegisterInfo *TRI) { // Due to remat, it's possible this reg isn't being reused. That is, // the def of this reg (by prev MI) is now dead. @@ -579,7 +579,7 @@ static void UpdateKills(MachineInstr &MI, const TargetRegisterInfo* TRI, unsigned Reg = MO.getReg(); if (Reg == 0) continue; - + if (RegKills[Reg] && KillOps[Reg]->getParent() != &MI) { // That can't be right. Register is killed but not re-defined and it's // being reused. Let's fix that. @@ -597,7 +597,7 @@ static void UpdateKills(MachineInstr &MI, const TargetRegisterInfo* TRI, } } else { // Check for subreg kills as well. - // d4 = + // d4 = // store d4, fi#0 // ... // = s8<kill> @@ -802,7 +802,7 @@ void AvailableSpills::ModifyStackSlotOrReMat(int SlotOrReMat) { if (It == SpillSlotsOrReMatsAvailable.end()) return; unsigned Reg = It->second >> 1; SpillSlotsOrReMatsAvailable.erase(It); - + // This register may hold the value of multiple stack slots, only remove this // stack slot from the set of values the register contains. std::multimap<unsigned, int>::iterator I = PhysRegsAvailable.lower_bound(Reg); @@ -832,7 +832,7 @@ unsigned ReuseInfo::GetRegForReload(const TargetRegisterClass *RC, VirtRegMap &VRM) { const TargetInstrInfo* TII = MF.getTarget().getInstrInfo(); const TargetRegisterInfo *TRI = Spills.getRegInfo(); - + if (Reuses.empty()) return PhysReg; // This is most often empty. for (unsigned ro = 0, e = Reuses.size(); ro != e; ++ro) { @@ -853,7 +853,7 @@ unsigned ReuseInfo::GetRegForReload(const TargetRegisterClass *RC, } else { // Otherwise, we might also have a problem if a previously reused // value aliases the new register. If so, codegen the previous reload - // and use this one. + // and use this one. unsigned PRRU = Op.PhysRegReused; if (TRI->regsOverlap(PRRU, PhysReg)) { // Okay, we found out that an alias of a reused register @@ -900,13 +900,13 @@ unsigned ReuseInfo::GetRegForReload(const TargetRegisterClass *RC, if (DoReMat) { ReMaterialize(*MBB, InsertLoc, NewPhysReg, NewOp.VirtReg, TII, TRI, VRM); - } else { + } else { TII->loadRegFromStackSlot(*MBB, InsertLoc, NewPhysReg, NewOp.StackSlotOrReMat, AliasRC); MachineInstr *LoadMI = prior(InsertLoc); VRM.addSpillSlotUse(NewOp.StackSlotOrReMat, LoadMI); // Any stores to this stack slot are not dead anymore. - MaybeDeadStores[NewOp.StackSlotOrReMat] = NULL; + MaybeDeadStores[NewOp.StackSlotOrReMat] = NULL; ++NumLoads; } Spills.ClobberPhysReg(NewPhysReg); @@ -919,10 +919,10 @@ unsigned ReuseInfo::GetRegForReload(const TargetRegisterClass *RC, Spills.addAvailable(NewOp.StackSlotOrReMat, NewPhysReg); UpdateKills(*prior(InsertLoc), TRI, RegKills, KillOps); DEBUG(dbgs() << '\t' << *prior(InsertLoc)); - + DEBUG(dbgs() << "Reuse undone!\n"); --NumReused; - + // Finally, PhysReg is now available, go ahead and use it. return PhysReg; } @@ -1037,1410 +1037,1476 @@ void AssignPhysToVirtReg(MachineInstr *MI, unsigned VirtReg, unsigned PhysReg, } namespace { - struct RefSorter { - bool operator()(const std::pair<MachineInstr*, int> &A, - const std::pair<MachineInstr*, int> &B) { - return A.second < B.second; - } - }; -} + +struct RefSorter { + bool operator()(const std::pair<MachineInstr*, int> &A, + const std::pair<MachineInstr*, int> &B) { + return A.second < B.second; + } +}; // ***************************** // // Local Spiller Implementation // // ***************************** // -namespace { - class LocalRewriter : public VirtRegRewriter { - MachineRegisterInfo *RegInfo; + MachineRegisterInfo *MRI; const TargetRegisterInfo *TRI; const TargetInstrInfo *TII; + VirtRegMap *VRM; BitVector AllocatableRegs; DenseMap<MachineInstr*, unsigned> DistanceMap; -public: - - bool runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM, - LiveIntervals* LIs) { - RegInfo = &MF.getRegInfo(); - TRI = MF.getTarget().getRegisterInfo(); - TII = MF.getTarget().getInstrInfo(); - AllocatableRegs = TRI->getAllocatableSet(MF); - DEBUG(dbgs() << "\n**** Local spiller rewriting function '" - << MF.getFunction()->getName() << "':\n"); - DEBUG(dbgs() << "**** Machine Instrs (NOTE! Does not include spills and" - " reloads!) ****\n"); - DEBUG(MF.dump()); - // Spills - Keep track of which spilled values are available in physregs - // so that we can choose to reuse the physregs instead of emitting - // reloads. This is usually refreshed per basic block. - AvailableSpills Spills(TRI, TII); - - // Keep track of kill information. - BitVector RegKills(TRI->getNumRegs()); - std::vector<MachineOperand*> KillOps; - KillOps.resize(TRI->getNumRegs(), NULL); - - // SingleEntrySuccs - Successor blocks which have a single predecessor. - SmallVector<MachineBasicBlock*, 4> SinglePredSuccs; - SmallPtrSet<MachineBasicBlock*,16> EarlyVisited; - - // Traverse the basic blocks depth first. - MachineBasicBlock *Entry = MF.begin(); - SmallPtrSet<MachineBasicBlock*,16> Visited; - for (df_ext_iterator<MachineBasicBlock*, - SmallPtrSet<MachineBasicBlock*,16> > - DFI = df_ext_begin(Entry, Visited), E = df_ext_end(Entry, Visited); - DFI != E; ++DFI) { - MachineBasicBlock *MBB = *DFI; - if (!EarlyVisited.count(MBB)) - RewriteMBB(*MBB, VRM, LIs, Spills, RegKills, KillOps); - - // If this MBB is the only predecessor of a successor. Keep the - // availability information and visit it next. - do { - // Keep visiting single predecessor successor as long as possible. - SinglePredSuccs.clear(); - findSinglePredSuccessor(MBB, SinglePredSuccs); - if (SinglePredSuccs.empty()) - MBB = 0; - else { - // FIXME: More than one successors, each of which has MBB has - // the only predecessor. - MBB = SinglePredSuccs[0]; - if (!Visited.count(MBB) && EarlyVisited.insert(MBB)) { - Spills.AddAvailableRegsToLiveIn(*MBB, RegKills, KillOps); - RewriteMBB(*MBB, VRM, LIs, Spills, RegKills, KillOps); - } - } - } while (MBB); - - // Clear the availability info. - Spills.clear(); - } + MachineBasicBlock *MBB; // Basic block currently being processed. - DEBUG(dbgs() << "**** Post Machine Instrs ****\n"); - DEBUG(MF.dump()); - - // Mark unused spill slots. - MachineFrameInfo *MFI = MF.getFrameInfo(); - int SS = VRM.getLowSpillSlot(); - if (SS != VirtRegMap::NO_STACK_SLOT) - for (int e = VRM.getHighSpillSlot(); SS <= e; ++SS) - if (!VRM.isSpillSlotUsed(SS)) { - MFI->RemoveStackObject(SS); - ++NumDSS; - } +public: - return true; - } + bool runOnMachineFunction(MachineFunction &MF, VirtRegMap &VRM, + LiveIntervals* LIs); private: - /// OptimizeByUnfold2 - Unfold a series of load / store folding instructions if - /// a scratch register is available. - /// xorq %r12<kill>, %r13 - /// addq %rax, -184(%rbp) - /// addq %r13, -184(%rbp) - /// ==> - /// xorq %r12<kill>, %r13 - /// movq -184(%rbp), %r12 - /// addq %rax, %r12 - /// addq %r13, %r12 - /// movq %r12, -184(%rbp) bool OptimizeByUnfold2(unsigned VirtReg, int SS, - MachineBasicBlock &MBB, MachineBasicBlock::iterator &MII, std::vector<MachineInstr*> &MaybeDeadStores, AvailableSpills &Spills, BitVector &RegKills, - std::vector<MachineOperand*> &KillOps, - VirtRegMap &VRM) { + std::vector<MachineOperand*> &KillOps); - MachineBasicBlock::iterator NextMII = llvm::next(MII); - if (NextMII == MBB.end()) - return false; + bool OptimizeByUnfold(MachineBasicBlock::iterator &MII, + std::vector<MachineInstr*> &MaybeDeadStores, + AvailableSpills &Spills, + BitVector &RegKills, + std::vector<MachineOperand*> &KillOps); - if (TII->getOpcodeAfterMemoryUnfold(MII->getOpcode(), true, true) == 0) - return false; + bool CommuteToFoldReload(MachineBasicBlock::iterator &MII, + unsigned VirtReg, unsigned SrcReg, int SS, + AvailableSpills &Spills, + BitVector &RegKills, + std::vector<MachineOperand*> &KillOps, + const TargetRegisterInfo *TRI); - // Now let's see if the last couple of instructions happens to have freed up - // a register. - const TargetRegisterClass* RC = RegInfo->getRegClass(VirtReg); - unsigned PhysReg = FindFreeRegister(MII, MBB, RC, TRI, AllocatableRegs); - if (!PhysReg) - return false; + void SpillRegToStackSlot(MachineBasicBlock::iterator &MII, + int Idx, unsigned PhysReg, int StackSlot, + const TargetRegisterClass *RC, + bool isAvailable, MachineInstr *&LastStore, + AvailableSpills &Spills, + SmallSet<MachineInstr*, 4> &ReMatDefs, + BitVector &RegKills, + std::vector<MachineOperand*> &KillOps); - MachineFunction &MF = *MBB.getParent(); - TRI = MF.getTarget().getRegisterInfo(); - MachineInstr &MI = *MII; - if (!FoldsStackSlotModRef(MI, SS, PhysReg, TII, TRI, VRM)) - return false; + void TransferDeadness(unsigned Reg, BitVector &RegKills, + std::vector<MachineOperand*> &KillOps); - // If the next instruction also folds the same SS modref and can be unfoled, - // then it's worthwhile to issue a load from SS into the free register and - // then unfold these instructions. - if (!FoldsStackSlotModRef(*NextMII, SS, PhysReg, TII, TRI, VRM)) - return false; + bool InsertEmergencySpills(MachineInstr *MI); - // Back-schedule reloads and remats. - ComputeReloadLoc(MII, MBB.begin(), PhysReg, TRI, false, SS, TII, MF); + bool InsertRestores(MachineInstr *MI, + AvailableSpills &Spills, + BitVector &RegKills, + std::vector<MachineOperand*> &KillOps); - // Load from SS to the spare physical register. - TII->loadRegFromStackSlot(MBB, MII, PhysReg, SS, RC); - // This invalidates Phys. - Spills.ClobberPhysReg(PhysReg); - // Remember it's available. - Spills.addAvailable(SS, PhysReg); - MaybeDeadStores[SS] = NULL; + bool InsertSpills(MachineInstr *MI); - // Unfold current MI. - SmallVector<MachineInstr*, 4> NewMIs; - if (!TII->unfoldMemoryOperand(MF, &MI, VirtReg, false, false, NewMIs)) + void RewriteMBB(LiveIntervals *LIs, + AvailableSpills &Spills, BitVector &RegKills, + std::vector<MachineOperand*> &KillOps); +}; +} + +bool LocalRewriter::runOnMachineFunction(MachineFunction &MF, VirtRegMap &vrm, + LiveIntervals* LIs) { + MRI = &MF.getRegInfo(); + TRI = MF.getTarget().getRegisterInfo(); + TII = MF.getTarget().getInstrInfo(); + VRM = &vrm; + AllocatableRegs = TRI->getAllocatableSet(MF); + DEBUG(dbgs() << "\n**** Local spiller rewriting function '" + << MF.getFunction()->getName() << "':\n"); + DEBUG(dbgs() << "**** Machine Instrs (NOTE! Does not include spills and" + " reloads!) ****\n"); + DEBUG(MF.dump()); + + // Spills - Keep track of which spilled values are available in physregs + // so that we can choose to reuse the physregs instead of emitting + // reloads. This is usually refreshed per basic block. + AvailableSpills Spills(TRI, TII); + + // Keep track of kill information. + BitVector RegKills(TRI->getNumRegs()); + std::vector<MachineOperand*> KillOps; + KillOps.resize(TRI->getNumRegs(), NULL); + + // SingleEntrySuccs - Successor blocks which have a single predecessor. + SmallVector<MachineBasicBlock*, 4> SinglePredSuccs; + SmallPtrSet<MachineBasicBlock*,16> EarlyVisited; + + // Traverse the basic blocks depth first. + MachineBasicBlock *Entry = MF.begin(); + SmallPtrSet<MachineBasicBlock*,16> Visited; + for (df_ext_iterator<MachineBasicBlock*, + SmallPtrSet<MachineBasicBlock*,16> > + DFI = df_ext_begin(Entry, Visited), E = df_ext_end(Entry, Visited); + DFI != E; ++DFI) { + MBB = *DFI; + if (!EarlyVisited.count(MBB)) + RewriteMBB(LIs, Spills, RegKills, KillOps); + + // If this MBB is the only predecessor of a successor. Keep the + // availability information and visit it next. + do { + // Keep visiting single predecessor successor as long as possible. + SinglePredSuccs.clear(); + findSinglePredSuccessor(MBB, SinglePredSuccs); + if (SinglePredSuccs.empty()) + MBB = 0; + else { + // FIXME: More than one successors, each of which has MBB has + // the only predecessor. + MBB = SinglePredSuccs[0]; + if (!Visited.count(MBB) && EarlyVisited.insert(MBB)) { + Spills.AddAvailableRegsToLiveIn(*MBB, RegKills, KillOps); + RewriteMBB(LIs, Spills, RegKills, KillOps); + } + } + } while (MBB); + + // Clear the availability info. + Spills.clear(); + } + + DEBUG(dbgs() << "**** Post Machine Instrs ****\n"); + DEBUG(MF.dump()); + + // Mark unused spill slots. + MachineFrameInfo *MFI = MF.getFrameInfo(); + int SS = VRM->getLowSpillSlot(); + if (SS != VirtRegMap::NO_STACK_SLOT) + for (int e = VRM->getHighSpillSlot(); SS <= e; ++SS) + if (!VRM->isSpillSlotUsed(SS)) { + MFI->RemoveStackObject(SS); + ++NumDSS; + } + + return true; +} + +/// OptimizeByUnfold2 - Unfold a series of load / store folding instructions if +/// a scratch register is available. +/// xorq %r12<kill>, %r13 +/// addq %rax, -184(%rbp) +/// addq %r13, -184(%rbp) +/// ==> +/// xorq %r12<kill>, %r13 +/// movq -184(%rbp), %r12 +/// addq %rax, %r12 +/// addq %r13, %r12 +/// movq %r12, -184(%rbp) +bool LocalRewriter:: +OptimizeByUnfold2(unsigned VirtReg, int SS, + MachineBasicBlock::iterator &MII, + std::vector<MachineInstr*> &MaybeDeadStores, + AvailableSpills &Spills, + BitVector &RegKills, + std::vector<MachineOperand*> &KillOps) { + + MachineBasicBlock::iterator NextMII = llvm::next(MII); + if (NextMII == MBB->end()) + return false; + + if (TII->getOpcodeAfterMemoryUnfold(MII->getOpcode(), true, true) == 0) + return false; + + // Now let's see if the last couple of instructions happens to have freed up + // a register. + const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); + unsigned PhysReg = FindFreeRegister(MII, *MBB, RC, TRI, AllocatableRegs); + if (!PhysReg) + return false; + + MachineFunction &MF = *MBB->getParent(); + TRI = MF.getTarget().getRegisterInfo(); + MachineInstr &MI = *MII; + if (!FoldsStackSlotModRef(MI, SS, PhysReg, TII, TRI, *VRM)) + return false; + + // If the next instruction also folds the same SS modref and can be unfoled, + // then it's worthwhile to issue a load from SS into the free register and + // then unfold these instructions. + if (!FoldsStackSlotModRef(*NextMII, SS, PhysReg, TII, TRI, *VRM)) + return false; + + // Back-schedule reloads and remats. + ComputeReloadLoc(MII, MBB->begin(), PhysReg, TRI, false, SS, TII, MF); + + // Load from SS to the spare physical register. + TII->loadRegFromStackSlot(*MBB, MII, PhysReg, SS, RC); + // This invalidates Phys. + Spills.ClobberPhysReg(PhysReg); + // Remember it's available. + Spills.addAvailable(SS, PhysReg); + MaybeDeadStores[SS] = NULL; + + // Unfold current MI. + SmallVector<MachineInstr*, 4> NewMIs; + if (!TII->unfoldMemoryOperand(MF, &MI, VirtReg, false, false, NewMIs)) + llvm_unreachable("Unable unfold the load / store folding instruction!"); + assert(NewMIs.size() == 1); + AssignPhysToVirtReg(NewMIs[0], VirtReg, PhysReg, *TRI); + VRM->transferRestorePts(&MI, NewMIs[0]); + MII = MBB->insert(MII, NewMIs[0]); + InvalidateKills(MI, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(&MI); + MBB->erase(&MI); + ++NumModRefUnfold; + + // Unfold next instructions that fold the same SS. + do { + MachineInstr &NextMI = *NextMII; + NextMII = llvm::next(NextMII); + NewMIs.clear(); + if (!TII->unfoldMemoryOperand(MF, &NextMI, VirtReg, false, false, NewMIs)) llvm_unreachable("Unable unfold the load / store folding instruction!"); assert(NewMIs.size() == 1); AssignPhysToVirtReg(NewMIs[0], VirtReg, PhysReg, *TRI); - VRM.transferRestorePts(&MI, NewMIs[0]); - MII = MBB.insert(MII, NewMIs[0]); - InvalidateKills(MI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(&MI); - MBB.erase(&MI); + VRM->transferRestorePts(&NextMI, NewMIs[0]); + MBB->insert(NextMII, NewMIs[0]); + InvalidateKills(NextMI, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(&NextMI); + MBB->erase(&NextMI); ++NumModRefUnfold; + if (NextMII == MBB->end()) + break; + } while (FoldsStackSlotModRef(*NextMII, SS, PhysReg, TII, TRI, *VRM)); - // Unfold next instructions that fold the same SS. - do { - MachineInstr &NextMI = *NextMII; - NextMII = llvm::next(NextMII); - NewMIs.clear(); - if (!TII->unfoldMemoryOperand(MF, &NextMI, VirtReg, false, false, NewMIs)) - llvm_unreachable("Unable unfold the load / store folding instruction!"); - assert(NewMIs.size() == 1); - AssignPhysToVirtReg(NewMIs[0], VirtReg, PhysReg, *TRI); - VRM.transferRestorePts(&NextMI, NewMIs[0]); - MBB.insert(NextMII, NewMIs[0]); - InvalidateKills(NextMI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(&NextMI); - MBB.erase(&NextMI); - ++NumModRefUnfold; - if (NextMII == MBB.end()) - break; - } while (FoldsStackSlotModRef(*NextMII, SS, PhysReg, TII, TRI, VRM)); - - // Store the value back into SS. - TII->storeRegToStackSlot(MBB, NextMII, PhysReg, true, SS, RC); - MachineInstr *StoreMI = prior(NextMII); - VRM.addSpillSlotUse(SS, StoreMI); - VRM.virtFolded(VirtReg, StoreMI, VirtRegMap::isMod); + // Store the value back into SS. + TII->storeRegToStackSlot(*MBB, NextMII, PhysReg, true, SS, RC); + MachineInstr *StoreMI = prior(NextMII); + VRM->addSpillSlotUse(SS, StoreMI); + VRM->virtFolded(VirtReg, StoreMI, VirtRegMap::isMod); - return true; - } + return true; +} - /// OptimizeByUnfold - Turn a store folding instruction into a load folding - /// instruction. e.g. - /// xorl %edi, %eax - /// movl %eax, -32(%ebp) - /// movl -36(%ebp), %eax - /// orl %eax, -32(%ebp) - /// ==> - /// xorl %edi, %eax - /// orl -36(%ebp), %eax - /// mov %eax, -32(%ebp) - /// This enables unfolding optimization for a subsequent instruction which will - /// also eliminate the newly introduced store instruction. - bool OptimizeByUnfold(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MII, - std::vector<MachineInstr*> &MaybeDeadStores, - AvailableSpills &Spills, - BitVector &RegKills, - std::vector<MachineOperand*> &KillOps, - VirtRegMap &VRM) { - MachineFunction &MF = *MBB.getParent(); - MachineInstr &MI = *MII; - unsigned UnfoldedOpc = 0; - unsigned UnfoldPR = 0; - unsigned UnfoldVR = 0; - int FoldedSS = VirtRegMap::NO_STACK_SLOT; - VirtRegMap::MI2VirtMapTy::const_iterator I, End; - for (tie(I, End) = VRM.getFoldedVirts(&MI); I != End; ) { - // Only transform a MI that folds a single register. - if (UnfoldedOpc) - return false; - UnfoldVR = I->second.first; - VirtRegMap::ModRef MR = I->second.second; - // MI2VirtMap be can updated which invalidate the iterator. - // Increment the iterator first. - ++I; - if (VRM.isAssignedReg(UnfoldVR)) +/// OptimizeByUnfold - Turn a store folding instruction into a load folding +/// instruction. e.g. +/// xorl %edi, %eax +/// movl %eax, -32(%ebp) +/// movl -36(%ebp), %eax +/// orl %eax, -32(%ebp) +/// ==> +/// xorl %edi, %eax +/// orl -36(%ebp), %eax +/// mov %eax, -32(%ebp) +/// This enables unfolding optimization for a subsequent instruction which will +/// also eliminate the newly introduced store instruction. +bool LocalRewriter:: +OptimizeByUnfold(MachineBasicBlock::iterator &MII, + std::vector<MachineInstr*> &MaybeDeadStores, + AvailableSpills &Spills, + BitVector &RegKills, + std::vector<MachineOperand*> &KillOps) { + MachineFunction &MF = *MBB->getParent(); + MachineInstr &MI = *MII; + unsigned UnfoldedOpc = 0; + unsigned UnfoldPR = 0; + unsigned UnfoldVR = 0; + int FoldedSS = VirtRegMap::NO_STACK_SLOT; + VirtRegMap::MI2VirtMapTy::const_iterator I, End; + for (tie(I, End) = VRM->getFoldedVirts(&MI); I != End; ) { + // Only transform a MI that folds a single register. + if (UnfoldedOpc) + return false; + UnfoldVR = I->second.first; + VirtRegMap::ModRef MR = I->second.second; + // MI2VirtMap be can updated which invalidate the iterator. + // Increment the iterator first. + ++I; + if (VRM->isAssignedReg(UnfoldVR)) + continue; + // If this reference is not a use, any previous store is now dead. + // Otherwise, the store to this stack slot is not dead anymore. + FoldedSS = VRM->getStackSlot(UnfoldVR); + MachineInstr* DeadStore = MaybeDeadStores[FoldedSS]; + if (DeadStore && (MR & VirtRegMap::isModRef)) { + unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(FoldedSS); + if (!PhysReg || !DeadStore->readsRegister(PhysReg)) continue; - // If this reference is not a use, any previous store is now dead. - // Otherwise, the store to this stack slot is not dead anymore. - FoldedSS = VRM.getStackSlot(UnfoldVR); - MachineInstr* DeadStore = MaybeDeadStores[FoldedSS]; - if (DeadStore && (MR & VirtRegMap::isModRef)) { - unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(FoldedSS); - if (!PhysReg || !DeadStore->readsRegister(PhysReg)) - continue; - UnfoldPR = PhysReg; - UnfoldedOpc = TII->getOpcodeAfterMemoryUnfold(MI.getOpcode(), - false, true); - } + UnfoldPR = PhysReg; + UnfoldedOpc = TII->getOpcodeAfterMemoryUnfold(MI.getOpcode(), + false, true); } + } - if (!UnfoldedOpc) { - if (!UnfoldVR) - return false; + if (!UnfoldedOpc) { + if (!UnfoldVR) + return false; - // Look for other unfolding opportunities. - return OptimizeByUnfold2(UnfoldVR, FoldedSS, MBB, MII, - MaybeDeadStores, Spills, RegKills, KillOps, VRM); - } + // Look for other unfolding opportunities. + return OptimizeByUnfold2(UnfoldVR, FoldedSS, MII, MaybeDeadStores, Spills, + RegKills, KillOps); + } - for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI.getOperand(i); - if (!MO.isReg() || MO.getReg() == 0 || !MO.isUse()) - continue; - unsigned VirtReg = MO.getReg(); - if (TargetRegisterInfo::isPhysicalRegister(VirtReg) || MO.getSubReg()) - continue; - if (VRM.isAssignedReg(VirtReg)) { - unsigned PhysReg = VRM.getPhys(VirtReg); - if (PhysReg && TRI->regsOverlap(PhysReg, UnfoldPR)) - return false; - } else if (VRM.isReMaterialized(VirtReg)) - continue; - int SS = VRM.getStackSlot(VirtReg); - unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SS); - if (PhysReg) { - if (TRI->regsOverlap(PhysReg, UnfoldPR)) - return false; + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI.getOperand(i); + if (!MO.isReg() || MO.getReg() == 0 || !MO.isUse()) + continue; + unsigned VirtReg = MO.getReg(); + if (TargetRegisterInfo::isPhysicalRegister(VirtReg) || MO.getSubReg()) + continue; + if (VRM->isAssignedReg(VirtReg)) { + unsigned PhysReg = VRM->getPhys(VirtReg); + if (PhysReg && TRI->regsOverlap(PhysReg, UnfoldPR)) + return false; + } else if (VRM->isReMaterialized(VirtReg)) + continue; + int SS = VRM->getStackSlot(VirtReg); + unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SS); + if (PhysReg) { + if (TRI->regsOverlap(PhysReg, UnfoldPR)) + return false; + continue; + } + if (VRM->hasPhys(VirtReg)) { + PhysReg = VRM->getPhys(VirtReg); + if (!TRI->regsOverlap(PhysReg, UnfoldPR)) continue; - } - if (VRM.hasPhys(VirtReg)) { - PhysReg = VRM.getPhys(VirtReg); - if (!TRI->regsOverlap(PhysReg, UnfoldPR)) - continue; - } + } - // Ok, we'll need to reload the value into a register which makes - // it impossible to perform the store unfolding optimization later. - // Let's see if it is possible to fold the load if the store is - // unfolded. This allows us to perform the store unfolding - // optimization. - SmallVector<MachineInstr*, 4> NewMIs; - if (TII->unfoldMemoryOperand(MF, &MI, UnfoldVR, false, false, NewMIs)) { - assert(NewMIs.size() == 1); - MachineInstr *NewMI = NewMIs.back(); - NewMIs.clear(); - int Idx = NewMI->findRegisterUseOperandIdx(VirtReg, false); - assert(Idx != -1); - SmallVector<unsigned, 1> Ops; - Ops.push_back(Idx); - MachineInstr *FoldedMI = TII->foldMemoryOperand(MF, NewMI, Ops, SS); - if (FoldedMI) { - VRM.addSpillSlotUse(SS, FoldedMI); - if (!VRM.hasPhys(UnfoldVR)) - VRM.assignVirt2Phys(UnfoldVR, UnfoldPR); - VRM.virtFolded(VirtReg, FoldedMI, VirtRegMap::isRef); - MII = MBB.insert(MII, FoldedMI); - InvalidateKills(MI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(&MI); - MBB.erase(&MI); - MF.DeleteMachineInstr(NewMI); - return true; - } + // Ok, we'll need to reload the value into a register which makes + // it impossible to perform the store unfolding optimization later. + // Let's see if it is possible to fold the load if the store is + // unfolded. This allows us to perform the store unfolding + // optimization. + SmallVector<MachineInstr*, 4> NewMIs; + if (TII->unfoldMemoryOperand(MF, &MI, UnfoldVR, false, false, NewMIs)) { + assert(NewMIs.size() == 1); + MachineInstr *NewMI = NewMIs.back(); + NewMIs.clear(); + int Idx = NewMI->findRegisterUseOperandIdx(VirtReg, false); + assert(Idx != -1); + SmallVector<unsigned, 1> Ops; + Ops.push_back(Idx); + MachineInstr *FoldedMI = TII->foldMemoryOperand(MF, NewMI, Ops, SS); + if (FoldedMI) { + VRM->addSpillSlotUse(SS, FoldedMI); + if (!VRM->hasPhys(UnfoldVR)) + VRM->assignVirt2Phys(UnfoldVR, UnfoldPR); + VRM->virtFolded(VirtReg, FoldedMI, VirtRegMap::isRef); + MII = MBB->insert(MII, FoldedMI); + InvalidateKills(MI, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(&MI); + MBB->erase(&MI); MF.DeleteMachineInstr(NewMI); + return true; } + MF.DeleteMachineInstr(NewMI); } + } + return false; +} + +/// CommuteChangesDestination - We are looking for r0 = op r1, r2 and +/// where SrcReg is r1 and it is tied to r0. Return true if after +/// commuting this instruction it will be r0 = op r2, r1. +static bool CommuteChangesDestination(MachineInstr *DefMI, + const TargetInstrDesc &TID, + unsigned SrcReg, + const TargetInstrInfo *TII, + unsigned &DstIdx) { + if (TID.getNumDefs() != 1 && TID.getNumOperands() != 3) + return false; + if (!DefMI->getOperand(1).isReg() || + DefMI->getOperand(1).getReg() != SrcReg) + return false; + unsigned DefIdx; + if (!DefMI->isRegTiedToDefOperand(1, &DefIdx) || DefIdx != 0) return false; + unsigned SrcIdx1, SrcIdx2; + if (!TII->findCommutedOpIndices(DefMI, SrcIdx1, SrcIdx2)) + return false; + if (SrcIdx1 == 1 && SrcIdx2 == 2) { + DstIdx = 2; + return true; } + return false; +} + +/// CommuteToFoldReload - +/// Look for +/// r1 = load fi#1 +/// r1 = op r1, r2<kill> +/// store r1, fi#1 +/// +/// If op is commutable and r2 is killed, then we can xform these to +/// r2 = op r2, fi#1 +/// store r2, fi#1 +bool LocalRewriter:: +CommuteToFoldReload(MachineBasicBlock::iterator &MII, + unsigned VirtReg, unsigned SrcReg, int SS, + AvailableSpills &Spills, + BitVector &RegKills, + std::vector<MachineOperand*> &KillOps, + const TargetRegisterInfo *TRI) { + if (MII == MBB->begin() || !MII->killsRegister(SrcReg)) + return false; - /// CommuteChangesDestination - We are looking for r0 = op r1, r2 and - /// where SrcReg is r1 and it is tied to r0. Return true if after - /// commuting this instruction it will be r0 = op r2, r1. - static bool CommuteChangesDestination(MachineInstr *DefMI, - const TargetInstrDesc &TID, - unsigned SrcReg, - const TargetInstrInfo *TII, - unsigned &DstIdx) { - if (TID.getNumDefs() != 1 && TID.getNumOperands() != 3) + MachineFunction &MF = *MBB->getParent(); + MachineInstr &MI = *MII; + MachineBasicBlock::iterator DefMII = prior(MII); + MachineInstr *DefMI = DefMII; + const TargetInstrDesc &TID = DefMI->getDesc(); + unsigned NewDstIdx; + if (DefMII != MBB->begin() && + TID.isCommutable() && + CommuteChangesDestination(DefMI, TID, SrcReg, TII, NewDstIdx)) { + MachineOperand &NewDstMO = DefMI->getOperand(NewDstIdx); + unsigned NewReg = NewDstMO.getReg(); + if (!NewDstMO.isKill() || TRI->regsOverlap(NewReg, SrcReg)) return false; - if (!DefMI->getOperand(1).isReg() || - DefMI->getOperand(1).getReg() != SrcReg) + MachineInstr *ReloadMI = prior(DefMII); + int FrameIdx; + unsigned DestReg = TII->isLoadFromStackSlot(ReloadMI, FrameIdx); + if (DestReg != SrcReg || FrameIdx != SS) return false; - unsigned DefIdx; - if (!DefMI->isRegTiedToDefOperand(1, &DefIdx) || DefIdx != 0) + int UseIdx = DefMI->findRegisterUseOperandIdx(DestReg, false); + if (UseIdx == -1) return false; - unsigned SrcIdx1, SrcIdx2; - if (!TII->findCommutedOpIndices(DefMI, SrcIdx1, SrcIdx2)) + unsigned DefIdx; + if (!MI.isRegTiedToDefOperand(UseIdx, &DefIdx)) return false; - if (SrcIdx1 == 1 && SrcIdx2 == 2) { - DstIdx = 2; - return true; - } - return false; - } + assert(DefMI->getOperand(DefIdx).isReg() && + DefMI->getOperand(DefIdx).getReg() == SrcReg); - /// CommuteToFoldReload - - /// Look for - /// r1 = load fi#1 - /// r1 = op r1, r2<kill> - /// store r1, fi#1 - /// - /// If op is commutable and r2 is killed, then we can xform these to - /// r2 = op r2, fi#1 - /// store r2, fi#1 - bool CommuteToFoldReload(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MII, - unsigned VirtReg, unsigned SrcReg, int SS, - AvailableSpills &Spills, - BitVector &RegKills, - std::vector<MachineOperand*> &KillOps, - const TargetRegisterInfo *TRI, - VirtRegMap &VRM) { - if (MII == MBB.begin() || !MII->killsRegister(SrcReg)) + // Now commute def instruction. + MachineInstr *CommutedMI = TII->commuteInstruction(DefMI, true); + if (!CommutedMI) + return false; + SmallVector<unsigned, 1> Ops; + Ops.push_back(NewDstIdx); + MachineInstr *FoldedMI = TII->foldMemoryOperand(MF, CommutedMI, Ops, SS); + // Not needed since foldMemoryOperand returns new MI. + MF.DeleteMachineInstr(CommutedMI); + if (!FoldedMI) return false; - MachineFunction &MF = *MBB.getParent(); - MachineInstr &MI = *MII; - MachineBasicBlock::iterator DefMII = prior(MII); - MachineInstr *DefMI = DefMII; - const TargetInstrDesc &TID = DefMI->getDesc(); - unsigned NewDstIdx; - if (DefMII != MBB.begin() && - TID.isCommutable() && - CommuteChangesDestination(DefMI, TID, SrcReg, TII, NewDstIdx)) { - MachineOperand &NewDstMO = DefMI->getOperand(NewDstIdx); - unsigned NewReg = NewDstMO.getReg(); - if (!NewDstMO.isKill() || TRI->regsOverlap(NewReg, SrcReg)) - return false; - MachineInstr *ReloadMI = prior(DefMII); - int FrameIdx; - unsigned DestReg = TII->isLoadFromStackSlot(ReloadMI, FrameIdx); - if (DestReg != SrcReg || FrameIdx != SS) - return false; - int UseIdx = DefMI->findRegisterUseOperandIdx(DestReg, false); - if (UseIdx == -1) - return false; - unsigned DefIdx; - if (!MI.isRegTiedToDefOperand(UseIdx, &DefIdx)) - return false; - assert(DefMI->getOperand(DefIdx).isReg() && - DefMI->getOperand(DefIdx).getReg() == SrcReg); + VRM->addSpillSlotUse(SS, FoldedMI); + VRM->virtFolded(VirtReg, FoldedMI, VirtRegMap::isRef); + // Insert new def MI and spill MI. + const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); + TII->storeRegToStackSlot(*MBB, &MI, NewReg, true, SS, RC); + MII = prior(MII); + MachineInstr *StoreMI = MII; + VRM->addSpillSlotUse(SS, StoreMI); + VRM->virtFolded(VirtReg, StoreMI, VirtRegMap::isMod); + MII = MBB->insert(MII, FoldedMI); // Update MII to backtrack. + + // Delete all 3 old instructions. + InvalidateKills(*ReloadMI, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(ReloadMI); + MBB->erase(ReloadMI); + InvalidateKills(*DefMI, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(DefMI); + MBB->erase(DefMI); + InvalidateKills(MI, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(&MI); + MBB->erase(&MI); - // Now commute def instruction. - MachineInstr *CommutedMI = TII->commuteInstruction(DefMI, true); - if (!CommutedMI) - return false; - SmallVector<unsigned, 1> Ops; - Ops.push_back(NewDstIdx); - MachineInstr *FoldedMI = TII->foldMemoryOperand(MF, CommutedMI, Ops, SS); - // Not needed since foldMemoryOperand returns new MI. - MF.DeleteMachineInstr(CommutedMI); - if (!FoldedMI) - return false; + // If NewReg was previously holding value of some SS, it's now clobbered. + // This has to be done now because it's a physical register. When this + // instruction is re-visited, it's ignored. + Spills.ClobberPhysReg(NewReg); - VRM.addSpillSlotUse(SS, FoldedMI); - VRM.virtFolded(VirtReg, FoldedMI, VirtRegMap::isRef); - // Insert new def MI and spill MI. - const TargetRegisterClass* RC = RegInfo->getRegClass(VirtReg); - TII->storeRegToStackSlot(MBB, &MI, NewReg, true, SS, RC); - MII = prior(MII); - MachineInstr *StoreMI = MII; - VRM.addSpillSlotUse(SS, StoreMI); - VRM.virtFolded(VirtReg, StoreMI, VirtRegMap::isMod); - MII = MBB.insert(MII, FoldedMI); // Update MII to backtrack. - - // Delete all 3 old instructions. - InvalidateKills(*ReloadMI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(ReloadMI); - MBB.erase(ReloadMI); - InvalidateKills(*DefMI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(DefMI); - MBB.erase(DefMI); - InvalidateKills(MI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(&MI); - MBB.erase(&MI); + ++NumCommutes; + return true; + } - // If NewReg was previously holding value of some SS, it's now clobbered. - // This has to be done now because it's a physical register. When this - // instruction is re-visited, it's ignored. - Spills.ClobberPhysReg(NewReg); + return false; +} - ++NumCommutes; - return true; +/// SpillRegToStackSlot - Spill a register to a specified stack slot. Check if +/// the last store to the same slot is now dead. If so, remove the last store. +void LocalRewriter:: +SpillRegToStackSlot(MachineBasicBlock::iterator &MII, + int Idx, unsigned PhysReg, int StackSlot, + const TargetRegisterClass *RC, + bool isAvailable, MachineInstr *&LastStore, + AvailableSpills &Spills, + SmallSet<MachineInstr*, 4> &ReMatDefs, + BitVector &RegKills, + std::vector<MachineOperand*> &KillOps) { + + MachineBasicBlock::iterator oldNextMII = llvm::next(MII); + TII->storeRegToStackSlot(*MBB, llvm::next(MII), PhysReg, true, StackSlot, RC); + MachineInstr *StoreMI = prior(oldNextMII); + VRM->addSpillSlotUse(StackSlot, StoreMI); + DEBUG(dbgs() << "Store:\t" << *StoreMI); + + // If there is a dead store to this stack slot, nuke it now. + if (LastStore) { + DEBUG(dbgs() << "Removed dead store:\t" << *LastStore); + ++NumDSE; + SmallVector<unsigned, 2> KillRegs; + InvalidateKills(*LastStore, TRI, RegKills, KillOps, &KillRegs); + MachineBasicBlock::iterator PrevMII = LastStore; + bool CheckDef = PrevMII != MBB->begin(); + if (CheckDef) + --PrevMII; + VRM->RemoveMachineInstrFromMaps(LastStore); + MBB->erase(LastStore); + if (CheckDef) { + // Look at defs of killed registers on the store. Mark the defs + // as dead since the store has been deleted and they aren't + // being reused. + for (unsigned j = 0, ee = KillRegs.size(); j != ee; ++j) { + bool HasOtherDef = false; + if (InvalidateRegDef(PrevMII, *MII, KillRegs[j], HasOtherDef, TRI)) { + MachineInstr *DeadDef = PrevMII; + if (ReMatDefs.count(DeadDef) && !HasOtherDef) { + // FIXME: This assumes a remat def does not have side effects. + VRM->RemoveMachineInstrFromMaps(DeadDef); + MBB->erase(DeadDef); + ++NumDRM; + } + } + } } + } + + // Allow for multi-instruction spill sequences, as on PPC Altivec. Presume + // the last of multiple instructions is the actual store. + LastStore = prior(oldNextMII); + + // If the stack slot value was previously available in some other + // register, change it now. Otherwise, make the register available, + // in PhysReg. + Spills.ModifyStackSlotOrReMat(StackSlot); + Spills.ClobberPhysReg(PhysReg); + Spills.addAvailable(StackSlot, PhysReg, isAvailable); + ++NumStores; +} +/// isSafeToDelete - Return true if this instruction doesn't produce any side +/// effect and all of its defs are dead. +static bool isSafeToDelete(MachineInstr &MI) { + const TargetInstrDesc &TID = MI.getDesc(); + if (TID.mayLoad() || TID.mayStore() || TID.isCall() || TID.isTerminator() || + TID.isCall() || TID.isBarrier() || TID.isReturn() || + TID.hasUnmodeledSideEffects()) return false; + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI.getOperand(i); + if (!MO.isReg() || !MO.getReg()) + continue; + if (MO.isDef() && !MO.isDead()) + return false; + if (MO.isUse() && MO.isKill()) + // FIXME: We can't remove kill markers or else the scavenger will assert. + // An alternative is to add a ADD pseudo instruction to replace kill + // markers. + return false; } + return true; +} - /// SpillRegToStackSlot - Spill a register to a specified stack slot. Check if - /// the last store to the same slot is now dead. If so, remove the last store. - void SpillRegToStackSlot(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MII, - int Idx, unsigned PhysReg, int StackSlot, - const TargetRegisterClass *RC, - bool isAvailable, MachineInstr *&LastStore, - AvailableSpills &Spills, - SmallSet<MachineInstr*, 4> &ReMatDefs, - BitVector &RegKills, - std::vector<MachineOperand*> &KillOps, - VirtRegMap &VRM) { +/// TransferDeadness - A identity copy definition is dead and it's being +/// removed. Find the last def or use and mark it as dead / kill. +void LocalRewriter:: +TransferDeadness(unsigned Reg, BitVector &RegKills, + std::vector<MachineOperand*> &KillOps) { + SmallPtrSet<MachineInstr*, 4> Seens; + SmallVector<std::pair<MachineInstr*, int>,8> Refs; + for (MachineRegisterInfo::reg_iterator RI = MRI->reg_begin(Reg), + RE = MRI->reg_end(); RI != RE; ++RI) { + MachineInstr *UDMI = &*RI; + if (UDMI->getParent() != MBB) + continue; + DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(UDMI); + if (DI == DistanceMap.end()) + continue; + if (Seens.insert(UDMI)) + Refs.push_back(std::make_pair(UDMI, DI->second)); + } - MachineBasicBlock::iterator oldNextMII = llvm::next(MII); - TII->storeRegToStackSlot(MBB, llvm::next(MII), PhysReg, true, StackSlot, RC); - MachineInstr *StoreMI = prior(oldNextMII); - VRM.addSpillSlotUse(StackSlot, StoreMI); - DEBUG(dbgs() << "Store:\t" << *StoreMI); + if (Refs.empty()) + return; + std::sort(Refs.begin(), Refs.end(), RefSorter()); - // If there is a dead store to this stack slot, nuke it now. - if (LastStore) { - DEBUG(dbgs() << "Removed dead store:\t" << *LastStore); - ++NumDSE; - SmallVector<unsigned, 2> KillRegs; - InvalidateKills(*LastStore, TRI, RegKills, KillOps, &KillRegs); - MachineBasicBlock::iterator PrevMII = LastStore; - bool CheckDef = PrevMII != MBB.begin(); - if (CheckDef) - --PrevMII; - VRM.RemoveMachineInstrFromMaps(LastStore); - MBB.erase(LastStore); - if (CheckDef) { - // Look at defs of killed registers on the store. Mark the defs - // as dead since the store has been deleted and they aren't - // being reused. - for (unsigned j = 0, ee = KillRegs.size(); j != ee; ++j) { - bool HasOtherDef = false; - if (InvalidateRegDef(PrevMII, *MII, KillRegs[j], HasOtherDef, TRI)) { - MachineInstr *DeadDef = PrevMII; - if (ReMatDefs.count(DeadDef) && !HasOtherDef) { - // FIXME: This assumes a remat def does not have side effects. - VRM.RemoveMachineInstrFromMaps(DeadDef); - MBB.erase(DeadDef); - ++NumDRM; - } - } - } + while (!Refs.empty()) { + MachineInstr *LastUDMI = Refs.back().first; + Refs.pop_back(); + + MachineOperand *LastUD = NULL; + for (unsigned i = 0, e = LastUDMI->getNumOperands(); i != e; ++i) { + MachineOperand &MO = LastUDMI->getOperand(i); + if (!MO.isReg() || MO.getReg() != Reg) + continue; + if (!LastUD || (LastUD->isUse() && MO.isDef())) + LastUD = &MO; + if (LastUDMI->isRegTiedToDefOperand(i)) + break; + } + if (LastUD->isDef()) { + // If the instruction has no side effect, delete it and propagate + // backward further. Otherwise, mark is dead and we are done. + if (!isSafeToDelete(*LastUDMI)) { + LastUD->setIsDead(); + break; } + VRM->RemoveMachineInstrFromMaps(LastUDMI); + MBB->erase(LastUDMI); + } else { + LastUD->setIsKill(); + RegKills.set(Reg); + KillOps[Reg] = LastUD; + break; } + } +} + +/// InsertEmergencySpills - Insert emergency spills before MI if requested by +/// VRM. Return true if spills were inserted. +bool LocalRewriter::InsertEmergencySpills(MachineInstr *MI) { + if (!VRM->hasEmergencySpills(MI)) + return false; + MachineBasicBlock::iterator MII = MI; + SmallSet<int, 4> UsedSS; + std::vector<unsigned> &EmSpills = VRM->getEmergencySpills(MI); + for (unsigned i = 0, e = EmSpills.size(); i != e; ++i) { + unsigned PhysReg = EmSpills[i]; + const TargetRegisterClass *RC = TRI->getPhysicalRegisterRegClass(PhysReg); + assert(RC && "Unable to determine register class!"); + int SS = VRM->getEmergencySpillSlot(RC); + if (UsedSS.count(SS)) + llvm_unreachable("Need to spill more than one physical registers!"); + UsedSS.insert(SS); + TII->storeRegToStackSlot(*MBB, MII, PhysReg, true, SS, RC); + MachineInstr *StoreMI = prior(MII); + VRM->addSpillSlotUse(SS, StoreMI); + + // Back-schedule reloads and remats. + MachineBasicBlock::iterator InsertLoc = + ComputeReloadLoc(llvm::next(MII), MBB->begin(), PhysReg, TRI, false, SS, + TII, *MBB->getParent()); + + TII->loadRegFromStackSlot(*MBB, InsertLoc, PhysReg, SS, RC); - // Allow for multi-instruction spill sequences, as on PPC Altivec. Presume - // the last of multiple instructions is the actual store. - LastStore = prior(oldNextMII); - - // If the stack slot value was previously available in some other - // register, change it now. Otherwise, make the register available, - // in PhysReg. - Spills.ModifyStackSlotOrReMat(StackSlot); - Spills.ClobberPhysReg(PhysReg); - Spills.addAvailable(StackSlot, PhysReg, isAvailable); - ++NumStores; + MachineInstr *LoadMI = prior(InsertLoc); + VRM->addSpillSlotUse(SS, LoadMI); + ++NumPSpills; + DistanceMap.insert(std::make_pair(LoadMI, DistanceMap.size())); } + return true; +} - /// isSafeToDelete - Return true if this instruction doesn't produce any side - /// effect and all of its defs are dead. - static bool isSafeToDelete(MachineInstr &MI) { - const TargetInstrDesc &TID = MI.getDesc(); - if (TID.mayLoad() || TID.mayStore() || TID.isCall() || TID.isTerminator() || - TID.isCall() || TID.isBarrier() || TID.isReturn() || - TID.hasUnmodeledSideEffects()) - return false; - for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI.getOperand(i); - if (!MO.isReg() || !MO.getReg()) - continue; - if (MO.isDef() && !MO.isDead()) - return false; - if (MO.isUse() && MO.isKill()) - // FIXME: We can't remove kill markers or else the scavenger will assert. - // An alternative is to add a ADD pseudo instruction to replace kill - // markers. - return false; +/// InsertRestores - Restore registers before MI is requested by VRM. Return +/// true is any instructions were inserted. +bool LocalRewriter::InsertRestores(MachineInstr *MI, + AvailableSpills &Spills, + BitVector &RegKills, + std::vector<MachineOperand*> &KillOps) { + if (!VRM->isRestorePt(MI)) + return false; + MachineBasicBlock::iterator MII = MI; + std::vector<unsigned> &RestoreRegs = VRM->getRestorePtRestores(MI); + for (unsigned i = 0, e = RestoreRegs.size(); i != e; ++i) { + unsigned VirtReg = RestoreRegs[e-i-1]; // Reverse order. + if (!VRM->getPreSplitReg(VirtReg)) + continue; // Split interval spilled again. + unsigned Phys = VRM->getPhys(VirtReg); + MRI->setPhysRegUsed(Phys); + + // Check if the value being restored if available. If so, it must be + // from a predecessor BB that fallthrough into this BB. We do not + // expect: + // BB1: + // r1 = load fi#1 + // ... + // = r1<kill> + // ... # r1 not clobbered + // ... + // = load fi#1 + bool DoReMat = VRM->isReMaterialized(VirtReg); + int SSorRMId = DoReMat + ? VRM->getReMatId(VirtReg) : VRM->getStackSlot(VirtReg); + const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); + unsigned InReg = Spills.getSpillSlotOrReMatPhysReg(SSorRMId); + if (InReg == Phys) { + // If the value is already available in the expected register, save + // a reload / remat. + if (SSorRMId) + DEBUG(dbgs() << "Reusing RM#" + << SSorRMId-VirtRegMap::MAX_STACK_SLOT-1); + else + DEBUG(dbgs() << "Reusing SS#" << SSorRMId); + DEBUG(dbgs() << " from physreg " + << TRI->getName(InReg) << " for vreg" + << VirtReg <<" instead of reloading into physreg " + << TRI->getName(Phys) << '\n'); + ++NumOmitted; + continue; + } else if (InReg && InReg != Phys) { + if (SSorRMId) + DEBUG(dbgs() << "Reusing RM#" + << SSorRMId-VirtRegMap::MAX_STACK_SLOT-1); + else + DEBUG(dbgs() << "Reusing SS#" << SSorRMId); + DEBUG(dbgs() << " from physreg " + << TRI->getName(InReg) << " for vreg" + << VirtReg <<" by copying it into physreg " + << TRI->getName(Phys) << '\n'); + + // If the reloaded / remat value is available in another register, + // copy it to the desired register. + + // Back-schedule reloads and remats. + MachineBasicBlock::iterator InsertLoc = + ComputeReloadLoc(MII, MBB->begin(), Phys, TRI, DoReMat, SSorRMId, TII, + *MBB->getParent()); + + TII->copyRegToReg(*MBB, InsertLoc, Phys, InReg, RC, RC); + + // This invalidates Phys. + Spills.ClobberPhysReg(Phys); + // Remember it's available. + Spills.addAvailable(SSorRMId, Phys); + + // Mark is killed. + MachineInstr *CopyMI = prior(InsertLoc); + CopyMI->setAsmPrinterFlag(MachineInstr::ReloadReuse); + MachineOperand *KillOpnd = CopyMI->findRegisterUseOperand(InReg); + KillOpnd->setIsKill(); + UpdateKills(*CopyMI, TRI, RegKills, KillOps); + + DEBUG(dbgs() << '\t' << *CopyMI); + ++NumCopified; + continue; } - return true; - } - /// TransferDeadness - A identity copy definition is dead and it's being - /// removed. Find the last def or use and mark it as dead / kill. - void TransferDeadness(MachineBasicBlock *MBB, unsigned CurDist, - unsigned Reg, BitVector &RegKills, - std::vector<MachineOperand*> &KillOps, - VirtRegMap &VRM) { - SmallPtrSet<MachineInstr*, 4> Seens; - SmallVector<std::pair<MachineInstr*, int>,8> Refs; - for (MachineRegisterInfo::reg_iterator RI = RegInfo->reg_begin(Reg), - RE = RegInfo->reg_end(); RI != RE; ++RI) { - MachineInstr *UDMI = &*RI; - if (UDMI->getParent() != MBB) - continue; - DenseMap<MachineInstr*, unsigned>::iterator DI = DistanceMap.find(UDMI); - if (DI == DistanceMap.end() || DI->second > CurDist) - continue; - if (Seens.insert(UDMI)) - Refs.push_back(std::make_pair(UDMI, DI->second)); + // Back-schedule reloads and remats. + MachineBasicBlock::iterator InsertLoc = + ComputeReloadLoc(MII, MBB->begin(), Phys, TRI, DoReMat, SSorRMId, TII, + *MBB->getParent()); + + if (VRM->isReMaterialized(VirtReg)) { + ReMaterialize(*MBB, InsertLoc, Phys, VirtReg, TII, TRI, *VRM); + } else { + const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); + TII->loadRegFromStackSlot(*MBB, InsertLoc, Phys, SSorRMId, RC); + MachineInstr *LoadMI = prior(InsertLoc); + VRM->addSpillSlotUse(SSorRMId, LoadMI); + ++NumLoads; + DistanceMap.insert(std::make_pair(LoadMI, DistanceMap.size())); } - if (Refs.empty()) - return; - std::sort(Refs.begin(), Refs.end(), RefSorter()); + // This invalidates Phys. + Spills.ClobberPhysReg(Phys); + // Remember it's available. + Spills.addAvailable(SSorRMId, Phys); - while (!Refs.empty()) { - MachineInstr *LastUDMI = Refs.back().first; - Refs.pop_back(); + UpdateKills(*prior(InsertLoc), TRI, RegKills, KillOps); + DEBUG(dbgs() << '\t' << *prior(MII)); + } + return true; +} - MachineOperand *LastUD = NULL; - for (unsigned i = 0, e = LastUDMI->getNumOperands(); i != e; ++i) { - MachineOperand &MO = LastUDMI->getOperand(i); - if (!MO.isReg() || MO.getReg() != Reg) - continue; - if (!LastUD || (LastUD->isUse() && MO.isDef())) - LastUD = &MO; - if (LastUDMI->isRegTiedToDefOperand(i)) - break; - } - if (LastUD->isDef()) { - // If the instruction has no side effect, delete it and propagate - // backward further. Otherwise, mark is dead and we are done. - if (!isSafeToDelete(*LastUDMI)) { - LastUD->setIsDead(); - break; - } - VRM.RemoveMachineInstrFromMaps(LastUDMI); - MBB->erase(LastUDMI); - } else { - LastUD->setIsKill(); - RegKills.set(Reg); - KillOps[Reg] = LastUD; - break; - } - } +/// InsertEmergencySpills - Insert spills after MI if requested by VRM. Return +/// true if spills were inserted. +bool LocalRewriter::InsertSpills(MachineInstr *MI) { + if (!VRM->isSpillPt(MI)) + return false; + MachineBasicBlock::iterator MII = MI; + std::vector<std::pair<unsigned,bool> > &SpillRegs = + VRM->getSpillPtSpills(MI); + for (unsigned i = 0, e = SpillRegs.size(); i != e; ++i) { + unsigned VirtReg = SpillRegs[i].first; + bool isKill = SpillRegs[i].second; + if (!VRM->getPreSplitReg(VirtReg)) + continue; // Split interval spilled again. + const TargetRegisterClass *RC = MRI->getRegClass(VirtReg); + unsigned Phys = VRM->getPhys(VirtReg); + int StackSlot = VRM->getStackSlot(VirtReg); + MachineBasicBlock::iterator oldNextMII = llvm::next(MII); + TII->storeRegToStackSlot(*MBB, llvm::next(MII), Phys, isKill, StackSlot, + RC); + MachineInstr *StoreMI = prior(oldNextMII); + VRM->addSpillSlotUse(StackSlot, StoreMI); + DEBUG(dbgs() << "Store:\t" << *StoreMI); + VRM->virtFolded(VirtReg, StoreMI, VirtRegMap::isMod); } + return true; +} - /// rewriteMBB - Keep track of which spills are available even after the - /// register allocator is done with them. If possible, avid reloading vregs. - void RewriteMBB(MachineBasicBlock &MBB, VirtRegMap &VRM, - LiveIntervals *LIs, - AvailableSpills &Spills, BitVector &RegKills, - std::vector<MachineOperand*> &KillOps) { - DEBUG(dbgs() << "\n**** Local spiller rewriting MBB '" - << MBB.getName() << "':\n"); - - MachineFunction &MF = *MBB.getParent(); - - // MaybeDeadStores - When we need to write a value back into a stack slot, - // keep track of the inserted store. If the stack slot value is never read - // (because the value was used from some available register, for example), and - // subsequently stored to, the original store is dead. This map keeps track - // of inserted stores that are not used. If we see a subsequent store to the - // same stack slot, the original store is deleted. - std::vector<MachineInstr*> MaybeDeadStores; - MaybeDeadStores.resize(MF.getFrameInfo()->getObjectIndexEnd(), NULL); - - // ReMatDefs - These are rematerializable def MIs which are not deleted. - SmallSet<MachineInstr*, 4> ReMatDefs; - - // Clear kill info. - SmallSet<unsigned, 2> KilledMIRegs; - RegKills.reset(); - KillOps.clear(); - KillOps.resize(TRI->getNumRegs(), NULL); - - unsigned Dist = 0; - DistanceMap.clear(); - for (MachineBasicBlock::iterator MII = MBB.begin(), E = MBB.end(); - MII != E; ) { - MachineBasicBlock::iterator NextMII = llvm::next(MII); - - VirtRegMap::MI2VirtMapTy::const_iterator I, End; - bool Erased = false; - bool BackTracked = false; - if (OptimizeByUnfold(MBB, MII, - MaybeDeadStores, Spills, RegKills, KillOps, VRM)) - NextMII = llvm::next(MII); +/// rewriteMBB - Keep track of which spills are available even after the +/// register allocator is done with them. If possible, avid reloading vregs. +void +LocalRewriter::RewriteMBB(LiveIntervals *LIs, + AvailableSpills &Spills, BitVector &RegKills, + std::vector<MachineOperand*> &KillOps) { - MachineInstr &MI = *MII; - - if (VRM.hasEmergencySpills(&MI)) { - // Spill physical register(s) in the rare case the allocator has run out - // of registers to allocate. - SmallSet<int, 4> UsedSS; - std::vector<unsigned> &EmSpills = VRM.getEmergencySpills(&MI); - for (unsigned i = 0, e = EmSpills.size(); i != e; ++i) { - unsigned PhysReg = EmSpills[i]; - const TargetRegisterClass *RC = - TRI->getPhysicalRegisterRegClass(PhysReg); - assert(RC && "Unable to determine register class!"); - int SS = VRM.getEmergencySpillSlot(RC); - if (UsedSS.count(SS)) - llvm_unreachable("Need to spill more than one physical registers!"); - UsedSS.insert(SS); - TII->storeRegToStackSlot(MBB, MII, PhysReg, true, SS, RC); - MachineInstr *StoreMI = prior(MII); - VRM.addSpillSlotUse(SS, StoreMI); - - // Back-schedule reloads and remats. - MachineBasicBlock::iterator InsertLoc = - ComputeReloadLoc(llvm::next(MII), MBB.begin(), PhysReg, TRI, false, - SS, TII, MF); - - TII->loadRegFromStackSlot(MBB, InsertLoc, PhysReg, SS, RC); + DEBUG(dbgs() << "\n**** Local spiller rewriting MBB '" + << MBB->getName() << "':\n"); - MachineInstr *LoadMI = prior(InsertLoc); - VRM.addSpillSlotUse(SS, LoadMI); - ++NumPSpills; - DistanceMap.insert(std::make_pair(LoadMI, Dist++)); - } - NextMII = llvm::next(MII); - } + MachineFunction &MF = *MBB->getParent(); - // Insert restores here if asked to. - if (VRM.isRestorePt(&MI)) { - std::vector<unsigned> &RestoreRegs = VRM.getRestorePtRestores(&MI); - for (unsigned i = 0, e = RestoreRegs.size(); i != e; ++i) { - unsigned VirtReg = RestoreRegs[e-i-1]; // Reverse order. - if (!VRM.getPreSplitReg(VirtReg)) - continue; // Split interval spilled again. - unsigned Phys = VRM.getPhys(VirtReg); - RegInfo->setPhysRegUsed(Phys); - - // Check if the value being restored if available. If so, it must be - // from a predecessor BB that fallthrough into this BB. We do not - // expect: - // BB1: - // r1 = load fi#1 - // ... - // = r1<kill> - // ... # r1 not clobbered - // ... - // = load fi#1 - bool DoReMat = VRM.isReMaterialized(VirtReg); - int SSorRMId = DoReMat - ? VRM.getReMatId(VirtReg) : VRM.getStackSlot(VirtReg); - const TargetRegisterClass* RC = RegInfo->getRegClass(VirtReg); - unsigned InReg = Spills.getSpillSlotOrReMatPhysReg(SSorRMId); - if (InReg == Phys) { - // If the value is already available in the expected register, save - // a reload / remat. - if (SSorRMId) - DEBUG(dbgs() << "Reusing RM#" - << SSorRMId-VirtRegMap::MAX_STACK_SLOT-1); - else - DEBUG(dbgs() << "Reusing SS#" << SSorRMId); - DEBUG(dbgs() << " from physreg " - << TRI->getName(InReg) << " for vreg" - << VirtReg <<" instead of reloading into physreg " - << TRI->getName(Phys) << '\n'); - ++NumOmitted; - continue; - } else if (InReg && InReg != Phys) { - if (SSorRMId) - DEBUG(dbgs() << "Reusing RM#" - << SSorRMId-VirtRegMap::MAX_STACK_SLOT-1); - else - DEBUG(dbgs() << "Reusing SS#" << SSorRMId); - DEBUG(dbgs() << " from physreg " - << TRI->getName(InReg) << " for vreg" - << VirtReg <<" by copying it into physreg " - << TRI->getName(Phys) << '\n'); - - // If the reloaded / remat value is available in another register, - // copy it to the desired register. - - // Back-schedule reloads and remats. - MachineBasicBlock::iterator InsertLoc = - ComputeReloadLoc(MII, MBB.begin(), Phys, TRI, DoReMat, - SSorRMId, TII, MF); - - TII->copyRegToReg(MBB, InsertLoc, Phys, InReg, RC, RC); - - // This invalidates Phys. - Spills.ClobberPhysReg(Phys); - // Remember it's available. - Spills.addAvailable(SSorRMId, Phys); - - // Mark is killed. - MachineInstr *CopyMI = prior(InsertLoc); - CopyMI->setAsmPrinterFlag(MachineInstr::ReloadReuse); - MachineOperand *KillOpnd = CopyMI->findRegisterUseOperand(InReg); - KillOpnd->setIsKill(); - UpdateKills(*CopyMI, TRI, RegKills, KillOps); - - DEBUG(dbgs() << '\t' << *CopyMI); - ++NumCopified; - continue; - } + // MaybeDeadStores - When we need to write a value back into a stack slot, + // keep track of the inserted store. If the stack slot value is never read + // (because the value was used from some available register, for example), and + // subsequently stored to, the original store is dead. This map keeps track + // of inserted stores that are not used. If we see a subsequent store to the + // same stack slot, the original store is deleted. + std::vector<MachineInstr*> MaybeDeadStores; + MaybeDeadStores.resize(MF.getFrameInfo()->getObjectIndexEnd(), NULL); - // Back-schedule reloads and remats. - MachineBasicBlock::iterator InsertLoc = - ComputeReloadLoc(MII, MBB.begin(), Phys, TRI, DoReMat, - SSorRMId, TII, MF); - - if (VRM.isReMaterialized(VirtReg)) { - ReMaterialize(MBB, InsertLoc, Phys, VirtReg, TII, TRI, VRM); - } else { - const TargetRegisterClass* RC = RegInfo->getRegClass(VirtReg); - TII->loadRegFromStackSlot(MBB, InsertLoc, Phys, SSorRMId, RC); - MachineInstr *LoadMI = prior(InsertLoc); - VRM.addSpillSlotUse(SSorRMId, LoadMI); - ++NumLoads; - DistanceMap.insert(std::make_pair(LoadMI, Dist++)); - } + // ReMatDefs - These are rematerializable def MIs which are not deleted. + SmallSet<MachineInstr*, 4> ReMatDefs; - // This invalidates Phys. - Spills.ClobberPhysReg(Phys); - // Remember it's available. - Spills.addAvailable(SSorRMId, Phys); + // Clear kill info. + SmallSet<unsigned, 2> KilledMIRegs; + RegKills.reset(); + KillOps.clear(); + KillOps.resize(TRI->getNumRegs(), NULL); - UpdateKills(*prior(InsertLoc), TRI, RegKills, KillOps); - DEBUG(dbgs() << '\t' << *prior(MII)); - } - } + DistanceMap.clear(); + for (MachineBasicBlock::iterator MII = MBB->begin(), E = MBB->end(); + MII != E; ) { + MachineBasicBlock::iterator NextMII = llvm::next(MII); - // Insert spills here if asked to. - if (VRM.isSpillPt(&MI)) { - std::vector<std::pair<unsigned,bool> > &SpillRegs = - VRM.getSpillPtSpills(&MI); - for (unsigned i = 0, e = SpillRegs.size(); i != e; ++i) { - unsigned VirtReg = SpillRegs[i].first; - bool isKill = SpillRegs[i].second; - if (!VRM.getPreSplitReg(VirtReg)) - continue; // Split interval spilled again. - const TargetRegisterClass *RC = RegInfo->getRegClass(VirtReg); - unsigned Phys = VRM.getPhys(VirtReg); - int StackSlot = VRM.getStackSlot(VirtReg); - MachineBasicBlock::iterator oldNextMII = llvm::next(MII); - TII->storeRegToStackSlot(MBB, llvm::next(MII), Phys, isKill, StackSlot, RC); - MachineInstr *StoreMI = prior(oldNextMII); - VRM.addSpillSlotUse(StackSlot, StoreMI); - DEBUG(dbgs() << "Store:\t" << *StoreMI); - VRM.virtFolded(VirtReg, StoreMI, VirtRegMap::isMod); - } - NextMII = llvm::next(MII); - } + if (OptimizeByUnfold(MII, MaybeDeadStores, Spills, RegKills, KillOps)) + NextMII = llvm::next(MII); - /// ReusedOperands - Keep track of operand reuse in case we need to undo - /// reuse. - ReuseInfo ReusedOperands(MI, TRI); - SmallVector<unsigned, 4> VirtUseOps; - for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI.getOperand(i); - if (!MO.isReg() || MO.getReg() == 0) - continue; // Ignore non-register operands. - - unsigned VirtReg = MO.getReg(); - if (TargetRegisterInfo::isPhysicalRegister(VirtReg)) { - // Ignore physregs for spilling, but remember that it is used by this - // function. - RegInfo->setPhysRegUsed(VirtReg); - continue; - } + if (InsertEmergencySpills(MII)) + NextMII = llvm::next(MII); + + InsertRestores(MII, Spills, RegKills, KillOps); + + if (InsertSpills(MII)) + NextMII = llvm::next(MII); + + VirtRegMap::MI2VirtMapTy::const_iterator I, End; + bool Erased = false; + bool BackTracked = false; + MachineInstr &MI = *MII; + + /// ReusedOperands - Keep track of operand reuse in case we need to undo + /// reuse. + ReuseInfo ReusedOperands(MI, TRI); + SmallVector<unsigned, 4> VirtUseOps; + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI.getOperand(i); + if (!MO.isReg() || MO.getReg() == 0) + continue; // Ignore non-register operands. - // We want to process implicit virtual register uses first. - if (MO.isImplicit()) - // If the virtual register is implicitly defined, emit a implicit_def - // before so scavenger knows it's "defined". - // FIXME: This is a horrible hack done the by register allocator to - // remat a definition with virtual register operand. - VirtUseOps.insert(VirtUseOps.begin(), i); - else - VirtUseOps.push_back(i); + unsigned VirtReg = MO.getReg(); + if (TargetRegisterInfo::isPhysicalRegister(VirtReg)) { + // Ignore physregs for spilling, but remember that it is used by this + // function. + MRI->setPhysRegUsed(VirtReg); + continue; } - // Process all of the spilled uses and all non spilled reg references. - SmallVector<int, 2> PotentialDeadStoreSlots; - KilledMIRegs.clear(); - for (unsigned j = 0, e = VirtUseOps.size(); j != e; ++j) { - unsigned i = VirtUseOps[j]; - unsigned VirtReg = MI.getOperand(i).getReg(); - assert(TargetRegisterInfo::isVirtualRegister(VirtReg) && - "Not a virtual register?"); - - unsigned SubIdx = MI.getOperand(i).getSubReg(); - if (VRM.isAssignedReg(VirtReg)) { - // This virtual register was assigned a physreg! - unsigned Phys = VRM.getPhys(VirtReg); - RegInfo->setPhysRegUsed(Phys); - if (MI.getOperand(i).isDef()) - ReusedOperands.markClobbered(Phys); - substitutePhysReg(MI.getOperand(i), Phys, *TRI); - if (VRM.isImplicitlyDefined(VirtReg)) - // FIXME: Is this needed? - BuildMI(MBB, &MI, MI.getDebugLoc(), - TII->get(TargetOpcode::IMPLICIT_DEF), Phys); - continue; - } + // We want to process implicit virtual register uses first. + if (MO.isImplicit()) + // If the virtual register is implicitly defined, emit a implicit_def + // before so scavenger knows it's "defined". + // FIXME: This is a horrible hack done the by register allocator to + // remat a definition with virtual register operand. + VirtUseOps.insert(VirtUseOps.begin(), i); + else + VirtUseOps.push_back(i); + } - // This virtual register is now known to be a spilled value. - if (!MI.getOperand(i).isUse()) - continue; // Handle defs in the loop below (handle use&def here though) - - bool AvoidReload = MI.getOperand(i).isUndef(); - // Check if it is defined by an implicit def. It should not be spilled. - // Note, this is for correctness reason. e.g. - // 8 %reg1024<def> = IMPLICIT_DEF - // 12 %reg1024<def> = INSERT_SUBREG %reg1024<kill>, %reg1025, 2 - // The live range [12, 14) are not part of the r1024 live interval since - // it's defined by an implicit def. It will not conflicts with live - // interval of r1025. Now suppose both registers are spilled, you can - // easily see a situation where both registers are reloaded before - // the INSERT_SUBREG and both target registers that would overlap. - bool DoReMat = VRM.isReMaterialized(VirtReg); - int SSorRMId = DoReMat - ? VRM.getReMatId(VirtReg) : VRM.getStackSlot(VirtReg); - int ReuseSlot = SSorRMId; - - // Check to see if this stack slot is available. - unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SSorRMId); - - // If this is a sub-register use, make sure the reuse register is in the - // right register class. For example, for x86 not all of the 32-bit - // registers have accessible sub-registers. - // Similarly so for EXTRACT_SUBREG. Consider this: - // EDI = op - // MOV32_mr fi#1, EDI - // ... - // = EXTRACT_SUBREG fi#1 - // fi#1 is available in EDI, but it cannot be reused because it's not in - // the right register file. - if (PhysReg && !AvoidReload && (SubIdx || MI.isExtractSubreg())) { - const TargetRegisterClass* RC = RegInfo->getRegClass(VirtReg); - if (!RC->contains(PhysReg)) - PhysReg = 0; - } + // Process all of the spilled uses and all non spilled reg references. + SmallVector<int, 2> PotentialDeadStoreSlots; + KilledMIRegs.clear(); + for (unsigned j = 0, e = VirtUseOps.size(); j != e; ++j) { + unsigned i = VirtUseOps[j]; + unsigned VirtReg = MI.getOperand(i).getReg(); + assert(TargetRegisterInfo::isVirtualRegister(VirtReg) && + "Not a virtual register?"); + + unsigned SubIdx = MI.getOperand(i).getSubReg(); + if (VRM->isAssignedReg(VirtReg)) { + // This virtual register was assigned a physreg! + unsigned Phys = VRM->getPhys(VirtReg); + MRI->setPhysRegUsed(Phys); + if (MI.getOperand(i).isDef()) + ReusedOperands.markClobbered(Phys); + substitutePhysReg(MI.getOperand(i), Phys, *TRI); + if (VRM->isImplicitlyDefined(VirtReg)) + // FIXME: Is this needed? + BuildMI(*MBB, &MI, MI.getDebugLoc(), + TII->get(TargetOpcode::IMPLICIT_DEF), Phys); + continue; + } - if (PhysReg && !AvoidReload) { - // This spilled operand might be part of a two-address operand. If this - // is the case, then changing it will necessarily require changing the - // def part of the instruction as well. However, in some cases, we - // aren't allowed to modify the reused register. If none of these cases - // apply, reuse it. - bool CanReuse = true; - bool isTied = MI.isRegTiedToDefOperand(i); - if (isTied) { - // Okay, we have a two address operand. We can reuse this physreg as - // long as we are allowed to clobber the value and there isn't an - // earlier def that has already clobbered the physreg. - CanReuse = !ReusedOperands.isClobbered(PhysReg) && - Spills.canClobberPhysReg(PhysReg); - } - - if (CanReuse) { - // If this stack slot value is already available, reuse it! - if (ReuseSlot > VirtRegMap::MAX_STACK_SLOT) - DEBUG(dbgs() << "Reusing RM#" - << ReuseSlot-VirtRegMap::MAX_STACK_SLOT-1); - else - DEBUG(dbgs() << "Reusing SS#" << ReuseSlot); - DEBUG(dbgs() << " from physreg " - << TRI->getName(PhysReg) << " for vreg" - << VirtReg <<" instead of reloading into physreg " - << TRI->getName(VRM.getPhys(VirtReg)) << '\n'); - unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; - MI.getOperand(i).setReg(RReg); - MI.getOperand(i).setSubReg(0); - - // The only technical detail we have is that we don't know that - // PhysReg won't be clobbered by a reloaded stack slot that occurs - // later in the instruction. In particular, consider 'op V1, V2'. - // If V1 is available in physreg R0, we would choose to reuse it - // here, instead of reloading it into the register the allocator - // indicated (say R1). However, V2 might have to be reloaded - // later, and it might indicate that it needs to live in R0. When - // this occurs, we need to have information available that - // indicates it is safe to use R1 for the reload instead of R0. - // - // To further complicate matters, we might conflict with an alias, - // or R0 and R1 might not be compatible with each other. In this - // case, we actually insert a reload for V1 in R1, ensuring that - // we can get at R0 or its alias. - ReusedOperands.addReuse(i, ReuseSlot, PhysReg, - VRM.getPhys(VirtReg), VirtReg); - if (isTied) - // Only mark it clobbered if this is a use&def operand. - ReusedOperands.markClobbered(PhysReg); - ++NumReused; - - if (MI.getOperand(i).isKill() && - ReuseSlot <= VirtRegMap::MAX_STACK_SLOT) { - - // The store of this spilled value is potentially dead, but we - // won't know for certain until we've confirmed that the re-use - // above is valid, which means waiting until the other operands - // are processed. For now we just track the spill slot, we'll - // remove it after the other operands are processed if valid. - - PotentialDeadStoreSlots.push_back(ReuseSlot); - } + // This virtual register is now known to be a spilled value. + if (!MI.getOperand(i).isUse()) + continue; // Handle defs in the loop below (handle use&def here though) + + bool AvoidReload = MI.getOperand(i).isUndef(); + // Check if it is defined by an implicit def. It should not be spilled. + // Note, this is for correctness reason. e.g. + // 8 %reg1024<def> = IMPLICIT_DEF + // 12 %reg1024<def> = INSERT_SUBREG %reg1024<kill>, %reg1025, 2 + // The live range [12, 14) are not part of the r1024 live interval since + // it's defined by an implicit def. It will not conflicts with live + // interval of r1025. Now suppose both registers are spilled, you can + // easily see a situation where both registers are reloaded before + // the INSERT_SUBREG and both target registers that would overlap. + bool DoReMat = VRM->isReMaterialized(VirtReg); + int SSorRMId = DoReMat + ? VRM->getReMatId(VirtReg) : VRM->getStackSlot(VirtReg); + int ReuseSlot = SSorRMId; + + // Check to see if this stack slot is available. + unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SSorRMId); + + // If this is a sub-register use, make sure the reuse register is in the + // right register class. For example, for x86 not all of the 32-bit + // registers have accessible sub-registers. + // Similarly so for EXTRACT_SUBREG. Consider this: + // EDI = op + // MOV32_mr fi#1, EDI + // ... + // = EXTRACT_SUBREG fi#1 + // fi#1 is available in EDI, but it cannot be reused because it's not in + // the right register file. + if (PhysReg && !AvoidReload && (SubIdx || MI.isExtractSubreg())) { + const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); + if (!RC->contains(PhysReg)) + PhysReg = 0; + } - // Mark is isKill if it's there no other uses of the same virtual - // register and it's not a two-address operand. IsKill will be - // unset if reg is reused. - if (!isTied && KilledMIRegs.count(VirtReg) == 0) { - MI.getOperand(i).setIsKill(); - KilledMIRegs.insert(VirtReg); - } + if (PhysReg && !AvoidReload) { + // This spilled operand might be part of a two-address operand. If this + // is the case, then changing it will necessarily require changing the + // def part of the instruction as well. However, in some cases, we + // aren't allowed to modify the reused register. If none of these cases + // apply, reuse it. + bool CanReuse = true; + bool isTied = MI.isRegTiedToDefOperand(i); + if (isTied) { + // Okay, we have a two address operand. We can reuse this physreg as + // long as we are allowed to clobber the value and there isn't an + // earlier def that has already clobbered the physreg. + CanReuse = !ReusedOperands.isClobbered(PhysReg) && + Spills.canClobberPhysReg(PhysReg); + } - continue; - } // CanReuse - - // Otherwise we have a situation where we have a two-address instruction - // whose mod/ref operand needs to be reloaded. This reload is already - // available in some register "PhysReg", but if we used PhysReg as the - // operand to our 2-addr instruction, the instruction would modify - // PhysReg. This isn't cool if something later uses PhysReg and expects - // to get its initial value. - // - // To avoid this problem, and to avoid doing a load right after a store, - // we emit a copy from PhysReg into the designated register for this - // operand. - unsigned DesignatedReg = VRM.getPhys(VirtReg); - assert(DesignatedReg && "Must map virtreg to physreg!"); - - // Note that, if we reused a register for a previous operand, the - // register we want to reload into might not actually be - // available. If this occurs, use the register indicated by the - // reuser. - if (ReusedOperands.hasReuses()) - DesignatedReg = ReusedOperands.GetRegForReload(VirtReg, - DesignatedReg, &MI, - Spills, MaybeDeadStores, RegKills, KillOps, VRM); - - // If the mapped designated register is actually the physreg we have - // incoming, we don't need to inserted a dead copy. - if (DesignatedReg == PhysReg) { - // If this stack slot value is already available, reuse it! - if (ReuseSlot > VirtRegMap::MAX_STACK_SLOT) - DEBUG(dbgs() << "Reusing RM#" - << ReuseSlot-VirtRegMap::MAX_STACK_SLOT-1); - else - DEBUG(dbgs() << "Reusing SS#" << ReuseSlot); - DEBUG(dbgs() << " from physreg " << TRI->getName(PhysReg) - << " for vreg" << VirtReg - << " instead of reloading into same physreg.\n"); - unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; - MI.getOperand(i).setReg(RReg); - MI.getOperand(i).setSubReg(0); - ReusedOperands.markClobbered(RReg); - ++NumReused; - continue; - } - - const TargetRegisterClass* RC = RegInfo->getRegClass(VirtReg); - RegInfo->setPhysRegUsed(DesignatedReg); - ReusedOperands.markClobbered(DesignatedReg); - - // Back-schedule reloads and remats. - MachineBasicBlock::iterator InsertLoc = - ComputeReloadLoc(&MI, MBB.begin(), PhysReg, TRI, DoReMat, - SSorRMId, TII, MF); - - TII->copyRegToReg(MBB, InsertLoc, DesignatedReg, PhysReg, RC, RC); - - MachineInstr *CopyMI = prior(InsertLoc); - CopyMI->setAsmPrinterFlag(MachineInstr::ReloadReuse); - UpdateKills(*CopyMI, TRI, RegKills, KillOps); - - // This invalidates DesignatedReg. - Spills.ClobberPhysReg(DesignatedReg); - - Spills.addAvailable(ReuseSlot, DesignatedReg); - unsigned RReg = - SubIdx ? TRI->getSubReg(DesignatedReg, SubIdx) : DesignatedReg; + if (CanReuse) { + // If this stack slot value is already available, reuse it! + if (ReuseSlot > VirtRegMap::MAX_STACK_SLOT) + DEBUG(dbgs() << "Reusing RM#" + << ReuseSlot-VirtRegMap::MAX_STACK_SLOT-1); + else + DEBUG(dbgs() << "Reusing SS#" << ReuseSlot); + DEBUG(dbgs() << " from physreg " + << TRI->getName(PhysReg) << " for vreg" + << VirtReg <<" instead of reloading into physreg " + << TRI->getName(VRM->getPhys(VirtReg)) << '\n'); + unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; MI.getOperand(i).setReg(RReg); MI.getOperand(i).setSubReg(0); - DEBUG(dbgs() << '\t' << *prior(MII)); + + // The only technical detail we have is that we don't know that + // PhysReg won't be clobbered by a reloaded stack slot that occurs + // later in the instruction. In particular, consider 'op V1, V2'. + // If V1 is available in physreg R0, we would choose to reuse it + // here, instead of reloading it into the register the allocator + // indicated (say R1). However, V2 might have to be reloaded + // later, and it might indicate that it needs to live in R0. When + // this occurs, we need to have information available that + // indicates it is safe to use R1 for the reload instead of R0. + // + // To further complicate matters, we might conflict with an alias, + // or R0 and R1 might not be compatible with each other. In this + // case, we actually insert a reload for V1 in R1, ensuring that + // we can get at R0 or its alias. + ReusedOperands.addReuse(i, ReuseSlot, PhysReg, + VRM->getPhys(VirtReg), VirtReg); + if (isTied) + // Only mark it clobbered if this is a use&def operand. + ReusedOperands.markClobbered(PhysReg); ++NumReused; + + if (MI.getOperand(i).isKill() && + ReuseSlot <= VirtRegMap::MAX_STACK_SLOT) { + + // The store of this spilled value is potentially dead, but we + // won't know for certain until we've confirmed that the re-use + // above is valid, which means waiting until the other operands + // are processed. For now we just track the spill slot, we'll + // remove it after the other operands are processed if valid. + + PotentialDeadStoreSlots.push_back(ReuseSlot); + } + + // Mark is isKill if it's there no other uses of the same virtual + // register and it's not a two-address operand. IsKill will be + // unset if reg is reused. + if (!isTied && KilledMIRegs.count(VirtReg) == 0) { + MI.getOperand(i).setIsKill(); + KilledMIRegs.insert(VirtReg); + } + continue; - } // if (PhysReg) - - // Otherwise, reload it and remember that we have it. - PhysReg = VRM.getPhys(VirtReg); - assert(PhysReg && "Must map virtreg to physreg!"); + } // CanReuse + + // Otherwise we have a situation where we have a two-address instruction + // whose mod/ref operand needs to be reloaded. This reload is already + // available in some register "PhysReg", but if we used PhysReg as the + // operand to our 2-addr instruction, the instruction would modify + // PhysReg. This isn't cool if something later uses PhysReg and expects + // to get its initial value. + // + // To avoid this problem, and to avoid doing a load right after a store, + // we emit a copy from PhysReg into the designated register for this + // operand. + unsigned DesignatedReg = VRM->getPhys(VirtReg); + assert(DesignatedReg && "Must map virtreg to physreg!"); // Note that, if we reused a register for a previous operand, the // register we want to reload into might not actually be // available. If this occurs, use the register indicated by the // reuser. if (ReusedOperands.hasReuses()) - PhysReg = ReusedOperands.GetRegForReload(VirtReg, PhysReg, &MI, - Spills, MaybeDeadStores, RegKills, KillOps, VRM); - - RegInfo->setPhysRegUsed(PhysReg); - ReusedOperands.markClobbered(PhysReg); - if (AvoidReload) - ++NumAvoided; - else { - // Back-schedule reloads and remats. - MachineBasicBlock::iterator InsertLoc = - ComputeReloadLoc(MII, MBB.begin(), PhysReg, TRI, DoReMat, - SSorRMId, TII, MF); - - if (DoReMat) { - ReMaterialize(MBB, InsertLoc, PhysReg, VirtReg, TII, TRI, VRM); - } else { - const TargetRegisterClass* RC = RegInfo->getRegClass(VirtReg); - TII->loadRegFromStackSlot(MBB, InsertLoc, PhysReg, SSorRMId, RC); - MachineInstr *LoadMI = prior(InsertLoc); - VRM.addSpillSlotUse(SSorRMId, LoadMI); - ++NumLoads; - DistanceMap.insert(std::make_pair(LoadMI, Dist++)); - } - // This invalidates PhysReg. - Spills.ClobberPhysReg(PhysReg); + DesignatedReg = ReusedOperands. + GetRegForReload(VirtReg, DesignatedReg, &MI, Spills, + MaybeDeadStores, RegKills, KillOps, *VRM); + + // If the mapped designated register is actually the physreg we have + // incoming, we don't need to inserted a dead copy. + if (DesignatedReg == PhysReg) { + // If this stack slot value is already available, reuse it! + if (ReuseSlot > VirtRegMap::MAX_STACK_SLOT) + DEBUG(dbgs() << "Reusing RM#" + << ReuseSlot-VirtRegMap::MAX_STACK_SLOT-1); + else + DEBUG(dbgs() << "Reusing SS#" << ReuseSlot); + DEBUG(dbgs() << " from physreg " << TRI->getName(PhysReg) + << " for vreg" << VirtReg + << " instead of reloading into same physreg.\n"); + unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; + MI.getOperand(i).setReg(RReg); + MI.getOperand(i).setSubReg(0); + ReusedOperands.markClobbered(RReg); + ++NumReused; + continue; + } - // Any stores to this stack slot are not dead anymore. - if (!DoReMat) - MaybeDeadStores[SSorRMId] = NULL; - Spills.addAvailable(SSorRMId, PhysReg); - // Assumes this is the last use. IsKill will be unset if reg is reused - // unless it's a two-address operand. - if (!MI.isRegTiedToDefOperand(i) && - KilledMIRegs.count(VirtReg) == 0) { - MI.getOperand(i).setIsKill(); - KilledMIRegs.insert(VirtReg); - } + const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); + MRI->setPhysRegUsed(DesignatedReg); + ReusedOperands.markClobbered(DesignatedReg); - UpdateKills(*prior(InsertLoc), TRI, RegKills, KillOps); - DEBUG(dbgs() << '\t' << *prior(InsertLoc)); - } - unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; + // Back-schedule reloads and remats. + MachineBasicBlock::iterator InsertLoc = + ComputeReloadLoc(&MI, MBB->begin(), PhysReg, TRI, DoReMat, + SSorRMId, TII, MF); + + TII->copyRegToReg(*MBB, InsertLoc, DesignatedReg, PhysReg, RC, RC); + + MachineInstr *CopyMI = prior(InsertLoc); + CopyMI->setAsmPrinterFlag(MachineInstr::ReloadReuse); + UpdateKills(*CopyMI, TRI, RegKills, KillOps); + + // This invalidates DesignatedReg. + Spills.ClobberPhysReg(DesignatedReg); + + Spills.addAvailable(ReuseSlot, DesignatedReg); + unsigned RReg = + SubIdx ? TRI->getSubReg(DesignatedReg, SubIdx) : DesignatedReg; MI.getOperand(i).setReg(RReg); MI.getOperand(i).setSubReg(0); - } + DEBUG(dbgs() << '\t' << *prior(MII)); + ++NumReused; + continue; + } // if (PhysReg) - // Ok - now we can remove stores that have been confirmed dead. - for (unsigned j = 0, e = PotentialDeadStoreSlots.size(); j != e; ++j) { - // This was the last use and the spilled value is still available - // for reuse. That means the spill was unnecessary! - int PDSSlot = PotentialDeadStoreSlots[j]; - MachineInstr* DeadStore = MaybeDeadStores[PDSSlot]; - if (DeadStore) { - DEBUG(dbgs() << "Removed dead store:\t" << *DeadStore); - InvalidateKills(*DeadStore, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(DeadStore); - MBB.erase(DeadStore); - MaybeDeadStores[PDSSlot] = NULL; - ++NumDSE; + // Otherwise, reload it and remember that we have it. + PhysReg = VRM->getPhys(VirtReg); + assert(PhysReg && "Must map virtreg to physreg!"); + + // Note that, if we reused a register for a previous operand, the + // register we want to reload into might not actually be + // available. If this occurs, use the register indicated by the + // reuser. + if (ReusedOperands.hasReuses()) + PhysReg = ReusedOperands.GetRegForReload(VirtReg, PhysReg, &MI, + Spills, MaybeDeadStores, RegKills, KillOps, *VRM); + + MRI->setPhysRegUsed(PhysReg); + ReusedOperands.markClobbered(PhysReg); + if (AvoidReload) + ++NumAvoided; + else { + // Back-schedule reloads and remats. + MachineBasicBlock::iterator InsertLoc = + ComputeReloadLoc(MII, MBB->begin(), PhysReg, TRI, DoReMat, + SSorRMId, TII, MF); + + if (DoReMat) { + ReMaterialize(*MBB, InsertLoc, PhysReg, VirtReg, TII, TRI, *VRM); + } else { + const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); + TII->loadRegFromStackSlot(*MBB, InsertLoc, PhysReg, SSorRMId, RC); + MachineInstr *LoadMI = prior(InsertLoc); + VRM->addSpillSlotUse(SSorRMId, LoadMI); + ++NumLoads; + DistanceMap.insert(std::make_pair(LoadMI, DistanceMap.size())); } + // This invalidates PhysReg. + Spills.ClobberPhysReg(PhysReg); + + // Any stores to this stack slot are not dead anymore. + if (!DoReMat) + MaybeDeadStores[SSorRMId] = NULL; + Spills.addAvailable(SSorRMId, PhysReg); + // Assumes this is the last use. IsKill will be unset if reg is reused + // unless it's a two-address operand. + if (!MI.isRegTiedToDefOperand(i) && + KilledMIRegs.count(VirtReg) == 0) { + MI.getOperand(i).setIsKill(); + KilledMIRegs.insert(VirtReg); + } + + UpdateKills(*prior(InsertLoc), TRI, RegKills, KillOps); + DEBUG(dbgs() << '\t' << *prior(InsertLoc)); } + unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; + MI.getOperand(i).setReg(RReg); + MI.getOperand(i).setSubReg(0); + } + // Ok - now we can remove stores that have been confirmed dead. + for (unsigned j = 0, e = PotentialDeadStoreSlots.size(); j != e; ++j) { + // This was the last use and the spilled value is still available + // for reuse. That means the spill was unnecessary! + int PDSSlot = PotentialDeadStoreSlots[j]; + MachineInstr* DeadStore = MaybeDeadStores[PDSSlot]; + if (DeadStore) { + DEBUG(dbgs() << "Removed dead store:\t" << *DeadStore); + InvalidateKills(*DeadStore, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(DeadStore); + MBB->erase(DeadStore); + MaybeDeadStores[PDSSlot] = NULL; + ++NumDSE; + } + } - DEBUG(dbgs() << '\t' << MI); + DEBUG(dbgs() << '\t' << MI); - // If we have folded references to memory operands, make sure we clear all - // physical registers that may contain the value of the spilled virtual - // register - SmallSet<int, 2> FoldedSS; - for (tie(I, End) = VRM.getFoldedVirts(&MI); I != End; ) { - unsigned VirtReg = I->second.first; - VirtRegMap::ModRef MR = I->second.second; - DEBUG(dbgs() << "Folded vreg: " << VirtReg << " MR: " << MR); - // MI2VirtMap be can updated which invalidate the iterator. - // Increment the iterator first. - ++I; - int SS = VRM.getStackSlot(VirtReg); - if (SS == VirtRegMap::NO_STACK_SLOT) - continue; - FoldedSS.insert(SS); - DEBUG(dbgs() << " - StackSlot: " << SS << "\n"); - - // If this folded instruction is just a use, check to see if it's a - // straight load from the virt reg slot. - if ((MR & VirtRegMap::isRef) && !(MR & VirtRegMap::isMod)) { - int FrameIdx; - unsigned DestReg = TII->isLoadFromStackSlot(&MI, FrameIdx); - if (DestReg && FrameIdx == SS) { - // If this spill slot is available, turn it into a copy (or nothing) - // instead of leaving it as a load! - if (unsigned InReg = Spills.getSpillSlotOrReMatPhysReg(SS)) { - DEBUG(dbgs() << "Promoted Load To Copy: " << MI); - if (DestReg != InReg) { - const TargetRegisterClass *RC = RegInfo->getRegClass(VirtReg); - TII->copyRegToReg(MBB, &MI, DestReg, InReg, RC, RC); - MachineOperand *DefMO = MI.findRegisterDefOperand(DestReg); - unsigned SubIdx = DefMO->getSubReg(); - // Revisit the copy so we make sure to notice the effects of the - // operation on the destreg (either needing to RA it if it's - // virtual or needing to clobber any values if it's physical). - NextMII = &MI; - --NextMII; // backtrack to the copy. - NextMII->setAsmPrinterFlag(MachineInstr::ReloadReuse); - // Propagate the sub-register index over. - if (SubIdx) { - DefMO = NextMII->findRegisterDefOperand(DestReg); - DefMO->setSubReg(SubIdx); - } - - // Mark is killed. - MachineOperand *KillOpnd = NextMII->findRegisterUseOperand(InReg); - KillOpnd->setIsKill(); - - BackTracked = true; - } else { - DEBUG(dbgs() << "Removing now-noop copy: " << MI); - // Unset last kill since it's being reused. - InvalidateKill(InReg, TRI, RegKills, KillOps); - Spills.disallowClobberPhysReg(InReg); + // If we have folded references to memory operands, make sure we clear all + // physical registers that may contain the value of the spilled virtual + // register + SmallSet<int, 2> FoldedSS; + for (tie(I, End) = VRM->getFoldedVirts(&MI); I != End; ) { + unsigned VirtReg = I->second.first; + VirtRegMap::ModRef MR = I->second.second; + DEBUG(dbgs() << "Folded vreg: " << VirtReg << " MR: " << MR); + + // MI2VirtMap be can updated which invalidate the iterator. + // Increment the iterator first. + ++I; + int SS = VRM->getStackSlot(VirtReg); + if (SS == VirtRegMap::NO_STACK_SLOT) + continue; + FoldedSS.insert(SS); + DEBUG(dbgs() << " - StackSlot: " << SS << "\n"); + + // If this folded instruction is just a use, check to see if it's a + // straight load from the virt reg slot. + if ((MR & VirtRegMap::isRef) && !(MR & VirtRegMap::isMod)) { + int FrameIdx; + unsigned DestReg = TII->isLoadFromStackSlot(&MI, FrameIdx); + if (DestReg && FrameIdx == SS) { + // If this spill slot is available, turn it into a copy (or nothing) + // instead of leaving it as a load! + if (unsigned InReg = Spills.getSpillSlotOrReMatPhysReg(SS)) { + DEBUG(dbgs() << "Promoted Load To Copy: " << MI); + if (DestReg != InReg) { + const TargetRegisterClass *RC = MRI->getRegClass(VirtReg); + TII->copyRegToReg(*MBB, &MI, DestReg, InReg, RC, RC); + MachineOperand *DefMO = MI.findRegisterDefOperand(DestReg); + unsigned SubIdx = DefMO->getSubReg(); + // Revisit the copy so we make sure to notice the effects of the + // operation on the destreg (either needing to RA it if it's + // virtual or needing to clobber any values if it's physical). + NextMII = &MI; + --NextMII; // backtrack to the copy. + NextMII->setAsmPrinterFlag(MachineInstr::ReloadReuse); + // Propagate the sub-register index over. + if (SubIdx) { + DefMO = NextMII->findRegisterDefOperand(DestReg); + DefMO->setSubReg(SubIdx); } - InvalidateKills(MI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(&MI); - MBB.erase(&MI); - Erased = true; - goto ProcessNextInst; + // Mark is killed. + MachineOperand *KillOpnd = NextMII->findRegisterUseOperand(InReg); + KillOpnd->setIsKill(); + + BackTracked = true; + } else { + DEBUG(dbgs() << "Removing now-noop copy: " << MI); + // Unset last kill since it's being reused. + InvalidateKill(InReg, TRI, RegKills, KillOps); + Spills.disallowClobberPhysReg(InReg); } - } else { - unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SS); - SmallVector<MachineInstr*, 4> NewMIs; - if (PhysReg && - TII->unfoldMemoryOperand(MF, &MI, PhysReg, false, false, NewMIs)) { - MBB.insert(MII, NewMIs[0]); + + InvalidateKills(MI, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(&MI); + MBB->erase(&MI); + Erased = true; + goto ProcessNextInst; + } + } else { + unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SS); + SmallVector<MachineInstr*, 4> NewMIs; + if (PhysReg && + TII->unfoldMemoryOperand(MF, &MI, PhysReg, false, false, NewMIs)) { + MBB->insert(MII, NewMIs[0]); + InvalidateKills(MI, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(&MI); + MBB->erase(&MI); + Erased = true; + --NextMII; // backtrack to the unfolded instruction. + BackTracked = true; + goto ProcessNextInst; + } + } + } + + // If this reference is not a use, any previous store is now dead. + // Otherwise, the store to this stack slot is not dead anymore. + MachineInstr* DeadStore = MaybeDeadStores[SS]; + if (DeadStore) { + bool isDead = !(MR & VirtRegMap::isRef); + MachineInstr *NewStore = NULL; + if (MR & VirtRegMap::isModRef) { + unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SS); + SmallVector<MachineInstr*, 4> NewMIs; + // We can reuse this physreg as long as we are allowed to clobber + // the value and there isn't an earlier def that has already clobbered + // the physreg. + if (PhysReg && + !ReusedOperands.isClobbered(PhysReg) && + Spills.canClobberPhysReg(PhysReg) && + !TII->isStoreToStackSlot(&MI, SS)) { // Not profitable! + MachineOperand *KillOpnd = + DeadStore->findRegisterUseOperand(PhysReg, true); + // Note, if the store is storing a sub-register, it's possible the + // super-register is needed below. + if (KillOpnd && !KillOpnd->getSubReg() && + TII->unfoldMemoryOperand(MF, &MI, PhysReg, false, true,NewMIs)){ + MBB->insert(MII, NewMIs[0]); + NewStore = NewMIs[1]; + MBB->insert(MII, NewStore); + VRM->addSpillSlotUse(SS, NewStore); InvalidateKills(MI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(&MI); - MBB.erase(&MI); + VRM->RemoveMachineInstrFromMaps(&MI); + MBB->erase(&MI); Erased = true; + --NextMII; --NextMII; // backtrack to the unfolded instruction. BackTracked = true; - goto ProcessNextInst; + isDead = true; + ++NumSUnfold; } } } - // If this reference is not a use, any previous store is now dead. - // Otherwise, the store to this stack slot is not dead anymore. - MachineInstr* DeadStore = MaybeDeadStores[SS]; - if (DeadStore) { - bool isDead = !(MR & VirtRegMap::isRef); - MachineInstr *NewStore = NULL; - if (MR & VirtRegMap::isModRef) { - unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SS); - SmallVector<MachineInstr*, 4> NewMIs; - // We can reuse this physreg as long as we are allowed to clobber - // the value and there isn't an earlier def that has already clobbered - // the physreg. - if (PhysReg && - !ReusedOperands.isClobbered(PhysReg) && - Spills.canClobberPhysReg(PhysReg) && - !TII->isStoreToStackSlot(&MI, SS)) { // Not profitable! - MachineOperand *KillOpnd = - DeadStore->findRegisterUseOperand(PhysReg, true); - // Note, if the store is storing a sub-register, it's possible the - // super-register is needed below. - if (KillOpnd && !KillOpnd->getSubReg() && - TII->unfoldMemoryOperand(MF, &MI, PhysReg, false, true,NewMIs)){ - MBB.insert(MII, NewMIs[0]); - NewStore = NewMIs[1]; - MBB.insert(MII, NewStore); - VRM.addSpillSlotUse(SS, NewStore); - InvalidateKills(MI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(&MI); - MBB.erase(&MI); - Erased = true; - --NextMII; - --NextMII; // backtrack to the unfolded instruction. - BackTracked = true; - isDead = true; - ++NumSUnfold; - } + if (isDead) { // Previous store is dead. + // If we get here, the store is dead, nuke it now. + DEBUG(dbgs() << "Removed dead store:\t" << *DeadStore); + InvalidateKills(*DeadStore, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(DeadStore); + MBB->erase(DeadStore); + if (!NewStore) + ++NumDSE; + } + + MaybeDeadStores[SS] = NULL; + if (NewStore) { + // Treat this store as a spill merged into a copy. That makes the + // stack slot value available. + VRM->virtFolded(VirtReg, NewStore, VirtRegMap::isMod); + goto ProcessNextInst; + } + } + + // If the spill slot value is available, and this is a new definition of + // the value, the value is not available anymore. + if (MR & VirtRegMap::isMod) { + // Notice that the value in this stack slot has been modified. + Spills.ModifyStackSlotOrReMat(SS); + + // If this is *just* a mod of the value, check to see if this is just a + // store to the spill slot (i.e. the spill got merged into the copy). If + // so, realize that the vreg is available now, and add the store to the + // MaybeDeadStore info. + int StackSlot; + if (!(MR & VirtRegMap::isRef)) { + if (unsigned SrcReg = TII->isStoreToStackSlot(&MI, StackSlot)) { + assert(TargetRegisterInfo::isPhysicalRegister(SrcReg) && + "Src hasn't been allocated yet?"); + + if (CommuteToFoldReload(MII, VirtReg, SrcReg, StackSlot, + Spills, RegKills, KillOps, TRI)) { + NextMII = llvm::next(MII); + BackTracked = true; + goto ProcessNextInst; } - } - if (isDead) { // Previous store is dead. - // If we get here, the store is dead, nuke it now. - DEBUG(dbgs() << "Removed dead store:\t" << *DeadStore); - InvalidateKills(*DeadStore, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(DeadStore); - MBB.erase(DeadStore); - if (!NewStore) - ++NumDSE; + // Okay, this is certainly a store of SrcReg to [StackSlot]. Mark + // this as a potentially dead store in case there is a subsequent + // store into the stack slot without a read from it. + MaybeDeadStores[StackSlot] = &MI; + + // If the stack slot value was previously available in some other + // register, change it now. Otherwise, make the register + // available in PhysReg. + Spills.addAvailable(StackSlot, SrcReg, MI.killsRegister(SrcReg)); } + } + } + } - MaybeDeadStores[SS] = NULL; - if (NewStore) { - // Treat this store as a spill merged into a copy. That makes the - // stack slot value available. - VRM.virtFolded(VirtReg, NewStore, VirtRegMap::isMod); - goto ProcessNextInst; + // Process all of the spilled defs. + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI.getOperand(i); + if (!(MO.isReg() && MO.getReg() && MO.isDef())) + continue; + + unsigned VirtReg = MO.getReg(); + if (!TargetRegisterInfo::isVirtualRegister(VirtReg)) { + // Check to see if this is a noop copy. If so, eliminate the + // instruction before considering the dest reg to be changed. + // Also check if it's copying from an "undef", if so, we can't + // eliminate this or else the undef marker is lost and it will + // confuses the scavenger. This is extremely rare. + unsigned Src, Dst, SrcSR, DstSR; + if (TII->isMoveInstr(MI, Src, Dst, SrcSR, DstSR) && Src == Dst && + !MI.findRegisterUseOperand(Src)->isUndef()) { + ++NumDCE; + DEBUG(dbgs() << "Removing now-noop copy: " << MI); + SmallVector<unsigned, 2> KillRegs; + InvalidateKills(MI, TRI, RegKills, KillOps, &KillRegs); + if (MO.isDead() && !KillRegs.empty()) { + // Source register or an implicit super/sub-register use is killed. + assert(KillRegs[0] == Dst || + TRI->isSubRegister(KillRegs[0], Dst) || + TRI->isSuperRegister(KillRegs[0], Dst)); + // Last def is now dead. + TransferDeadness(Src, RegKills, KillOps); } + VRM->RemoveMachineInstrFromMaps(&MI); + MBB->erase(&MI); + Erased = true; + Spills.disallowClobberPhysReg(VirtReg); + goto ProcessNextInst; } - // If the spill slot value is available, and this is a new definition of - // the value, the value is not available anymore. - if (MR & VirtRegMap::isMod) { - // Notice that the value in this stack slot has been modified. - Spills.ModifyStackSlotOrReMat(SS); - - // If this is *just* a mod of the value, check to see if this is just a - // store to the spill slot (i.e. the spill got merged into the copy). If - // so, realize that the vreg is available now, and add the store to the - // MaybeDeadStore info. - int StackSlot; - if (!(MR & VirtRegMap::isRef)) { - if (unsigned SrcReg = TII->isStoreToStackSlot(&MI, StackSlot)) { - assert(TargetRegisterInfo::isPhysicalRegister(SrcReg) && - "Src hasn't been allocated yet?"); - - if (CommuteToFoldReload(MBB, MII, VirtReg, SrcReg, StackSlot, - Spills, RegKills, KillOps, TRI, VRM)) { - NextMII = llvm::next(MII); - BackTracked = true; - goto ProcessNextInst; - } + // If it's not a no-op copy, it clobbers the value in the destreg. + Spills.ClobberPhysReg(VirtReg); + ReusedOperands.markClobbered(VirtReg); + + // Check to see if this instruction is a load from a stack slot into + // a register. If so, this provides the stack slot value in the reg. + int FrameIdx; + if (unsigned DestReg = TII->isLoadFromStackSlot(&MI, FrameIdx)) { + assert(DestReg == VirtReg && "Unknown load situation!"); + + // If it is a folded reference, then it's not safe to clobber. + bool Folded = FoldedSS.count(FrameIdx); + // Otherwise, if it wasn't available, remember that it is now! + Spills.addAvailable(FrameIdx, DestReg, !Folded); + goto ProcessNextInst; + } - // Okay, this is certainly a store of SrcReg to [StackSlot]. Mark - // this as a potentially dead store in case there is a subsequent - // store into the stack slot without a read from it. - MaybeDeadStores[StackSlot] = &MI; + continue; + } - // If the stack slot value was previously available in some other - // register, change it now. Otherwise, make the register - // available in PhysReg. - Spills.addAvailable(StackSlot, SrcReg, MI.killsRegister(SrcReg)); - } - } + unsigned SubIdx = MO.getSubReg(); + bool DoReMat = VRM->isReMaterialized(VirtReg); + if (DoReMat) + ReMatDefs.insert(&MI); + + // The only vregs left are stack slot definitions. + int StackSlot = VRM->getStackSlot(VirtReg); + const TargetRegisterClass *RC = MRI->getRegClass(VirtReg); + + // If this def is part of a two-address operand, make sure to execute + // the store from the correct physical register. + unsigned PhysReg; + unsigned TiedOp; + if (MI.isRegTiedToUseOperand(i, &TiedOp)) { + PhysReg = MI.getOperand(TiedOp).getReg(); + if (SubIdx) { + unsigned SuperReg = findSuperReg(RC, PhysReg, SubIdx, TRI); + assert(SuperReg && TRI->getSubReg(SuperReg, SubIdx) == PhysReg && + "Can't find corresponding super-register!"); + PhysReg = SuperReg; + } + } else { + PhysReg = VRM->getPhys(VirtReg); + if (ReusedOperands.isClobbered(PhysReg)) { + // Another def has taken the assigned physreg. It must have been a + // use&def which got it due to reuse. Undo the reuse! + PhysReg = ReusedOperands.GetRegForReload(VirtReg, PhysReg, &MI, + Spills, MaybeDeadStores, RegKills, KillOps, *VRM); } } - // Process all of the spilled defs. - for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI.getOperand(i); - if (!(MO.isReg() && MO.getReg() && MO.isDef())) - continue; + assert(PhysReg && "VR not assigned a physical register?"); + MRI->setPhysRegUsed(PhysReg); + unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; + ReusedOperands.markClobbered(RReg); + MI.getOperand(i).setReg(RReg); + MI.getOperand(i).setSubReg(0); + + if (!MO.isDead()) { + MachineInstr *&LastStore = MaybeDeadStores[StackSlot]; + SpillRegToStackSlot(MII, -1, PhysReg, StackSlot, RC, true, + LastStore, Spills, ReMatDefs, RegKills, KillOps); + NextMII = llvm::next(MII); - unsigned VirtReg = MO.getReg(); - if (!TargetRegisterInfo::isVirtualRegister(VirtReg)) { - // Check to see if this is a noop copy. If so, eliminate the - // instruction before considering the dest reg to be changed. - // Also check if it's copying from an "undef", if so, we can't - // eliminate this or else the undef marker is lost and it will - // confuses the scavenger. This is extremely rare. + // Check to see if this is a noop copy. If so, eliminate the + // instruction before considering the dest reg to be changed. + { unsigned Src, Dst, SrcSR, DstSR; - if (TII->isMoveInstr(MI, Src, Dst, SrcSR, DstSR) && Src == Dst && - !MI.findRegisterUseOperand(Src)->isUndef()) { + if (TII->isMoveInstr(MI, Src, Dst, SrcSR, DstSR) && Src == Dst) { ++NumDCE; DEBUG(dbgs() << "Removing now-noop copy: " << MI); - SmallVector<unsigned, 2> KillRegs; - InvalidateKills(MI, TRI, RegKills, KillOps, &KillRegs); - if (MO.isDead() && !KillRegs.empty()) { - // Source register or an implicit super/sub-register use is killed. - assert(KillRegs[0] == Dst || - TRI->isSubRegister(KillRegs[0], Dst) || - TRI->isSuperRegister(KillRegs[0], Dst)); - // Last def is now dead. - TransferDeadness(&MBB, Dist, Src, RegKills, KillOps, VRM); - } - VRM.RemoveMachineInstrFromMaps(&MI); - MBB.erase(&MI); + InvalidateKills(MI, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(&MI); + MBB->erase(&MI); Erased = true; - Spills.disallowClobberPhysReg(VirtReg); + UpdateKills(*LastStore, TRI, RegKills, KillOps); goto ProcessNextInst; } - - // If it's not a no-op copy, it clobbers the value in the destreg. - Spills.ClobberPhysReg(VirtReg); - ReusedOperands.markClobbered(VirtReg); - - // Check to see if this instruction is a load from a stack slot into - // a register. If so, this provides the stack slot value in the reg. - int FrameIdx; - if (unsigned DestReg = TII->isLoadFromStackSlot(&MI, FrameIdx)) { - assert(DestReg == VirtReg && "Unknown load situation!"); - - // If it is a folded reference, then it's not safe to clobber. - bool Folded = FoldedSS.count(FrameIdx); - // Otherwise, if it wasn't available, remember that it is now! - Spills.addAvailable(FrameIdx, DestReg, !Folded); - goto ProcessNextInst; - } - - continue; - } - - unsigned SubIdx = MO.getSubReg(); - bool DoReMat = VRM.isReMaterialized(VirtReg); - if (DoReMat) - ReMatDefs.insert(&MI); - - // The only vregs left are stack slot definitions. - int StackSlot = VRM.getStackSlot(VirtReg); - const TargetRegisterClass *RC = RegInfo->getRegClass(VirtReg); - - // If this def is part of a two-address operand, make sure to execute - // the store from the correct physical register. - unsigned PhysReg; - unsigned TiedOp; - if (MI.isRegTiedToUseOperand(i, &TiedOp)) { - PhysReg = MI.getOperand(TiedOp).getReg(); - if (SubIdx) { - unsigned SuperReg = findSuperReg(RC, PhysReg, SubIdx, TRI); - assert(SuperReg && TRI->getSubReg(SuperReg, SubIdx) == PhysReg && - "Can't find corresponding super-register!"); - PhysReg = SuperReg; - } - } else { - PhysReg = VRM.getPhys(VirtReg); - if (ReusedOperands.isClobbered(PhysReg)) { - // Another def has taken the assigned physreg. It must have been a - // use&def which got it due to reuse. Undo the reuse! - PhysReg = ReusedOperands.GetRegForReload(VirtReg, PhysReg, &MI, - Spills, MaybeDeadStores, RegKills, KillOps, VRM); - } } - - assert(PhysReg && "VR not assigned a physical register?"); - RegInfo->setPhysRegUsed(PhysReg); - unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; - ReusedOperands.markClobbered(RReg); - MI.getOperand(i).setReg(RReg); - MI.getOperand(i).setSubReg(0); - - if (!MO.isDead()) { - MachineInstr *&LastStore = MaybeDeadStores[StackSlot]; - SpillRegToStackSlot(MBB, MII, -1, PhysReg, StackSlot, RC, true, - LastStore, Spills, ReMatDefs, RegKills, KillOps, VRM); - NextMII = llvm::next(MII); - - // Check to see if this is a noop copy. If so, eliminate the - // instruction before considering the dest reg to be changed. - { - unsigned Src, Dst, SrcSR, DstSR; - if (TII->isMoveInstr(MI, Src, Dst, SrcSR, DstSR) && Src == Dst) { - ++NumDCE; - DEBUG(dbgs() << "Removing now-noop copy: " << MI); - InvalidateKills(MI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(&MI); - MBB.erase(&MI); - Erased = true; - UpdateKills(*LastStore, TRI, RegKills, KillOps); - goto ProcessNextInst; - } - } - } } + } ProcessNextInst: - // Delete dead instructions without side effects. - if (!Erased && !BackTracked && isSafeToDelete(MI)) { - InvalidateKills(MI, TRI, RegKills, KillOps); - VRM.RemoveMachineInstrFromMaps(&MI); - MBB.erase(&MI); - Erased = true; - } - if (!Erased) - DistanceMap.insert(std::make_pair(&MI, Dist++)); - if (!Erased && !BackTracked) { - for (MachineBasicBlock::iterator II = &MI; II != NextMII; ++II) - UpdateKills(*II, TRI, RegKills, KillOps); - } - MII = NextMII; + // Delete dead instructions without side effects. + if (!Erased && !BackTracked && isSafeToDelete(MI)) { + InvalidateKills(MI, TRI, RegKills, KillOps); + VRM->RemoveMachineInstrFromMaps(&MI); + MBB->erase(&MI); + Erased = true; } - + if (!Erased) + DistanceMap.insert(std::make_pair(&MI, DistanceMap.size())); + if (!Erased && !BackTracked) { + for (MachineBasicBlock::iterator II = &MI; II != NextMII; ++II) + UpdateKills(*II, TRI, RegKills, KillOps); + } + MII = NextMII; } -}; - } llvm::VirtRegRewriter* llvm::createVirtRegRewriter() { diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp index 565509cd1f36..68471bd4d5f4 100644 --- a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp +++ b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp @@ -165,7 +165,7 @@ void JITDebugRegisterer::RegisterFunction(const Function *F, DebugInfo &I) { void JITDebugRegisterer::UnregisterFunctionInternal( RegisteredFunctionsMap::iterator I) { - jit_code_entry *JITCodeEntry = I->second.second; + jit_code_entry *&JITCodeEntry = I->second.second; // Acquire the lock and do the unregistration. { @@ -190,6 +190,9 @@ void JITDebugRegisterer::UnregisterFunctionInternal( __jit_debug_register_code(); } + delete JITCodeEntry; + JITCodeEntry = NULL; + // Free the ELF file in memory. std::string &Buffer = I->second.first; Buffer.clear(); diff --git a/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp b/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp index da5435a0c70d..2f42e6bfe6d9 100644 --- a/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp @@ -23,6 +23,7 @@ #include "llvm/ExecutionEngine/JITMemoryManager.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetFrameInfo.h" @@ -67,33 +68,29 @@ JITDwarfEmitter::EmitFrameMoves(intptr_t BaseLabelPtr, unsigned PointerSize = TD->getPointerSize(); int stackGrowth = stackGrowthDirection == TargetFrameInfo::StackGrowsUp ? PointerSize : -PointerSize; - bool IsLocal = false; - unsigned BaseLabelID = 0; + MCSymbol *BaseLabel = 0; for (unsigned i = 0, N = Moves.size(); i < N; ++i) { const MachineMove &Move = Moves[i]; - unsigned LabelID = Move.getLabelID(); + MCSymbol *Label = Move.getLabel(); - if (LabelID) { - // Throw out move if the label is invalid. - if (MMI->isLabelDeleted(LabelID)) - continue; - } + // Throw out move if the label is invalid. + if (Label && !Label->isDefined()) + continue; intptr_t LabelPtr = 0; - if (LabelID) LabelPtr = JCE->getLabelAddress(LabelID); + if (Label) LabelPtr = JCE->getLabelAddress(Label); const MachineLocation &Dst = Move.getDestination(); const MachineLocation &Src = Move.getSource(); // Advance row if new location. - if (BaseLabelPtr && LabelID && (BaseLabelID != LabelID || !IsLocal)) { + if (BaseLabelPtr && Label && BaseLabel != Label) { JCE->emitByte(dwarf::DW_CFA_advance_loc4); JCE->emitInt32(LabelPtr - BaseLabelPtr); - BaseLabelID = LabelID; + BaseLabel = Label; BaseLabelPtr = LabelPtr; - IsLocal = true; } // If advancing cfa. @@ -169,13 +166,6 @@ static bool PadLT(const LandingPadInfo *L, const LandingPadInfo *R) { namespace { -struct KeyInfo { - static inline unsigned getEmptyKey() { return -1U; } - static inline unsigned getTombstoneKey() { return -2U; } - static unsigned getHashValue(const unsigned &Key) { return Key; } - static bool isEqual(unsigned LHS, unsigned RHS) { return LHS == RHS; } -}; - /// ActionEntry - Structure describing an entry in the actions table. struct ActionEntry { int ValueForTypeID; // The value to write - may not be equal to the type id. @@ -191,13 +181,13 @@ struct PadRange { unsigned RangeIndex; }; -typedef DenseMap<unsigned, PadRange, KeyInfo> RangeMapType; +typedef DenseMap<MCSymbol*, PadRange> RangeMapType; /// CallSiteEntry - Structure describing an entry in the call-site table. struct CallSiteEntry { - unsigned BeginLabel; // zero indicates the start of the function. - unsigned EndLabel; // zero indicates the end of the function. - unsigned PadLabel; // zero indicates that there is no landing pad. + MCSymbol *BeginLabel; // zero indicates the start of the function. + MCSymbol *EndLabel; // zero indicates the end of the function. + MCSymbol *PadLabel; // zero indicates that there is no landing pad. unsigned Action; }; @@ -308,7 +298,7 @@ unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF, for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { const LandingPadInfo *LandingPad = LandingPads[i]; for (unsigned j=0, E = LandingPad->BeginLabels.size(); j != E; ++j) { - unsigned BeginLabel = LandingPad->BeginLabels[j]; + MCSymbol *BeginLabel = LandingPad->BeginLabels[j]; assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); PadRange P = { i, j }; PadMap[BeginLabel] = P; @@ -316,7 +306,7 @@ unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF, } bool MayThrow = false; - unsigned LastLabel = 0; + MCSymbol *LastLabel = 0; for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); I != E; ++I) { for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end(); @@ -326,7 +316,7 @@ unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF, continue; } - unsigned BeginLabel = MI->getOperand(0).getImm(); + MCSymbol *BeginLabel = MI->getOperand(0).getMCSymbol(); assert(BeginLabel && "Invalid label!"); if (BeginLabel == LastLabel) @@ -718,22 +708,20 @@ JITDwarfEmitter::GetFrameMovesSizeInBytes(intptr_t BaseLabelPtr, for (unsigned i = 0, N = Moves.size(); i < N; ++i) { const MachineMove &Move = Moves[i]; - unsigned LabelID = Move.getLabelID(); + MCSymbol *Label = Move.getLabel(); - if (LabelID) { - // Throw out move if the label is invalid. - if (MMI->isLabelDeleted(LabelID)) - continue; - } + // Throw out move if the label is invalid. + if (Label && !Label->isDefined()) + continue; intptr_t LabelPtr = 0; - if (LabelID) LabelPtr = JCE->getLabelAddress(LabelID); + if (Label) LabelPtr = JCE->getLabelAddress(Label); const MachineLocation &Dst = Move.getDestination(); const MachineLocation &Src = Move.getSource(); // Advance row if new location. - if (BaseLabelPtr && LabelID && (BaseLabelPtr != LabelPtr || !IsLocal)) { + if (BaseLabelPtr && Label && (BaseLabelPtr != LabelPtr || !IsLocal)) { FinalSize++; FinalSize += PointerSize; BaseLabelPtr = LabelPtr; @@ -891,7 +879,7 @@ JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const { for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { const LandingPadInfo *LandingPad = LandingPads[i]; for (unsigned j=0, E = LandingPad->BeginLabels.size(); j != E; ++j) { - unsigned BeginLabel = LandingPad->BeginLabels[j]; + MCSymbol *BeginLabel = LandingPad->BeginLabels[j]; assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); PadRange P = { i, j }; PadMap[BeginLabel] = P; @@ -899,7 +887,7 @@ JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const { } bool MayThrow = false; - unsigned LastLabel = 0; + MCSymbol *LastLabel = 0; for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); I != E; ++I) { for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end(); @@ -909,9 +897,8 @@ JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const { continue; } - unsigned BeginLabel = MI->getOperand(0).getImm(); - assert(BeginLabel && "Invalid label!"); - + MCSymbol *BeginLabel = MI->getOperand(0).getMCSymbol(); + if (BeginLabel == LastLabel) MayThrow = false; diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 783ebb4deb61..83acb5df9768 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -341,7 +341,7 @@ namespace { /// LabelLocations - This vector is a mapping from Label ID's to their /// address. - std::vector<uintptr_t> LabelLocations; + DenseMap<MCSymbol*, uintptr_t> LabelLocations; /// MMI - Machine module info for exception informations MachineModuleInfo* MMI; @@ -459,16 +459,13 @@ namespace { virtual void processDebugLoc(DebugLoc DL, bool BeforePrintingInsn); - virtual void emitLabel(uint64_t LabelID) { - if (LabelLocations.size() <= LabelID) - LabelLocations.resize((LabelID+1)*2); - LabelLocations[LabelID] = getCurrentPCValue(); + virtual void emitLabel(MCSymbol *Label) { + LabelLocations[Label] = getCurrentPCValue(); } - virtual uintptr_t getLabelAddress(uint64_t LabelID) const { - assert(LabelLocations.size() > (unsigned)LabelID && - LabelLocations[LabelID] && "Label not emitted!"); - return LabelLocations[LabelID]; + virtual uintptr_t getLabelAddress(MCSymbol *Label) const { + assert(LabelLocations.count(Label) && "Label not emitted!"); + return LabelLocations.find(Label)->second; } virtual void setModuleInfo(MachineModuleInfo* Info) { @@ -1393,6 +1390,8 @@ void JITEmitter::emitConstantPool(MachineConstantPool *MCP) { void JITEmitter::initJumpTableInfo(MachineJumpTableInfo *MJTI) { if (TheJIT->getJITInfo().hasCustomJumpTables()) return; + if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_Inline) + return; const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); if (JT.empty()) return; @@ -1420,6 +1419,8 @@ void JITEmitter::emitJumpTableInfo(MachineJumpTableInfo *MJTI) { switch (MJTI->getEntryKind()) { + case MachineJumpTableInfo::EK_Inline: + return; case MachineJumpTableInfo::EK_BlockAddress: { // EK_BlockAddress - Each entry is a plain address of block, e.g.: // .word LBB123 diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp index bda700b6aa73..c96ff82b308d 100644 --- a/lib/MC/MCAsmInfo.cpp +++ b/lib/MC/MCAsmInfo.cpp @@ -69,6 +69,7 @@ MCAsmInfo::MCAsmInfo() { DwarfRequiresFrameSection = true; DwarfUsesInlineInfoSection = false; DwarfSectionOffsetDirective = 0; + HasMicrosoftFastStdCallMangling = false; AsmTransCBE = 0; } diff --git a/lib/MC/MCAsmInfoCOFF.cpp b/lib/MC/MCAsmInfoCOFF.cpp index 9130493de277..5170206c729b 100644 --- a/lib/MC/MCAsmInfoCOFF.cpp +++ b/lib/MC/MCAsmInfoCOFF.cpp @@ -35,4 +35,5 @@ MCAsmInfoCOFF::MCAsmInfoCOFF() { AbsoluteEHSectionOffsets = false; SupportsDebugInformation = true; DwarfSectionOffsetDirective = "\t.secrel32\t"; + HasMicrosoftFastStdCallMangling = true; } diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 66a0a24bedeb..7f3947114fe4 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -41,11 +41,10 @@ class MCAsmStreamer : public MCStreamer { public: MCAsmStreamer(MCContext &Context, formatted_raw_ostream &os, - const MCAsmInfo &mai, bool isLittleEndian, bool isVerboseAsm, MCInstPrinter *printer, MCCodeEmitter *emitter, bool showInst) - : MCStreamer(Context), OS(os), MAI(mai), InstPrinter(printer), - Emitter(emitter), CommentStream(CommentToEmit), + : MCStreamer(Context), OS(os), MAI(Context.getAsmInfo()), + InstPrinter(printer), Emitter(emitter), CommentStream(CommentToEmit), IsLittleEndian(isLittleEndian), IsVerboseAsm(isVerboseAsm), ShowInst(showInst) { if (InstPrinter && IsVerboseAsm) @@ -654,9 +653,9 @@ void MCAsmStreamer::Finish() { MCStreamer *llvm::createAsmStreamer(MCContext &Context, formatted_raw_ostream &OS, - const MCAsmInfo &MAI, bool isLittleEndian, + bool isLittleEndian, bool isVerboseAsm, MCInstPrinter *IP, MCCodeEmitter *CE, bool ShowInst) { - return new MCAsmStreamer(Context, OS, MAI, isLittleEndian, isVerboseAsm, + return new MCAsmStreamer(Context, OS, isLittleEndian, isVerboseAsm, IP, CE, ShowInst); } diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 00b02e0c6c43..4cf8b7e522b3 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -9,6 +9,7 @@ #define DEBUG_TYPE "assembler" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSymbol.h" @@ -23,6 +24,8 @@ #include "llvm/Support/MachO.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Debug.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetAsmBackend.h" // FIXME: Gross. #include "../Target/X86/X86FixupKinds.h" @@ -49,8 +52,7 @@ static uint64_t WriteNopData(uint64_t Count, MachObjectWriter &MOW); static bool isVirtualSection(const MCSection &Section) { // FIXME: Lame. const MCSectionMachO &SMO = static_cast<const MCSectionMachO&>(Section); - unsigned Type = SMO.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; - return (Type == MCSectionMachO::S_ZEROFILL); + return (SMO.getType() == MCSectionMachO::S_ZEROFILL); } static unsigned getFixupKindLog2Size(unsigned Kind) { @@ -84,14 +86,19 @@ class MachObjectWriter { Header_Magic64 = 0xFEEDFACF }; - static const unsigned Header32Size = 28; - static const unsigned Header64Size = 32; - static const unsigned SegmentLoadCommand32Size = 56; - static const unsigned Section32Size = 68; - static const unsigned SymtabLoadCommandSize = 24; - static const unsigned DysymtabLoadCommandSize = 80; - static const unsigned Nlist32Size = 12; - static const unsigned RelocationInfoSize = 8; + enum { + Header32Size = 28, + Header64Size = 32, + SegmentLoadCommand32Size = 56, + SegmentLoadCommand64Size = 72, + Section32Size = 68, + Section64Size = 80, + SymtabLoadCommandSize = 24, + DysymtabLoadCommandSize = 80, + Nlist32Size = 12, + Nlist64Size = 16, + RelocationInfoSize = 8 + }; enum HeaderFileType { HFT_Object = 0x1 @@ -104,7 +111,8 @@ class MachObjectWriter { enum LoadCommandType { LCT_Segment = 0x1, LCT_Symtab = 0x2, - LCT_Dysymtab = 0xb + LCT_Dysymtab = 0xb, + LCT_Segment64 = 0x19 }; // See <mach-o/nlist.h>. @@ -159,11 +167,12 @@ class MachObjectWriter { }; raw_ostream &OS; - bool IsLSB; + unsigned Is64Bit : 1; + unsigned IsLSB : 1; public: - MachObjectWriter(raw_ostream &_OS, bool _IsLSB = true) - : OS(_OS), IsLSB(_IsLSB) { + MachObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool _IsLSB = true) + : OS(_OS), Is64Bit(_Is64Bit), IsLSB(_IsLSB) { } /// @name Helper Methods @@ -220,22 +229,23 @@ public: /// @} - void WriteHeader32(unsigned NumLoadCommands, unsigned LoadCommandsSize, - bool SubsectionsViaSymbols) { + void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize, + bool SubsectionsViaSymbols) { uint32_t Flags = 0; if (SubsectionsViaSymbols) Flags |= HF_SubsectionsViaSymbols; - // struct mach_header (28 bytes) + // struct mach_header (28 bytes) or + // struct mach_header_64 (32 bytes) uint64_t Start = OS.tell(); (void) Start; - Write32(Header_Magic32); + Write32(Is64Bit ? Header_Magic64 : Header_Magic32); // FIXME: Support cputype. - Write32(MachO::CPUTypeI386); + Write32(Is64Bit ? MachO::CPUTypeX86_64 : MachO::CPUTypeI386); // FIXME: Support cpusubtype. Write32(MachO::CPUSubType_I386_ALL); Write32(HFT_Object); @@ -243,48 +253,62 @@ public: // segment. Write32(LoadCommandsSize); Write32(Flags); + if (Is64Bit) + Write32(0); // reserved - assert(OS.tell() - Start == Header32Size); + assert(OS.tell() - Start == Is64Bit ? Header64Size : Header32Size); } - /// WriteSegmentLoadCommand32 - Write a 32-bit segment load command. + /// WriteSegmentLoadCommand - Write a segment load command. /// /// \arg NumSections - The number of sections in this segment. /// \arg SectionDataSize - The total size of the sections. - void WriteSegmentLoadCommand32(unsigned NumSections, - uint64_t VMSize, - uint64_t SectionDataStartOffset, - uint64_t SectionDataSize) { - // struct segment_command (56 bytes) + void WriteSegmentLoadCommand(unsigned NumSections, + uint64_t VMSize, + uint64_t SectionDataStartOffset, + uint64_t SectionDataSize) { + // struct segment_command (56 bytes) or + // struct segment_command_64 (72 bytes) uint64_t Start = OS.tell(); (void) Start; - Write32(LCT_Segment); - Write32(SegmentLoadCommand32Size + NumSections * Section32Size); + unsigned SegmentLoadCommandSize = Is64Bit ? SegmentLoadCommand64Size : + SegmentLoadCommand32Size; + Write32(Is64Bit ? LCT_Segment64 : LCT_Segment); + Write32(SegmentLoadCommandSize + + NumSections * (Is64Bit ? Section64Size : Section32Size)); WriteString("", 16); - Write32(0); // vmaddr - Write32(VMSize); // vmsize - Write32(SectionDataStartOffset); // file offset - Write32(SectionDataSize); // file size + if (Is64Bit) { + Write64(0); // vmaddr + Write64(VMSize); // vmsize + Write64(SectionDataStartOffset); // file offset + Write64(SectionDataSize); // file size + } else { + Write32(0); // vmaddr + Write32(VMSize); // vmsize + Write32(SectionDataStartOffset); // file offset + Write32(SectionDataSize); // file size + } Write32(0x7); // maxprot Write32(0x7); // initprot Write32(NumSections); Write32(0); // flags - assert(OS.tell() - Start == SegmentLoadCommand32Size); + assert(OS.tell() - Start == SegmentLoadCommandSize); } - void WriteSection32(const MCSectionData &SD, uint64_t FileOffset, - uint64_t RelocationsStart, unsigned NumRelocations) { + void WriteSection(const MCSectionData &SD, uint64_t FileOffset, + uint64_t RelocationsStart, unsigned NumRelocations) { // The offset is unused for virtual sections. if (isVirtualSection(SD.getSection())) { assert(SD.getFileSize() == 0 && "Invalid file size!"); FileOffset = 0; } - // struct section (68 bytes) + // struct section (68 bytes) or + // struct section_64 (80 bytes) uint64_t Start = OS.tell(); (void) Start; @@ -294,8 +318,13 @@ public: static_cast<const MCSectionMachO&>(SD.getSection()); WriteString(Section.getSectionName(), 16); WriteString(Section.getSegmentName(), 16); - Write32(SD.getAddress()); // address - Write32(SD.getSize()); // size + if (Is64Bit) { + Write64(SD.getAddress()); // address + Write64(SD.getSize()); // size + } else { + Write32(SD.getAddress()); // address + Write32(SD.getSize()); // size + } Write32(FileOffset); unsigned Flags = Section.getTypeAndAttributes(); @@ -309,8 +338,10 @@ public: Write32(Flags); Write32(0); // reserved1 Write32(Section.getStubSize()); // reserved2 + if (Is64Bit) + Write32(0); // reserved3 - assert(OS.tell() - Start == Section32Size); + assert(OS.tell() - Start == Is64Bit ? Section64Size : Section32Size); } void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols, @@ -368,7 +399,7 @@ public: assert(OS.tell() - Start == DysymtabLoadCommandSize); } - void WriteNlist32(MachSymbolData &MSD) { + void WriteNlist(MachSymbolData &MSD) { MCSymbolData &Data = *MSD.SymbolData; const MCSymbol &Symbol = Data.getSymbol(); uint8_t Type = 0; @@ -399,7 +430,7 @@ public: if (Symbol.isAbsolute()) { llvm_unreachable("FIXME: Not yet implemented!"); } else { - Address = Data.getFragment()->getAddress() + Data.getOffset(); + Address = Data.getAddress(); } } else if (Data.isCommon()) { // Common symbols are encoded with the size in the address @@ -427,7 +458,10 @@ public: // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' // value. Write16(Flags); - Write32(Address); + if (Is64Bit) + Write64(Address); + else + Write32(Address); } struct MachRelocationEntry { @@ -437,7 +471,6 @@ public: void ComputeScatteredRelocationInfo(MCAssembler &Asm, MCFragment &Fragment, MCAsmFixup &Fixup, const MCValue &Target, - DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap, std::vector<MachRelocationEntry> &Relocs) { uint32_t Address = Fragment.getOffset() + Fixup.Offset; unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind); @@ -446,17 +479,17 @@ public: // See <reloc.h>. const MCSymbol *A = Target.getSymA(); - MCSymbolData *A_SD = SymbolMap.lookup(A); + MCSymbolData *A_SD = &Asm.getSymbolData(*A); if (!A_SD->getFragment()) llvm_report_error("symbol '" + A->getName() + "' can not be undefined in a subtraction expression"); - uint32_t Value = A_SD->getFragment()->getAddress() + A_SD->getOffset(); + uint32_t Value = A_SD->getAddress(); uint32_t Value2 = 0; if (const MCSymbol *B = Target.getSymB()) { - MCSymbolData *B_SD = SymbolMap.lookup(B); + MCSymbolData *B_SD = &Asm.getSymbolData(*B); if (!B_SD->getFragment()) llvm_report_error("symbol '" + B->getName() + @@ -468,22 +501,9 @@ public: // relocation types from the linkers point of view, this is done solely // for pedantic compatibility with 'as'. Type = A_SD->isExternal() ? RIT_Difference : RIT_LocalDifference; - Value2 = B_SD->getFragment()->getAddress() + B_SD->getOffset(); + Value2 = B_SD->getAddress(); } - // The value which goes in the fixup is current value of the expression. - Fixup.FixedValue = Value - Value2 + Target.getConstant(); - if (IsPCRel) - Fixup.FixedValue -= Address; - - // If this fixup is a vanilla PC relative relocation for a local label, we - // don't need a relocation. - // - // FIXME: Implement proper atom support. - if (IsPCRel && Target.getSymA() && Target.getSymA()->isTemporary() && - !Target.getSymB()) - return; - MachRelocationEntry MRE; MRE.Word0 = ((Address << 0) | (Type << 24) | @@ -507,14 +527,17 @@ public: void ComputeRelocationInfo(MCAssembler &Asm, MCDataFragment &Fragment, MCAsmFixup &Fixup, - DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap, std::vector<MachRelocationEntry> &Relocs) { unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind); unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind); + // FIXME: Share layout object. + MCAsmLayout Layout(Asm); + + // Evaluate the fixup; if the value was resolved, no relocation is needed. MCValue Target; - if (!Fixup.Value->EvaluateAsRelocatable(Target)) - llvm_report_error("expected relocatable expression"); + if (Asm.EvaluateFixup(Layout, Fixup, &Fragment, Target, Fixup.FixedValue)) + return; // If this is a difference or a defined symbol plus an offset, then we need // a scattered relocation entry. @@ -525,7 +548,7 @@ public: (Target.getSymA() && !Target.getSymA()->isUndefined() && Offset)) return ComputeScatteredRelocationInfo(Asm, Fragment, Fixup, Target, - SymbolMap, Relocs); + Relocs); // See <reloc.h>. uint32_t Address = Fragment.getOffset() + Fixup.Offset; @@ -537,13 +560,13 @@ public: if (Target.isAbsolute()) { // constant // SymbolNum of 0 indicates the absolute section. // - // FIXME: When is this generated? + // FIXME: Currently, these are never generated (see code below). I cannot + // find a case where they are actually emitted. Type = RIT_Vanilla; Value = 0; - llvm_unreachable("FIXME: Not yet implemented!"); } else { const MCSymbol *Symbol = Target.getSymA(); - MCSymbolData *SD = SymbolMap.lookup(Symbol); + MCSymbolData *SD = &Asm.getSymbolData(*Symbol); if (Symbol->isUndefined()) { IsExtern = 1; @@ -559,24 +582,12 @@ public: if (&*it == SD->getFragment()->getParent()) break; assert(it != ie && "Unable to find section index!"); - Value = SD->getFragment()->getAddress() + SD->getOffset(); + Value = SD->getAddress(); } Type = RIT_Vanilla; } - // The value which goes in the fixup is current value of the expression. - Fixup.FixedValue = Value + Target.getConstant(); - if (IsPCRel) - Fixup.FixedValue -= Address; - - // If this fixup is a vanilla PC relative relocation for a local label, we - // don't need a relocation. - // - // FIXME: Implement proper atom support. - if (IsPCRel && Target.getSymA() && Target.getSymA()->isTemporary()) - return; - // struct relocation_info (8 bytes) MachRelocationEntry MRE; MRE.Word0 = Address; @@ -588,8 +599,7 @@ public: Relocs.push_back(MRE); } - void BindIndirectSymbols(MCAssembler &Asm, - DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap) { + void BindIndirectSymbols(MCAssembler &Asm) { // This is the point where 'as' creates actual symbols for indirect symbols // (in the following two passes). It would be easier for us to do this // sooner when we see the attribute, but that makes getting the order in the @@ -604,14 +614,10 @@ public: const MCSectionMachO &Section = static_cast<const MCSectionMachO&>(it->SectionData->getSection()); - unsigned Type = - Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; - if (Type != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) + if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) continue; - MCSymbolData *&Entry = SymbolMap[it->Symbol]; - if (!Entry) - Entry = new MCSymbolData(*it->Symbol, 0, 0, &Asm); + Asm.getOrCreateSymbolData(*it->Symbol); } // Then lazy symbol pointers and symbol stubs. @@ -621,21 +627,17 @@ public: const MCSectionMachO &Section = static_cast<const MCSectionMachO&>(it->SectionData->getSection()); - unsigned Type = - Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; - if (Type != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && - Type != MCSectionMachO::S_SYMBOL_STUBS) + if (Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && + Section.getType() != MCSectionMachO::S_SYMBOL_STUBS) continue; - MCSymbolData *&Entry = SymbolMap[it->Symbol]; - if (!Entry) { - Entry = new MCSymbolData(*it->Symbol, 0, 0, &Asm); - - // Set the symbol type to undefined lazy, but only on construction. - // - // FIXME: Do not hardcode. - Entry->setFlags(Entry->getFlags() | 0x0001); - } + // Set the symbol type to undefined lazy, but only on construction. + // + // FIXME: Do not hardcode. + bool Created; + MCSymbolData &Entry = Asm.getOrCreateSymbolData(*it->Symbol, &Created); + if (Created) + Entry.setFlags(Entry.getFlags() | 0x0001); } } @@ -672,7 +674,10 @@ public: const MCSymbol &Symbol = it->getSymbol(); // Ignore assembler temporaries. - if (it->getSymbol().isTemporary()) + if (it->getSymbol().isTemporary() && + (!it->getFragment() || + !Asm.getBackend().doesSectionRequireSymbols( + it->getFragment()->getParent()->getSection()))) continue; if (!it->isExternal() && !Symbol.isUndefined()) @@ -708,7 +713,10 @@ public: const MCSymbol &Symbol = it->getSymbol(); // Ignore assembler temporaries. - if (it->getSymbol().isTemporary()) + if (it->getSymbol().isTemporary() && + (!it->getFragment() || + !Asm.getBackend().doesSectionRequireSymbols( + it->getFragment()->getParent()->getSection()))) continue; if (it->isExternal() || Symbol.isUndefined()) @@ -756,16 +764,8 @@ public: void WriteObject(MCAssembler &Asm) { unsigned NumSections = Asm.size(); - // Compute the symbol -> symbol data map. - // - // FIXME: This should not be here. - DenseMap<const MCSymbol*, MCSymbolData *> SymbolMap; - for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), - ie = Asm.symbol_end(); it != ie; ++it) - SymbolMap[&it->getSymbol()] = it; - // Create symbol data for any indirect symbols. - BindIndirectSymbols(Asm, SymbolMap); + BindIndirectSymbols(Asm); // Compute symbol table information. SmallString<256> StringTable; @@ -782,7 +782,8 @@ public: // The section data starts after the header, the segment load command (and // section headers) and the symbol table. unsigned NumLoadCommands = 1; - uint64_t LoadCommandsSize = + uint64_t LoadCommandsSize = Is64Bit ? + SegmentLoadCommand64Size + NumSections * Section64Size : SegmentLoadCommand32Size + NumSections * Section32Size; // Add the symbol table load command sizes, if used. @@ -793,7 +794,8 @@ public: // Compute the total size of the section data, as well as its file size and // vm size. - uint64_t SectionDataStart = Header32Size + LoadCommandsSize; + uint64_t SectionDataStart = (Is64Bit ? Header64Size : Header32Size) + + LoadCommandsSize; uint64_t SectionDataSize = 0; uint64_t SectionDataFileSize = 0; uint64_t VMSize = 0; @@ -819,10 +821,10 @@ public: SectionDataFileSize += SectionDataPadding; // Write the prolog, starting with the header and load command... - WriteHeader32(NumLoadCommands, LoadCommandsSize, - Asm.getSubsectionsViaSymbols()); - WriteSegmentLoadCommand32(NumSections, VMSize, - SectionDataStart, SectionDataSize); + WriteHeader(NumLoadCommands, LoadCommandsSize, + Asm.getSubsectionsViaSymbols()); + WriteSegmentLoadCommand(NumSections, VMSize, + SectionDataStart, SectionDataSize); // ... and then the section headers. // @@ -845,11 +847,11 @@ public: if (MCDataFragment *DF = dyn_cast<MCDataFragment>(&*it2)) for (unsigned i = 0, e = DF->fixup_size(); i != e; ++i) ComputeRelocationInfo(Asm, *DF, DF->getFixups()[e - i - 1], - SymbolMap, RelocInfos); + RelocInfos); unsigned NumRelocs = RelocInfos.size() - NumRelocsStart; uint64_t SectionStart = SectionDataStart + SD.getAddress(); - WriteSection32(SD, SectionStart, RelocTableEnd, NumRelocs); + WriteSection(SD, SectionStart, RelocTableEnd, NumRelocs); RelocTableEnd += NumRelocs * RelocationInfoSize; } @@ -876,7 +878,8 @@ public: // The string table is written after symbol table. uint64_t StringTableOffset = - SymbolTableOffset + NumSymTabSymbols * Nlist32Size; + SymbolTableOffset + NumSymTabSymbols * (Is64Bit ? Nlist64Size : + Nlist32Size); WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols, StringTableOffset, StringTable.size()); @@ -909,12 +912,10 @@ public: // special handling. const MCSectionMachO &Section = static_cast<const MCSectionMachO&>(it->SectionData->getSection()); - unsigned Type = - Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; - if (Type == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) { + if (Section.getType() == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) { // If this symbol is defined and internal, mark it as such. if (it->Symbol->isDefined() && - !SymbolMap.lookup(it->Symbol)->isExternal()) { + !Asm.getSymbolData(*it->Symbol).isExternal()) { uint32_t Flags = ISF_Local; if (it->Symbol->isAbsolute()) Flags |= ISF_Absolute; @@ -923,18 +924,18 @@ public: } } - Write32(SymbolMap[it->Symbol]->getIndex()); + Write32(Asm.getSymbolData(*it->Symbol).getIndex()); } // FIXME: Check that offsets match computed ones. // Write the symbol table entries. for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) - WriteNlist32(LocalSymbolData[i]); + WriteNlist(LocalSymbolData[i]); for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) - WriteNlist32(ExternalSymbolData[i]); + WriteNlist(ExternalSymbolData[i]); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) - WriteNlist32(UndefinedSymbolData[i]); + WriteNlist(UndefinedSymbolData[i]); // Write the string table. OS << StringTable.str(); @@ -1006,15 +1007,65 @@ MCSymbolData::MCSymbolData(const MCSymbol &_Symbol, MCFragment *_Fragment, /* *** */ -MCAssembler::MCAssembler(MCContext &_Context, raw_ostream &_OS) - : Context(_Context), OS(_OS), SubsectionsViaSymbols(false) +MCAssembler::MCAssembler(MCContext &_Context, TargetAsmBackend &_Backend, + raw_ostream &_OS) + : Context(_Context), Backend(_Backend), OS(_OS), SubsectionsViaSymbols(false) { } MCAssembler::~MCAssembler() { } +bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout, MCAsmFixup &Fixup, + MCDataFragment *DF, + MCValue &Target, uint64_t &Value) const { + if (!Fixup.Value->EvaluateAsRelocatable(Target, &Layout)) + llvm_report_error("expected relocatable expression"); + + // FIXME: How do non-scattered symbols work in ELF? I presume the linker + // doesn't support small relocations, but then under what criteria does the + // assembler allow symbol differences? + + Value = Target.getConstant(); + + // FIXME: This "resolved" check isn't quite right. The assumption is that if + // we have a PCrel access to a temporary, then that temporary is in the same + // atom, and so the value is resolved. We need explicit atom's to implement + // this more precisely. + bool IsResolved = true, IsPCRel = isFixupKindPCRel(Fixup.Kind); + if (const MCSymbol *Symbol = Target.getSymA()) { + if (Symbol->isDefined()) + Value += getSymbolData(*Symbol).getAddress(); + else + IsResolved = false; + + // With scattered symbols, we assume anything that isn't a PCrel temporary + // access can have an arbitrary value. + if (getBackend().hasScatteredSymbols() && + (!IsPCRel || !Symbol->isTemporary())) + IsResolved = false; + } + if (const MCSymbol *Symbol = Target.getSymB()) { + if (Symbol->isDefined()) + Value -= getSymbolData(*Symbol).getAddress(); + else + IsResolved = false; + + // With scattered symbols, we assume anything that isn't a PCrel temporary + // access can have an arbitrary value. + if (getBackend().hasScatteredSymbols() && + (!IsPCRel || !Symbol->isTemporary())) + IsResolved = false; + } + + if (IsPCRel) + Value -= DF->getAddress() + Fixup.Offset; + + return IsResolved; +} + void MCAssembler::LayoutSection(MCSectionData &SD) { + MCAsmLayout Layout(*this); uint64_t Address = SD.getAddress(); for (MCSectionData::iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) { @@ -1043,21 +1094,17 @@ void MCAssembler::LayoutSection(MCSectionData &SD) { case MCFragment::FT_Org: { MCOrgFragment &OF = cast<MCOrgFragment>(F); - MCValue Target; - if (!OF.getOffset().EvaluateAsRelocatable(Target)) - llvm_report_error("expected relocatable expression"); - - if (!Target.isAbsolute()) - llvm_unreachable("FIXME: Not yet implemented!"); - uint64_t OrgOffset = Target.getConstant(); - uint64_t Offset = Address - SD.getAddress(); + int64_t TargetLocation; + if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, &Layout)) + llvm_report_error("expected assembly-time absolute expression"); // FIXME: We need a way to communicate this error. - if (OrgOffset < Offset) - llvm_report_error("invalid .org offset '" + Twine(OrgOffset) + - "' (at offset '" + Twine(Offset) + "'"); + int64_t Offset = TargetLocation - F.getOffset(); + if (Offset < 0) + llvm_report_error("invalid .org offset '" + Twine(TargetLocation) + + "' (at offset '" + Twine(F.getOffset()) + "'"); - F.setFileSize(OrgOffset - Offset); + F.setFileSize(Offset); break; } @@ -1263,6 +1310,43 @@ void MCAssembler::Finish() { llvm::errs() << "assembler backend - pre-layout\n--\n"; dump(); }); + // Layout until everything fits. + while (LayoutOnce()) + continue; + + DEBUG_WITH_TYPE("mc-dump", { + llvm::errs() << "assembler backend - post-layout\n--\n"; + dump(); }); + + // Write the object file. + // + // FIXME: Factor out MCObjectWriter. + bool Is64Bit = StringRef(getBackend().getTarget().getName()) == "x86-64"; + MachObjectWriter MOW(OS, Is64Bit); + MOW.WriteObject(*this); + + OS.flush(); +} + +bool MCAssembler::FixupNeedsRelaxation(MCAsmFixup &Fixup, MCDataFragment *DF) { + // FIXME: Share layout object. + MCAsmLayout Layout(*this); + + // Currently we only need to relax X86::reloc_pcrel_1byte. + if (unsigned(Fixup.Kind) != X86::reloc_pcrel_1byte) + return false; + + // If we cannot resolve the fixup value, it requires relaxation. + MCValue Target; + uint64_t Value; + if (!EvaluateFixup(Layout, Fixup, DF, Target, Value)) + return true; + + // Otherwise, relax if the value is too big for a (signed) i8. + return int64_t(Value) != int64_t(int8_t(Value)); +} + +bool MCAssembler::LayoutOnce() { // Layout the concrete sections and fragments. uint64_t Address = 0; MCSectionData *Prev = 0; @@ -1304,20 +1388,94 @@ void MCAssembler::Finish() { SD.setAddress(Address); LayoutSection(SD); Address += SD.getSize(); - } - DEBUG_WITH_TYPE("mc-dump", { - llvm::errs() << "assembler backend - post-layout\n--\n"; - dump(); }); + // Scan the fixups in order and relax any that don't fit. + for (iterator it = begin(), ie = end(); it != ie; ++it) { + MCSectionData &SD = *it; - // Write the object file. - MachObjectWriter MOW(OS); - MOW.WriteObject(*this); + for (MCSectionData::iterator it2 = SD.begin(), + ie2 = SD.end(); it2 != ie2; ++it2) { + MCDataFragment *DF = dyn_cast<MCDataFragment>(it2); + if (!DF) + continue; - OS.flush(); -} + for (MCDataFragment::fixup_iterator it3 = DF->fixup_begin(), + ie3 = DF->fixup_end(); it3 != ie3; ++it3) { + MCAsmFixup &Fixup = *it3; + + // Check whether we need to relax this fixup. + if (!FixupNeedsRelaxation(Fixup, DF)) + continue; + + // Relax the instruction. + // + // FIXME: This is a huge temporary hack which just looks for x86 + // branches; the only thing we need to relax on x86 is + // 'X86::reloc_pcrel_1byte'. Once we have MCInst fragments, this will be + // replaced by a TargetAsmBackend hook (most likely tblgen'd) to relax + // an individual MCInst. + SmallVectorImpl<char> &C = DF->getContents(); + uint64_t PrevOffset = Fixup.Offset; + unsigned Amt = 0; + + // jcc instructions + if (unsigned(C[Fixup.Offset-1]) >= 0x70 && + unsigned(C[Fixup.Offset-1]) <= 0x7f) { + C[Fixup.Offset] = C[Fixup.Offset-1] + 0x10; + C[Fixup.Offset-1] = char(0x0f); + ++Fixup.Offset; + Amt = 4; + + // jmp rel8 + } else if (C[Fixup.Offset-1] == char(0xeb)) { + C[Fixup.Offset-1] = char(0xe9); + Amt = 3; + + } else + llvm_unreachable("unknown 1 byte pcrel instruction!"); + + Fixup.Value = MCBinaryExpr::Create( + MCBinaryExpr::Sub, Fixup.Value, + MCConstantExpr::Create(3, getContext()), + getContext()); + C.insert(C.begin() + Fixup.Offset, Amt, char(0)); + Fixup.Kind = MCFixupKind(X86::reloc_pcrel_4byte); + + // Update the remaining fixups, which have slid. + // + // FIXME: This is bad for performance, but will be eliminated by the + // move to MCInst specific fragments. + ++it3; + for (; it3 != ie3; ++it3) + it3->Offset += Amt; + + // Update all the symbols for this fragment, which may have slid. + // + // FIXME: This is really really bad for performance, but will be + // eliminated by the move to MCInst specific fragments. + for (MCAssembler::symbol_iterator it = symbol_begin(), + ie = symbol_end(); it != ie; ++it) { + MCSymbolData &SD = *it; + if (it->getFragment() != DF) + continue; + + if (SD.getOffset() > PrevOffset) + SD.setOffset(SD.getOffset() + Amt); + } + + // Restart layout. + // + // FIXME: This is O(N^2), but will be eliminated once we have a smart + // MCAsmLayout object. + return true; + } + } + } + + return false; +} // Debugging methods diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 63264f63c448..70c89a2333af 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -8,14 +8,14 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCValue.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" using namespace llvm; -MCContext::MCContext() { +MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0) { } MCContext::~MCContext() { @@ -23,30 +23,41 @@ MCContext::~MCContext() { // we don't need to free them here. } -MCSymbol *MCContext::GetOrCreateSymbol(StringRef Name) { +MCSymbol *MCContext::GetOrCreateSymbol(StringRef Name, bool isTemporary) { assert(!Name.empty() && "Normal symbols cannot be unnamed!"); - MCSymbol *&Entry = Symbols[Name]; - if (Entry) return Entry; + + // Do the lookup and get the entire StringMapEntry. We want access to the + // key if we are creating the entry. + StringMapEntry<MCSymbol*> &Entry = Symbols.GetOrCreateValue(Name); + if (Entry.getValue()) return Entry.getValue(); - return Entry = new (*this) MCSymbol(Name, false); + // Ok, the entry doesn't already exist. Have the MCSymbol object itself refer + // to the copy of the string that is embedded in the StringMapEntry. + MCSymbol *Result = new (*this) MCSymbol(Entry.getKey(), isTemporary); + Entry.setValue(Result); + return Result; } -MCSymbol *MCContext::GetOrCreateSymbol(const Twine &Name) { +MCSymbol *MCContext::GetOrCreateSymbol(const Twine &Name, bool isTemporary) { SmallString<128> NameSV; Name.toVector(NameSV); - return GetOrCreateSymbol(NameSV.str()); + return GetOrCreateSymbol(NameSV.str(), isTemporary); +} + +MCSymbol *MCContext::CreateTempSymbol() { + return GetOrCreateTemporarySymbol(Twine(MAI.getPrivateGlobalPrefix()) + + "tmp" + Twine(NextUniqueID++)); } MCSymbol *MCContext::GetOrCreateTemporarySymbol(StringRef Name) { - // If unnamed, just create a symbol. + // If there is no name, create a new anonymous symbol. + // FIXME: Remove this. This form of the method should always take a name. if (Name.empty()) - new (*this) MCSymbol("", true); - - // Otherwise create as usual. - MCSymbol *&Entry = Symbols[Name]; - if (Entry) return Entry; - return Entry = new (*this) MCSymbol(Name, true); + return GetOrCreateTemporarySymbol(Twine(MAI.getPrivateGlobalPrefix()) + + "tmp" + Twine(NextUniqueID++)); + + return GetOrCreateSymbol(Name, true); } MCSymbol *MCContext::GetOrCreateTemporarySymbol(const Twine &Name) { diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 4439eba5d475..a2ed20bb28ca 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -8,11 +8,15 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCExpr.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmBackend.h" using namespace llvm; void MCExpr::print(raw_ostream &OS) const { @@ -24,7 +28,8 @@ void MCExpr::print(raw_ostream &OS) const { return; case MCExpr::SymbolRef: { - const MCSymbol &Sym = cast<MCSymbolRefExpr>(*this).getSymbol(); + const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*this); + const MCSymbol &Sym = SRE.getSymbol(); // Parenthesize names that start with $ so that they don't look like // absolute names. @@ -32,6 +37,10 @@ void MCExpr::print(raw_ostream &OS) const { OS << '(' << Sym << ')'; else OS << Sym; + + if (SRE.getKind() != MCSymbolRefExpr::VK_None) + OS << '@' << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); + return; } @@ -124,28 +133,68 @@ const MCConstantExpr *MCConstantExpr::Create(int64_t Value, MCContext &Ctx) { return new (Ctx) MCConstantExpr(Value); } +/* *** */ + const MCSymbolRefExpr *MCSymbolRefExpr::Create(const MCSymbol *Sym, + VariantKind Kind, MCContext &Ctx) { - return new (Ctx) MCSymbolRefExpr(Sym); + return new (Ctx) MCSymbolRefExpr(Sym, Kind); } -const MCSymbolRefExpr *MCSymbolRefExpr::Create(StringRef Name, MCContext &Ctx) { - return Create(Ctx.GetOrCreateSymbol(Name), Ctx); +const MCSymbolRefExpr *MCSymbolRefExpr::Create(StringRef Name, VariantKind Kind, + MCContext &Ctx) { + return Create(Ctx.GetOrCreateSymbol(Name), Kind, Ctx); } const MCSymbolRefExpr *MCSymbolRefExpr::CreateTemp(StringRef Name, + VariantKind Kind, MCContext &Ctx) { - return Create(Ctx.GetOrCreateTemporarySymbol(Name), Ctx); + return Create(Ctx.GetOrCreateTemporarySymbol(Name), Kind, Ctx); } +StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { + switch (Kind) { + default: + case VK_Invalid: return "<<invalid>>"; + case VK_None: return "<<none>>"; + + case VK_GOT: return "GOT"; + case VK_GOTOFF: return "GOTOFF"; + case VK_GOTPCREL: return "GOTPCREL"; + case VK_GOTTPOFF: return "GOTTPOFF"; + case VK_INDNTPOFF: return "INDNTPOFF"; + case VK_NTPOFF: return "NTPOFF"; + case VK_PLT: return "PLT"; + case VK_TLSGD: return "TLSGD"; + case VK_TPOFF: return "TPOFF"; + } +} + +MCSymbolRefExpr::VariantKind +MCSymbolRefExpr::getVariantKindForName(StringRef Name) { + return StringSwitch<VariantKind>(Name) + .Case("GOT", VK_GOT) + .Case("GOTOFF", VK_GOTOFF) + .Case("GOTPCREL", VK_GOTPCREL) + .Case("GOTTPOFF", VK_GOTTPOFF) + .Case("INDNTPOFF", VK_INDNTPOFF) + .Case("NTPOFF", VK_NTPOFF) + .Case("PLT", VK_PLT) + .Case("TLSGD", VK_TLSGD) + .Case("TPOFF", VK_TPOFF) + .Default(VK_Invalid); +} + +/* *** */ + void MCTargetExpr::Anchor() {} /* *** */ -bool MCExpr::EvaluateAsAbsolute(int64_t &Res) const { +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const { MCValue Value; - if (!EvaluateAsRelocatable(Value) || !Value.isAbsolute()) + if (!EvaluateAsRelocatable(Value, Layout) || !Value.isAbsolute()) return false; Res = Value.getConstant(); @@ -174,10 +223,11 @@ static bool EvaluateSymbolicAdd(const MCValue &LHS, const MCSymbol *RHS_A, return true; } -bool MCExpr::EvaluateAsRelocatable(MCValue &Res) const { +bool MCExpr::EvaluateAsRelocatable(MCValue &Res, + const MCAsmLayout *Layout) const { switch (getKind()) { case Target: - return cast<MCTargetExpr>(this)->EvaluateAsRelocatableImpl(Res); + return cast<MCTargetExpr>(this)->EvaluateAsRelocatableImpl(Res, Layout); case Constant: Res = MCValue::get(cast<MCConstantExpr>(this)->getValue()); @@ -187,8 +237,24 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res) const { const MCSymbol &Sym = cast<MCSymbolRefExpr>(this)->getSymbol(); // Evaluate recursively if this is a variable. - if (Sym.isVariable()) - return Sym.getValue()->EvaluateAsRelocatable(Res); + if (Sym.isVariable()) { + if (!Sym.getValue()->EvaluateAsRelocatable(Res, Layout)) + return false; + + // Absolutize symbol differences between defined symbols when we have a + // layout object and the target requests it. + if (Layout && Res.getSymB() && + Layout->getAssembler().getBackend().hasAbsolutizedSet() && + Res.getSymA()->isDefined() && Res.getSymB()->isDefined()) { + MCSymbolData &A = Layout->getAssembler().getSymbolData(*Res.getSymA()); + MCSymbolData &B = Layout->getAssembler().getSymbolData(*Res.getSymB()); + Res = MCValue::get(+ A.getFragment()->getAddress() + A.getOffset() + - B.getFragment()->getAddress() - B.getOffset() + + Res.getConstant()); + } + + return true; + } Res = MCValue::get(&Sym, 0, 0); return true; @@ -198,7 +264,7 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res) const { const MCUnaryExpr *AUE = cast<MCUnaryExpr>(this); MCValue Value; - if (!AUE->getSubExpr()->EvaluateAsRelocatable(Value)) + if (!AUE->getSubExpr()->EvaluateAsRelocatable(Value, Layout)) return false; switch (AUE->getOpcode()) { @@ -231,8 +297,8 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res) const { const MCBinaryExpr *ABE = cast<MCBinaryExpr>(this); MCValue LHSValue, RHSValue; - if (!ABE->getLHS()->EvaluateAsRelocatable(LHSValue) || - !ABE->getRHS()->EvaluateAsRelocatable(RHSValue)) + if (!ABE->getLHS()->EvaluateAsRelocatable(LHSValue, Layout) || + !ABE->getRHS()->EvaluateAsRelocatable(RHSValue, Layout)) return false; // We only support a few operations on non-constant expressions, handle diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index a7a8a5daed9f..73b1074531d1 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -16,7 +16,6 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCValue.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -48,8 +47,6 @@ private: MCAssembler Assembler; MCCodeEmitter *Emitter; MCSectionData *CurSectionData; - DenseMap<const MCSection*, MCSectionData*> SectionMap; - DenseMap<const MCSymbol*, MCSymbolData*> SymbolMap; private: MCFragment *getCurrentFragment() const { @@ -61,27 +58,10 @@ private: return 0; } - MCSectionData &getSectionData(const MCSection &Section) { - MCSectionData *&Entry = SectionMap[&Section]; - - if (!Entry) - Entry = new MCSectionData(Section, &Assembler); - - return *Entry; - } - - MCSymbolData &getSymbolData(const MCSymbol &Symbol) { - MCSymbolData *&Entry = SymbolMap[&Symbol]; - - if (!Entry) - Entry = new MCSymbolData(Symbol, 0, 0, &Assembler); - - return *Entry; - } - public: - MCMachOStreamer(MCContext &Context, raw_ostream &_OS, MCCodeEmitter *_Emitter) - : MCStreamer(Context), Assembler(Context, _OS), Emitter(_Emitter), + MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB, + raw_ostream &_OS, MCCodeEmitter *_Emitter) + : MCStreamer(Context), Assembler(Context, TAB, _OS), Emitter(_Emitter), CurSectionData(0) {} ~MCMachOStreamer() {} @@ -99,7 +79,8 @@ public: } case MCExpr::SymbolRef: - getSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol()); + Assembler.getOrCreateSymbolData( + cast<MCSymbolRefExpr>(Value)->getSymbol()); break; case MCExpr::Unary: @@ -164,7 +145,7 @@ void MCMachOStreamer::SwitchSection(const MCSection *Section) { if (Section == CurSection) return; CurSection = Section; - CurSectionData = &getSectionData(*Section); + CurSectionData = &Assembler.getOrCreateSectionData(*Section); } void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { @@ -175,7 +156,7 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { if (!F) F = new MCDataFragment(CurSectionData); - MCSymbolData &SD = getSymbolData(*Symbol); + MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol); assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); SD.setFragment(F); SD.setOffset(F->getContents().size()); @@ -203,7 +184,7 @@ void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { // FIXME: Lift context changes into super class. // FIXME: Set associated section. - Symbol->setValue(Value); + Symbol->setValue(AddValueSymbols(Value)); } void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, @@ -221,9 +202,9 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, } // Adding a symbol attribute always introduces the symbol, note that an - // important side effect of calling getSymbolData here is to register the - // symbol with the assembler. - MCSymbolData &SD = getSymbolData(*Symbol); + // important side effect of calling getOrCreateSymbolData here is to register + // the symbol with the assembler. + MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol); // The implementation of symbol attributes is designed to match 'as', but it // leaves much to desired. It doesn't really make sense to arbitrarily add and @@ -289,7 +270,7 @@ void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { // Encode the 'desc' value into the lowest implementation defined bits. assert(DescValue == (DescValue & SF_DescFlagsMask) && "Invalid .desc value!"); - getSymbolData(*Symbol).setFlags(DescValue & SF_DescFlagsMask); + Assembler.getOrCreateSymbolData(*Symbol).setFlags(DescValue&SF_DescFlagsMask); } void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, @@ -297,14 +278,14 @@ void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself. assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - MCSymbolData &SD = getSymbolData(*Symbol); + MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol); SD.setExternal(true); SD.setCommon(Size, ByteAlignment); } void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, unsigned Size, unsigned ByteAlignment) { - MCSectionData &SectData = getSectionData(*Section); + MCSectionData &SectData = Assembler.getOrCreateSectionData(*Section); // The symbol may not be present, which only creates the section. if (!Symbol) @@ -314,7 +295,7 @@ void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - MCSymbolData &SD = getSymbolData(*Symbol); + MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol); MCFragment *F = new MCZeroFillFragment(Size, ByteAlignment, &SectData); SD.setFragment(F); @@ -346,9 +327,8 @@ void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, for (unsigned i = 0; i != Size; ++i) DF->getContents().push_back(uint8_t(AbsValue >> (i * 8))); } else { - DF->getFixups().push_back(MCAsmFixup(DF->getContents().size(), - *AddValueSymbols(Value), - MCFixup::getKindForSize(Size))); + DF->addFixup(MCAsmFixup(DF->getContents().size(), *AddValueSymbols(Value), + MCFixup::getKindForSize(Size))); DF->getContents().resize(DF->getContents().size() + Size, 0); } } @@ -407,9 +387,8 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { DF = new MCDataFragment(CurSectionData); for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; - DF->getFixups().push_back(MCAsmFixup(DF->getContents().size()+F.getOffset(), - *F.getValue(), - F.getKind())); + DF->addFixup(MCAsmFixup(DF->getContents().size()+F.getOffset(), + *F.getValue(), F.getKind())); } DF->getContents().append(Code.begin(), Code.end()); } @@ -418,7 +397,7 @@ void MCMachOStreamer::Finish() { Assembler.Finish(); } -MCStreamer *llvm::createMachOStreamer(MCContext &Context, raw_ostream &OS, - MCCodeEmitter *CE) { - return new MCMachOStreamer(Context, OS, CE); +MCStreamer *llvm::createMachOStreamer(MCContext &Context, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *CE) { + return new MCMachOStreamer(Context, TAB, OS, CE); } diff --git a/lib/MC/MCParser/AsmLexer.cpp b/lib/MC/MCParser/AsmLexer.cpp index 482eefd93e04..22c8d762df3a 100644 --- a/lib/MC/MCParser/AsmLexer.cpp +++ b/lib/MC/MCParser/AsmLexer.cpp @@ -140,8 +140,14 @@ AsmToken AsmLexer::LexDigit() { StringRef Result(TokStart, CurPtr - TokStart); long long Value; - if (Result.getAsInteger(10, Value)) - return ReturnError(TokStart, "Invalid decimal number"); + if (Result.getAsInteger(10, Value)) { + // We have to handle minint_as_a_positive_value specially, because + // - minint_as_a_positive_value = minint and it is valid. + if (Result == "9223372036854775808") + Value = -9223372036854775808ULL; + else + return ReturnError(TokStart, "Invalid decimal number"); + } return AsmToken(AsmToken::Integer, Result, Value); } diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index fc8d549b8a12..4ec5247d62eb 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -20,7 +20,6 @@ #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCValue.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/SourceMgr.h" @@ -139,15 +138,14 @@ const AsmToken &AsmParser::Lex() { return *tok; } -bool AsmParser::Run() { - // Create the initial section. +bool AsmParser::Run(bool NoInitialTextSection) { + // Create the initial section, if requested. // - // FIXME: Support -n. // FIXME: Target hook & command line option for initial section. - Out.SwitchSection(getMachOSection("__TEXT", "__text", - MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, - 0, SectionKind::getText())); - + if (!NoInitialTextSection) + Out.SwitchSection(getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); // Prime the lexer. Lex(); @@ -264,19 +262,29 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { case AsmToken::String: case AsmToken::Identifier: { // This is a symbol reference. - MCSymbol *Sym = CreateSymbol(getTok().getIdentifier()); + std::pair<StringRef, StringRef> Split = getTok().getIdentifier().split('@'); + MCSymbol *Sym = CreateSymbol(Split.first); + + // Lookup the symbol variant if used. + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + if (Split.first.size() != getTok().getIdentifier().size()) + Variant = MCSymbolRefExpr::getVariantKindForName(Split.second); + EndLoc = Lexer.getLoc(); Lex(); // Eat identifier. // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. if (Sym->getValue() && isa<MCConstantExpr>(Sym->getValue())) { + if (Variant) + return Error(EndLoc, "unexpected modified on variable reference"); + Res = Sym->getValue(); return false; } // Otherwise create a symbol ref. - Res = MCSymbolRefExpr::Create(Sym, getContext()); + Res = MCSymbolRefExpr::Create(Sym, Variant, getContext()); return false; } case AsmToken::Integer: diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index eb046d0eaf38..345a78c190c0 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -136,10 +136,11 @@ MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size, /// returns an empty buffer. MemoryBuffer *MemoryBuffer::getFileOrSTDIN(StringRef Filename, std::string *ErrStr, - int64_t FileSize) { + int64_t FileSize, + struct stat *FileInfo) { if (Filename == "-") return getSTDIN(); - return getFile(Filename, ErrStr, FileSize); + return getFile(Filename, ErrStr, FileSize, FileInfo); } //===----------------------------------------------------------------------===// @@ -169,7 +170,7 @@ public: } MemoryBuffer *MemoryBuffer::getFile(StringRef Filename, std::string *ErrStr, - int64_t FileSize) { + int64_t FileSize, struct stat *FileInfo) { int OpenFlags = 0; #ifdef O_BINARY OpenFlags |= O_BINARY; // Open input file in binary mode on win32. @@ -183,15 +184,17 @@ MemoryBuffer *MemoryBuffer::getFile(StringRef Filename, std::string *ErrStr, // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. - if (FileSize == -1) { - struct stat FileInfo; + if (FileSize == -1 || FileInfo) { + struct stat MyFileInfo; + struct stat *FileInfoPtr = FileInfo? FileInfo : &MyFileInfo; + // TODO: This should use fstat64 when available. - if (fstat(FD, &FileInfo) == -1) { + if (fstat(FD, FileInfoPtr) == -1) { if (ErrStr) *ErrStr = strerror(errno); ::close(FD); return 0; } - FileSize = FileInfo.st_size; + FileSize = FileInfoPtr->st_size; } diff --git a/lib/System/CMakeLists.txt b/lib/System/CMakeLists.txt index a56a1f78bb72..b43c3afa5248 100644 --- a/lib/System/CMakeLists.txt +++ b/lib/System/CMakeLists.txt @@ -12,10 +12,12 @@ add_llvm_library(LLVMSystem Process.cpp Program.cpp RWMutex.cpp + SearchForAddressOfSpecialSymbol.cpp Signals.cpp ThreadLocal.cpp Threading.cpp TimeValue.cpp + Valgrind.cpp Unix/Alarm.inc Unix/Host.inc Unix/Memory.inc diff --git a/lib/System/DynamicLibrary.cpp b/lib/System/DynamicLibrary.cpp index 63baa6d787c2..d6f3140a88e8 100644 --- a/lib/System/DynamicLibrary.cpp +++ b/lib/System/DynamicLibrary.cpp @@ -69,44 +69,8 @@ bool DynamicLibrary::LoadLibraryPermanently(const char *Filename, return false; } -static void *SearchForAddressOfSpecialSymbol(const char* symbolName) { -#define EXPLICIT_SYMBOL(SYM) \ - extern void *SYM; if (!strcmp(symbolName, #SYM)) return &SYM - - // If this is darwin, it has some funky issues, try to solve them here. Some - // important symbols are marked 'private external' which doesn't allow - // SearchForAddressOfSymbol to find them. As such, we special case them here, - // there is only a small handful of them. - -#ifdef __APPLE__ - { - EXPLICIT_SYMBOL(__ashldi3); - EXPLICIT_SYMBOL(__ashrdi3); - EXPLICIT_SYMBOL(__cmpdi2); - EXPLICIT_SYMBOL(__divdi3); - EXPLICIT_SYMBOL(__eprintf); - EXPLICIT_SYMBOL(__fixdfdi); - EXPLICIT_SYMBOL(__fixsfdi); - EXPLICIT_SYMBOL(__fixunsdfdi); - EXPLICIT_SYMBOL(__fixunssfdi); - EXPLICIT_SYMBOL(__floatdidf); - EXPLICIT_SYMBOL(__floatdisf); - EXPLICIT_SYMBOL(__lshrdi3); - EXPLICIT_SYMBOL(__moddi3); - EXPLICIT_SYMBOL(__udivdi3); - EXPLICIT_SYMBOL(__umoddi3); - } -#endif - -#ifdef __CYGWIN__ - { - EXPLICIT_SYMBOL(_alloca); - EXPLICIT_SYMBOL(__main); - } -#endif - -#undef EXPLICIT_SYMBOL - return 0; +namespace llvm { +void *SearchForAddressOfSpecialSymbol(const char* symbolName); } void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { @@ -132,7 +96,7 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { } } - if (void *Result = SearchForAddressOfSpecialSymbol(symbolName)) + if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName)) return Result; // This macro returns the address of a well-known, explicit symbol diff --git a/lib/System/Memory.cpp b/lib/System/Memory.cpp index e2d838dce026..ef23b8d12aab 100644 --- a/lib/System/Memory.cpp +++ b/lib/System/Memory.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/System/Memory.h" +#include "llvm/System/Valgrind.h" #include "llvm/Config/config.h" namespace llvm { @@ -68,4 +69,6 @@ void llvm::sys::Memory::InvalidateInstructionCache(const void *Addr, # endif #endif // end apple + + ValgrindDiscardTranslations(Addr, Len); } diff --git a/lib/System/SearchForAddressOfSpecialSymbol.cpp b/lib/System/SearchForAddressOfSpecialSymbol.cpp new file mode 100644 index 000000000000..73b484c2e917 --- /dev/null +++ b/lib/System/SearchForAddressOfSpecialSymbol.cpp @@ -0,0 +1,64 @@ +//===- SearchForAddressOfSpecialSymbol.cpp - Function addresses -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file pulls the addresses of certain symbols out of the linker. It must +// include as few header files as possible because it declares the symbols as +// void*, which would conflict with the actual symbol type if any header +// declared it. +// +//===----------------------------------------------------------------------===// + +#include <string.h> + +// Must declare the symbols in the global namespace. +static void *DoSearch(const char* symbolName) { +#define EXPLICIT_SYMBOL(SYM) \ + extern void *SYM; if (!strcmp(symbolName, #SYM)) return &SYM + + // If this is darwin, it has some funky issues, try to solve them here. Some + // important symbols are marked 'private external' which doesn't allow + // SearchForAddressOfSymbol to find them. As such, we special case them here, + // there is only a small handful of them. + +#ifdef __APPLE__ + { + EXPLICIT_SYMBOL(__ashldi3); + EXPLICIT_SYMBOL(__ashrdi3); + EXPLICIT_SYMBOL(__cmpdi2); + EXPLICIT_SYMBOL(__divdi3); + EXPLICIT_SYMBOL(__eprintf); + EXPLICIT_SYMBOL(__fixdfdi); + EXPLICIT_SYMBOL(__fixsfdi); + EXPLICIT_SYMBOL(__fixunsdfdi); + EXPLICIT_SYMBOL(__fixunssfdi); + EXPLICIT_SYMBOL(__floatdidf); + EXPLICIT_SYMBOL(__floatdisf); + EXPLICIT_SYMBOL(__lshrdi3); + EXPLICIT_SYMBOL(__moddi3); + EXPLICIT_SYMBOL(__udivdi3); + EXPLICIT_SYMBOL(__umoddi3); + } +#endif + +#ifdef __CYGWIN__ + { + EXPLICIT_SYMBOL(_alloca); + EXPLICIT_SYMBOL(__main); + } +#endif + +#undef EXPLICIT_SYMBOL + return 0; +} + +namespace llvm { +void *SearchForAddressOfSpecialSymbol(const char* symbolName) { + return DoSearch(symbolName); +} +} // namespace llvm diff --git a/lib/System/Unix/Program.inc b/lib/System/Unix/Program.inc index c10498a375ac..b4cc875df8c7 100644 --- a/lib/System/Unix/Program.inc +++ b/lib/System/Unix/Program.inc @@ -113,8 +113,9 @@ static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) { } // Install it as the requested FD - if (-1 == dup2(InFD, FD)) { + if (dup2(InFD, FD) == -1) { MakeErrMsg(ErrMsg, "Cannot dup2"); + close(InFD); return true; } close(InFD); // Close the original FD diff --git a/lib/System/Valgrind.cpp b/lib/System/Valgrind.cpp new file mode 100644 index 000000000000..c76cfe40d3e0 --- /dev/null +++ b/lib/System/Valgrind.cpp @@ -0,0 +1,54 @@ +//===-- Valgrind.cpp - Implement Valgrind communication ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines Valgrind communication methods, if HAVE_VALGRIND_VALGRIND_H is +// defined. If we have valgrind.h but valgrind isn't running, its macros are +// no-ops. +// +//===----------------------------------------------------------------------===// + +#include "llvm/System/Valgrind.h" +#include "llvm/Config/config.h" + +#if HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> + +static bool InitNotUnderValgrind() { + return !RUNNING_ON_VALGRIND; +} + +// This bool is negated from what we'd expect because code may run before it +// gets initialized. If that happens, it will appear to be 0 (false), and we +// want that to cause the rest of the code in this file to run the +// Valgrind-provided macros. +static const bool NotUnderValgrind = InitNotUnderValgrind(); + +bool llvm::sys::RunningOnValgrind() { + if (NotUnderValgrind) + return false; + return RUNNING_ON_VALGRIND; +} + +void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { + if (NotUnderValgrind) + return; + + VALGRIND_DISCARD_TRANSLATIONS(Addr, Len); +} + +#else // !HAVE_VALGRIND_VALGRIND_H + +bool llvm::sys::RunningOnValgrind() { + return false; +} + +void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { +} + +#endif // !HAVE_VALGRIND_VALGRIND_H diff --git a/lib/System/Win32/Path.inc b/lib/System/Win32/Path.inc index b5f63743c9c9..5a0052f3cb21 100644 --- a/lib/System/Win32/Path.inc +++ b/lib/System/Win32/Path.inc @@ -126,7 +126,7 @@ Path::isValid() const { } void Path::makeAbsolute() { - TCHAR FullPath[MAX_PATH + 1] = {0}; + TCHAR FullPath[MAX_PATH + 1] = {0}; LPTSTR FilePart = NULL; DWORD RetLength = ::GetFullPathNameA(path.c_str(), @@ -161,7 +161,7 @@ Path::isAbsolute(const char *NameStart, unsigned NameLen) { } } -bool +bool Path::isAbsolute() const { // FIXME: This does not handle correctly an absolute path starting from // a drive letter or in UNC format. @@ -174,9 +174,9 @@ Path::isAbsolute() const { default: return path[0] == '/' || (path[1] == ':' && path[2] == '/'); } -} +} -static Path *TempDirectory = NULL; +static Path *TempDirectory; Path Path::GetTemporaryDirectory(std::string* ErrMsg) { @@ -266,7 +266,7 @@ Path Path::GetCurrentDirectory() { char pathname[MAX_PATH]; ::GetCurrentDirectoryA(MAX_PATH,pathname); - return Path(pathname); + return Path(pathname); } /// GetMainExecutable - Return the path to the main executable, given the @@ -448,7 +448,7 @@ Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const { MakeErrMsg(ErrMsg, path + ": can't get status of file"); return true; } - + if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if (ErrMsg) *ErrMsg = path + ": not a directory"; @@ -617,7 +617,7 @@ Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) { *next = 0; if (!CreateDirectory(pathname, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) - return MakeErrMsg(ErrMsg, + return MakeErrMsg(ErrMsg, std::string(pathname) + ": Can't create directory: "); *next++ = '/'; } @@ -649,7 +649,7 @@ Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { WIN32_FILE_ATTRIBUTE_DATA fi; if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) return true; - + if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // If it doesn't exist, we're done. if (!exists()) @@ -706,7 +706,7 @@ Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { pathname[lastchar] = 0; if (!RemoveDirectory(pathname)) - return MakeErrMsg(ErrStr, + return MakeErrMsg(ErrStr, std::string(pathname) + ": Can't destroy directory: "); return false; } else { @@ -753,7 +753,7 @@ bool Path::getMagicNumber(std::string& Magic, unsigned len) const { bool Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING)) - return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path + return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path + "': "); return false; } @@ -764,7 +764,7 @@ Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const { if (!si.isFile) { return true; } - + HANDLE h = CreateFile(path.c_str(), FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, diff --git a/lib/Target/ARM/ARM.td b/lib/Target/ARM/ARM.td index 70338612d9c4..bbb1dbdc9a4a 100644 --- a/lib/Target/ARM/ARM.td +++ b/lib/Target/ARM/ARM.td @@ -40,6 +40,8 @@ def FeatureNEON : SubtargetFeature<"neon", "ARMFPUType", "NEON", "Enable NEON instructions">; def FeatureThumb2 : SubtargetFeature<"thumb2", "ThumbMode", "Thumb2", "Enable Thumb2 instructions">; +def FeatureFP16 : SubtargetFeature<"fp16", "HasFP16", "true", + "Enable half-precision floating point">; //===----------------------------------------------------------------------===// // ARM Processors supported. diff --git a/lib/Target/ARM/ARMBaseInstrInfo.h b/lib/Target/ARM/ARMBaseInstrInfo.h index 01942319b219..767d5ec92651 100644 --- a/lib/Target/ARM/ARMBaseInstrInfo.h +++ b/lib/Target/ARM/ARMBaseInstrInfo.h @@ -58,12 +58,13 @@ namespace ARMII { Size4Bytes = 3, Size2Bytes = 4, - // IndexMode - Unindex, pre-indexed, or post-indexed. Only valid for load - // and store ops + // IndexMode - Unindex, pre-indexed, or post-indexed are valid for load + // and store ops only. Generic "updating" flag is used for ld/st multiple. IndexModeShift = 7, IndexModeMask = 3 << IndexModeShift, IndexModePre = 1, IndexModePost = 2, + IndexModeUpd = 3, //===------------------------------------------------------------------===// // Instruction encoding formats. diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/lib/Target/ARM/ARMBaseRegisterInfo.cpp index d9b8323f4ae1..11e1c4862b41 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ b/lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -590,6 +590,10 @@ ARMBaseRegisterInfo::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, AFI->isThumb2Function()) MF.getRegInfo().setPhysRegUsed(ARM::R4); + // Spill LR if Thumb1 function uses variable length argument lists. + if (AFI->isThumb1OnlyFunction() && AFI->getVarArgsRegSaveSize() > 0) + MF.getRegInfo().setPhysRegUsed(ARM::LR); + // Don't spill FP if the frame can be eliminated. This is determined // by scanning the callee-save registers to see if any is used. const unsigned *CSRegs = getCalleeSavedRegs(); diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index 108a2445c3ff..334c820b91cb 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -51,6 +51,7 @@ namespace { const ARMSubtarget *Subtarget; TargetMachine &TM; JITCodeEmitter &MCE; + MachineModuleInfo *MMI; const std::vector<MachineConstantPoolEntry> *MCPEs; const std::vector<MachineJumpTableEntry> *MJTEs; bool IsPIC; @@ -182,7 +183,8 @@ bool ARMCodeEmitter::runOnMachineFunction(MachineFunction &MF) { if (MF.getJumpTableInfo()) MJTEs = &MF.getJumpTableInfo()->getJumpTables(); IsPIC = TM.getRelocationModel() == Reloc::PIC_; JTI->Initialize(MF, IsPIC); - MCE.setModuleInfo(&getAnalysis<MachineModuleInfo>()); + MMI = &getAnalysis<MachineModuleInfo>(); + MCE.setModuleInfo(MMI); do { DEBUG(errs() << "JITTing function '" @@ -436,8 +438,8 @@ void ARMCodeEmitter::emitConstPoolInstruction(const MachineInstr &MI) { void ARMCodeEmitter::emitMOVi2piecesInstruction(const MachineInstr &MI) { const MachineOperand &MO0 = MI.getOperand(0); const MachineOperand &MO1 = MI.getOperand(1); - assert(MO1.isImm() && ARM_AM::getSOImmVal(MO1.isImm()) != -1 && - "Not a valid so_imm value!"); + assert(MO1.isImm() && ARM_AM::isSOImmTwoPartVal(MO1.getImm()) && + "Not a valid so_imm value!"); unsigned V1 = ARM_AM::getSOImmTwoPartFirst(MO1.getImm()); unsigned V2 = ARM_AM::getSOImmTwoPartSecond(MO1.getImm()); @@ -563,7 +565,7 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) { } case TargetOpcode::DBG_LABEL: case TargetOpcode::EH_LABEL: - MCE.emitLabel(MI.getOperand(0).getImm()); + MCE.emitLabel(MI.getOperand(0).getMCSymbol()); break; case TargetOpcode::IMPLICIT_DEF: case TargetOpcode::KILL: @@ -925,19 +927,26 @@ static unsigned getAddrModeUPBits(unsigned Mode) { return Binary; } -void ARMCodeEmitter::emitLoadStoreMultipleInstruction( - const MachineInstr &MI) { +void ARMCodeEmitter::emitLoadStoreMultipleInstruction(const MachineInstr &MI) { + const TargetInstrDesc &TID = MI.getDesc(); + bool IsUpdating = (TID.TSFlags & ARMII::IndexModeMask) != 0; + // Part of binary is determined by TableGn. unsigned Binary = getBinaryCodeForInstr(MI); // Set the conditional execution predicate Binary |= II->getPredicate(&MI) << ARMII::CondShift; + // Skip operand 0 of an instruction with base register update. + unsigned OpIdx = 0; + if (IsUpdating) + ++OpIdx; + // Set base address operand - Binary |= getMachineOpValue(MI, 0) << ARMII::RegRnShift; + Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift; // Set addressing mode by modifying bits U(23) and P(24) - const MachineOperand &MO = MI.getOperand(1); + const MachineOperand &MO = MI.getOperand(OpIdx++); Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(MO.getImm())); // Set bit W(21) @@ -945,7 +954,7 @@ void ARMCodeEmitter::emitLoadStoreMultipleInstruction( Binary |= 0x1 << ARMII::W_BitShift; // Set registers - for (unsigned i = 5, e = MI.getNumOperands(); i != e; ++i) { + for (unsigned i = OpIdx+2, e = MI.getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI.getOperand(i); if (!MO.isReg() || MO.isImplicit()) break; @@ -1322,17 +1331,25 @@ void ARMCodeEmitter::emitVFPLoadStoreInstruction(const MachineInstr &MI) { void ARMCodeEmitter::emitVFPLoadStoreMultipleInstruction( const MachineInstr &MI) { + const TargetInstrDesc &TID = MI.getDesc(); + bool IsUpdating = (TID.TSFlags & ARMII::IndexModeMask) != 0; + // Part of binary is determined by TableGn. unsigned Binary = getBinaryCodeForInstr(MI); // Set the conditional execution predicate Binary |= II->getPredicate(&MI) << ARMII::CondShift; + // Skip operand 0 of an instruction with base register update. + unsigned OpIdx = 0; + if (IsUpdating) + ++OpIdx; + // Set base address operand - Binary |= getMachineOpValue(MI, 0) << ARMII::RegRnShift; + Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift; // Set addressing mode by modifying bits U(23) and P(24) - const MachineOperand &MO = MI.getOperand(1); + const MachineOperand &MO = MI.getOperand(OpIdx++); Binary |= getAddrModeUPBits(ARM_AM::getAM5SubMode(MO.getImm())); // Set bit W(21) @@ -1340,11 +1357,11 @@ void ARMCodeEmitter::emitVFPLoadStoreMultipleInstruction( Binary |= 0x1 << ARMII::W_BitShift; // First register is encoded in Dd. - Binary |= encodeVFPRd(MI, 5); + Binary |= encodeVFPRd(MI, OpIdx+2); // Number of registers are encoded in offset field. unsigned NumRegs = 1; - for (unsigned i = 6, e = MI.getNumOperands(); i != e; ++i) { + for (unsigned i = OpIdx+3, e = MI.getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI.getOperand(i); if (!MO.isReg() || MO.isImplicit()) break; diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp index 8fa3c04b6c4d..1c5bd42d63da 100644 --- a/lib/Target/ARM/ARMConstantIslandPass.cpp +++ b/lib/Target/ARM/ARMConstantIslandPass.cpp @@ -1473,11 +1473,10 @@ bool ARMConstantIslands::UndoLRSpillRestore() { bool MadeChange = false; for (unsigned i = 0, e = PushPopMIs.size(); i != e; ++i) { MachineInstr *MI = PushPopMIs[i]; - // First two operands are predicates, the third is a zero since there - // is no writeback. + // First two operands are predicates. if (MI->getOpcode() == ARM::tPOP_RET && - MI->getOperand(3).getReg() == ARM::PC && - MI->getNumExplicitOperands() == 4) { + MI->getOperand(2).getReg() == ARM::PC && + MI->getNumExplicitOperands() == 3) { BuildMI(MI->getParent(), MI->getDebugLoc(), TII->get(ARM::tBX_RET)); MI->eraseFromParent(); MadeChange = true; diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 3dd0313f4b14..8f208432ab7e 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -130,7 +130,7 @@ void ARMTargetLowering::addQRTypeForNEON(EVT VT) { static TargetLoweringObjectFile *createTLOF(TargetMachine &TM) { if (TM.getSubtarget<ARMSubtarget>().isTargetDarwin()) - return new ARMMachOTargetObjectFile(); + return new TargetLoweringObjectFileMachO(); return new ARMElfTargetObjectFile(); } @@ -426,12 +426,20 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setOperationAction(ISD::FPOW, MVT::f64, Expand); setOperationAction(ISD::FPOW, MVT::f32, Expand); - // int <-> fp are custom expanded into bit_convert + ARMISD ops. - if (!UseSoftFloat && Subtarget->hasVFP2() && !Subtarget->isThumb1Only()) { - setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom); - setOperationAction(ISD::UINT_TO_FP, MVT::i32, Custom); - setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); - setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); + // Various VFP goodness + if (!UseSoftFloat && !Subtarget->isThumb1Only()) { + // int <-> fp are custom expanded into bit_convert + ARMISD ops. + if (Subtarget->hasVFP2()) { + setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom); + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); + } + // Special handling for half-precision FP. + if (Subtarget->hasVFP3() && Subtarget->hasFP16()) { + setOperationAction(ISD::FP16_TO_FP32, MVT::f32, Custom); + setOperationAction(ISD::FP32_TO_FP16, MVT::i32, Custom); + } } // We have target-specific dag combine patterns for the following nodes: @@ -491,6 +499,8 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { case ARMISD::FTOUI: return "ARMISD::FTOUI"; case ARMISD::SITOF: return "ARMISD::SITOF"; case ARMISD::UITOF: return "ARMISD::UITOF"; + case ARMISD::F16_TO_F32: return "ARMISD::F16_TO_F32"; + case ARMISD::F32_TO_F16: return "ARMISD::F32_TO_F16"; case ARMISD::SRL_FLAG: return "ARMISD::SRL_FLAG"; case ARMISD::SRA_FLAG: return "ARMISD::SRA_FLAG"; @@ -1972,8 +1982,21 @@ SDValue ARMTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) { static SDValue LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) { DebugLoc dl = Op.getDebugLoc(); - unsigned Opc = - Op.getOpcode() == ISD::FP_TO_SINT ? ARMISD::FTOSI : ARMISD::FTOUI; + unsigned Opc; + + switch (Op.getOpcode()) { + default: + assert(0 && "Invalid opcode!"); + case ISD::FP32_TO_FP16: + Opc = ARMISD::F32_TO_F16; + break; + case ISD::FP_TO_SINT: + Opc = ARMISD::FTOSI; + break; + case ISD::FP_TO_UINT: + Opc = ARMISD::FTOUI; + break; + } Op = DAG.getNode(Opc, dl, MVT::f32, Op.getOperand(0)); return DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, Op); } @@ -1981,8 +2004,21 @@ static SDValue LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) { static SDValue LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) { EVT VT = Op.getValueType(); DebugLoc dl = Op.getDebugLoc(); - unsigned Opc = - Op.getOpcode() == ISD::SINT_TO_FP ? ARMISD::SITOF : ARMISD::UITOF; + unsigned Opc; + + switch (Op.getOpcode()) { + default: + assert(0 && "Invalid opcode!"); + case ISD::FP16_TO_FP32: + Opc = ARMISD::F16_TO_F32; + break; + case ISD::SINT_TO_FP: + Opc = ARMISD::SITOF; + break; + case ISD::UINT_TO_FP: + Opc = ARMISD::UITOF; + break; + } Op = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, Op.getOperand(0)); return DAG.getNode(Opc, dl, VT, Op); @@ -3042,8 +3078,10 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); case ISD::VASTART: return LowerVASTART(Op, DAG, VarArgsFrameIndex); case ISD::MEMBARRIER: return LowerMEMBARRIER(Op, DAG, Subtarget); + case ISD::FP16_TO_FP32: case ISD::SINT_TO_FP: case ISD::UINT_TO_FP: return LowerINT_TO_FP(Op, DAG); + case ISD::FP32_TO_FP16: case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: return LowerFP_TO_INT(Op, DAG); case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG); @@ -4411,6 +4449,9 @@ ARMTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint, break; } } + if (StringRef("{cc}").equals_lower(Constraint)) + return std::make_pair(0U, ARM::CCRRegisterClass); + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); } diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h index f8f8adc70af8..d7b2ba3b5c72 100644 --- a/lib/Target/ARM/ARMISelLowering.h +++ b/lib/Target/ARM/ARMISelLowering.h @@ -59,6 +59,8 @@ namespace llvm { FTOUI, // FP to uint within a FP register. SITOF, // sint to FP within a FP register. UITOF, // uint to FP within a FP register. + F16_TO_F32, // Half FP to single FP within a FP register. + F32_TO_F16, // Single FP to half FP within a FP register. SRL_FLAG, // V,Flag = srl_flag X -> srl X, 1 + save carry out. SRA_FLAG, // V,Flag = sra_flag X -> sra X, 1 + save carry out. diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index 76595fa2952a..258a96b9216e 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -112,6 +112,7 @@ class IndexMode<bits<2> val> { def IndexModeNone : IndexMode<0>; def IndexModePre : IndexMode<1>; def IndexModePost : IndexMode<2>; +def IndexModeUpd : IndexMode<3>; // Instruction execution domain. class Domain<bits<2> val> { @@ -144,6 +145,23 @@ def s_cc_out : OptionalDefOperand<OtherVT, (ops CCR), (ops (i32 CPSR))> { let PrintMethod = "printSBitModifierOperand"; } +// ARM special operands for disassembly only. +// + +def cps_opt : Operand<i32> { + let PrintMethod = "printCPSOptionOperand"; +} + +def msr_mask : Operand<i32> { + let PrintMethod = "printMSRMaskOperand"; +} + +// A8.6.117, A8.6.118. Different instructions are generated for #0 and #-0. +// The neg_zero operand translates -0 to -1, -1 to -2, ..., etc. +def neg_zero : Operand<i32> { + let PrintMethod = "printNegZeroOperand"; +} + //===----------------------------------------------------------------------===// // ARM Instruction templates. @@ -835,18 +853,18 @@ class AI3stdpo<dag oops, dag iops, Format f, InstrItinClass itin, // addrmode4 instructions -class AXI4ld<dag oops, dag iops, Format f, InstrItinClass itin, - string asm, list<dag> pattern> - : XI<oops, iops, AddrMode4, Size4Bytes, IndexModeNone, f, itin, - asm, "", pattern> { +class AXI4ld<dag oops, dag iops, IndexMode im, Format f, InstrItinClass itin, + string asm, string cstr, list<dag> pattern> + : XI<oops, iops, AddrMode4, Size4Bytes, im, f, itin, + asm, cstr, pattern> { let Inst{20} = 1; // L bit let Inst{22} = 0; // S bit let Inst{27-25} = 0b100; } -class AXI4st<dag oops, dag iops, Format f, InstrItinClass itin, - string asm, list<dag> pattern> - : XI<oops, iops, AddrMode4, Size4Bytes, IndexModeNone, f, itin, - asm, "", pattern> { +class AXI4st<dag oops, dag iops, IndexMode im, Format f, InstrItinClass itin, + string asm, string cstr, list<dag> pattern> + : XI<oops, iops, AddrMode4, Size4Bytes, im, f, itin, + asm, cstr, pattern> { let Inst{20} = 0; // L bit let Inst{22} = 0; // S bit let Inst{27-25} = 0b100; @@ -980,9 +998,9 @@ class T1JTI<dag oops, dag iops, InstrItinClass itin, // Two-address instructions class T1It<dag oops, dag iops, InstrItinClass itin, - string asm, list<dag> pattern> + string asm, string cstr, list<dag> pattern> : Thumb1I<oops, iops, AddrModeNone, Size2Bytes, itin, - asm, "$lhs = $dst", pattern>; + asm, cstr, pattern>; // Thumb1 instruction that can either be predicated or set CPSR. class Thumb1sI<dag oops, dag iops, AddrMode am, SizeFlagVal sz, @@ -1179,6 +1197,10 @@ class T2Ix2<dag oops, dag iops, InstrItinClass itin, string opc, string asm, list<dag> pattern> : Thumb2I<oops, iops, AddrModeNone, Size8Bytes, itin, opc, asm, "", pattern>; +// Two-address instructions +class T2XIt<dag oops, dag iops, InstrItinClass itin, + string asm, string cstr, list<dag> pattern> + : Thumb2XI<oops, iops, AddrModeNone, Size4Bytes, itin, asm, cstr, pattern>; // T2Iidxldst - Thumb2 indexed load / store instructions. class T2Iidxldst<bit signed, bits<2> opcod, bit load, bit pre, @@ -1293,10 +1315,10 @@ class ASI5<bits<4> opcod1, bits<2> opcod2, dag oops, dag iops, } // Load / store multiple -class AXDI5<dag oops, dag iops, InstrItinClass itin, - string asm, list<dag> pattern> - : VFPXI<oops, iops, AddrMode5, Size4Bytes, IndexModeNone, - VFPLdStMulFrm, itin, asm, "", pattern> { +class AXDI5<dag oops, dag iops, IndexMode im, InstrItinClass itin, + string asm, string cstr, list<dag> pattern> + : VFPXI<oops, iops, AddrMode5, Size4Bytes, im, + VFPLdStMulFrm, itin, asm, cstr, pattern> { // TODO: Mark the instructions with the appropriate subtarget info. let Inst{27-25} = 0b110; let Inst{11-8} = 0b1011; @@ -1305,10 +1327,10 @@ class AXDI5<dag oops, dag iops, InstrItinClass itin, let Dom = VFPNeonDomain.Value; } -class AXSI5<dag oops, dag iops, InstrItinClass itin, - string asm, list<dag> pattern> - : VFPXI<oops, iops, AddrMode5, Size4Bytes, IndexModeNone, - VFPLdStMulFrm, itin, asm, "", pattern> { +class AXSI5<dag oops, dag iops, IndexMode im, InstrItinClass itin, + string asm, string cstr, list<dag> pattern> + : VFPXI<oops, iops, AddrMode5, Size4Bytes, im, + VFPLdStMulFrm, itin, asm, cstr, pattern> { // TODO: Mark the instructions with the appropriate subtarget info. let Inst{27-25} = 0b110; let Inst{11-8} = 0b1010; diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index af82a5ff7750..3fc37dae4e4e 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -378,7 +378,7 @@ def am3offset : Operand<i32>, def addrmode4 : Operand<i32>, ComplexPattern<i32, 2, "SelectAddrMode4", []> { let PrintMethod = "printAddrMode4Operand"; - let MIOperandInfo = (ops GPR, i32imm); + let MIOperandInfo = (ops GPR:$addr, i32imm); } // addrmode5 := reg +/- imm8*4 @@ -386,7 +386,7 @@ def addrmode4 : Operand<i32>, def addrmode5 : Operand<i32>, ComplexPattern<i32, 2, "SelectAddrMode5", []> { let PrintMethod = "printAddrMode5Operand"; - let MIOperandInfo = (ops GPR, i32imm); + let MIOperandInfo = (ops GPR:$base, i32imm); } // addrmode6 := reg with optional writeback @@ -710,7 +710,7 @@ def BKPT : AI<(outs), (ins i32imm:$val), MiscFrm, NoItinerary, "bkpt", "\t$val", // opt{5} = changemode from Inst{17} // opt{8-6} = AIF from Inst{8-6} // opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable -def CPS : AXI<(outs),(ins i32imm:$opt), MiscFrm, NoItinerary, "cps${opt:cps}", +def CPS : AXI<(outs), (ins cps_opt:$opt), MiscFrm, NoItinerary, "cps$opt", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM]> { let Inst{31-28} = 0b1111; @@ -721,9 +721,12 @@ def CPS : AXI<(outs),(ins i32imm:$opt), MiscFrm, NoItinerary, "cps${opt:cps}", // Preload signals the memory system of possible future data/instruction access. // These are for disassembly only. +// +// A8.6.117, A8.6.118. Different instructions are generated for #0 and #-0. +// The neg_zero operand translates -0 to -1, -1 to -2, ..., etc. multiclass APreLoad<bit data, bit read, string opc> { - def i : AXI<(outs), (ins GPR:$base, i32imm:$imm), MiscFrm, NoItinerary, + def i : AXI<(outs), (ins GPR:$base, neg_zero:$imm), MiscFrm, NoItinerary, !strconcat(opc, "\t[$base, $imm]"), []> { let Inst{31-26} = 0b111101; let Inst{25} = 0; // 0 for immediate form @@ -903,10 +906,11 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { // FIXME: Should pc be an implicit operand like PICADD, etc? let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1, hasExtraDefRegAllocReq = 1 in - def LDM_RET : AXI4ld<(outs), - (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops), - LdStMulFrm, IIC_Br, "ldm${addr:submode}${p}\t$addr, $wb", - []>; + def LDM_RET : AXI4ld<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, + reglist:$dsts, variable_ops), + IndexModeUpd, LdStMulFrm, IIC_Br, + "ldm${addr:submode}${p}\t$addr, $dsts", + "$addr.addr = $wb", []>; // On non-Darwin platforms R9 is callee-saved. let isCall = 1, @@ -1341,17 +1345,31 @@ def STRHT: AI3sthpo<(outs GPR:$base_wb), // Load / store multiple Instructions. // -let mayLoad = 1, hasExtraDefRegAllocReq = 1 in -def LDM : AXI4ld<(outs), - (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops), - LdStMulFrm, IIC_iLoadm, "ldm${addr:submode}${p}\t$addr, $wb", - []>; - -let mayStore = 1, hasExtraSrcRegAllocReq = 1 in -def STM : AXI4st<(outs), - (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops), - LdStMulFrm, IIC_iStorem, "stm${addr:submode}${p}\t$addr, $wb", - []>; +let mayLoad = 1, hasExtraDefRegAllocReq = 1 in { +def LDM : AXI4ld<(outs), (ins addrmode4:$addr, pred:$p, + reglist:$dsts, variable_ops), + IndexModeNone, LdStMulFrm, IIC_iLoadm, + "ldm${addr:submode}${p}\t$addr, $dsts", "", []>; + +def LDM_UPD : AXI4ld<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, + reglist:$dsts, variable_ops), + IndexModeUpd, LdStMulFrm, IIC_iLoadm, + "ldm${addr:submode}${p}\t$addr, $dsts", + "$addr.addr = $wb", []>; +} // mayLoad, hasExtraDefRegAllocReq + +let mayStore = 1, hasExtraSrcRegAllocReq = 1 in { +def STM : AXI4st<(outs), (ins addrmode4:$addr, pred:$p, + reglist:$srcs, variable_ops), + IndexModeNone, LdStMulFrm, IIC_iStorem, + "stm${addr:submode}${p}\t$addr, $srcs", "", []>; + +def STM_UPD : AXI4st<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, + reglist:$srcs, variable_ops), + IndexModeUpd, LdStMulFrm, IIC_iStorem, + "stm${addr:submode}${p}\t$addr, $srcs", + "$addr.addr = $wb", []>; +} // mayStore, hasExtraSrcRegAllocReq //===----------------------------------------------------------------------===// // Move Instructions. @@ -2844,29 +2862,29 @@ def MRSsys : ABI<0b0001,(outs GPR:$dst),(ins), NoItinerary,"mrs","\t$dst, spsr", let Inst{7-4} = 0b0000; } -def MSR : ABI<0b0001, (outs), (ins GPR:$src, i32imm:$mask), NoItinerary, "msr", - "\tcpsr${mask:msr}, $src", +def MSR : ABI<0b0001, (outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, + "msr", "\tcpsr$mask, $src", [/* For disassembly only; pattern left blank */]> { let Inst{23-20} = 0b0010; let Inst{7-4} = 0b0000; } -def MSRi : ABI<0b0011, (outs), (ins so_imm:$a, i32imm:$mask), NoItinerary,"msr", - "\tcpsr${mask:msr}, $a", +def MSRi : ABI<0b0011, (outs), (ins so_imm:$a, msr_mask:$mask), NoItinerary, + "msr", "\tcpsr$mask, $a", [/* For disassembly only; pattern left blank */]> { let Inst{23-20} = 0b0010; let Inst{7-4} = 0b0000; } -def MSRsys : ABI<0b0001, (outs), (ins GPR:$src, i32imm:$mask),NoItinerary,"msr", - "\tspsr${mask:msr}, $src", +def MSRsys : ABI<0b0001, (outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, + "msr", "\tspsr$mask, $src", [/* For disassembly only; pattern left blank */]> { let Inst{23-20} = 0b0110; let Inst{7-4} = 0b0000; } -def MSRsysi : ABI<0b0011,(outs),(ins so_imm:$a, i32imm:$mask),NoItinerary,"msr", - "\tspsr${mask:msr}, $a", +def MSRsysi : ABI<0b0011, (outs), (ins so_imm:$a, msr_mask:$mask), NoItinerary, + "msr", "\tspsr$mask, $a", [/* For disassembly only; pattern left blank */]> { let Inst{23-20} = 0b0110; let Inst{7-4} = 0b0000; diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td index 7c44a2fe49e3..8fee6fa9527a 100644 --- a/lib/Target/ARM/ARMInstrNEON.td +++ b/lib/Target/ARM/ARMInstrNEON.td @@ -98,16 +98,6 @@ def NEONfmin : SDNode<"ARMISD::FMIN", SDTARMFMAX>; // NEON operand definitions //===----------------------------------------------------------------------===// -// addrmode_neonldstm := reg -// -/* TODO: Take advantage of vldm. -def addrmode_neonldstm : Operand<i32>, - ComplexPattern<i32, 2, "SelectAddrModeNeonLdStM", []> { - let PrintMethod = "printAddrNeonLdStMOperand"; - let MIOperandInfo = (ops GPR, i32imm); -} -*/ - def h8imm : Operand<i8> { let PrintMethod = "printHex8ImmOperand"; } @@ -125,26 +115,6 @@ def h64imm : Operand<i64> { // NEON load / store instructions //===----------------------------------------------------------------------===// -/* TODO: Take advantage of vldm. -let mayLoad = 1, hasExtraDefRegAllocReq = 1 in { -def VLDMD : NI<(outs), - (ins addrmode_neonldstm:$addr, reglist:$dst1, variable_ops), - IIC_fpLoadm, "vldm", "${addr:submode} ${addr:base}, $dst1", []> { - let Inst{27-25} = 0b110; - let Inst{20} = 1; - let Inst{11-9} = 0b101; -} - -def VLDMS : NI<(outs), - (ins addrmode_neonldstm:$addr, reglist:$dst1, variable_ops), - IIC_fpLoadm, "vldm", "${addr:submode} ${addr:base}, $dst1", []> { - let Inst{27-25} = 0b110; - let Inst{20} = 1; - let Inst{11-9} = 0b101; -} -} -*/ - // Use vldmia to load a Q register as a D register pair. def VLDRQ : NI4<(outs QPR:$dst), (ins addrmode4:$addr), IIC_fpLoadm, "vldmia", "$addr, ${dst:dregpair}", @@ -2738,7 +2708,7 @@ def : Pat<(v2f64 (insertelt QPR:$src1, DPR:$src2, imm:$src3)), def : Pat<(v2f32 (scalar_to_vector SPR:$src)), (INSERT_SUBREG (v2f32 (IMPLICIT_DEF)), SPR:$src, arm_ssubreg_0)>; -def : Pat<(v2f64 (scalar_to_vector DPR:$src)), +def : Pat<(v2f64 (scalar_to_vector (f64 DPR:$src))), (INSERT_SUBREG (v2f64 (IMPLICIT_DEF)), DPR:$src, arm_dsubreg_0)>; def : Pat<(v4f32 (scalar_to_vector SPR:$src)), (INSERT_SUBREG (v4f32 (IMPLICIT_DEF)), SPR:$src, arm_ssubreg_0)>; diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td index 786dd65b8742..37c9fc5f734e 100644 --- a/lib/Target/ARM/ARMInstrThumb.td +++ b/lib/Target/ARM/ARMInstrThumb.td @@ -201,7 +201,7 @@ def tBKPT : T1I<(outs), (ins i32imm:$val), NoItinerary, "bkpt\t$val", // // The opt{4-0} and opt{5} sub-fields are to accommodate 32-bit Thumb and ARM // CPS which has more options. -def tCPS : T1I<(outs), (ins i32imm:$opt), NoItinerary, "cps${opt:cps}", +def tCPS : T1I<(outs), (ins cps_opt:$opt), NoItinerary, "cps$opt", [/* For disassembly only; pattern left blank */]>, T1Misc<0b0110011>; @@ -290,8 +290,8 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { // FIXME: remove when we have a way to marking a MI with these properties. let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1, hasExtraDefRegAllocReq = 1 in -def tPOP_RET : T1I<(outs), (ins pred:$p, reglist:$wb, variable_ops), IIC_Br, - "pop${p}\t$wb", []>, +def tPOP_RET : T1I<(outs), (ins pred:$p, reglist:$dsts, variable_ops), IIC_Br, + "pop${p}\t$dsts", []>, T1Misc<{1,1,0,?,?,?,?}>; let isCall = 1, @@ -539,28 +539,37 @@ def tSpill : T1pIs<(outs), (ins tGPR:$src, t_addrmode_sp:$addr), IIC_iStorei, // // These requires base address to be written back or one of the loaded regs. -let mayLoad = 1, hasExtraDefRegAllocReq = 1 in +let mayLoad = 1, hasExtraDefRegAllocReq = 1 in { def tLDM : T1I<(outs), - (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops), + (ins addrmode4:$addr, pred:$p, reglist:$dsts, variable_ops), IIC_iLoadm, - "ldm${addr:submode}${p}\t$addr, $wb", []>, + "ldm${addr:submode}${p}\t$addr, $dsts", []>, T1Encoding<{1,1,0,0,1,?}>; // A6.2 & A8.6.53 +def tLDM_UPD : T1It<(outs tGPR:$wb), + (ins addrmode4:$addr, pred:$p, reglist:$dsts, variable_ops), + IIC_iLoadm, + "ldm${addr:submode}${p}\t$addr, $dsts", + "$addr.addr = $wb", []>, + T1Encoding<{1,1,0,0,1,?}>; // A6.2 & A8.6.53 +} // mayLoad, hasExtraDefRegAllocReq + let mayStore = 1, hasExtraSrcRegAllocReq = 1 in -def tSTM : T1I<(outs), - (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops), - IIC_iStorem, - "stm${addr:submode}${p}\t$addr, $wb", []>, +def tSTM_UPD : T1It<(outs tGPR:$wb), + (ins addrmode4:$addr, pred:$p, reglist:$srcs, variable_ops), + IIC_iStorem, + "stm${addr:submode}${p}\t$addr, $srcs", + "$addr.addr = $wb", []>, T1Encoding<{1,1,0,0,0,?}>; // A6.2 & A8.6.189 let mayLoad = 1, Uses = [SP], Defs = [SP], hasExtraDefRegAllocReq = 1 in -def tPOP : T1I<(outs), (ins pred:$p, reglist:$wb, variable_ops), IIC_Br, - "pop${p}\t$wb", []>, +def tPOP : T1I<(outs), (ins pred:$p, reglist:$dsts, variable_ops), IIC_Br, + "pop${p}\t$dsts", []>, T1Misc<{1,1,0,?,?,?,?}>; let mayStore = 1, Uses = [SP], Defs = [SP], hasExtraSrcRegAllocReq = 1 in -def tPUSH : T1I<(outs), (ins pred:$p, reglist:$wb, variable_ops), IIC_Br, - "push${p}\t$wb", []>, +def tPUSH : T1I<(outs), (ins pred:$p, reglist:$srcs, variable_ops), IIC_Br, + "push${p}\t$srcs", []>, T1Misc<{0,1,0,?,?,?,?}>; //===----------------------------------------------------------------------===// diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 2fc7d2f76960..ab9e926099c2 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -150,6 +150,10 @@ def t2addrmode_imm8s4 : Operand<i32>, let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); } +def t2am_imm8s4_offset : Operand<i32> { + let PrintMethod = "printT2AddrModeImm8s4OffsetOperand"; +} + // t2addrmode_so_reg := reg + (reg << imm2) def t2addrmode_so_reg : Operand<i32>, ComplexPattern<i32, 3, "SelectT2AddrModeSoReg", []> { @@ -903,7 +907,7 @@ let mayLoad = 1, hasExtraDefRegAllocReq = 1 in { def t2LDRDi8 : T2Ii8s4<1, 0, 1, (outs GPR:$dst1, GPR:$dst2), (ins t2addrmode_imm8s4:$addr), IIC_iLoadi, "ldrd", "\t$dst1, $addr", []>; -def t2LDRDpci : T2Ii8s4<?, ?, 1, (outs GPR:$dst1, GPR:$dst2), +def t2LDRDpci : T2Ii8s4<1, 0, 1, (outs GPR:$dst1, GPR:$dst2), (ins i32imm:$addr), IIC_iLoadi, "ldrd", "\t$dst1, $addr", []> { let Inst{19-16} = 0b1111; // Rn @@ -1105,14 +1109,34 @@ def t2STRT : T2IstT<0b10, "strt">; def t2STRBT : T2IstT<0b00, "strbt">; def t2STRHT : T2IstT<0b01, "strht">; -// FIXME: ldrd / strd pre / post variants +// ldrd / strd pre / post variants +// For disassembly only. + +def t2LDRD_PRE : T2Ii8s4<1, 1, 1, (outs GPR:$dst1, GPR:$dst2), + (ins GPR:$base, t2am_imm8s4_offset:$imm), NoItinerary, + "ldrd", "\t$dst1, $dst2, [$base, $imm]!", []>; + +def t2LDRD_POST : T2Ii8s4<0, 1, 1, (outs GPR:$dst1, GPR:$dst2), + (ins GPR:$base, t2am_imm8s4_offset:$imm), NoItinerary, + "ldrd", "\t$dst1, $dst2, [$base], $imm", []>; + +def t2STRD_PRE : T2Ii8s4<1, 1, 0, (outs), + (ins GPR:$src1, GPR:$src2, GPR:$base, t2am_imm8s4_offset:$imm), + NoItinerary, "strd", "\t$src1, $src2, [$base, $imm]!", []>; + +def t2STRD_POST : T2Ii8s4<0, 1, 0, (outs), + (ins GPR:$src1, GPR:$src2, GPR:$base, t2am_imm8s4_offset:$imm), + NoItinerary, "strd", "\t$src1, $src2, [$base], $imm", []>; // T2Ipl (Preload Data/Instruction) signals the memory system of possible future // data/instruction access. These are for disassembly only. +// +// A8.6.117, A8.6.118. Different instructions are generated for #0 and #-0. +// The neg_zero operand translates -0 to -1, -1 to -2, ..., etc. multiclass T2Ipl<bit instr, bit write, string opc> { - def i12 : T2I<(outs), (ins t2addrmode_imm12:$addr), IIC_iLoadi, opc, - "\t$addr", []> { + def i12 : T2I<(outs), (ins GPR:$base, i32imm:$imm), IIC_iLoadi, opc, + "\t[$base, $imm]", []> { let Inst{31-25} = 0b1111100; let Inst{24} = instr; let Inst{23} = 1; // U = 1 @@ -1122,8 +1146,8 @@ multiclass T2Ipl<bit instr, bit write, string opc> { let Inst{15-12} = 0b1111; } - def i8 : T2I<(outs), (ins t2addrmode_imm8:$addr), IIC_iLoadi, opc, - "\t$addr", []> { + def i8 : T2I<(outs), (ins GPR:$base, neg_zero:$imm), IIC_iLoadi, opc, + "\t[$base, $imm]", []> { let Inst{31-25} = 0b1111100; let Inst{24} = instr; let Inst{23} = 0; // U = 0 @@ -1134,9 +1158,8 @@ multiclass T2Ipl<bit instr, bit write, string opc> { let Inst{11-8} = 0b1100; } - // A8.6.118 #0 and #-0 differs. Translates -0 to -1, -1 to -2, ..., etc. - def pci : T2I<(outs), (ins GPR:$base, i32imm:$imm), IIC_iLoadi, opc, - "\t[pc, ${imm:negzero}]", []> { + def pci : T2I<(outs), (ins GPR:$base, neg_zero:$imm), IIC_iLoadi, opc, + "\t[pc, $imm]", []> { let Inst{31-25} = 0b1111100; let Inst{24} = instr; let Inst{23} = ?; // add = (U == 1) @@ -1181,29 +1204,56 @@ defm t2PLI : T2Ipl<1, 0, "pli">; // Load / store multiple Instructions. // -let mayLoad = 1, hasExtraDefRegAllocReq = 1 in -def t2LDM : T2XI<(outs), - (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops), - IIC_iLoadm, "ldm${addr:submode}${p}${addr:wide}\t$addr, $wb", []> { +let mayLoad = 1, hasExtraDefRegAllocReq = 1 in { +def t2LDM : T2XI<(outs), (ins addrmode4:$addr, pred:$p, + reglist:$dsts, variable_ops), IIC_iLoadm, + "ldm${addr:submode}${p}${addr:wide}\t$addr, $dsts", []> { + let Inst{31-27} = 0b11101; + let Inst{26-25} = 0b00; + let Inst{24-23} = {?, ?}; // IA: '01', DB: '10' + let Inst{22} = 0; + let Inst{21} = 0; // The W bit. + let Inst{20} = 1; // Load +} + +def t2LDM_UPD : T2XIt<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, + reglist:$dsts, variable_ops), IIC_iLoadm, + "ldm${addr:submode}${p}${addr:wide}\t$addr, $dsts", + "$addr.addr = $wb", []> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = {?, ?}; // IA: '01', DB: '10' let Inst{22} = 0; - let Inst{21} = ?; // The W bit. + let Inst{21} = 1; // The W bit. let Inst{20} = 1; // Load } +} // mayLoad, hasExtraDefRegAllocReq + +let mayStore = 1, hasExtraSrcRegAllocReq = 1 in { +def t2STM : T2XI<(outs), (ins addrmode4:$addr, pred:$p, + reglist:$srcs, variable_ops), IIC_iStorem, + "stm${addr:submode}${p}${addr:wide}\t$addr, $srcs", []> { + let Inst{31-27} = 0b11101; + let Inst{26-25} = 0b00; + let Inst{24-23} = {?, ?}; // IA: '01', DB: '10' + let Inst{22} = 0; + let Inst{21} = 0; // The W bit. + let Inst{20} = 0; // Store +} -let mayStore = 1, hasExtraSrcRegAllocReq = 1 in -def t2STM : T2XI<(outs), - (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops), - IIC_iStorem, "stm${addr:submode}${p}${addr:wide}\t$addr, $wb", []> { +def t2STM_UPD : T2XIt<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, + reglist:$srcs, variable_ops), + IIC_iStorem, + "stm${addr:submode}${p}${addr:wide}\t$addr, $srcs", + "$addr.addr = $wb", []> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = {?, ?}; // IA: '01', DB: '10' let Inst{22} = 0; - let Inst{21} = ?; // The W bit. + let Inst{21} = 1; // The W bit. let Inst{20} = 0; // Store } +} // mayStore, hasExtraSrcRegAllocReq //===----------------------------------------------------------------------===// // Move Instructions. @@ -2136,7 +2186,7 @@ def t2MOVCCror : T2I_movcc_sh<0b11, (outs GPR:$dst), // memory barriers protect the atomic sequences let hasSideEffects = 1 in { def t2Int_MemBarrierV7 : AInoP<(outs), (ins), - Pseudo, NoItinerary, + ThumbFrm, NoItinerary, "dmb", "", [(ARMMemBarrierV7)]>, Requires<[IsThumb2]> { @@ -2146,7 +2196,7 @@ def t2Int_MemBarrierV7 : AInoP<(outs), (ins), } def t2Int_SyncBarrierV7 : AInoP<(outs), (ins), - Pseudo, NoItinerary, + ThumbFrm, NoItinerary, "dsb", "", [(ARMSyncBarrierV7)]>, Requires<[IsThumb2]> { @@ -2351,15 +2401,15 @@ let Defs = // FIXME: Should pc be an implicit operand like PICADD, etc? let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1, hasExtraDefRegAllocReq = 1 in - def t2LDM_RET : T2XI<(outs), - (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops), - IIC_Br, "ldm${addr:submode}${p}${addr:wide}\t$addr, $wb", - []> { + def t2LDM_RET : T2XIt<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, + reglist:$dsts, variable_ops), IIC_Br, + "ldm${addr:submode}${p}${addr:wide}\t$addr, $dsts", + "$addr.addr = $wb", []> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; let Inst{24-23} = {?, ?}; // IA: '01', DB: '10' let Inst{22} = 0; - let Inst{21} = ?; // The W bit. + let Inst{21} = 1; // The W bit. let Inst{20} = 1; // Load } @@ -2469,7 +2519,7 @@ def t2BXJ : T2I<(outs), (ins GPR:$func), NoItinerary, "bxj", "\t$func", // opt{5} = changemode from Inst{17} // opt{8-6} = AIF from Inst{8-6} // opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable -def t2CPS : T2XI<(outs),(ins i32imm:$opt), NoItinerary, "cps${opt:cps}", +def t2CPS : T2XI<(outs),(ins cps_opt:$opt), NoItinerary, "cps$opt", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; let Inst{26} = 0; @@ -2638,8 +2688,8 @@ def t2MRSsys : T2I<(outs GPR:$dst), (ins), NoItinerary, "mrs", "\t$dst, spsr", } // Rn = Inst{19-16} -def t2MSR : T2I<(outs), (ins GPR:$src, i32imm:$mask), NoItinerary, "msr", - "\tcpsr${mask:msr}, $src", +def t2MSR : T2I<(outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, "msr", + "\tcpsr$mask, $src", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; let Inst{26} = 0; @@ -2650,8 +2700,8 @@ def t2MSR : T2I<(outs), (ins GPR:$src, i32imm:$mask), NoItinerary, "msr", } // Rn = Inst{19-16} -def t2MSRsys : T2I<(outs), (ins GPR:$src, i32imm:$mask), NoItinerary, "msr", - "\tspsr${mask:msr}, $src", +def t2MSRsys : T2I<(outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, "msr", + "\tspsr$mask, $src", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; let Inst{26} = 0; diff --git a/lib/Target/ARM/ARMInstrVFP.td b/lib/Target/ARM/ARMInstrVFP.td index cad24c4834d8..4d1d48a11341 100644 --- a/lib/Target/ARM/ARMInstrVFP.td +++ b/lib/Target/ARM/ARMInstrVFP.td @@ -25,6 +25,8 @@ def arm_ftoui : SDNode<"ARMISD::FTOUI", SDT_FTOI>; def arm_ftosi : SDNode<"ARMISD::FTOSI", SDT_FTOI>; def arm_sitof : SDNode<"ARMISD::SITOF", SDT_ITOF>; def arm_uitof : SDNode<"ARMISD::UITOF", SDT_ITOF>; +def arm_f16tof32 : SDNode<"ARMISD::F16_TO_F32", SDT_ITOF>; +def arm_f32tof16 : SDNode<"ARMISD::F32_TO_F16", SDT_FTOI>; def arm_fmstat : SDNode<"ARMISD::FMSTAT", SDTNone, [SDNPInFlag,SDNPOutFlag]>; def arm_cmpfp : SDNode<"ARMISD::CMPFP", SDT_ARMCmp, [SDNPOutFlag]>; def arm_cmpfp0 : SDNode<"ARMISD::CMPFPw0",SDT_CMPFP0, [SDNPOutFlag]>; @@ -77,33 +79,61 @@ def VSTRS : ASI5<0b1101, 0b00, (outs), (ins SPR:$src, addrmode5:$addr), // let mayLoad = 1, hasExtraDefRegAllocReq = 1 in { -def VLDMD : AXDI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$wb, - variable_ops), IIC_fpLoadm, - "vldm${addr:submode}${p}\t${addr:base}, $wb", - []> { +def VLDMD : AXDI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$dsts, + variable_ops), IndexModeNone, IIC_fpLoadm, + "vldm${addr:submode}${p}\t${addr:base}, $dsts", "", []> { let Inst{20} = 1; } -def VLDMS : AXSI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$wb, - variable_ops), IIC_fpLoadm, - "vldm${addr:submode}${p}\t${addr:base}, $wb", - []> { +def VLDMS : AXSI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$dsts, + variable_ops), IndexModeNone, IIC_fpLoadm, + "vldm${addr:submode}${p}\t${addr:base}, $dsts", "", []> { + let Inst{20} = 1; +} + +def VLDMD_UPD : AXDI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, + reglist:$dsts, variable_ops), + IndexModeUpd, IIC_fpLoadm, + "vldm${addr:submode}${p}\t${addr:base}, $dsts", + "$addr.base = $wb", []> { + let Inst{20} = 1; +} + +def VLDMS_UPD : AXSI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, + reglist:$dsts, variable_ops), + IndexModeUpd, IIC_fpLoadm, + "vldm${addr:submode}${p}\t${addr:base}, $dsts", + "$addr.base = $wb", []> { let Inst{20} = 1; } } // mayLoad, hasExtraDefRegAllocReq let mayStore = 1, hasExtraSrcRegAllocReq = 1 in { -def VSTMD : AXDI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$wb, - variable_ops), IIC_fpStorem, - "vstm${addr:submode}${p}\t${addr:base}, $wb", - []> { +def VSTMD : AXDI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$srcs, + variable_ops), IndexModeNone, IIC_fpStorem, + "vstm${addr:submode}${p}\t${addr:base}, $srcs", "", []> { + let Inst{20} = 0; +} + +def VSTMS : AXSI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$srcs, + variable_ops), IndexModeNone, IIC_fpStorem, + "vstm${addr:submode}${p}\t${addr:base}, $srcs", "", []> { let Inst{20} = 0; } -def VSTMS : AXSI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$wb, - variable_ops), IIC_fpStorem, - "vstm${addr:submode}${p}\t${addr:base}, $wb", - []> { +def VSTMD_UPD : AXDI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, + reglist:$srcs, variable_ops), + IndexModeUpd, IIC_fpStorem, + "vstm${addr:submode}${p}\t${addr:base}, $srcs", + "$addr.base = $wb", []> { + let Inst{20} = 0; +} + +def VSTMS_UPD : AXSI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, + reglist:$srcs, variable_ops), + IndexModeUpd, IIC_fpStorem, + "vstm${addr:submode}${p}\t${addr:base}, $srcs", + "$addr.base = $wb", []> { let Inst{20} = 0; } } // mayStore, hasExtraSrcRegAllocReq @@ -229,11 +259,11 @@ def VCVTSD : VFPAI<(outs SPR:$dst), (ins DPR:$a), VFPUnaryFrm, def VCVTBSH : ASuI<0b11101, 0b11, 0b0010, 0b01, 0, (outs SPR:$dst), (ins SPR:$a), /* FIXME */ IIC_fpCVTDS, "vcvtb", ".f32.f16\t$dst, $a", - [/* For disassembly only; pattern left blank */]>; + [(set SPR:$dst, (f32 (arm_f32tof16 SPR:$a)))]>; def VCVTBHS : ASuI<0b11101, 0b11, 0b0011, 0b01, 0, (outs SPR:$dst), (ins SPR:$a), /* FIXME */ IIC_fpCVTDS, "vcvtb", ".f16.f32\t$dst, $a", - [/* For disassembly only; pattern left blank */]>; + [(set SPR:$dst, (arm_f16tof32 SPR:$a))]>; def VCVTTSH : ASuI<0b11101, 0b11, 0b0010, 0b11, 0, (outs SPR:$dst), (ins SPR:$a), /* FIXME */ IIC_fpCVTDS, "vcvtt", ".f32.f16\t$dst, $a", diff --git a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp index 19f1e3ba12cf..8fbcf45dfd63 100644 --- a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp +++ b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp @@ -243,8 +243,9 @@ ARMLoadStoreOpt::MergeOps(MachineBasicBlock &MBB, BaseKill = true; // New base is always killed right its use. } - bool isDPR = Opcode == ARM::VLDRD || Opcode == ARM::VSTRD; - bool isDef = isi32Load(Opcode) || Opcode == ARM::VLDRS || Opcode == ARM::VLDRD; + bool isDPR = (Opcode == ARM::VLDRD || Opcode == ARM::VSTRD); + bool isDef = (isi32Load(Opcode) || Opcode == ARM::VLDRS || + Opcode == ARM::VLDRD); Opcode = getLoadStoreMultipleOpcode(Opcode); MachineInstrBuilder MIB = (isAM4) ? BuildMI(MBB, MBBI, dl, TII->get(Opcode)) @@ -254,7 +255,6 @@ ARMLoadStoreOpt::MergeOps(MachineBasicBlock &MBB, .addReg(Base, getKillRegState(BaseKill)) .addImm(ARM_AM::getAM5Opc(Mode, false, isDPR ? NumRegs<<1 : NumRegs)) .addImm(Pred).addReg(PredReg); - MIB.addReg(0); // Add optional writeback (0 for now). for (unsigned i = 0; i != NumRegs; ++i) MIB = MIB.addReg(Regs[i].first, getDefRegState(isDef) | getKillRegState(Regs[i].second)); @@ -443,7 +443,7 @@ static inline unsigned getLSMultipleTransferSize(MachineInstr *MI) { case ARM::STM: case ARM::t2LDM: case ARM::t2STM: - return (MI->getNumOperands() - 5) * 4; + return (MI->getNumOperands() - 4) * 4; case ARM::VLDMS: case ARM::VSTMS: case ARM::VLDMD: @@ -452,6 +452,21 @@ static inline unsigned getLSMultipleTransferSize(MachineInstr *MI) { } } +static unsigned getUpdatingLSMultipleOpcode(unsigned Opc) { + switch (Opc) { + case ARM::LDM: return ARM::LDM_UPD; + case ARM::STM: return ARM::STM_UPD; + case ARM::t2LDM: return ARM::t2LDM_UPD; + case ARM::t2STM: return ARM::t2STM_UPD; + case ARM::VLDMS: return ARM::VLDMS_UPD; + case ARM::VLDMD: return ARM::VLDMD_UPD; + case ARM::VSTMS: return ARM::VSTMS_UPD; + case ARM::VSTMD: return ARM::VSTMD_UPD; + default: llvm_unreachable("Unhandled opcode!"); + } + return 0; +} + /// MergeBaseUpdateLSMultiple - Fold proceeding/trailing inc/dec of base /// register into the LDM/STM/VLDM{D|S}/VSTM{D|S} op when possible: /// @@ -470,117 +485,119 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLSMultiple(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I) { MachineInstr *MI = MBBI; unsigned Base = MI->getOperand(0).getReg(); + bool BaseKill = MI->getOperand(0).isKill(); unsigned Bytes = getLSMultipleTransferSize(MI); unsigned PredReg = 0; ARMCC::CondCodes Pred = llvm::getInstrPredicate(MI, PredReg); int Opcode = MI->getOpcode(); - bool isAM4 = Opcode == ARM::LDM || Opcode == ARM::t2LDM || - Opcode == ARM::STM || Opcode == ARM::t2STM; + DebugLoc dl = MI->getDebugLoc(); + bool isAM4 = (Opcode == ARM::LDM || Opcode == ARM::t2LDM || + Opcode == ARM::STM || Opcode == ARM::t2STM); - if (isAM4) { - if (ARM_AM::getAM4WBFlag(MI->getOperand(1).getImm())) - return false; + bool DoMerge = false; + ARM_AM::AMSubMode Mode = ARM_AM::ia; + unsigned Offset = 0; - // Can't use the updating AM4 sub-mode if the base register is also a dest + if (isAM4) { + // Can't use an updating ld/st if the base register is also a dest // register. e.g. ldmdb r0!, {r0, r1, r2}. The behavior is undefined. for (unsigned i = 3, e = MI->getNumOperands(); i != e; ++i) { if (MI->getOperand(i).getReg() == Base) return false; } + assert(!ARM_AM::getAM4WBFlag(MI->getOperand(1).getImm())); + Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm()); + } else { + // VLDM{D|S}, VSTM{D|S} addressing mode 5 ops. + assert(!ARM_AM::getAM5WBFlag(MI->getOperand(1).getImm())); + Mode = ARM_AM::getAM5SubMode(MI->getOperand(1).getImm()); + Offset = ARM_AM::getAM5Offset(MI->getOperand(1).getImm()); + } - ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm()); - if (MBBI != MBB.begin()) { - MachineBasicBlock::iterator PrevMBBI = prior(MBBI); + // Try merging with the previous instruction. + if (MBBI != MBB.begin()) { + MachineBasicBlock::iterator PrevMBBI = prior(MBBI); + if (isAM4) { if (Mode == ARM_AM::ia && isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) { - MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::db, true)); - MI->getOperand(4).setReg(Base); - MI->getOperand(4).setIsDef(); - MBB.erase(PrevMBBI); - return true; - } else if (Mode == ARM_AM::ib && + DoMerge = true; + Mode = ARM_AM::db; + } else if (isAM4 && Mode == ARM_AM::ib && isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) { - MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::da, true)); - MI->getOperand(4).setReg(Base); // WB to base - MI->getOperand(4).setIsDef(); - MBB.erase(PrevMBBI); - return true; + DoMerge = true; + Mode = ARM_AM::da; + } + } else { + if (Mode == ARM_AM::ia && + isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) { + Mode = ARM_AM::db; + DoMerge = true; } } + if (DoMerge) + MBB.erase(PrevMBBI); + } - if (MBBI != MBB.end()) { - MachineBasicBlock::iterator NextMBBI = llvm::next(MBBI); + // Try merging with the next instruction. + if (!DoMerge && MBBI != MBB.end()) { + MachineBasicBlock::iterator NextMBBI = llvm::next(MBBI); + if (isAM4) { if ((Mode == ARM_AM::ia || Mode == ARM_AM::ib) && isMatchingIncrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) { - MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true)); - MI->getOperand(4).setReg(Base); // WB to base - MI->getOperand(4).setIsDef(); - if (NextMBBI == I) { - Advance = true; - ++I; - } - MBB.erase(NextMBBI); - return true; + DoMerge = true; } else if ((Mode == ARM_AM::da || Mode == ARM_AM::db) && isMatchingDecrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) { - MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true)); - MI->getOperand(4).setReg(Base); // WB to base - MI->getOperand(4).setIsDef(); - if (NextMBBI == I) { - Advance = true; - ++I; - } - MBB.erase(NextMBBI); - return true; + DoMerge = true; } - } - } else { - // VLDM{D|S}, VSTM{D|S} addressing mode 5 ops. - if (ARM_AM::getAM5WBFlag(MI->getOperand(1).getImm())) - return false; - - ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MI->getOperand(1).getImm()); - unsigned Offset = ARM_AM::getAM5Offset(MI->getOperand(1).getImm()); - if (MBBI != MBB.begin()) { - MachineBasicBlock::iterator PrevMBBI = prior(MBBI); + } else { if (Mode == ARM_AM::ia && - isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) { - MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::db, true, Offset)); - MI->getOperand(4).setReg(Base); // WB to base - MI->getOperand(4).setIsDef(); - MBB.erase(PrevMBBI); - return true; + isMatchingIncrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) { + DoMerge = true; } } - - if (MBBI != MBB.end()) { - MachineBasicBlock::iterator NextMBBI = llvm::next(MBBI); - if (Mode == ARM_AM::ia && - isMatchingIncrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) { - MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::ia, true, Offset)); - MI->getOperand(4).setReg(Base); // WB to base - MI->getOperand(4).setIsDef(); - if (NextMBBI == I) { - Advance = true; - ++I; - } - MBB.erase(NextMBBI); + if (DoMerge) { + if (NextMBBI == I) { + Advance = true; + ++I; } - return true; + MBB.erase(NextMBBI); } } - return false; + if (!DoMerge) + return false; + + unsigned NewOpc = getUpdatingLSMultipleOpcode(Opcode); + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII->get(NewOpc)) + .addReg(Base, getDefRegState(true)) // WB base register + .addReg(Base, getKillRegState(BaseKill)); + if (isAM4) { + // [t2]LDM_UPD, [t2]STM_UPD + MIB.addImm(ARM_AM::getAM4ModeImm(Mode, true)) + .addImm(Pred).addReg(PredReg); + } else { + // VLDM[SD}_UPD, VSTM[SD]_UPD + MIB.addImm(ARM_AM::getAM5Opc(Mode, true, Offset)) + .addImm(Pred).addReg(PredReg); + } + // Transfer the rest of operands. + for (unsigned OpNum = 4, e = MI->getNumOperands(); OpNum != e; ++OpNum) + MIB.addOperand(MI->getOperand(OpNum)); + // Transfer memoperands. + (*MIB).setMemRefs(MI->memoperands_begin(), MI->memoperands_end()); + + MBB.erase(MBBI); + return true; } static unsigned getPreIndexedLoadStoreOpcode(unsigned Opc) { switch (Opc) { case ARM::LDR: return ARM::LDR_PRE; case ARM::STR: return ARM::STR_PRE; - case ARM::VLDRS: return ARM::VLDMS; - case ARM::VLDRD: return ARM::VLDMD; - case ARM::VSTRS: return ARM::VSTMS; - case ARM::VSTRD: return ARM::VSTMD; + case ARM::VLDRS: return ARM::VLDMS_UPD; + case ARM::VLDRD: return ARM::VLDMD_UPD; + case ARM::VSTRS: return ARM::VSTMS_UPD; + case ARM::VSTRD: return ARM::VSTMD_UPD; case ARM::t2LDRi8: case ARM::t2LDRi12: return ARM::t2LDR_PRE; @@ -596,10 +613,10 @@ static unsigned getPostIndexedLoadStoreOpcode(unsigned Opc) { switch (Opc) { case ARM::LDR: return ARM::LDR_POST; case ARM::STR: return ARM::STR_POST; - case ARM::VLDRS: return ARM::VLDMS; - case ARM::VLDRD: return ARM::VLDMD; - case ARM::VSTRS: return ARM::VSTMS; - case ARM::VSTRD: return ARM::VSTMD; + case ARM::VLDRS: return ARM::VLDMS_UPD; + case ARM::VLDRD: return ARM::VLDMD_UPD; + case ARM::VSTRS: return ARM::VSTMS_UPD; + case ARM::VSTRD: return ARM::VSTMD_UPD; case ARM::t2LDRi8: case ARM::t2LDRi12: return ARM::t2LDR_POST; @@ -624,14 +641,14 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLoadStore(MachineBasicBlock &MBB, unsigned Bytes = getLSMultipleTransferSize(MI); int Opcode = MI->getOpcode(); DebugLoc dl = MI->getDebugLoc(); - bool isAM5 = Opcode == ARM::VLDRD || Opcode == ARM::VLDRS || - Opcode == ARM::VSTRD || Opcode == ARM::VSTRS; - bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR; + bool isAM5 = (Opcode == ARM::VLDRD || Opcode == ARM::VLDRS || + Opcode == ARM::VSTRD || Opcode == ARM::VSTRS); + bool isAM2 = (Opcode == ARM::LDR || Opcode == ARM::STR); if (isAM2 && ARM_AM::getAM2Offset(MI->getOperand(3).getImm()) != 0) return false; - else if (isAM5 && ARM_AM::getAM5Offset(MI->getOperand(2).getImm()) != 0) + if (isAM5 && ARM_AM::getAM5Offset(MI->getOperand(2).getImm()) != 0) return false; - else if (isT2i32Load(Opcode) || isT2i32Store(Opcode)) + if (isT2i32Load(Opcode) || isT2i32Store(Opcode)) if (MI->getOperand(2).getImm() != 0) return false; @@ -648,33 +665,35 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLoadStore(MachineBasicBlock &MBB, unsigned NewOpc = 0; // AM2 - 12 bits, thumb2 - 8 bits. unsigned Limit = isAM5 ? 0 : (isAM2 ? 0x1000 : 0x100); + + // Try merging with the previous instruction. if (MBBI != MBB.begin()) { MachineBasicBlock::iterator PrevMBBI = prior(MBBI); if (isMatchingDecrement(PrevMBBI, Base, Bytes, Limit, Pred, PredReg)) { DoMerge = true; AddSub = ARM_AM::sub; - NewOpc = getPreIndexedLoadStoreOpcode(Opcode); } else if (!isAM5 && isMatchingIncrement(PrevMBBI, Base, Bytes, Limit,Pred,PredReg)) { DoMerge = true; - NewOpc = getPreIndexedLoadStoreOpcode(Opcode); } - if (DoMerge) + if (DoMerge) { + NewOpc = getPreIndexedLoadStoreOpcode(Opcode); MBB.erase(PrevMBBI); + } } + // Try merging with the next instruction. if (!DoMerge && MBBI != MBB.end()) { MachineBasicBlock::iterator NextMBBI = llvm::next(MBBI); if (!isAM5 && isMatchingDecrement(NextMBBI, Base, Bytes, Limit, Pred, PredReg)) { DoMerge = true; AddSub = ARM_AM::sub; - NewOpc = getPostIndexedLoadStoreOpcode(Opcode); } else if (isMatchingIncrement(NextMBBI, Base, Bytes, Limit,Pred,PredReg)) { DoMerge = true; - NewOpc = getPostIndexedLoadStoreOpcode(Opcode); } if (DoMerge) { + NewOpc = getPostIndexedLoadStoreOpcode(Opcode); if (NextMBBI == I) { Advance = true; ++I; @@ -689,22 +708,25 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLoadStore(MachineBasicBlock &MBB, bool isDPR = NewOpc == ARM::VLDMD || NewOpc == ARM::VSTMD; unsigned Offset = 0; if (isAM5) - Offset = ARM_AM::getAM5Opc((AddSub == ARM_AM::sub) - ? ARM_AM::db - : ARM_AM::ia, true, (isDPR ? 2 : 1)); + Offset = ARM_AM::getAM5Opc(AddSub == ARM_AM::sub ? ARM_AM::db : ARM_AM::ia, + true, (isDPR ? 2 : 1)); else if (isAM2) Offset = ARM_AM::getAM2Opc(AddSub, Bytes, ARM_AM::no_shift); else Offset = AddSub == ARM_AM::sub ? -Bytes : Bytes; - if (isLd) { - if (isAM5) - // VLDMS, VLDMD - BuildMI(MBB, MBBI, dl, TII->get(NewOpc)) - .addReg(Base, getKillRegState(BaseKill)) - .addImm(Offset).addImm(Pred).addReg(PredReg) - .addReg(Base, getDefRegState(true)) // WB base register - .addReg(MI->getOperand(0).getReg(), RegState::Define); - else if (isAM2) + + if (isAM5) { + // VLDM[SD}_UPD, VSTM[SD]_UPD + MachineOperand &MO = MI->getOperand(0); + BuildMI(MBB, MBBI, dl, TII->get(NewOpc)) + .addReg(Base, getDefRegState(true)) // WB base register + .addReg(Base, getKillRegState(isLd ? BaseKill : false)) + .addImm(Offset) + .addImm(Pred).addReg(PredReg) + .addReg(MO.getReg(), (isLd ? getDefRegState(true) : + getKillRegState(MO.isKill()))); + } else if (isLd) { + if (isAM2) // LDR_PRE, LDR_POST, BuildMI(MBB, MBBI, dl, TII->get(NewOpc), MI->getOperand(0).getReg()) .addReg(Base, RegState::Define) @@ -716,13 +738,7 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLoadStore(MachineBasicBlock &MBB, .addReg(Base).addImm(Offset).addImm(Pred).addReg(PredReg); } else { MachineOperand &MO = MI->getOperand(0); - if (isAM5) - // VSTMS, VSTMD - BuildMI(MBB, MBBI, dl, TII->get(NewOpc)).addReg(Base).addImm(Offset) - .addImm(Pred).addReg(PredReg) - .addReg(Base, getDefRegState(true)) // WB base register - .addReg(MO.getReg(), getKillRegState(MO.isKill())); - else if (isAM2) + if (isAM2) // STR_PRE, STR_POST BuildMI(MBB, MBBI, dl, TII->get(NewOpc), Base) .addReg(MO.getReg(), getKillRegState(MO.isKill())) @@ -910,7 +926,6 @@ bool ARMLoadStoreOpt::FixInvalidRegPairOp(MachineBasicBlock &MBB, .addReg(BaseReg, getKillRegState(BaseKill)) .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia)) .addImm(Pred).addReg(PredReg) - .addReg(0) .addReg(EvenReg, getDefRegState(isLd) | getDeadRegState(EvenDeadKill)) .addReg(OddReg, getDefRegState(isLd) | getDeadRegState(OddDeadKill)); ++NumLDRD2LDM; @@ -919,7 +934,6 @@ bool ARMLoadStoreOpt::FixInvalidRegPairOp(MachineBasicBlock &MBB, .addReg(BaseReg, getKillRegState(BaseKill)) .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia)) .addImm(Pred).addReg(PredReg) - .addReg(0) .addReg(EvenReg, getKillRegState(EvenDeadKill) | getUndefRegState(EvenUndef)) .addReg(OddReg, @@ -1157,7 +1171,8 @@ bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) { if (MBBI != MBB.begin() && (MBBI->getOpcode() == ARM::BX_RET || MBBI->getOpcode() == ARM::tBX_RET)) { MachineInstr *PrevMI = prior(MBBI); - if (PrevMI->getOpcode() == ARM::LDM || PrevMI->getOpcode() == ARM::t2LDM) { + if (PrevMI->getOpcode() == ARM::LDM_UPD || + PrevMI->getOpcode() == ARM::t2LDM_UPD) { MachineOperand &MO = PrevMI->getOperand(PrevMI->getNumOperands()-1); if (MO.getReg() != ARM::LR) return false; diff --git a/lib/Target/ARM/ARMSubtarget.cpp b/lib/Target/ARM/ARMSubtarget.cpp index 622034bd2d99..2dad7f110621 100644 --- a/lib/Target/ARM/ARMSubtarget.cpp +++ b/lib/Target/ARM/ARMSubtarget.cpp @@ -41,6 +41,7 @@ ARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &FS, , PostRAScheduler(false) , IsR9Reserved(ReserveR9) , UseMovt(UseMOVT) + , HasFP16(false) , stackAlignment(4) , CPUString("generic") , TargetType(isELF) // Default to ELF unless otherwise specified. diff --git a/lib/Target/ARM/ARMSubtarget.h b/lib/Target/ARM/ARMSubtarget.h index 69808511fb88..2dc81a4d6d26 100644 --- a/lib/Target/ARM/ARMSubtarget.h +++ b/lib/Target/ARM/ARMSubtarget.h @@ -66,6 +66,10 @@ protected: /// imms (including global addresses). bool UseMovt; + /// HasFP16 - True if subtarget supports half-precision FP (We support VFP+HF + /// only so far) + bool HasFP16; + /// stackAlignment - The minimum alignment known to hold of the stack frame on /// entry to the function and which must be maintained by every function. unsigned stackAlignment; @@ -94,9 +98,9 @@ protected: /// getMaxInlineSizeThreshold - Returns the maximum memset / memcpy size /// that still makes it profitable to inline the call. unsigned getMaxInlineSizeThreshold() const { - // FIXME: For now, we don't lower memcpy's to loads / stores for Thumb. - // Change this once Thumb ldmia / stmia support is added. - return isThumb() ? 0 : 64; + // FIXME: For now, we don't lower memcpy's to loads / stores for Thumb1. + // Change this once Thumb1 ldmia / stmia support is added. + return isThumb1Only() ? 0 : 64; } /// ParseSubtargetFeatures - Parses features string setting specified /// subtarget options. Definition of function is auto generated by tblgen. @@ -116,6 +120,8 @@ protected: bool useNEONForSinglePrecisionFP() const { return hasNEON() && UseNEONForSinglePrecisionFP; } + bool hasFP16() const { return HasFP16; } + bool isTargetDarwin() const { return TargetType == isDarwin; } bool isTargetELF() const { return TargetType == isELF; } diff --git a/lib/Target/ARM/ARMTargetObjectFile.cpp b/lib/Target/ARM/ARMTargetObjectFile.cpp index 7463e309a8ef..680d03254f10 100644 --- a/lib/Target/ARM/ARMTargetObjectFile.cpp +++ b/lib/Target/ARM/ARMTargetObjectFile.cpp @@ -10,7 +10,6 @@ #include "ARMTargetObjectFile.h" #include "ARMSubtarget.h" #include "llvm/MC/MCSectionELF.h" -#include "llvm/MC/MCSectionMachO.h" #include "llvm/Support/Dwarf.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; @@ -35,20 +34,3 @@ void ARMElfTargetObjectFile::Initialize(MCContext &Ctx, SectionKind::getDataRel()); } } - -//===----------------------------------------------------------------------===// -// Mach-O Target -//===----------------------------------------------------------------------===// - -void ARMMachOTargetObjectFile::Initialize(MCContext &Ctx, - const TargetMachine &TM) { - TargetLoweringObjectFileMachO::Initialize(Ctx, TM); - - // Exception Handling. - LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, - SectionKind::getReadOnlyWithRel()); -} - -unsigned ARMMachOTargetObjectFile::getTTypeEncoding() const { - return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; -} diff --git a/lib/Target/ARM/ARMTargetObjectFile.h b/lib/Target/ARM/ARMTargetObjectFile.h index 481d7abd3107..097fc2cceba3 100644 --- a/lib/Target/ARM/ARMTargetObjectFile.h +++ b/lib/Target/ARM/ARMTargetObjectFile.h @@ -24,18 +24,6 @@ public: virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); }; -// FIXME: This subclass isn't 100% necessary. It will become obsolete once we -// can place all LSDAs into the TEXT section. See -// <rdar://problem/6804645>. -class ARMMachOTargetObjectFile : public TargetLoweringObjectFileMachO { -public: - ARMMachOTargetObjectFile() : TargetLoweringObjectFileMachO() {} - - virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); - - virtual unsigned getTTypeEncoding() const; -}; - } // end namespace llvm #endif diff --git a/lib/Target/ARM/AsmParser/Makefile b/lib/Target/ARM/AsmParser/Makefile index 97e56126d8eb..841516fffbd5 100644 --- a/lib/Target/ARM/AsmParser/Makefile +++ b/lib/Target/ARM/AsmParser/Makefile @@ -10,6 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMARMAsmParser # Hack: we need to include 'main' ARM target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp index 314114c96215..4db14a334ab9 100644 --- a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp @@ -38,6 +38,7 @@ #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -74,9 +75,8 @@ namespace { public: explicit ARMAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) - : AsmPrinter(O, TM, Ctx, Streamer, T), AFI(NULL), MCP(NULL) { + MCStreamer &Streamer) + : AsmPrinter(O, TM, Streamer), AFI(NULL), MCP(NULL) { Subtarget = &TM.getSubtarget<ARMSubtarget>(); } @@ -120,8 +120,12 @@ namespace { void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum); void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum); void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum); + void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum) {} void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum); + void printCPSOptionOperand(const MachineInstr *MI, int OpNum) {} + void printMSRMaskOperand(const MachineInstr *MI, int OpNum) {} + void printNegZeroOperand(const MachineInstr *MI, int OpNum) {} void printPredicateOperand(const MachineInstr *MI, int OpNum); void printMandatoryPredicateOperand(const MachineInstr *MI, int OpNum); void printSBitModifierOperand(const MachineInstr *MI, int OpNum); @@ -194,7 +198,7 @@ namespace { bool isIndirect = Subtarget->isTargetDarwin() && Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel()); if (!isIndirect) - O << *GetGlobalValueSymbol(GV); + O << *Mang->getSymbol(GV); else { // FIXME: Remove this when Darwin transition to @GOT like syntax. MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); @@ -202,11 +206,12 @@ namespace { MachineModuleInfoMachO &MMIMachO = MMI->getObjFileInfo<MachineModuleInfoMachO>(); - MCSymbol *&StubSym = + MachineModuleInfoImpl::StubValueTy &StubSym = GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(Sym) : MMIMachO.getGVStubEntry(Sym); - if (StubSym == 0) - StubSym = GetGlobalValueSymbol(GV); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); } } else { assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); @@ -299,7 +304,7 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, break; } case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: { bool isCallOp = Modifier && !strcmp(Modifier, "call"); @@ -311,7 +316,7 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, else if ((Modifier && strcmp(Modifier, "hi16") == 0) || (TF & ARMII::MO_HI16)) O << ":upper16:"; - O << *GetGlobalValueSymbol(GV); + O << *Mang->getSymbol(GV); printOffset(MO.getOffset()); @@ -516,8 +521,10 @@ void ARMAsmPrinter::printAddrMode4Operand(const MachineInstr *MI, int Op, if (MO1.getReg() == ARM::SP) { // FIXME bool isLDM = (MI->getOpcode() == ARM::LDM || + MI->getOpcode() == ARM::LDM_UPD || MI->getOpcode() == ARM::LDM_RET || MI->getOpcode() == ARM::t2LDM || + MI->getOpcode() == ARM::t2LDM_UPD || MI->getOpcode() == ARM::t2LDM_RET); O << ARM_AM::getAMSubModeAltStr(Mode, isLDM); } else @@ -810,11 +817,10 @@ void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int OpNum) { void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int OpNum) { O << "{"; - // Always skip the first operand, it's the optional (and implicit writeback). - for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) { + for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { if (MI->getOperand(i).isImplicit()) continue; - if ((int)i != OpNum+1) O << ", "; + if ((int)i != OpNum) O << ", "; printOperand(MI, i); } O << "}"; @@ -884,16 +890,16 @@ void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNum) { if (UseSet && isNew) { O << "\t.set\t" << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB) << ',' - << *MBB->getSymbol(OutContext) << '-' << *JTISymbol << '\n'; + << *MBB->getSymbol() << '-' << *JTISymbol << '\n'; } O << JTEntryDirective << ' '; if (UseSet) O << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB); else if (TM.getRelocationModel() == Reloc::PIC_) - O << *MBB->getSymbol(OutContext) << '-' << *JTISymbol; + O << *MBB->getSymbol() << '-' << *JTISymbol; else - O << *MBB->getSymbol(OutContext); + O << *MBB->getSymbol(); if (i != e-1) O << '\n'; @@ -925,9 +931,9 @@ void ARMAsmPrinter::printJT2BlockOperand(const MachineInstr *MI, int OpNum) { O << MAI->getData16bitsDirective(); if (ByteOffset || HalfWordOffset) - O << '(' << *MBB->getSymbol(OutContext) << "-" << *JTISymbol << ")/2"; + O << '(' << *MBB->getSymbol() << "-" << *JTISymbol << ")/2"; else - O << "\tb.w " << *MBB->getSymbol(OutContext); + O << "\tb.w " << *MBB->getSymbol(); if (i != e-1) O << '\n'; @@ -1123,7 +1129,7 @@ void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { // Output non-lazy-pointers for external and common global variables. MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList(); - + if (!Stubs.empty()) { // Switch with ".non_lazy_symbol_pointer" directive. OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection()); @@ -1132,15 +1138,16 @@ void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { // L_foo$stub: OutStreamer.EmitLabel(Stubs[i].first); // .indirect_symbol _foo - MCSymbol *MCSym = Stubs[i].second; - OutStreamer.EmitSymbolAttribute(MCSym, MCSA_IndirectSymbol); + MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second; + OutStreamer.EmitSymbolAttribute(MCSym.getPointer(),MCSA_IndirectSymbol); - if (MCSym->isUndefined()) + if (MCSym.getInt()) // External to current translation unit. OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); else // Internal to current translation unit. - OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym, OutContext), + OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), + OutContext), 4/*size*/, 0/*addrspace*/); } @@ -1156,8 +1163,9 @@ void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { // L_foo$stub: OutStreamer.EmitLabel(Stubs[i].first); // .long _foo - OutStreamer.EmitValue(MCSymbolRefExpr::Create(Stubs[i].second, - OutContext), + OutStreamer.EmitValue(MCSymbolRefExpr:: + Create(Stubs[i].second.getPointer(), + OutContext), 4/*size*/, 0/*addrspace*/); } diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h index b7964c9071fe..9a3cbc3f5d04 100644 --- a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h @@ -50,7 +50,7 @@ public: void printAddrMode6Operand(const MCInst *MI, unsigned OpNum); void printAddrModePCOperand(const MCInst *MI, unsigned OpNum, const char *Modifier = 0); - + void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum); void printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum); @@ -68,8 +68,12 @@ public: void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum) {} void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum) {} void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum) {} void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum) {} + void printCPSOptionOperand(const MCInst *MI, unsigned OpNum) {} + void printMSRMaskOperand(const MCInst *MI, unsigned OpNum) {} + void printNegZeroOperand(const MCInst *MI, unsigned OpNum) {} void printPredicateOperand(const MCInst *MI, unsigned OpNum); void printMandatoryPredicateOperand(const MCInst *MI, unsigned OpNum); void printSBitModifierOperand(const MCInst *MI, unsigned OpNum); diff --git a/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp index 5f8705ee0849..7cb305fc41c7 100644 --- a/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp +++ b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp @@ -21,6 +21,7 @@ #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" //#include "llvm/MC/MCStreamer.h" +#include "llvm/Target/Mangler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallString.h" using namespace llvm; @@ -45,7 +46,7 @@ GetGlobalAddressSymbol(const MachineOperand &MO) const { case 0: break; } - return Printer.GetGlobalValueSymbol(MO.getGlobal()); + return Printer.Mang->getSymbol(MO.getGlobal()); } MCSymbol *ARMMCInstLower:: @@ -135,7 +136,7 @@ void ARMMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { break; case MachineOperand::MO_MachineBasicBlock: MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( - MO.getMBB()->getSymbol(Ctx), Ctx)); + MO.getMBB()->getSymbol(), Ctx)); break; case MachineOperand::MO_GlobalAddress: MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); diff --git a/lib/Target/ARM/AsmPrinter/Makefile b/lib/Target/ARM/AsmPrinter/Makefile index 208beccce8a3..65d372e44b88 100644 --- a/lib/Target/ARM/AsmPrinter/Makefile +++ b/lib/Target/ARM/AsmPrinter/Makefile @@ -10,6 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMARMAsmPrinter # Hack: we need to include 'main' arm target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/ARM/Thumb1InstrInfo.cpp b/lib/Target/ARM/Thumb1InstrInfo.cpp index 7f42c82abe99..29ae631269a1 100644 --- a/lib/Target/ARM/Thumb1InstrInfo.cpp +++ b/lib/Target/ARM/Thumb1InstrInfo.cpp @@ -159,7 +159,6 @@ spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, get(ARM::tPUSH)); AddDefaultPred(MIB); - MIB.addReg(0); // No write back. for (unsigned i = CSI.size(); i != 0; --i) { unsigned Reg = CSI[i-1].getReg(); // Add the callee-saved register as live-in. It's killed at the spill. @@ -182,7 +181,6 @@ restoreCalleeSavedRegisters(MachineBasicBlock &MBB, DebugLoc DL = MI->getDebugLoc(); MachineInstrBuilder MIB = BuildMI(MF, DL, get(ARM::tPOP)); AddDefaultPred(MIB); - MIB.addReg(0); // No write back. bool NumRegs = false; for (unsigned i = CSI.size(); i != 0; --i) { diff --git a/lib/Target/ARM/Thumb1RegisterInfo.cpp b/lib/Target/ARM/Thumb1RegisterInfo.cpp index 6215d2fa82c6..99c38b1f4d4b 100644 --- a/lib/Target/ARM/Thumb1RegisterInfo.cpp +++ b/lib/Target/ARM/Thumb1RegisterInfo.cpp @@ -791,9 +791,9 @@ static bool isCSRestore(MachineInstr *MI, const unsigned *CSRegs) { isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs)) return true; else if (MI->getOpcode() == ARM::tPOP) { - // The first three operands are predicates and such. The last two are + // The first two operands are predicates. The last two are // imp-def and imp-use of SP. Check everything in between. - for (int i = 3, e = MI->getNumOperands() - 2; i != e; ++i) + for (int i = 2, e = MI->getNumOperands() - 2; i != e; ++i) if (!isCalleeSavedRegister(MI->getOperand(i).getReg(), CSRegs)) return false; return true; @@ -854,12 +854,16 @@ void Thumb1RegisterInfo::emitEpilogue(MachineFunction &MF, } if (VARegSaveSize) { + // Unlike T2 and ARM mode, the T1 pop instruction cannot restore + // to LR, and we can't pop the value directly to the PC since + // we need to update the SP after popping the value. Therefore, we + // pop the old LR into R3 as a temporary. + // Move back past the callee-saved register restoration while (MBBI != MBB.end() && isCSRestore(MBBI, CSRegs)) ++MBBI; // Epilogue for vararg functions: pop LR to R3 and branch off it. AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tPOP))) - .addReg(0) // No write back. .addReg(ARM::R3, RegState::Define); emitSPUpdate(MBB, MBBI, TII, dl, *this, VARegSaveSize); diff --git a/lib/Target/ARM/Thumb2SizeReduction.cpp b/lib/Target/ARM/Thumb2SizeReduction.cpp index 5086eff59df6..2bc75f28d503 100644 --- a/lib/Target/ARM/Thumb2SizeReduction.cpp +++ b/lib/Target/ARM/Thumb2SizeReduction.cpp @@ -121,9 +121,11 @@ namespace { { ARM::t2STRHi12,ARM::tSTRH, 0, 5, 0, 1, 0, 0,0, 1 }, { ARM::t2STRHs, ARM::tSTRH, 0, 0, 0, 1, 0, 0,0, 1 }, + { ARM::t2LDM, ARM::tLDM, 0, 0, 0, 1, 1, 1,1, 1 }, { ARM::t2LDM_RET,0, ARM::tPOP_RET, 0, 0, 1, 1, 1,1, 1 }, - { ARM::t2LDM, ARM::tLDM, ARM::tPOP, 0, 0, 1, 1, 1,1, 1 }, - { ARM::t2STM, ARM::tSTM, ARM::tPUSH, 0, 0, 1, 1, 1,1, 1 }, + { ARM::t2LDM_UPD,ARM::tLDM_UPD,ARM::tPOP, 0, 0, 1, 1, 1,1, 1 }, + // ARM::t2STM (with no basereg writeback) has no Thumb1 equivalent + { ARM::t2STM_UPD,ARM::tSTM_UPD,ARM::tPUSH, 0, 0, 1, 1, 1,1, 1 }, }; class Thumb2SizeReduce : public MachineFunctionPass { @@ -231,8 +233,9 @@ Thumb2SizeReduce::VerifyPredAndCC(MachineInstr *MI, const ReduceEntry &Entry, static bool VerifyLowRegs(MachineInstr *MI) { unsigned Opc = MI->getOpcode(); - bool isPCOk = (Opc == ARM::t2LDM_RET) || (Opc == ARM::t2LDM); - bool isLROk = (Opc == ARM::t2STM); + bool isPCOk = (Opc == ARM::t2LDM_RET || Opc == ARM::t2LDM || + Opc == ARM::t2LDM_UPD); + bool isLROk = (Opc == ARM::t2STM_UPD); bool isSPOk = isPCOk || isLROk || (Opc == ARM::t2ADDrSPi); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); @@ -307,19 +310,35 @@ Thumb2SizeReduce::ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI, HasShift = true; OpNum = 4; break; - case ARM::t2LDM_RET: - case ARM::t2LDM: - case ARM::t2STM: { - OpNum = 0; + case ARM::t2LDM: { unsigned BaseReg = MI->getOperand(0).getReg(); - unsigned Mode = MI->getOperand(1).getImm(); - if (BaseReg == ARM::SP && ARM_AM::getAM4WBFlag(Mode)) { - Opc = Entry.NarrowOpc2; - OpNum = 2; - } else if (Entry.WideOpc == ARM::t2LDM_RET || - !isARMLowRegister(BaseReg) || - !ARM_AM::getAM4WBFlag(Mode) || - ARM_AM::getAM4SubMode(Mode) != ARM_AM::ia) { + ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm()); + if (!isARMLowRegister(BaseReg) || Mode != ARM_AM::ia) + return false; + OpNum = 0; + isLdStMul = true; + break; + } + case ARM::t2LDM_RET: { + unsigned BaseReg = MI->getOperand(1).getReg(); + if (BaseReg != ARM::SP) + return false; + Opc = Entry.NarrowOpc2; // tPOP_RET + OpNum = 3; + isLdStMul = true; + break; + } + case ARM::t2LDM_UPD: + case ARM::t2STM_UPD: { + OpNum = 0; + unsigned BaseReg = MI->getOperand(1).getReg(); + ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MI->getOperand(2).getImm()); + if (BaseReg == ARM::SP && + ((Entry.WideOpc == ARM::t2LDM_UPD && Mode == ARM_AM::ia) || + (Entry.WideOpc == ARM::t2STM_UPD && Mode == ARM_AM::db))) { + Opc = Entry.NarrowOpc2; // tPOP or tPUSH + OpNum = 3; + } else if (!isARMLowRegister(BaseReg) || Mode != ARM_AM::ia) { return false; } isLdStMul = true; diff --git a/lib/Target/Alpha/AlphaInstrInfo.td b/lib/Target/Alpha/AlphaInstrInfo.td index 95de3d85f8a2..91e58ceef4bc 100644 --- a/lib/Target/Alpha/AlphaInstrInfo.td +++ b/lib/Target/Alpha/AlphaInstrInfo.td @@ -1059,8 +1059,8 @@ def : Pat<(i64 immSExt16:$imm), def : Pat<(i64 immSExt16int:$imm), (ZAPNOTi (LDA (SExt16 immSExt16int:$imm), R31), 15)>; def : Pat<(i64 immConst2PartInt:$imm), - (ZAPNOTi (LDA (LL16 (SExt32 immConst2PartInt:$imm)), - (LDAH (LH16 (SExt32 immConst2PartInt:$imm)), R31)), 15)>; + (ZAPNOTi (LDA (LL16 (i64 (SExt32 immConst2PartInt:$imm))), + (LDAH (LH16 (i64 (SExt32 immConst2PartInt:$imm))), R31)), 15)>; //TODO: I want to just define these like this! diff --git a/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp b/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp index 733a46c0ad24..093cf0528030 100644 --- a/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp +++ b/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp @@ -24,6 +24,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegistry.h" @@ -37,9 +38,8 @@ namespace { /// explicit AlphaAsmPrinter(formatted_raw_ostream &o, TargetMachine &tm, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) - : AsmPrinter(o, tm, Ctx, Streamer, T) {} + MCStreamer &Streamer) + : AsmPrinter(o, tm, Streamer) {} virtual const char *getPassName() const { return "Alpha Assembly Printer"; @@ -96,7 +96,7 @@ void AlphaAsmPrinter::printOp(const MachineOperand &MO, bool IsCallOp) { return; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_ConstantPoolIndex: @@ -109,7 +109,7 @@ void AlphaAsmPrinter::printOp(const MachineOperand &MO, bool IsCallOp) { return; case MachineOperand::MO_GlobalAddress: - O << *GetGlobalValueSymbol(MO.getGlobal()); + O << *Mang->getSymbol(MO.getGlobal()); return; case MachineOperand::MO_JumpTableIndex: diff --git a/lib/Target/Alpha/AsmPrinter/Makefile b/lib/Target/Alpha/AsmPrinter/Makefile index 3c64a3c606f3..ea13c38df4aa 100644 --- a/lib/Target/Alpha/AsmPrinter/Makefile +++ b/lib/Target/Alpha/AsmPrinter/Makefile @@ -10,6 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMAlphaAsmPrinter # Hack: we need to include 'main' alpha target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp b/lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp index fe13e14844c4..1c6d841cf3eb 100644 --- a/lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp +++ b/lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp @@ -27,6 +27,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegistry.h" @@ -39,9 +40,8 @@ namespace { class BlackfinAsmPrinter : public AsmPrinter { public: BlackfinAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *MAI) - : AsmPrinter(O, TM, Ctx, Streamer, MAI) {} + MCStreamer &Streamer) + : AsmPrinter(O, TM, Streamer) {} virtual const char *getPassName() const { return "Blackfin Assembly Printer"; @@ -82,10 +82,10 @@ void BlackfinAsmPrinter::printOperand(const MachineInstr *MI, int opNum) { O << MO.getImm(); break; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: - O << *GetGlobalValueSymbol(MO.getGlobal()); + O << *Mang->getSymbol(MO.getGlobal()); printOffset(MO.getOffset()); break; case MachineOperand::MO_ExternalSymbol: diff --git a/lib/Target/Blackfin/AsmPrinter/Makefile b/lib/Target/Blackfin/AsmPrinter/Makefile index 091d4df0bcb8..a106a2382a14 100644 --- a/lib/Target/Blackfin/AsmPrinter/Makefile +++ b/lib/Target/Blackfin/AsmPrinter/Makefile @@ -11,6 +11,6 @@ LIBRARYNAME = LLVMBlackfinAsmPrinter # Hack: we need to include 'main' Blackfin target directory to grab private # headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp index 10f873ffcb7b..b1ba0d2b9fd4 100644 --- a/lib/Target/CBackend/CBackend.cpp +++ b/lib/Target/CBackend/CBackend.cpp @@ -36,6 +36,7 @@ #include "llvm/Target/Mangler.h" #include "llvm/Transforms/Scalar.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetRegistry.h" @@ -95,6 +96,7 @@ namespace { LoopInfo *LI; const Module *TheModule; const MCAsmInfo* TAsm; + MCContext *TCtx; const TargetData* TD; std::map<const Type *, std::string> TypeNames; std::map<const ConstantFP *, unsigned> FPConstantMap; @@ -1731,7 +1733,8 @@ bool CWriter::doInitialization(Module &M) { TAsm = Match->createAsmInfo(Triple); #endif TAsm = new CBEMCAsmInfo(); - Mang = new Mangler(*TAsm); + TCtx = new MCContext(*TAsm); + Mang = new Mangler(*TCtx, *TD); // Keep track of which functions are static ctors/dtors so they can have // an attribute added to their prototypes. diff --git a/lib/Target/CellSPU/AsmPrinter/Makefile b/lib/Target/CellSPU/AsmPrinter/Makefile index 69639efca748..4ec9d04c0020 100644 --- a/lib/Target/CellSPU/AsmPrinter/Makefile +++ b/lib/Target/CellSPU/AsmPrinter/Makefile @@ -12,6 +12,6 @@ LIBRARYNAME = LLVMCellSPUAsmPrinter # Hack: we need to include 'main' CellSPU target directory to grab # private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/CellSPU/AsmPrinter/SPUAsmPrinter.cpp b/lib/Target/CellSPU/AsmPrinter/SPUAsmPrinter.cpp index 2ca05c24f204..857ddcf92a5f 100644 --- a/lib/Target/CellSPU/AsmPrinter/SPUAsmPrinter.cpp +++ b/lib/Target/CellSPU/AsmPrinter/SPUAsmPrinter.cpp @@ -24,6 +24,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetOptions.h" @@ -38,9 +39,8 @@ namespace { class SPUAsmPrinter : public AsmPrinter { public: explicit SPUAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) : - AsmPrinter(O, TM, Ctx, Streamer, T) {} + MCStreamer &Streamer) : + AsmPrinter(O, TM, Streamer) {} virtual const char *getPassName() const { return "STI CBEA SPU Assembly Printer"; @@ -281,7 +281,7 @@ void SPUAsmPrinter::printOp(const MachineOperand &MO) { return; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_JumpTableIndex: O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() @@ -311,7 +311,7 @@ void SPUAsmPrinter::printOp(const MachineOperand &MO) { return; } } - O << *GetGlobalValueSymbol(MO.getGlobal()); + O << *Mang->getSymbol(MO.getGlobal()); return; default: O << "<unknown operand type: " << MO.getType() << ">"; diff --git a/lib/Target/CellSPU/CellSDKIntrinsics.td b/lib/Target/CellSPU/CellSDKIntrinsics.td index 1fe7aff94a7e..9468aee067a3 100644 --- a/lib/Target/CellSPU/CellSDKIntrinsics.td +++ b/lib/Target/CellSPU/CellSDKIntrinsics.td @@ -205,10 +205,9 @@ def CellSDKnand: // Shift/rotate intrinsics: //===----------------------------------------------------------------------===// -/* FIXME: These have (currently unenforced) type conflicts. */ def CellSDKshli: Pat<(int_spu_si_shli (v4i32 VECREG:$rA), uimm7:$val), - (SHLIv4i32 VECREG:$rA, uimm7:$val)>; + (SHLIv4i32 VECREG:$rA, (TO_IMM32 imm:$val))>; def CellSDKshlqbi: Pat<(int_spu_si_shlqbi VECREG:$rA, R32C:$rB), @@ -216,7 +215,7 @@ def CellSDKshlqbi: def CellSDKshlqii: Pat<(int_spu_si_shlqbii VECREG:$rA, uimm7:$val), - (SHLQBIIv16i8 VECREG:$rA, uimm7:$val)>; + (SHLQBIIv16i8 VECREG:$rA, (TO_IMM32 imm:$val))>; def CellSDKshlqby: Pat<(int_spu_si_shlqby VECREG:$rA, R32C:$rB), @@ -224,7 +223,8 @@ def CellSDKshlqby: def CellSDKshlqbyi: Pat<(int_spu_si_shlqbyi VECREG:$rA, uimm7:$val), - (SHLQBYIv16i8 VECREG:$rA, uimm7:$val)>; + (SHLQBYIv16i8 VECREG:$rA, (TO_IMM32 imm:$val))>; + //===----------------------------------------------------------------------===// // Branch/compare intrinsics: diff --git a/lib/Target/CellSPU/SPU64InstrInfo.td b/lib/Target/CellSPU/SPU64InstrInfo.td index 47cb579d9dec..069a182c26df 100644 --- a/lib/Target/CellSPU/SPU64InstrInfo.td +++ b/lib/Target/CellSPU/SPU64InstrInfo.td @@ -155,8 +155,9 @@ multiclass CompareLogicalGreaterEqual64 { defm I64LGE: CompareLogicalGreaterEqual64; def : Pat<(setuge R64C:$rA, R64C:$rB), I64LGEr64.Fragment>; -def : Pat<(setuge (v2i64 VECREG:$rA), (v2i64 VECREG:$rB)), - I64LGEv2i64.Fragment>; +def : Pat<(v2i64 (setuge (v2i64 VECREG:$rA), (v2i64 VECREG:$rB))), + I64LGEv2i64.Fragment>; + // i64 setult: def : I64SETCCNegCond<setult, I64LGEr64>; @@ -233,8 +234,8 @@ multiclass CompareGreaterEqual64 { defm I64GE: CompareGreaterEqual64; def : Pat<(setge R64C:$rA, R64C:$rB), I64GEr64.Fragment>; -def : Pat<(setge (v2i64 VECREG:$rA), (v2i64 VECREG:$rB)), - I64GEv2i64.Fragment>; +def : Pat<(v2i64 (setge (v2i64 VECREG:$rA), (v2i64 VECREG:$rB))), + I64GEv2i64.Fragment>; // i64 setult: def : I64SETCCNegCond<setlt, I64GEr64>; diff --git a/lib/Target/CellSPU/SPUInstrInfo.td b/lib/Target/CellSPU/SPUInstrInfo.td index b96b64ecd065..ad12604faa19 100644 --- a/lib/Target/CellSPU/SPUInstrInfo.td +++ b/lib/Target/CellSPU/SPUInstrInfo.td @@ -2179,10 +2179,10 @@ multiclass ShiftLeftHalfwordImm defm SHLHI : ShiftLeftHalfwordImm; def : Pat<(SPUvec_shl (v8i16 VECREG:$rA), (i32 uimm7:$val)), - (SHLHIv8i16 VECREG:$rA, uimm7:$val)>; + (SHLHIv8i16 VECREG:$rA, (TO_IMM16 uimm7:$val))>; def : Pat<(shl R16C:$rA, (i32 uimm7:$val)), - (SHLHIr16 R16C:$rA, uimm7:$val)>; + (SHLHIr16 R16C:$rA, (TO_IMM16 uimm7:$val))>; //===----------------------------------------------------------------------===// @@ -2410,8 +2410,8 @@ multiclass RotateLeftHalfwordImm defm ROTHI: RotateLeftHalfwordImm; -def : Pat<(SPUvec_rotl VECREG:$rA, (i32 uimm7:$val)), - (ROTHIv8i16 VECREG:$rA, imm:$val)>; +def : Pat<(SPUvec_rotl (v8i16 VECREG:$rA), (i32 uimm7:$val)), + (ROTHIv8i16 VECREG:$rA, (TO_IMM16 imm:$val))>; //-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ // Rotate word: @@ -2682,10 +2682,10 @@ def : Pat<(SPUvec_srl (v8i16 VECREG:$rA), (i32 imm:$val)), (ROTHMIv8i16 VECREG:$rA, imm:$val)>; def: Pat<(SPUvec_srl (v8i16 VECREG:$rA), (i16 imm:$val)), - (ROTHMIv8i16 VECREG:$rA, imm:$val)>; + (ROTHMIv8i16 VECREG:$rA, (TO_IMM32 imm:$val))>; def: Pat<(SPUvec_srl (v8i16 VECREG:$rA), (i8 imm:$val)), - (ROTHMIv8i16 VECREG:$rA, imm:$val)>; + (ROTHMIv8i16 VECREG:$rA, (TO_IMM32 imm:$val))>; def ROTHMIr16: ROTHMIInst<(outs R16C:$rT), (ins R16C:$rA, rothNeg7imm:$val), @@ -2695,10 +2695,10 @@ def: Pat<(srl R16C:$rA, (i32 uimm7:$val)), (ROTHMIr16 R16C:$rA, uimm7:$val)>; def: Pat<(srl R16C:$rA, (i16 uimm7:$val)), - (ROTHMIr16 R16C:$rA, uimm7:$val)>; + (ROTHMIr16 R16C:$rA, (TO_IMM32 uimm7:$val))>; def: Pat<(srl R16C:$rA, (i8 uimm7:$val)), - (ROTHMIr16 R16C:$rA, uimm7:$val)>; + (ROTHMIr16 R16C:$rA, (TO_IMM32 uimm7:$val))>; // ROTM v4i32 form: See the ROTHM v8i16 comments. class ROTMInst<dag OOL, dag IOL, list<dag> pattern>: @@ -2709,14 +2709,14 @@ def ROTMv4i32: ROTMInst<(outs VECREG:$rT), (ins VECREG:$rA, R32C:$rB), [/* see patterns below - $rB must be negated */]>; -def : Pat<(SPUvec_srl VECREG:$rA, R32C:$rB), +def : Pat<(SPUvec_srl (v4i32 VECREG:$rA), R32C:$rB), (ROTMv4i32 VECREG:$rA, (SFIr32 R32C:$rB, 0))>; -def : Pat<(SPUvec_srl VECREG:$rA, R16C:$rB), +def : Pat<(SPUvec_srl (v4i32 VECREG:$rA), R16C:$rB), (ROTMv4i32 VECREG:$rA, (SFIr32 (XSHWr16 R16C:$rB), 0))>; -def : Pat<(SPUvec_srl VECREG:$rA, R8C:$rB), +def : Pat<(SPUvec_srl (v4i32 VECREG:$rA), R8C:$rB), (ROTMv4i32 VECREG:$rA, (SFIr32 (XSHWr16 (XSBHr8 R8C:$rB)), 0))>; @@ -2742,11 +2742,11 @@ def ROTMIv4i32: [(set (v4i32 VECREG:$rT), (SPUvec_srl VECREG:$rA, (i32 uimm7:$val)))]>; -def : Pat<(SPUvec_srl VECREG:$rA, (i16 uimm7:$val)), - (ROTMIv4i32 VECREG:$rA, uimm7:$val)>; +def : Pat<(SPUvec_srl (v4i32 VECREG:$rA), (i16 uimm7:$val)), + (ROTMIv4i32 VECREG:$rA, (TO_IMM32 uimm7:$val))>; -def : Pat<(SPUvec_srl VECREG:$rA, (i8 uimm7:$val)), - (ROTMIv4i32 VECREG:$rA, uimm7:$val)>; +def : Pat<(SPUvec_srl (v4i32 VECREG:$rA), (i8 uimm7:$val)), + (ROTMIv4i32 VECREG:$rA, (TO_IMM32 uimm7:$val))>; // ROTMI r32 form: know how to complement the immediate value. def ROTMIr32: @@ -2755,10 +2755,10 @@ def ROTMIr32: [(set R32C:$rT, (srl R32C:$rA, (i32 uimm7:$val)))]>; def : Pat<(srl R32C:$rA, (i16 imm:$val)), - (ROTMIr32 R32C:$rA, uimm7:$val)>; + (ROTMIr32 R32C:$rA, (TO_IMM32 uimm7:$val))>; def : Pat<(srl R32C:$rA, (i8 imm:$val)), - (ROTMIr32 R32C:$rA, uimm7:$val)>; + (ROTMIr32 R32C:$rA, (TO_IMM32 uimm7:$val))>; //-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ // ROTQMBY: This is a vector form merely so that when used in an @@ -2916,14 +2916,14 @@ def ROTMAHv8i16: "rotmah\t$rT, $rA, $rB", RotateShift, [/* see patterns below - $rB must be negated */]>; -def : Pat<(SPUvec_sra VECREG:$rA, R32C:$rB), +def : Pat<(SPUvec_sra (v8i16 VECREG:$rA), R32C:$rB), (ROTMAHv8i16 VECREG:$rA, (SFIr32 R32C:$rB, 0))>; -def : Pat<(SPUvec_sra VECREG:$rA, R16C:$rB), +def : Pat<(SPUvec_sra (v8i16 VECREG:$rA), R16C:$rB), (ROTMAHv8i16 VECREG:$rA, (SFIr32 (XSHWr16 R16C:$rB), 0))>; -def : Pat<(SPUvec_sra VECREG:$rA, R8C:$rB), +def : Pat<(SPUvec_sra (v8i16 VECREG:$rA), R8C:$rB), (ROTMAHv8i16 VECREG:$rA, (SFIr32 (XSHWr16 (XSBHr8 R8C:$rB)), 0))>; @@ -2950,10 +2950,10 @@ def ROTMAHIv8i16: (SPUvec_sra (v8i16 VECREG:$rA), (i32 uimm7:$val)))]>; def : Pat<(SPUvec_sra (v8i16 VECREG:$rA), (i16 uimm7:$val)), - (ROTMAHIv8i16 (v8i16 VECREG:$rA), (i32 uimm7:$val))>; + (ROTMAHIv8i16 (v8i16 VECREG:$rA), (TO_IMM32 uimm7:$val))>; def : Pat<(SPUvec_sra (v8i16 VECREG:$rA), (i8 uimm7:$val)), - (ROTMAHIv8i16 (v8i16 VECREG:$rA), (i32 uimm7:$val))>; + (ROTMAHIv8i16 (v8i16 VECREG:$rA), (TO_IMM32 uimm7:$val))>; def ROTMAHIr16: RRForm<0b01111110000, (outs R16C:$rT), (ins R16C:$rA, rothNeg7imm_i16:$val), @@ -2961,25 +2961,25 @@ def ROTMAHIr16: [(set R16C:$rT, (sra R16C:$rA, (i16 uimm7:$val)))]>; def : Pat<(sra R16C:$rA, (i32 imm:$val)), - (ROTMAHIr16 R16C:$rA, uimm7:$val)>; + (ROTMAHIr16 R16C:$rA, (TO_IMM32 uimm7:$val))>; def : Pat<(sra R16C:$rA, (i8 imm:$val)), - (ROTMAHIr16 R16C:$rA, uimm7:$val)>; + (ROTMAHIr16 R16C:$rA, (TO_IMM32 uimm7:$val))>; def ROTMAv4i32: RRForm<0b01011010000, (outs VECREG:$rT), (ins VECREG:$rA, R32C:$rB), "rotma\t$rT, $rA, $rB", RotateShift, [/* see patterns below - $rB must be negated */]>; -def : Pat<(SPUvec_sra VECREG:$rA, R32C:$rB), - (ROTMAv4i32 (v4i32 VECREG:$rA), (SFIr32 R32C:$rB, 0))>; +def : Pat<(SPUvec_sra (v4i32 VECREG:$rA), R32C:$rB), + (ROTMAv4i32 VECREG:$rA, (SFIr32 R32C:$rB, 0))>; -def : Pat<(SPUvec_sra VECREG:$rA, R16C:$rB), - (ROTMAv4i32 (v4i32 VECREG:$rA), +def : Pat<(SPUvec_sra (v4i32 VECREG:$rA), R16C:$rB), + (ROTMAv4i32 VECREG:$rA, (SFIr32 (XSHWr16 R16C:$rB), 0))>; -def : Pat<(SPUvec_sra VECREG:$rA, R8C:$rB), - (ROTMAv4i32 (v4i32 VECREG:$rA), +def : Pat<(SPUvec_sra (v4i32 VECREG:$rA), R8C:$rB), + (ROTMAv4i32 VECREG:$rA, (SFIr32 (XSHWr16 (XSBHr8 R8C:$rB)), 0))>; def ROTMAr32: diff --git a/lib/Target/CellSPU/SPUOperands.td b/lib/Target/CellSPU/SPUOperands.td index 802628f89965..6216651e48a4 100644 --- a/lib/Target/CellSPU/SPUOperands.td +++ b/lib/Target/CellSPU/SPUOperands.td @@ -9,6 +9,17 @@ // Cell SPU Instruction Operands: //===----------------------------------------------------------------------===// +// TO_IMM32 - Convert an i8/i16 to i32. +def TO_IMM32 : SDNodeXForm<imm, [{ + return getI32Imm(N->getZExtValue()); +}]>; + +// TO_IMM16 - Convert an i8/i32 to i16. +def TO_IMM16 : SDNodeXForm<imm, [{ + return CurDAG->getTargetConstant(N->getZExtValue(), MVT::i16); +}]>; + + def LO16 : SDNodeXForm<imm, [{ unsigned val = N->getZExtValue(); // Transformation function: get the low 16 bits. diff --git a/lib/Target/CellSPU/SPURegisterInfo.cpp b/lib/Target/CellSPU/SPURegisterInfo.cpp index 4ba0cb13dff9..8c78bab37b6f 100644 --- a/lib/Target/CellSPU/SPURegisterInfo.cpp +++ b/lib/Target/CellSPU/SPURegisterInfo.cpp @@ -436,7 +436,7 @@ void SPURegisterInfo::emitPrologue(MachineFunction &MF) const // Prepare for debug frame info. bool hasDebugInfo = MMI && MMI->hasDebugInfo(); - unsigned FrameLabelId = 0; + MCSymbol *FrameLabel = 0; // Move MBBI back to the beginning of the function. MBBI = MBB.begin(); @@ -452,8 +452,8 @@ void SPURegisterInfo::emitPrologue(MachineFunction &MF) const FrameSize = -(FrameSize + SPUFrameInfo::minStackSize()); if (hasDebugInfo) { // Mark effective beginning of when frame pointer becomes valid. - FrameLabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, dl, TII.get(SPU::DBG_LABEL)).addImm(FrameLabelId); + FrameLabel = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, TII.get(SPU::DBG_LABEL)).addSym(FrameLabel); } // Adjust stack pointer, spilling $lr -> 16($sp) and $sp -> -FrameSize($sp) @@ -500,7 +500,7 @@ void SPURegisterInfo::emitPrologue(MachineFunction &MF) const // Show update of SP. MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, -FrameSize); - Moves.push_back(MachineMove(FrameLabelId, SPDst, SPSrc)); + Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); // Add callee saved registers to move list. const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); @@ -510,16 +510,16 @@ void SPURegisterInfo::emitPrologue(MachineFunction &MF) const if (Reg == SPU::R0) continue; MachineLocation CSDst(MachineLocation::VirtualFP, Offset); MachineLocation CSSrc(Reg); - Moves.push_back(MachineMove(FrameLabelId, CSDst, CSSrc)); + Moves.push_back(MachineMove(FrameLabel, CSDst, CSSrc)); } // Mark effective beginning of when frame pointer is ready. - unsigned ReadyLabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, dl, TII.get(SPU::DBG_LABEL)).addImm(ReadyLabelId); + MCSymbol *ReadyLabel = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, TII.get(SPU::DBG_LABEL)).addSym(ReadyLabel); MachineLocation FPDst(SPU::R1); MachineLocation FPSrc(MachineLocation::VirtualFP); - Moves.push_back(MachineMove(ReadyLabelId, FPDst, FPSrc)); + Moves.push_back(MachineMove(ReadyLabel, FPDst, FPSrc)); } } else { // This is a leaf function -- insert a branch hint iff there are @@ -530,8 +530,8 @@ void SPURegisterInfo::emitPrologue(MachineFunction &MF) const dl = MBBI->getDebugLoc(); // Insert terminator label - unsigned BranchLabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, dl, TII.get(SPU::DBG_LABEL)).addImm(BranchLabelId); + BuildMI(MBB, MBBI, dl, TII.get(SPU::DBG_LABEL)) + .addSym(MMI->getContext().CreateTempSymbol()); } } } diff --git a/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp b/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp index 6fe102645a43..ee2c7c8e05fb 100644 --- a/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp +++ b/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp @@ -31,6 +31,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" @@ -52,9 +53,8 @@ namespace { const MBlazeSubtarget *Subtarget; public: explicit MBlazeAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T ) - : AsmPrinter(O, TM, Ctx, Streamer, T) { + MCStreamer &Streamer) + : AsmPrinter(O, TM, Streamer) { Subtarget = &TM.getSubtarget<MBlazeSubtarget>(); } @@ -236,11 +236,11 @@ void MBlazeAsmPrinter::printOperand(const MachineInstr *MI, int opNum) { } case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: - O << *GetGlobalValueSymbol(MO.getGlobal()); + O << *Mang->getSymbol(MO.getGlobal()); break; case MachineOperand::MO_ExternalSymbol: diff --git a/lib/Target/MBlaze/AsmPrinter/Makefile b/lib/Target/MBlaze/AsmPrinter/Makefile index c8e4d8f644ad..c44651cc93bd 100644 --- a/lib/Target/MBlaze/AsmPrinter/Makefile +++ b/lib/Target/MBlaze/AsmPrinter/Makefile @@ -12,6 +12,6 @@ LIBRARYNAME = LLVMMBlazeAsmPrinter # Hack: we need to include 'main' MBlaze target directory to grab # private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp b/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp index 7a35eb092ae3..04ac6f1949f1 100644 --- a/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp +++ b/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp @@ -32,6 +32,7 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegistry.h" @@ -42,9 +43,8 @@ namespace { class MSP430AsmPrinter : public AsmPrinter { public: MSP430AsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *MAI) - : AsmPrinter(O, TM, Ctx, Streamer, MAI) {} + MCStreamer &Streamer) + : AsmPrinter(O, TM, Streamer) {} virtual const char *getPassName() const { return "MSP430 Assembly Printer"; @@ -92,7 +92,7 @@ void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum, O << MO.getImm(); return; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: { bool isMemOp = Modifier && !strcmp(Modifier, "mem"); @@ -109,7 +109,7 @@ void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum, if (Offset) O << '(' << Offset << '+'; - O << *GetGlobalValueSymbol(MO.getGlobal()); + O << *Mang->getSymbol(MO.getGlobal()); if (Offset) O << ')'; diff --git a/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp index 2e5ef8edcc67..32c6b0435a7a 100644 --- a/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp +++ b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp @@ -20,6 +20,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/Target/Mangler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/ADT/SmallString.h" @@ -32,7 +33,7 @@ GetGlobalAddressSymbol(const MachineOperand &MO) const { case 0: break; } - return Printer.GetGlobalValueSymbol(MO.getGlobal()); + return Printer.Mang->getSymbol(MO.getGlobal()); } MCSymbol *MSP430MCInstLower:: @@ -116,7 +117,7 @@ void MSP430MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { break; case MachineOperand::MO_MachineBasicBlock: MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( - MO.getMBB()->getSymbol(Printer.OutContext), Ctx)); + MO.getMBB()->getSymbol(), Ctx)); break; case MachineOperand::MO_GlobalAddress: MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); diff --git a/lib/Target/MSP430/AsmPrinter/Makefile b/lib/Target/MSP430/AsmPrinter/Makefile index 4f340c673358..a5293ab8a234 100644 --- a/lib/Target/MSP430/AsmPrinter/Makefile +++ b/lib/Target/MSP430/AsmPrinter/Makefile @@ -10,6 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMMSP430AsmPrinter # Hack: we need to include 'main' MSP430 target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/Mangler.cpp b/lib/Target/Mangler.cpp index ef6defc58dc7..fb9370607499 100644 --- a/lib/Target/Mangler.cpp +++ b/lib/Target/Mangler.cpp @@ -12,8 +12,12 @@ //===----------------------------------------------------------------------===// #include "llvm/Target/Mangler.h" -#include "llvm/GlobalValue.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Target/TargetData.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" using namespace llvm; @@ -59,11 +63,10 @@ static bool NameNeedsEscaping(StringRef Str, const MCAsmInfo &MAI) { /// appendMangledName - Add the specified string in mangled form if it uses /// any unusual characters. static void appendMangledName(SmallVectorImpl<char> &OutName, StringRef Str, - const MCAsmInfo *MAI) { + const MCAsmInfo &MAI) { // The first character is not allowed to be a number unless the target // explicitly allows it. - if ((MAI == 0 || !MAI->doesAllowNameToStartWithDigit()) && - Str[0] >= '0' && Str[0] <= '9') { + if (!MAI.doesAllowNameToStartWithDigit() && Str[0] >= '0' && Str[0] <= '9') { MangleLetter(OutName, Str[0]); Str = Str.substr(1); } @@ -100,6 +103,8 @@ void Mangler::getNameWithPrefix(SmallVectorImpl<char> &OutName, StringRef Name = GVName.toStringRef(TmpData); assert(!Name.empty() && "getNameWithPrefix requires non-empty name"); + const MCAsmInfo &MAI = Context.getAsmInfo(); + // If the global name is not led with \1, add the appropriate prefixes. if (Name[0] == '\1') { Name = Name.substr(1); @@ -134,7 +139,7 @@ void Mangler::getNameWithPrefix(SmallVectorImpl<char> &OutName, // On systems that do not allow quoted names, we need to mangle most // strange characters. if (!MAI.doesAllowQuotesInName()) - return appendMangledName(OutName, Name, &MAI); + return appendMangledName(OutName, Name, MAI); // Okay, the system allows quoted strings. We can quote most anything, the // only characters that need escaping are " and \n. @@ -142,6 +147,26 @@ void Mangler::getNameWithPrefix(SmallVectorImpl<char> &OutName, return appendMangledQuotedName(OutName, Name); } +/// AddFastCallStdCallSuffix - Microsoft fastcall and stdcall functions require +/// a suffix on their name indicating the number of words of arguments they +/// take. +static void AddFastCallStdCallSuffix(SmallVectorImpl<char> &OutName, + const Function *F, const TargetData &TD) { + // Calculate arguments size total. + unsigned ArgWords = 0; + for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end(); + AI != AE; ++AI) { + const Type *Ty = AI->getType(); + // 'Dereference' type in case of byval parameter attribute + if (AI->hasByValAttr()) + Ty = cast<PointerType>(Ty)->getElementType(); + // Size should be aligned to DWORD boundary + ArgWords += ((TD.getTypeAllocSize(Ty) + 3)/4)*4; + } + + raw_svector_ostream(OutName) << '@' << ArgWords; +} + /// getNameWithPrefix - Fill OutName with the name of the appropriate prefix /// and the specified global variable's name. If the global variable doesn't @@ -156,16 +181,43 @@ void Mangler::getNameWithPrefix(SmallVectorImpl<char> &OutName, PrefixTy = Mangler::LinkerPrivate; // If this global has a name, handle it simply. - if (GV->hasName()) - return getNameWithPrefix(OutName, GV->getName(), PrefixTy); + if (GV->hasName()) { + getNameWithPrefix(OutName, GV->getName(), PrefixTy); + } else { + // Get the ID for the global, assigning a new one if we haven't got one + // already. + unsigned &ID = AnonGlobalIDs[GV]; + if (ID == 0) ID = NextAnonGlobalID++; - // Get the ID for the global, assigning a new one if we haven't got one - // already. - unsigned &ID = AnonGlobalIDs[GV]; - if (ID == 0) ID = NextAnonGlobalID++; + // Must mangle the global into a unique ID. + getNameWithPrefix(OutName, "__unnamed_" + Twine(ID), PrefixTy); + } - // Must mangle the global into a unique ID. - getNameWithPrefix(OutName, "__unnamed_" + Twine(ID), PrefixTy); + // If we are supposed to add a microsoft-style suffix for stdcall/fastcall, + // add it. + if (Context.getAsmInfo().hasMicrosoftFastStdCallMangling()) { + if (const Function *F = dyn_cast<Function>(GV)) { + CallingConv::ID CC = F->getCallingConv(); + + // fastcall functions need to start with @. + // FIXME: This logic seems unlikely to be right. + if (CC == CallingConv::X86_FastCall) { + if (OutName[0] == '_') + OutName[0] = '@'; + else + OutName.insert(OutName.begin(), '@'); + } + + // fastcall and stdcall functions usually need @42 at the end to specify + // the argument info. + const FunctionType *FT = F->getFunctionType(); + if ((CC == CallingConv::X86_FastCall || CC == CallingConv::X86_StdCall) && + // "Pure" variadic functions do not receive @0 suffix. + (!FT->isVarArg() || FT->getNumParams() == 0 || + (FT->getNumParams() == 1 && F->hasStructRetAttr()))) + AddFastCallStdCallSuffix(OutName, F, TD); + } + } } /// getNameWithPrefix - Fill OutName with the name of the appropriate prefix @@ -177,3 +229,16 @@ std::string Mangler::getNameWithPrefix(const GlobalValue *GV, getNameWithPrefix(Buf, GV, isImplicitlyPrivate); return std::string(Buf.begin(), Buf.end()); } + +/// getSymbol - Return the MCSymbol for the specified global value. This +/// symbol is the main label that is the address of the global. +MCSymbol *Mangler::getSymbol(const GlobalValue *GV) { + SmallString<60> NameStr; + getNameWithPrefix(NameStr, GV, false); + if (!GV->hasPrivateLinkage()) + return Context.GetOrCreateSymbol(NameStr.str()); + + return Context.GetOrCreateTemporarySymbol(NameStr.str()); +} + + diff --git a/lib/Target/Mips/AsmPrinter/Makefile b/lib/Target/Mips/AsmPrinter/Makefile index a2fecf44e8e1..b1efe9b94479 100644 --- a/lib/Target/Mips/AsmPrinter/Makefile +++ b/lib/Target/Mips/AsmPrinter/Makefile @@ -12,6 +12,6 @@ LIBRARYNAME = LLVMMipsAsmPrinter # Hack: we need to include 'main' Mips target directory to grab # private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp b/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp index b8641c309762..2a2d9dcaf5a6 100644 --- a/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp @@ -31,6 +31,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" @@ -50,9 +51,8 @@ namespace { const MipsSubtarget *Subtarget; public: explicit MipsAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) - : AsmPrinter(O, TM, Ctx, Streamer, T) { + MCStreamer &Streamer) + : AsmPrinter(O, TM, Streamer) { Subtarget = &TM.getSubtarget<MipsSubtarget>(); } @@ -277,11 +277,11 @@ void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum) { break; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: - O << *GetGlobalValueSymbol(MO.getGlobal()); + O << *Mang->getSymbol(MO.getGlobal()); break; case MachineOperand::MO_ExternalSymbol: diff --git a/lib/Target/PIC16/AsmPrinter/Makefile b/lib/Target/PIC16/AsmPrinter/Makefile index f4db57e60716..e3c0684ebcf8 100644 --- a/lib/Target/PIC16/AsmPrinter/Makefile +++ b/lib/Target/PIC16/AsmPrinter/Makefile @@ -10,6 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMPIC16AsmPrinter # Hack: we need to include 'main' pic16 target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp index 44a6cc0acb94..b6eceb36a473 100644 --- a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp +++ b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp @@ -25,6 +25,7 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Support/ErrorHandling.h" @@ -35,11 +36,10 @@ using namespace llvm; #include "PIC16GenAsmWriter.inc" PIC16AsmPrinter::PIC16AsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) -: AsmPrinter(O, TM, Ctx, Streamer, T), DbgInfo(O, T) { + MCStreamer &Streamer) +: AsmPrinter(O, TM, Streamer), DbgInfo(O, TM.getMCAsmInfo()) { PTLI = static_cast<PIC16TargetLowering*>(TM.getTargetLowering()); - PMAI = static_cast<const PIC16MCAsmInfo*>(T); + PMAI = static_cast<const PIC16MCAsmInfo*>(TM.getMCAsmInfo()); PTOF = (PIC16TargetObjectFile *)&PTLI->getObjFileLowering(); } @@ -179,7 +179,7 @@ void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) { return; case MachineOperand::MO_GlobalAddress: { - MCSymbol *Sym = GetGlobalValueSymbol(MO.getGlobal()); + MCSymbol *Sym = Mang->getSymbol(MO.getGlobal()); // FIXME: currently we do not have a memcpy def coming in the module // by any chance, as we do not link in those as .bc lib. So these calls // are always external and it is safe to emit an extern. @@ -206,7 +206,7 @@ void PIC16AsmPrinter::printOperand(const MachineInstr *MI, int opNum) { break; } case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; default: @@ -312,7 +312,7 @@ void PIC16AsmPrinter::EmitFunctionDecls(Module &M) { if (!I->isDeclaration() && !I->hasExternalLinkage()) continue; - MCSymbol *Sym = GetGlobalValueSymbol(I); + MCSymbol *Sym = Mang->getSymbol(I); // Do not emit memcpy, memset, and memmove here. // Calls to these routines can be generated in two ways, @@ -342,7 +342,7 @@ void PIC16AsmPrinter::EmitUndefinedVars(Module &M) { O << "\n" << MAI->getCommentString() << "Imported Variables - BEGIN" << "\n"; for (unsigned j = 0; j < Items.size(); j++) - O << MAI->getExternDirective() << *GetGlobalValueSymbol(Items[j]) << "\n"; + O << MAI->getExternDirective() << *Mang->getSymbol(Items[j]) << "\n"; O << MAI->getCommentString() << "Imported Variables - END" << "\n"; } @@ -353,7 +353,7 @@ void PIC16AsmPrinter::EmitDefinedVars(Module &M) { O << "\n" << MAI->getCommentString() << "Exported Variables - BEGIN" << "\n"; for (unsigned j = 0; j < Items.size(); j++) - O << MAI->getGlobalDirective() << *GetGlobalValueSymbol(Items[j]) << "\n"; + O << MAI->getGlobalDirective() << *Mang->getSymbol(Items[j]) << "\n"; O << MAI->getCommentString() << "Exported Variables - END" << "\n"; } @@ -432,7 +432,7 @@ void PIC16AsmPrinter::EmitInitializedDataSection(const PIC16Section *S) { for (unsigned j = 0; j < Items.size(); j++) { Constant *C = Items[j]->getInitializer(); int AddrSpace = Items[j]->getType()->getAddressSpace(); - O << *GetGlobalValueSymbol(Items[j]); + O << *Mang->getSymbol(Items[j]); EmitGlobalConstant(C, AddrSpace); } } @@ -451,7 +451,7 @@ EmitUninitializedDataSection(const PIC16Section *S) { Constant *C = Items[j]->getInitializer(); const Type *Ty = C->getType(); unsigned Size = TD->getTypeAllocSize(Ty); - O << *GetGlobalValueSymbol(Items[j]) << " RES " << Size << "\n"; + O << *Mang->getSymbol(Items[j]) << " RES " << Size << "\n"; } } diff --git a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h index 77b6e6347101..519be4cf8f25 100644 --- a/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h +++ b/lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h @@ -31,8 +31,7 @@ namespace llvm { class VISIBILITY_HIDDEN PIC16AsmPrinter : public AsmPrinter { public: explicit PIC16AsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T); + MCStreamer &Streamer); private: virtual const char *getPassName() const { return "PIC16 Assembly Printer"; diff --git a/lib/Target/PowerPC/AsmPrinter/Makefile b/lib/Target/PowerPC/AsmPrinter/Makefile index 269ef9204433..bd5dce12dc43 100644 --- a/lib/Target/PowerPC/AsmPrinter/Makefile +++ b/lib/Target/PowerPC/AsmPrinter/Makefile @@ -10,6 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMPowerPCAsmPrinter # Hack: we need to include 'main' PowerPC target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp b/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp index 3c7dfaf0f6e0..ed6fc9d51cb2 100644 --- a/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp +++ b/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp @@ -34,6 +34,7 @@ #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" @@ -60,9 +61,8 @@ namespace { uint64_t LabelID; public: explicit PPCAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) - : AsmPrinter(O, TM, Ctx, Streamer, T), + MCStreamer &Streamer) + : AsmPrinter(O, TM, Streamer), Subtarget(TM.getSubtarget<PPCSubtarget>()), LabelID(0) {} virtual const char *getPassName() const { @@ -198,10 +198,11 @@ namespace { if (GV->isDeclaration() || GV->isWeakForLinker()) { // Dynamically-resolved functions need a stub for the function. MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$stub"); - MCSymbol *&StubSym = + MachineModuleInfoImpl::StubValueTy &StubSym = MMI->getObjFileInfo<MachineModuleInfoMachO>().getFnStubEntry(Sym); - if (StubSym == 0) - StubSym = GetGlobalValueSymbol(GV); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); O << *Sym; return; } @@ -212,10 +213,11 @@ namespace { TempNameStr += StringRef("$stub"); MCSymbol *Sym = GetExternalSymbolSymbol(TempNameStr.str()); - MCSymbol *&StubSym = + MachineModuleInfoImpl::StubValueTy &StubSym = MMI->getObjFileInfo<MachineModuleInfoMachO>().getFnStubEntry(Sym); - if (StubSym == 0) - StubSym = GetExternalSymbolSymbol(MO.getSymbolName()); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(GetExternalSymbolSymbol(MO.getSymbolName()), true); O << *Sym; return; } @@ -300,10 +302,8 @@ namespace { void printTOCEntryLabel(const MachineInstr *MI, unsigned OpNo) { const MachineOperand &MO = MI->getOperand(OpNo); - assert(MO.getType() == MachineOperand::MO_GlobalAddress); - - const MCSymbol *Sym = GetGlobalValueSymbol(MO.getGlobal()); + const MCSymbol *Sym = Mang->getSymbol(MO.getGlobal()); // Map symbol -> label of TOC entry. const MCSymbol *&TOCEntry = TOC[Sym]; @@ -323,9 +323,8 @@ namespace { class PPCLinuxAsmPrinter : public PPCAsmPrinter { public: explicit PPCLinuxAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) - : PPCAsmPrinter(O, TM, Ctx, Streamer, T) {} + MCStreamer &Streamer) + : PPCAsmPrinter(O, TM, Streamer) {} virtual const char *getPassName() const { return "Linux PPC Assembly Printer"; @@ -349,9 +348,8 @@ namespace { formatted_raw_ostream &OS; public: explicit PPCDarwinAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) - : PPCAsmPrinter(O, TM, Ctx, Streamer, T), OS(O) {} + MCStreamer &Streamer) + : PPCAsmPrinter(O, TM, Streamer), OS(O) {} virtual const char *getPassName() const { return "Darwin PPC Assembly Printer"; @@ -380,7 +378,7 @@ void PPCAsmPrinter::printOp(const MachineOperand &MO) { llvm_unreachable("printOp() does not handle immediate values"); case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_JumpTableIndex: O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() @@ -404,10 +402,11 @@ void PPCAsmPrinter::printOp(const MachineOperand &MO) { MCSymbol *NLPSym = OutContext.GetOrCreateSymbol(StringRef(MAI->getGlobalPrefix())+ MO.getSymbolName()+"$non_lazy_ptr"); - MCSymbol *&StubSym = + MachineModuleInfoImpl::StubValueTy &StubSym = MMI->getObjFileInfo<MachineModuleInfoMachO>().getGVStubEntry(NLPSym); - if (StubSym == 0) - StubSym = GetExternalSymbolSymbol(MO.getSymbolName()); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(GetExternalSymbolSymbol(MO.getSymbolName()), true); O << *NLPSym; return; @@ -422,24 +421,27 @@ void PPCAsmPrinter::printOp(const MachineOperand &MO) { (GV->isDeclaration() || GV->isWeakForLinker())) { if (!GV->hasHiddenVisibility()) { SymToPrint = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - MCSymbol *&StubSym = - MMI->getObjFileInfo<MachineModuleInfoMachO>().getGVStubEntry(SymToPrint); - if (StubSym == 0) - StubSym = GetGlobalValueSymbol(GV); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo<MachineModuleInfoMachO>() + .getGVStubEntry(SymToPrint); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); } else if (GV->isDeclaration() || GV->hasCommonLinkage() || GV->hasAvailableExternallyLinkage()) { SymToPrint = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - MCSymbol *&StubSym = + MachineModuleInfoImpl::StubValueTy &StubSym = MMI->getObjFileInfo<MachineModuleInfoMachO>(). getHiddenGVStubEntry(SymToPrint); - if (StubSym == 0) - StubSym = GetGlobalValueSymbol(GV); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); } else { - SymToPrint = GetGlobalValueSymbol(GV); + SymToPrint = Mang->getSymbol(GV); } } else { - SymToPrint = GetGlobalValueSymbol(GV); + SymToPrint = Mang->getSymbol(GV); } O << *SymToPrint; @@ -704,7 +706,7 @@ EmitFunctionStubs(const MachineModuleInfoMachO::SymbolListTy &Stubs) { EmitAlignment(4); const MCSymbol *Stub = Stubs[i].first; - const MCSymbol *RawSym = Stubs[i].second; + const MCSymbol *RawSym = Stubs[i].second.getPointer(); const MCSymbol *LazyPtr = GetLazyPtr(Stub, OutContext); const MCSymbol *AnonSymbol = GetAnonSym(Stub, OutContext); @@ -738,7 +740,7 @@ EmitFunctionStubs(const MachineModuleInfoMachO::SymbolListTy &Stubs) { 16, SectionKind::getText()); for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { const MCSymbol *Stub = Stubs[i].first; - const MCSymbol *RawSym = Stubs[i].second; + const MCSymbol *RawSym = Stubs[i].second.getPointer(); const MCSymbol *LazyPtr = GetLazyPtr(Stub, OutContext); OutStreamer.SwitchSection(StubSection); @@ -781,8 +783,9 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) { E = Personalities.end(); I != E; ++I) { if (*I) { MCSymbol *NLPSym = GetSymbolWithGlobalValueBase(*I, "$non_lazy_ptr"); - MCSymbol *&StubSym = MMIMacho.getGVStubEntry(NLPSym); - StubSym = GetGlobalValueSymbol(*I); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMIMacho.getGVStubEntry(NLPSym); + StubSym = MachineModuleInfoImpl::StubValueTy(Mang->getSymbol(*I), true); } } } @@ -797,10 +800,24 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) { EmitAlignment(isPPC64 ? 3 : 2); for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { - O << *Stubs[i].first << ":\n"; - O << "\t.indirect_symbol " << *Stubs[i].second << '\n'; - O << (isPPC64 ? "\t.quad\t0\n" : "\t.long\t0\n"); + // L_foo$stub: + OutStreamer.EmitLabel(Stubs[i].first); + // .indirect_symbol _foo + MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second; + OutStreamer.EmitSymbolAttribute(MCSym.getPointer(), MCSA_IndirectSymbol); + + if (MCSym.getInt()) + // External to current translation unit. + OutStreamer.EmitIntValue(0, isPPC64 ? 8 : 4/*size*/, 0/*addrspace*/); + else + // Internal to current translation unit. + OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), + OutContext), + isPPC64 ? 8 : 4/*size*/, 0/*addrspace*/); } + + Stubs.clear(); + OutStreamer.AddBlankLine(); } Stubs = MMIMacho.GetHiddenGVStubList(); @@ -809,9 +826,17 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) { EmitAlignment(isPPC64 ? 3 : 2); for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { - O << *Stubs[i].first << ":\n"; - O << (isPPC64 ? "\t.quad\t" : "\t.long\t") << *Stubs[i].second << '\n'; + // L_foo$stub: + OutStreamer.EmitLabel(Stubs[i].first); + // .long _foo + OutStreamer.EmitValue(MCSymbolRefExpr:: + Create(Stubs[i].second.getPointer(), + OutContext), + isPPC64 ? 8 : 4/*size*/, 0/*addrspace*/); } + + Stubs.clear(); + OutStreamer.AddBlankLine(); } // Funny Darwin hack: This flag tells the linker that no global symbols @@ -824,21 +849,18 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) { return AsmPrinter::doFinalization(M); } - - /// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code /// for a MachineFunction to the given output stream, in a format that the /// Darwin assembler can deal with. /// static AsmPrinter *createPPCAsmPrinterPass(formatted_raw_ostream &o, TargetMachine &tm, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *tai) { + MCStreamer &Streamer) { const PPCSubtarget *Subtarget = &tm.getSubtarget<PPCSubtarget>(); if (Subtarget->isDarwin()) - return new PPCDarwinAsmPrinter(o, tm, Ctx, Streamer, tai); - return new PPCLinuxAsmPrinter(o, tm, Ctx, Streamer, tai); + return new PPCDarwinAsmPrinter(o, tm, Streamer); + return new PPCLinuxAsmPrinter(o, tm, Streamer); } // Force static initialization. diff --git a/lib/Target/PowerPC/PPCCodeEmitter.cpp b/lib/Target/PowerPC/PPCCodeEmitter.cpp index 327470dd103e..f7c27d40a5b3 100644 --- a/lib/Target/PowerPC/PPCCodeEmitter.cpp +++ b/lib/Target/PowerPC/PPCCodeEmitter.cpp @@ -30,6 +30,7 @@ namespace { class PPCCodeEmitter : public MachineFunctionPass { TargetMachine &TM; JITCodeEmitter &MCE; + MachineModuleInfo *MMI; void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<MachineModuleInfo>(); @@ -87,7 +88,8 @@ bool PPCCodeEmitter::runOnMachineFunction(MachineFunction &MF) { MF.getTarget().getRelocationModel() != Reloc::Static) && "JIT relocation model must be set to static or default!"); - MCE.setModuleInfo(&getAnalysis<MachineModuleInfo>()); + MMI = &getAnalysis<MachineModuleInfo>(); + MCE.setModuleInfo(MMI); do { MovePCtoLROffset = 0; MCE.startFunction(MF); @@ -110,7 +112,7 @@ void PPCCodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) { break; case TargetOpcode::DBG_LABEL: case TargetOpcode::EH_LABEL: - MCE.emitLabel(MI.getOperand(0).getImm()); + MCE.emitLabel(MI.getOperand(0).getMCSymbol()); break; case TargetOpcode::IMPLICIT_DEF: case TargetOpcode::KILL: diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index aeaa7c6816d8..2c072c1290f6 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -13,9 +13,9 @@ #include "PPCISelLowering.h" #include "PPCMachineFunctionInfo.h" +#include "PPCPerfectShuffle.h" #include "PPCPredicates.h" #include "PPCTargetMachine.h" -#include "PPCPerfectShuffle.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/VectorExtras.h" #include "llvm/CodeGen/CallingConvLower.h" @@ -60,10 +60,10 @@ cl::desc("enable preincrement load/store generation on PPC (experimental)"), static TargetLoweringObjectFile *CreateTLOF(const PPCTargetMachine &TM) { if (TM.getSubtargetImpl()->isDarwin()) return new TargetLoweringObjectFileMachO(); + return new TargetLoweringObjectFileELF(); } - PPCTargetLowering::PPCTargetLowering(PPCTargetMachine &TM) : TargetLowering(TM, CreateTLOF(TM)), PPCSubTarget(*TM.getSubtargetImpl()) { @@ -4216,7 +4216,7 @@ static bool getAltivecCompareInfo(SDValue Intrin, int &CompareOpc, /// LowerINTRINSIC_WO_CHAIN - If this is an intrinsic that we want to custom /// lower, do it, otherwise return null. SDValue PPCTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, - SelectionDAG &DAG) { + SelectionDAG &DAG) { // If this is a lowered altivec predicate compare, CompareOpc is set to the // opcode number of the comparison. DebugLoc dl = Op.getDebugLoc(); @@ -4228,8 +4228,8 @@ SDValue PPCTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, // If this is a non-dot comparison, make the VCMP node and we are done. if (!isDot) { SDValue Tmp = DAG.getNode(PPCISD::VCMP, dl, Op.getOperand(2).getValueType(), - Op.getOperand(1), Op.getOperand(2), - DAG.getConstant(CompareOpc, MVT::i32)); + Op.getOperand(1), Op.getOperand(2), + DAG.getConstant(CompareOpc, MVT::i32)); return DAG.getNode(ISD::BIT_CONVERT, dl, Op.getValueType(), Tmp); } diff --git a/lib/Target/PowerPC/PPCRegisterInfo.cpp b/lib/Target/PowerPC/PPCRegisterInfo.cpp index 31bca16c864a..6e7880e22ce2 100644 --- a/lib/Target/PowerPC/PPCRegisterInfo.cpp +++ b/lib/Target/PowerPC/PPCRegisterInfo.cpp @@ -1287,7 +1287,7 @@ PPCRegisterInfo::emitPrologue(MachineFunction &MF) const { UnwindTablesMandatory; // Prepare for frame info. - unsigned FrameLabelId = 0; + MCSymbol *FrameLabel = 0; // Scan the prolog, looking for an UPDATE_VRSAVE instruction. If we find it, // process it. @@ -1446,33 +1446,33 @@ PPCRegisterInfo::emitPrologue(MachineFunction &MF) const { // reverse order. if (needsFrameMoves) { // Mark effective beginning of when frame pointer becomes valid. - FrameLabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, dl, TII.get(PPC::DBG_LABEL)).addImm(FrameLabelId); + FrameLabel = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, TII.get(PPC::DBG_LABEL)).addSym(FrameLabel); // Show update of SP. if (NegFrameSize) { MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, NegFrameSize); - Moves.push_back(MachineMove(FrameLabelId, SPDst, SPSrc)); + Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); } else { MachineLocation SP(isPPC64 ? PPC::X31 : PPC::R31); - Moves.push_back(MachineMove(FrameLabelId, SP, SP)); + Moves.push_back(MachineMove(FrameLabel, SP, SP)); } if (HasFP) { MachineLocation FPDst(MachineLocation::VirtualFP, FPOffset); MachineLocation FPSrc(isPPC64 ? PPC::X31 : PPC::R31); - Moves.push_back(MachineMove(FrameLabelId, FPDst, FPSrc)); + Moves.push_back(MachineMove(FrameLabel, FPDst, FPSrc)); } if (MustSaveLR) { MachineLocation LRDst(MachineLocation::VirtualFP, LROffset); MachineLocation LRSrc(isPPC64 ? PPC::LR8 : PPC::LR); - Moves.push_back(MachineMove(FrameLabelId, LRDst, LRSrc)); + Moves.push_back(MachineMove(FrameLabel, LRDst, LRSrc)); } } - unsigned ReadyLabelId = 0; + MCSymbol *ReadyLabel = 0; // If there is a frame pointer, copy R1 into R31 if (HasFP) { @@ -1487,20 +1487,20 @@ PPCRegisterInfo::emitPrologue(MachineFunction &MF) const { } if (needsFrameMoves) { - ReadyLabelId = MMI->NextLabelID(); + ReadyLabel = MMI->getContext().CreateTempSymbol(); // Mark effective beginning of when frame pointer is ready. - BuildMI(MBB, MBBI, dl, TII.get(PPC::DBG_LABEL)).addImm(ReadyLabelId); + BuildMI(MBB, MBBI, dl, TII.get(PPC::DBG_LABEL)).addSym(ReadyLabel); MachineLocation FPDst(HasFP ? (isPPC64 ? PPC::X31 : PPC::R31) : (isPPC64 ? PPC::X1 : PPC::R1)); MachineLocation FPSrc(MachineLocation::VirtualFP); - Moves.push_back(MachineMove(ReadyLabelId, FPDst, FPSrc)); + Moves.push_back(MachineMove(ReadyLabel, FPDst, FPSrc)); } } if (needsFrameMoves) { - unsigned LabelId = HasFP ? ReadyLabelId : FrameLabelId; + MCSymbol *Label = HasFP ? ReadyLabel : FrameLabel; // Add callee saved registers to move list. const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); @@ -1510,7 +1510,7 @@ PPCRegisterInfo::emitPrologue(MachineFunction &MF) const { if (Reg == PPC::LR || Reg == PPC::LR8 || Reg == PPC::RM) continue; MachineLocation CSDst(MachineLocation::VirtualFP, Offset); MachineLocation CSSrc(Reg); - Moves.push_back(MachineMove(LabelId, CSDst, CSSrc)); + Moves.push_back(MachineMove(Label, CSDst, CSSrc)); } } } diff --git a/lib/Target/README.txt b/lib/Target/README.txt index 4fd46a8b28ad..052a5756da9f 100644 --- a/lib/Target/README.txt +++ b/lib/Target/README.txt @@ -1819,3 +1819,27 @@ int test2(int mainType, int subType) { } //===---------------------------------------------------------------------===// + +The following test case (from PR6576): + +define i32 @mul(i32 %a, i32 %b) nounwind readnone { +entry: + %cond1 = icmp eq i32 %b, 0 ; <i1> [#uses=1] + br i1 %cond1, label %exit, label %bb.nph +bb.nph: ; preds = %entry + %tmp = mul i32 %b, %a ; <i32> [#uses=1] + ret i32 %tmp +exit: ; preds = %entry + ret i32 0 +} + +could be reduced to: + +define i32 @mul(i32 %a, i32 %b) nounwind readnone { +entry: + %tmp = mul i32 %b, %a + ret i32 %tmp +} + +//===---------------------------------------------------------------------===// + diff --git a/lib/Target/Sparc/AsmPrinter/Makefile b/lib/Target/Sparc/AsmPrinter/Makefile index a856828ce401..fe475389c680 100644 --- a/lib/Target/Sparc/AsmPrinter/Makefile +++ b/lib/Target/Sparc/AsmPrinter/Makefile @@ -10,6 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMSparcAsmPrinter # Hack: we need to include 'main' Sparc target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/Sparc/AsmPrinter/SparcAsmPrinter.cpp b/lib/Target/Sparc/AsmPrinter/SparcAsmPrinter.cpp index f6753a637cd0..3e40dbb17f88 100644 --- a/lib/Target/Sparc/AsmPrinter/SparcAsmPrinter.cpp +++ b/lib/Target/Sparc/AsmPrinter/SparcAsmPrinter.cpp @@ -21,6 +21,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/FormattedStream.h" @@ -30,9 +31,8 @@ namespace { class SparcAsmPrinter : public AsmPrinter { public: explicit SparcAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) - : AsmPrinter(O, TM, Ctx, Streamer, T) {} + MCStreamer &Streamer) + : AsmPrinter(O, TM, Streamer) {} virtual const char *getPassName() const { return "Sparc Assembly Printer"; @@ -84,10 +84,10 @@ void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum) { O << (int)MO.getImm(); break; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: - O << *GetGlobalValueSymbol(MO.getGlobal()); + O << *Mang->getSymbol(MO.getGlobal()); break; case MachineOperand::MO_ExternalSymbol: O << MO.getSymbolName(); diff --git a/lib/Target/SystemZ/AsmPrinter/Makefile b/lib/Target/SystemZ/AsmPrinter/Makefile index 9a350dfe62e7..0f90ed369f77 100644 --- a/lib/Target/SystemZ/AsmPrinter/Makefile +++ b/lib/Target/SystemZ/AsmPrinter/Makefile @@ -10,6 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMSystemZAsmPrinter # Hack: we need to include 'main' SystemZ target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/SystemZ/AsmPrinter/SystemZAsmPrinter.cpp b/lib/Target/SystemZ/AsmPrinter/SystemZAsmPrinter.cpp index 7a9e8dd20736..b29dfcdc9846 100644 --- a/lib/Target/SystemZ/AsmPrinter/SystemZAsmPrinter.cpp +++ b/lib/Target/SystemZ/AsmPrinter/SystemZAsmPrinter.cpp @@ -29,6 +29,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegistry.h" @@ -40,9 +41,8 @@ namespace { class SystemZAsmPrinter : public AsmPrinter { public: SystemZAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *MAI) - : AsmPrinter(O, TM, Ctx, Streamer, MAI) {} + MCStreamer &Streamer) + : AsmPrinter(O, TM, Streamer) {} virtual const char *getPassName() const { return "SystemZ Assembly Printer"; @@ -89,11 +89,11 @@ void SystemZAsmPrinter::printPCRelImmOperand(const MachineInstr *MI, int OpNum){ O << MO.getImm(); return; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: { const GlobalValue *GV = MO.getGlobal(); - O << *GetGlobalValueSymbol(GV); + O << *Mang->getSymbol(GV); // Assemble calls via PLT for externally visible symbols if PIC. if (TM.getRelocationModel() == Reloc::PIC_ && @@ -144,7 +144,7 @@ void SystemZAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, O << MO.getImm(); return; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_JumpTableIndex: O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_' @@ -158,7 +158,7 @@ void SystemZAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, printOffset(MO.getOffset()); break; case MachineOperand::MO_GlobalAddress: - O << *GetGlobalValueSymbol(MO.getGlobal()); + O << *Mang->getSymbol(MO.getGlobal()); break; case MachineOperand::MO_ExternalSymbol: { O << *GetExternalSymbolSymbol(MO.getSymbolName()); diff --git a/lib/Target/TargetLoweringObjectFile.cpp b/lib/Target/TargetLoweringObjectFile.cpp index 8c12039516b5..a093e2db8b2e 100644 --- a/lib/Target/TargetLoweringObjectFile.cpp +++ b/lib/Target/TargetLoweringObjectFile.cpp @@ -19,6 +19,7 @@ #include "llvm/GlobalVariable.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" @@ -290,45 +291,38 @@ TargetLoweringObjectFile::getSectionForConstant(SectionKind Kind) const { return DataSection; } -/// getSymbolForDwarfGlobalReference - Return an MCExpr to use for a +/// getExprForDwarfGlobalReference - Return an MCExpr to use for a /// reference to the specified global variable from exception /// handling information. const MCExpr *TargetLoweringObjectFile:: -getSymbolForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, - MachineModuleInfo *MMI, unsigned Encoding) const { - // FIXME: Use GetGlobalValueSymbol. - SmallString<128> Name; - Mang->getNameWithPrefix(Name, GV, false); - const MCSymbol *Sym; - - if (GV->hasPrivateLinkage()) - Sym = getContext().GetOrCreateTemporarySymbol(Name.str()); - else - Sym = getContext().GetOrCreateSymbol(Name.str()); - - return getSymbolForDwarfReference(Sym, MMI, Encoding); +getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const { + const MCSymbol *Sym = Mang->getSymbol(GV); + return getExprForDwarfReference(Sym, Mang, MMI, Encoding, Streamer); } const MCExpr *TargetLoweringObjectFile:: -getSymbolForDwarfReference(const MCSymbol *Sym, MachineModuleInfo *MMI, - unsigned Encoding) const { +getExprForDwarfReference(const MCSymbol *Sym, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const { const MCExpr *Res = MCSymbolRefExpr::Create(Sym, getContext()); switch (Encoding & 0xF0) { default: llvm_report_error("We do not support this DWARF encoding yet!"); - break; case dwarf::DW_EH_PE_absptr: // Do nothing special - break; - case dwarf::DW_EH_PE_pcrel: - // FIXME: PCSymbol - const MCExpr *PC = MCSymbolRefExpr::Create(".", getContext()); - Res = MCBinaryExpr::CreateSub(Res, PC, getContext()); - break; + return Res; + case dwarf::DW_EH_PE_pcrel: { + // Emit a label to the streamer for the current position. This gives us + // .-foo addressing. + MCSymbol *PCSym = getContext().GetOrCreateTemporarySymbol(); + Streamer.EmitLabel(PCSym); + const MCExpr *PC = MCSymbolRefExpr::Create(PCSym, getContext()); + return MCBinaryExpr::CreateSub(Res, PC, getContext()); + } } - - return Res; } unsigned TargetLoweringObjectFile::getPersonalityEncoding() const { diff --git a/lib/Target/X86/AsmParser/Makefile b/lib/Target/X86/AsmParser/Makefile index 25fb0a2836db..fb9760796622 100644 --- a/lib/Target/X86/AsmParser/Makefile +++ b/lib/Target/X86/AsmParser/Makefile @@ -10,6 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMX86AsmParser # Hack: we need to include 'main' x86 target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index 84d7bb7a6f3c..dde86fbbe440 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -542,6 +542,15 @@ ParseInstruction(const StringRef &Name, SMLoc NameLoc, } } + // FIXME: Hack to handle recognizing s{hr,ar,hl}? $1. + if ((Name.startswith("shr") || Name.startswith("sar") || + Name.startswith("shl")) && + Operands.size() == 3 && + static_cast<X86Operand*>(Operands[1])->isImm() && + isa<MCConstantExpr>(static_cast<X86Operand*>(Operands[1])->getImm()) && + cast<MCConstantExpr>(static_cast<X86Operand*>(Operands[1])->getImm())->getValue() == 1) + Operands.erase(Operands.begin() + 1); + return false; } diff --git a/lib/Target/X86/AsmPrinter/Makefile b/lib/Target/X86/AsmPrinter/Makefile index 2368761ac9f4..c82aa330a20c 100644 --- a/lib/Target/X86/AsmPrinter/Makefile +++ b/lib/Target/X86/AsmPrinter/Makefile @@ -10,6 +10,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMX86AsmPrinter # Hack: we need to include 'main' x86 target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp b/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp index caf84b67f940..c3dcf8e66eab 100644 --- a/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp +++ b/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp @@ -53,30 +53,6 @@ void X86AsmPrinter::PrintPICBaseSymbol() const { OutContext); } -MCSymbol *X86AsmPrinter::GetGlobalValueSymbol(const GlobalValue *GV) const { - SmallString<60> NameStr; - Mang->getNameWithPrefix(NameStr, GV, false); - MCSymbol *Symb; - if (GV->hasPrivateLinkage()) - Symb = OutContext.GetOrCreateTemporarySymbol(NameStr.str()); - else - Symb = OutContext.GetOrCreateSymbol(NameStr.str()); - - if (Subtarget->isTargetCygMing()) { - X86COFFMachineModuleInfo &COFFMMI = - MMI->getObjFileInfo<X86COFFMachineModuleInfo>(); - COFFMMI.DecorateCygMingName(Symb, OutContext, GV, *TM.getTargetData()); - - // Save function name for later type emission. - if (const Function *F = dyn_cast<Function>(GV)) - if (F->isDeclaration()) - COFFMMI.addExternalFunction(Symb->getName()); - - } - - return Symb; -} - /// runOnMachineFunction - Emit the function body. /// bool X86AsmPrinter::runOnMachineFunction(MachineFunction &MF) { @@ -124,7 +100,7 @@ void X86AsmPrinter::printSymbolOperand(const MachineOperand &MO) { MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE) GVSym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); else - GVSym = GetGlobalValueSymbol(GV); + GVSym = Mang->getSymbol(GV); // Handle dllimport linkage. if (MO.getTargetFlags() == X86II::MO_DLLIMPORT) @@ -133,24 +109,25 @@ void X86AsmPrinter::printSymbolOperand(const MachineOperand &MO) { if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE) { MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - - MCSymbol *&StubSym = + MachineModuleInfoImpl::StubValueTy &StubSym = MMI->getObjFileInfo<MachineModuleInfoMachO>().getGVStubEntry(Sym); - if (StubSym == 0) - StubSym = GetGlobalValueSymbol(GV); - + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); } else if (MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE){ MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - MCSymbol *&StubSym = + MachineModuleInfoImpl::StubValueTy &StubSym = MMI->getObjFileInfo<MachineModuleInfoMachO>().getHiddenGVStubEntry(Sym); - if (StubSym == 0) - StubSym = GetGlobalValueSymbol(GV); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); } else if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) { MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$stub"); - MCSymbol *&StubSym = + MachineModuleInfoImpl::StubValueTy &StubSym = MMI->getObjFileInfo<MachineModuleInfoMachO>().getFnStubEntry(Sym); - if (StubSym == 0) - StubSym = GetGlobalValueSymbol(GV); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); } // If the name begins with a dollar-sign, enclose it in parens. We do this @@ -170,13 +147,15 @@ void X86AsmPrinter::printSymbolOperand(const MachineOperand &MO) { TempNameStr += StringRef("$stub"); MCSymbol *Sym = GetExternalSymbolSymbol(TempNameStr.str()); - MCSymbol *&StubSym = + MachineModuleInfoImpl::StubValueTy &StubSym = MMI->getObjFileInfo<MachineModuleInfoMachO>().getFnStubEntry(Sym); - if (StubSym == 0) { + if (StubSym.getPointer() == 0) { TempNameStr.erase(TempNameStr.end()-5, TempNameStr.end()); - StubSym = OutContext.GetOrCreateSymbol(TempNameStr.str()); + StubSym = MachineModuleInfoImpl:: + StubValueTy(OutContext.GetOrCreateSymbol(TempNameStr.str()), + true); } - SymToPrint = StubSym; + SymToPrint = StubSym.getPointer(); } else { SymToPrint = GetExternalSymbolSymbol(MO.getSymbolName()); } @@ -235,7 +214,7 @@ void X86AsmPrinter::print_pcrel_imm(const MachineInstr *MI, unsigned OpNo) { O << MO.getImm(); return; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_ExternalSymbol: @@ -480,6 +459,11 @@ bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, return false; } +void X86AsmPrinter::EmitStartOfAsmFile(Module &M) { + if (Subtarget->isTargetDarwin()) + OutStreamer.SwitchSection(getObjFileLowering().getTextSection()); +} + void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { if (Subtarget->isTargetDarwin()) { @@ -507,7 +491,8 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { // L_foo$stub: OutStreamer.EmitLabel(Stubs[i].first); // .indirect_symbol _foo - OutStreamer.EmitSymbolAttribute(Stubs[i].second, MCSA_IndirectSymbol); + OutStreamer.EmitSymbolAttribute(Stubs[i].second.getPointer(), + MCSA_IndirectSymbol); // hlt; hlt; hlt; hlt; hlt hlt = 0xf4 = -12. const char HltInsts[] = { -12, -12, -12, -12, -12 }; OutStreamer.EmitBytes(StringRef(HltInsts, 5), 0/*addrspace*/); @@ -530,9 +515,18 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { // L_foo$non_lazy_ptr: OutStreamer.EmitLabel(Stubs[i].first); // .indirect_symbol _foo - OutStreamer.EmitSymbolAttribute(Stubs[i].second, MCSA_IndirectSymbol); + MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second; + OutStreamer.EmitSymbolAttribute(MCSym.getPointer(), + MCSA_IndirectSymbol); // .long 0 - OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); + if (MCSym.getInt()) + // External to current translation unit. + OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); + else + // Internal to current translation unit. + OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), + OutContext), + 4/*size*/, 0/*addrspace*/); } Stubs.clear(); OutStreamer.AddBlankLine(); @@ -547,8 +541,9 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { // L_foo$non_lazy_ptr: OutStreamer.EmitLabel(Stubs[i].first); // .long _foo - OutStreamer.EmitValue(MCSymbolRefExpr::Create(Stubs[i].second, - OutContext), + OutStreamer.EmitValue(MCSymbolRefExpr:: + Create(Stubs[i].second.getPointer(), + OutContext), 4/*size*/, 0/*addrspace*/); } Stubs.clear(); @@ -584,15 +579,13 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { static_cast<TargetLoweringObjectFileCOFF&>(getObjFileLowering()); for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) - if (I->hasDLLExportLinkage()) { - MCSymbol *Sym = GetGlobalValueSymbol(I); - DLLExportedFns.push_back(Sym); - } + if (I->hasDLLExportLinkage()) + DLLExportedFns.push_back(Mang->getSymbol(I)); for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) if (I->hasDLLExportLinkage()) - DLLExportedGlobals.push_back(GetGlobalValueSymbol(I)); + DLLExportedGlobals.push_back(Mang->getSymbol(I)); // Output linker support code for dllexported globals on windows. if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) { @@ -624,7 +617,7 @@ void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { O << *Stubs[i].first << ":\n" << (TD->getPointerSize() == 8 ? MAI->getData64bitsDirective() : MAI->getData32bitsDirective()) - << *Stubs[i].second << '\n'; + << *Stubs[i].second.getPointer() << '\n'; Stubs.clear(); } diff --git a/lib/Target/X86/AsmPrinter/X86AsmPrinter.h b/lib/Target/X86/AsmPrinter/X86AsmPrinter.h index 039214ac2930..28c25f9b8abe 100644 --- a/lib/Target/X86/AsmPrinter/X86AsmPrinter.h +++ b/lib/Target/X86/AsmPrinter/X86AsmPrinter.h @@ -36,9 +36,8 @@ class VISIBILITY_HIDDEN X86AsmPrinter : public AsmPrinter { const X86Subtarget *Subtarget; public: explicit X86AsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) - : AsmPrinter(O, TM, Ctx, Streamer, T) { + MCStreamer &Streamer) + : AsmPrinter(O, TM, Streamer) { Subtarget = &TM.getSubtarget<X86Subtarget>(); } @@ -55,13 +54,13 @@ class VISIBILITY_HIDDEN X86AsmPrinter : public AsmPrinter { AsmPrinter::getAnalysisUsage(AU); } - + virtual void EmitStartOfAsmFile(Module &M); + virtual void EmitEndOfAsmFile(Module &M); virtual void EmitInstruction(const MachineInstr *MI); void printSymbolOperand(const MachineOperand &MO); - virtual MCSymbol *GetGlobalValueSymbol(const GlobalValue *GV) const; // These methods are used by the tablegen'erated instruction printer. void printOperand(const MachineInstr *MI, unsigned OpNo, diff --git a/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp b/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp index b8a6eeb518aa..cbfc57a0ab74 100644 --- a/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp +++ b/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp @@ -16,13 +16,13 @@ #include "X86AsmPrinter.h" #include "X86COFFMachineModuleInfo.h" #include "X86MCAsmInfo.h" -#include "X86MCTargetExpr.h" #include "llvm/Analysis/DebugInfo.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Target/Mangler.h" #include "llvm/Support/FormattedStream.h" #include "llvm/ADT/SmallString.h" @@ -54,7 +54,12 @@ GetSymbolFromOperand(const MachineOperand &MO) const { SmallString<128> Name; - if (MO.isGlobal()) { + if (!MO.isGlobal()) { + assert(MO.isSymbol()); + Name += AsmPrinter.MAI->getGlobalPrefix(); + Name += MO.getSymbolName(); + } else { + const GlobalValue *GV = MO.getGlobal(); bool isImplicitlyPrivate = false; if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB || MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || @@ -62,18 +67,7 @@ GetSymbolFromOperand(const MachineOperand &MO) const { MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE) isImplicitlyPrivate = true; - const GlobalValue *GV = MO.getGlobal(); Mang->getNameWithPrefix(Name, GV, isImplicitlyPrivate); - - if (getSubtarget().isTargetCygMing()) { - X86COFFMachineModuleInfo &COFFMMI = - AsmPrinter.MMI->getObjFileInfo<X86COFFMachineModuleInfo>(); - COFFMMI.DecorateCygMingName(Name, GV, *AsmPrinter.TM.getTargetData()); - } - } else { - assert(MO.isSymbol()); - Name += AsmPrinter.MAI->getGlobalPrefix(); - Name += MO.getSymbolName(); } // If the target flags on the operand changes the name of the symbol, do that @@ -91,35 +85,49 @@ GetSymbolFromOperand(const MachineOperand &MO) const { Name += "$non_lazy_ptr"; MCSymbol *Sym = Ctx.GetOrCreateTemporarySymbol(Name.str()); - MCSymbol *&StubSym = getMachOMMI().getGVStubEntry(Sym); - if (StubSym == 0) { + MachineModuleInfoImpl::StubValueTy &StubSym = + getMachOMMI().getGVStubEntry(Sym); + if (StubSym.getPointer() == 0) { assert(MO.isGlobal() && "Extern symbol not handled yet"); - StubSym = AsmPrinter.GetGlobalValueSymbol(MO.getGlobal()); + StubSym = + MachineModuleInfoImpl:: + StubValueTy(AsmPrinter.Mang->getSymbol(MO.getGlobal()), + !MO.getGlobal()->hasInternalLinkage()); } return Sym; } case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: { Name += "$non_lazy_ptr"; MCSymbol *Sym = Ctx.GetOrCreateTemporarySymbol(Name.str()); - MCSymbol *&StubSym = getMachOMMI().getHiddenGVStubEntry(Sym); - if (StubSym == 0) { + MachineModuleInfoImpl::StubValueTy &StubSym = + getMachOMMI().getHiddenGVStubEntry(Sym); + if (StubSym.getPointer() == 0) { assert(MO.isGlobal() && "Extern symbol not handled yet"); - StubSym = AsmPrinter.GetGlobalValueSymbol(MO.getGlobal()); + StubSym = + MachineModuleInfoImpl:: + StubValueTy(AsmPrinter.Mang->getSymbol(MO.getGlobal()), + !MO.getGlobal()->hasInternalLinkage()); } return Sym; } case X86II::MO_DARWIN_STUB: { Name += "$stub"; MCSymbol *Sym = Ctx.GetOrCreateTemporarySymbol(Name.str()); - MCSymbol *&StubSym = getMachOMMI().getFnStubEntry(Sym); - if (StubSym) + MachineModuleInfoImpl::StubValueTy &StubSym = + getMachOMMI().getFnStubEntry(Sym); + if (StubSym.getPointer()) return Sym; if (MO.isGlobal()) { - StubSym = AsmPrinter.GetGlobalValueSymbol(MO.getGlobal()); + StubSym = + MachineModuleInfoImpl:: + StubValueTy(AsmPrinter.Mang->getSymbol(MO.getGlobal()), + !MO.getGlobal()->hasInternalLinkage()); } else { Name.erase(Name.end()-5, Name.end()); - StubSym = Ctx.GetOrCreateTemporarySymbol(Name.str()); + StubSym = + MachineModuleInfoImpl:: + StubValueTy(Ctx.GetOrCreateTemporarySymbol(Name.str()), false); } return Sym; } @@ -133,7 +141,7 @@ MCOperand X86MCInstLower::LowerSymbolOperand(const MachineOperand &MO, // FIXME: We would like an efficient form for this, so we don't have to do a // lot of extra uniquing. const MCExpr *Expr = 0; - X86MCTargetExpr::VariantKind RefKind = X86MCTargetExpr::Invalid; + MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None; switch (MO.getTargetFlags()) { default: llvm_unreachable("Unknown target flag on GV operand"); @@ -144,15 +152,15 @@ MCOperand X86MCInstLower::LowerSymbolOperand(const MachineOperand &MO, case X86II::MO_DARWIN_STUB: break; - case X86II::MO_TLSGD: RefKind = X86MCTargetExpr::TLSGD; break; - case X86II::MO_GOTTPOFF: RefKind = X86MCTargetExpr::GOTTPOFF; break; - case X86II::MO_INDNTPOFF: RefKind = X86MCTargetExpr::INDNTPOFF; break; - case X86II::MO_TPOFF: RefKind = X86MCTargetExpr::TPOFF; break; - case X86II::MO_NTPOFF: RefKind = X86MCTargetExpr::NTPOFF; break; - case X86II::MO_GOTPCREL: RefKind = X86MCTargetExpr::GOTPCREL; break; - case X86II::MO_GOT: RefKind = X86MCTargetExpr::GOT; break; - case X86II::MO_GOTOFF: RefKind = X86MCTargetExpr::GOTOFF; break; - case X86II::MO_PLT: RefKind = X86MCTargetExpr::PLT; break; + case X86II::MO_TLSGD: RefKind = MCSymbolRefExpr::VK_TLSGD; break; + case X86II::MO_GOTTPOFF: RefKind = MCSymbolRefExpr::VK_GOTTPOFF; break; + case X86II::MO_INDNTPOFF: RefKind = MCSymbolRefExpr::VK_INDNTPOFF; break; + case X86II::MO_TPOFF: RefKind = MCSymbolRefExpr::VK_TPOFF; break; + case X86II::MO_NTPOFF: RefKind = MCSymbolRefExpr::VK_NTPOFF; break; + case X86II::MO_GOTPCREL: RefKind = MCSymbolRefExpr::VK_GOTPCREL; break; + case X86II::MO_GOT: RefKind = MCSymbolRefExpr::VK_GOT; break; + case X86II::MO_GOTOFF: RefKind = MCSymbolRefExpr::VK_GOTOFF; break; + case X86II::MO_PLT: RefKind = MCSymbolRefExpr::VK_PLT; break; case X86II::MO_PIC_BASE_OFFSET: case X86II::MO_DARWIN_NONLAZY_PIC_BASE: case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: @@ -164,12 +172,8 @@ MCOperand X86MCInstLower::LowerSymbolOperand(const MachineOperand &MO, break; } - if (Expr == 0) { - if (RefKind == X86MCTargetExpr::Invalid) - Expr = MCSymbolRefExpr::Create(Sym, Ctx); - else - Expr = X86MCTargetExpr::Create(Sym, RefKind, Ctx); - } + if (Expr == 0) + Expr = MCSymbolRefExpr::Create(Sym, RefKind, Ctx); if (!MO.isJTI() && MO.getOffset()) Expr = MCBinaryExpr::CreateAdd(Expr, @@ -233,7 +237,7 @@ void X86MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { break; case MachineOperand::MO_MachineBasicBlock: MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( - MO.getMBB()->getSymbol(Ctx), Ctx)); + MO.getMBB()->getSymbol(), Ctx)); break; case MachineOperand::MO_GlobalAddress: MCOp = LowerSymbolOperand(MO, GetSymbolFromOperand(MO)); @@ -294,6 +298,29 @@ void X86MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { LowerSubReg32_Op0(OutMI, X86::MOV32r0); // MOV64r0 -> MOV32r0 LowerUnaryToTwoAddr(OutMI, X86::XOR32rr); // MOV32r0 -> XOR32rr break; + + + // The assembler backend wants to see branches in their small form and relax + // them to their large form. The JIT can only handle the large form because + // it does not do relaxation. For now, translate the large form to the + // small one here. + case X86::JMP_4: OutMI.setOpcode(X86::JMP_1); break; + case X86::JO_4: OutMI.setOpcode(X86::JO_1); break; + case X86::JNO_4: OutMI.setOpcode(X86::JNO_1); break; + case X86::JB_4: OutMI.setOpcode(X86::JB_1); break; + case X86::JAE_4: OutMI.setOpcode(X86::JAE_1); break; + case X86::JE_4: OutMI.setOpcode(X86::JE_1); break; + case X86::JNE_4: OutMI.setOpcode(X86::JNE_1); break; + case X86::JBE_4: OutMI.setOpcode(X86::JBE_1); break; + case X86::JA_4: OutMI.setOpcode(X86::JA_1); break; + case X86::JS_4: OutMI.setOpcode(X86::JS_1); break; + case X86::JNS_4: OutMI.setOpcode(X86::JNS_1); break; + case X86::JP_4: OutMI.setOpcode(X86::JP_1); break; + case X86::JNP_4: OutMI.setOpcode(X86::JNP_1); break; + case X86::JL_4: OutMI.setOpcode(X86::JL_1); break; + case X86::JGE_4: OutMI.setOpcode(X86::JGE_1); break; + case X86::JLE_4: OutMI.setOpcode(X86::JLE_1); break; + case X86::JG_4: OutMI.setOpcode(X86::JG_1); break; } } @@ -344,6 +371,13 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) { } else printOperand(MI, 0); } else { + if (MI->getOperand(0).getType()==MachineOperand::MO_Register && + MI->getOperand(0).getReg()==0) { + // Suppress offset in this case, it is not meaningful. + O << "undef"; + OutStreamer.AddBlankLine(); + return; + } // Frame address. Currently handles register +- offset only. assert(MI->getOperand(0).getType()==MachineOperand::MO_Register); assert(MI->getOperand(3).getType()==MachineOperand::MO_Immediate); @@ -392,11 +426,8 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) { // For this, we want to print something like: // MYGLOBAL + (. - PICBASE) // However, we can't generate a ".", so just emit a new label here and refer - // to it. We know that this operand flag occurs at most once per function. - const char *Prefix = MAI->getPrivateGlobalPrefix(); - MCSymbol *DotSym = OutContext.GetOrCreateTemporarySymbol(Twine(Prefix)+ - "picbaseref" + - Twine(getFunctionNumber())); + // to it. + MCSymbol *DotSym = OutContext.GetOrCreateTemporarySymbol(); OutStreamer.EmitLabel(DotSym); // Now that we have emitted the label, lower the complex operand expression. diff --git a/lib/Target/X86/CMakeLists.txt b/lib/Target/X86/CMakeLists.txt index eed3b45d7438..4d3dedf0e5f1 100644 --- a/lib/Target/X86/CMakeLists.txt +++ b/lib/Target/X86/CMakeLists.txt @@ -27,7 +27,6 @@ set(sources X86JITInfo.cpp X86MCAsmInfo.cpp X86MCCodeEmitter.cpp - X86MCTargetExpr.cpp X86RegisterInfo.cpp X86Subtarget.cpp X86TargetMachine.cpp diff --git a/lib/Target/X86/Disassembler/Makefile b/lib/Target/X86/Disassembler/Makefile index b2896477df48..8669fd8fd930 100644 --- a/lib/Target/X86/Disassembler/Makefile +++ b/lib/Target/X86/Disassembler/Makefile @@ -11,6 +11,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMX86Disassembler # Hack: we need to include 'main' x86 target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/X86/TargetInfo/Makefile b/lib/Target/X86/TargetInfo/Makefile index 9858e6a099a2..ee91982df0c8 100644 --- a/lib/Target/X86/TargetInfo/Makefile +++ b/lib/Target/X86/TargetInfo/Makefile @@ -11,6 +11,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMX86Info # Hack: we need to include 'main' target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/X86/X86.h b/lib/Target/X86/X86.h index ba0ee6cedd71..c753cf2a530f 100644 --- a/lib/Target/X86/X86.h +++ b/lib/Target/X86/X86.h @@ -21,7 +21,6 @@ namespace llvm { class FunctionPass; class JITCodeEmitter; -class MCAssembler; class MCCodeEmitter; class MCContext; class MachineCodeEmitter; @@ -57,8 +56,8 @@ MCCodeEmitter *createX86_32MCCodeEmitter(const Target &, TargetMachine &TM, MCCodeEmitter *createX86_64MCCodeEmitter(const Target &, TargetMachine &TM, MCContext &Ctx); -TargetAsmBackend *createX86_32AsmBackend(const Target &, MCAssembler &); -TargetAsmBackend *createX86_64AsmBackend(const Target &, MCAssembler &); +TargetAsmBackend *createX86_32AsmBackend(const Target &, const std::string &); +TargetAsmBackend *createX86_64AsmBackend(const Target &, const std::string &); /// createX86EmitCodeToMemory - Returns a pass that converts a register /// allocated function into raw machine code in a dynamically diff --git a/lib/Target/X86/X86.td b/lib/Target/X86/X86.td index 7919559058b1..6a4bdb58603b 100644 --- a/lib/Target/X86/X86.td +++ b/lib/Target/X86/X86.td @@ -55,7 +55,8 @@ def Feature3DNowA : SubtargetFeature<"3dnowa", "X863DNowLevel", "ThreeDNowA", // feature, because SSE2 can be disabled (e.g. for compiling OS kernels) // without disabling 64-bit mode. def Feature64Bit : SubtargetFeature<"64bit", "HasX86_64", "true", - "Support 64-bit instructions">; + "Support 64-bit instructions", + [FeatureCMOV]>; def FeatureSlowBTMem : SubtargetFeature<"slow-bt-mem", "IsBTMemSlow", "true", "Bit testing of memory is slow">; def FeatureSSE4A : SubtargetFeature<"sse4a", "HasSSE4A", "true", diff --git a/lib/Target/X86/X86AsmBackend.cpp b/lib/Target/X86/X86AsmBackend.cpp index e6654efbbb48..a44afc6984d3 100644 --- a/lib/Target/X86/X86AsmBackend.cpp +++ b/lib/Target/X86/X86AsmBackend.cpp @@ -9,6 +9,7 @@ #include "llvm/Target/TargetAsmBackend.h" #include "X86.h" +#include "llvm/MC/MCSectionMachO.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetAsmBackend.h" using namespace llvm; @@ -17,18 +18,63 @@ namespace { class X86AsmBackend : public TargetAsmBackend { public: - X86AsmBackend(const Target &T, MCAssembler &A) + X86AsmBackend(const Target &T) : TargetAsmBackend(T) {} }; +class DarwinX86AsmBackend : public X86AsmBackend { +public: + DarwinX86AsmBackend(const Target &T) + : X86AsmBackend(T) {} + + virtual bool hasAbsolutizedSet() const { return true; } + + virtual bool hasScatteredSymbols() const { return true; } +}; + +class DarwinX86_32AsmBackend : public DarwinX86AsmBackend { +public: + DarwinX86_32AsmBackend(const Target &T) + : DarwinX86AsmBackend(T) {} +}; + +class DarwinX86_64AsmBackend : public DarwinX86AsmBackend { +public: + DarwinX86_64AsmBackend(const Target &T) + : DarwinX86AsmBackend(T) {} + + virtual bool doesSectionRequireSymbols(const MCSection &Section) const { + // Temporary labels in the string literals sections require symbols. The + // issue is that the x86_64 relocation format does not allow symbol + + // offset, and so the linker does not have enough information to resolve the + // access to the appropriate atom unless an external relocation is used. For + // non-cstring sections, we expect the compiler to use a non-temporary label + // for anything that could have an addend pointing outside the symbol. + // + // See <rdar://problem/4765733>. + const MCSectionMachO &SMO = static_cast<const MCSectionMachO&>(Section); + return SMO.getType() == MCSectionMachO::S_CSTRING_LITERALS; + } +}; + } TargetAsmBackend *llvm::createX86_32AsmBackend(const Target &T, - MCAssembler &A) { - return new X86AsmBackend(T, A); + const std::string &TT) { + switch (Triple(TT).getOS()) { + case Triple::Darwin: + return new DarwinX86_32AsmBackend(T); + default: + return new X86AsmBackend(T); + } } TargetAsmBackend *llvm::createX86_64AsmBackend(const Target &T, - MCAssembler &A) { - return new X86AsmBackend(T, A); + const std::string &TT) { + switch (Triple(TT).getOS()) { + case Triple::Darwin: + return new DarwinX86_64AsmBackend(T); + default: + return new X86AsmBackend(T); + } } diff --git a/lib/Target/X86/X86COFFMachineModuleInfo.cpp b/lib/Target/X86/X86COFFMachineModuleInfo.cpp index ab67acbadb52..4326814a7a96 100644 --- a/lib/Target/X86/X86COFFMachineModuleInfo.cpp +++ b/lib/Target/X86/X86COFFMachineModuleInfo.cpp @@ -12,80 +12,9 @@ //===----------------------------------------------------------------------===// #include "X86COFFMachineModuleInfo.h" -#include "X86MachineFunctionInfo.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/Target/TargetData.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/raw_ostream.h" using namespace llvm; -X86COFFMachineModuleInfo::X86COFFMachineModuleInfo(const MachineModuleInfo &) { -} -X86COFFMachineModuleInfo::~X86COFFMachineModuleInfo() { -} - -void X86COFFMachineModuleInfo::addExternalFunction(const StringRef& Name) { - CygMingStubs.insert(Name); -} - -/// DecorateCygMingName - Apply various name decorations if the function uses -/// stdcall or fastcall calling convention. -void X86COFFMachineModuleInfo::DecorateCygMingName(SmallVectorImpl<char> &Name, - const GlobalValue *GV, - const TargetData &TD) { - const Function *F = dyn_cast<Function>(GV); - if (!F) return; - - // We don't want to decorate non-stdcall or non-fastcall functions right now - CallingConv::ID CC = F->getCallingConv(); - if (CC != CallingConv::X86_StdCall && CC != CallingConv::X86_FastCall) - return; - - unsigned ArgWords = 0; - DenseMap<const Function*, unsigned>::const_iterator item = FnArgWords.find(F); - if (item == FnArgWords.end()) { - // Calculate arguments sizes - for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end(); - AI != AE; ++AI) { - const Type* Ty = AI->getType(); - // 'Dereference' type in case of byval parameter attribute - if (AI->hasByValAttr()) - Ty = cast<PointerType>(Ty)->getElementType(); - - // Size should be aligned to DWORD boundary - ArgWords += ((TD.getTypeAllocSize(Ty) + 3)/4)*4; - } - - FnArgWords[F] = ArgWords; - } else - ArgWords = item->second; - - const FunctionType *FT = F->getFunctionType(); - // "Pure" variadic functions do not receive @0 suffix. - if (!FT->isVarArg() || FT->getNumParams() == 0 || - (FT->getNumParams() == 1 && F->hasStructRetAttr())) - raw_svector_ostream(Name) << '@' << ArgWords; - - if (CC == CallingConv::X86_FastCall) { - if (Name[0] == '_') - Name[0] = '@'; - else - Name.insert(Name.begin(), '@'); - } +X86COFFMachineModuleInfo::~X86COFFMachineModuleInfo() { } -/// DecorateCygMingName - Query FunctionInfoMap and use this information for -/// various name decorations for Cygwin and MingW. -void X86COFFMachineModuleInfo::DecorateCygMingName(MCSymbol *&Name, - MCContext &Ctx, - const GlobalValue *GV, - const TargetData &TD) { - SmallString<128> NameStr(Name->getName().begin(), Name->getName().end()); - DecorateCygMingName(NameStr, GV, TD); - - Name = Ctx.GetOrCreateSymbol(NameStr.str()); -} diff --git a/lib/Target/X86/X86COFFMachineModuleInfo.h b/lib/Target/X86/X86COFFMachineModuleInfo.h index 9de3dcd63495..eece462eac5a 100644 --- a/lib/Target/X86/X86COFFMachineModuleInfo.h +++ b/lib/Target/X86/X86COFFMachineModuleInfo.h @@ -26,17 +26,14 @@ namespace llvm { /// for X86 COFF targets. class X86COFFMachineModuleInfo : public MachineModuleInfoImpl { StringSet<> CygMingStubs; - DenseMap<const Function*, unsigned> FnArgWords; public: - X86COFFMachineModuleInfo(const MachineModuleInfo &); - ~X86COFFMachineModuleInfo(); + X86COFFMachineModuleInfo(const MachineModuleInfo &) {} + virtual ~X86COFFMachineModuleInfo(); - void DecorateCygMingName(MCSymbol* &Name, MCContext &Ctx, - const GlobalValue *GV, const TargetData &TD); - void DecorateCygMingName(SmallVectorImpl<char> &Name, const GlobalValue *GV, - const TargetData &TD); - - void addExternalFunction(const StringRef& Name); + void addExternalFunction(StringRef Name) { + CygMingStubs.insert(Name); + } + typedef StringSet<>::const_iterator stub_iterator; stub_iterator stub_begin() const { return CygMingStubs.begin(); } stub_iterator stub_end() const { return CygMingStubs.end(); } diff --git a/lib/Target/X86/X86CallingConv.td b/lib/Target/X86/X86CallingConv.td index 12d3d04eb6bd..fd15efd6262a 100644 --- a/lib/Target/X86/X86CallingConv.td +++ b/lib/Target/X86/X86CallingConv.td @@ -221,6 +221,20 @@ def CC_X86_Win64_C : CallingConv<[ CCIfType<[v8i8, v4i16, v2i32, v1i64], CCAssignToStack<8, 8>> ]>; +def CC_X86_64_GHC : CallingConv<[ + // Promote i8/i16/i32 arguments to i64. + CCIfType<[i8, i16, i32], CCPromoteToType<i64>>, + + // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, R6, SpLim + CCIfType<[i64], + CCAssignToReg<[R13, RBP, R12, RBX, R14, RSI, RDI, R8, R9, R15]>>, + + // Pass in STG registers: F1, F2, F3, F4, D1, D2 + CCIfType<[f32, f64, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], + CCIfSubtarget<"hasSSE1()", + CCAssignToReg<[XMM1, XMM2, XMM3, XMM4, XMM5, XMM6]>>> +]>; + //===----------------------------------------------------------------------===// // X86 C Calling Convention //===----------------------------------------------------------------------===// @@ -320,3 +334,11 @@ def CC_X86_32_FastCC : CallingConv<[ // Otherwise, same as everything else. CCDelegateTo<CC_X86_32_Common> ]>; + +def CC_X86_32_GHC : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, + + // Pass in STG registers: Base, Sp, Hp, R1 + CCIfType<[i32], CCAssignToReg<[EBX, EBP, EDI, ESI]>> +]>; diff --git a/lib/Target/X86/X86CodeEmitter.cpp b/lib/Target/X86/X86CodeEmitter.cpp index 8deadf628c07..6638e110f4f4 100644 --- a/lib/Target/X86/X86CodeEmitter.cpp +++ b/lib/Target/X86/X86CodeEmitter.cpp @@ -46,6 +46,7 @@ namespace { const TargetData *TD; X86TargetMachine &TM; CodeEmitter &MCE; + MachineModuleInfo *MMI; intptr_t PICBaseOffset; bool Is64BitMode; bool IsPIC; @@ -115,8 +116,8 @@ FunctionPass *llvm::createX86JITCodeEmitterPass(X86TargetMachine &TM, template<class CodeEmitter> bool Emitter<CodeEmitter>::runOnMachineFunction(MachineFunction &MF) { - - MCE.setModuleInfo(&getAnalysis<MachineModuleInfo>()); + MMI = &getAnalysis<MachineModuleInfo>(); + MCE.setModuleInfo(MMI); II = TM.getInstrInfo(); TD = TM.getTargetData(); @@ -602,10 +603,11 @@ void Emitter<CodeEmitter>::emitInstruction(const MachineInstr &MI, llvm_report_error("JIT does not support inline asm!"); break; case TargetOpcode::DBG_LABEL: - case TargetOpcode::EH_LABEL: case TargetOpcode::GC_LABEL: - MCE.emitLabel(MI.getOperand(0).getImm()); + case TargetOpcode::EH_LABEL: + MCE.emitLabel(MI.getOperand(0).getMCSymbol()); break; + case TargetOpcode::IMPLICIT_DEF: case TargetOpcode::KILL: case X86::FP_REG_KILL: diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index 98e3f4efe588..96b652d39e0d 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -172,7 +172,9 @@ bool X86FastISel::isTypeLegal(const Type *Ty, EVT &VT, bool AllowI1) { CCAssignFn *X86FastISel::CCAssignFnForCall(CallingConv::ID CC, bool isTaillCall) { if (Subtarget->is64Bit()) { - if (Subtarget->isTargetWin64()) + if (CC == CallingConv::GHC) + return CC_X86_64_GHC; + else if (Subtarget->isTargetWin64()) return CC_X86_Win64_C; else return CC_X86_64_C; @@ -182,6 +184,8 @@ CCAssignFn *X86FastISel::CCAssignFnForCall(CallingConv::ID CC, return CC_X86_32_FastCall; else if (CC == CallingConv::Fast) return CC_X86_32_FastCC; + else if (CC == CallingConv::GHC) + return CC_X86_32_GHC; else return CC_X86_32_C; } @@ -1162,6 +1166,30 @@ bool X86FastISel::X86VisitIntrinsicCall(IntrinsicInst &I) { // FIXME: Handle more intrinsics. switch (I.getIntrinsicID()) { default: return false; + case Intrinsic::objectsize: { + ConstantInt *CI = dyn_cast<ConstantInt>(I.getOperand(2)); + const Type *Ty = I.getCalledFunction()->getReturnType(); + + assert(CI && "Non-constant type in Intrinsic::objectsize?"); + + EVT VT; + if (!isTypeLegal(Ty, VT)) + return false; + + unsigned OpC = 0; + if (VT == MVT::i32) + OpC = X86::MOV32ri; + else if (VT == MVT::i64) + OpC = X86::MOV64ri; + else + return false; + + unsigned ResultReg = createResultReg(TLI.getRegClassFor(VT)); + BuildMI(MBB, DL, TII.get(OpC), ResultReg). + addImm(CI->getZExtValue() == 0 ? -1ULL : 0); + UpdateValueMap(&I, ResultReg); + return true; + } case Intrinsic::dbg_declare: { DbgDeclareInst *DI = cast<DbgDeclareInst>(&I); X86AddressMode AM; diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp index 3fad8ade41ba..405888565251 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -349,17 +349,17 @@ X86DAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const { return true; } -/// MoveBelowCallSeqStart - Replace CALLSEQ_START operand with load's chain -/// operand and move load below the call's chain operand. -static void MoveBelowCallSeqStart(SelectionDAG *CurDAG, SDValue Load, - SDValue Call, SDValue CallSeqStart) { +/// MoveBelowCallOrigChain - Replace the original chain operand of the call with +/// load's chain operand and move load below the call's chain operand. +static void MoveBelowOrigChain(SelectionDAG *CurDAG, SDValue Load, + SDValue Call, SDValue OrigChain) { SmallVector<SDValue, 8> Ops; - SDValue Chain = CallSeqStart.getOperand(0); + SDValue Chain = OrigChain.getOperand(0); if (Chain.getNode() == Load.getNode()) Ops.push_back(Load.getOperand(0)); else { assert(Chain.getOpcode() == ISD::TokenFactor && - "Unexpected CallSeqStart chain operand"); + "Unexpected chain operand"); for (unsigned i = 0, e = Chain.getNumOperands(); i != e; ++i) if (Chain.getOperand(i).getNode() == Load.getNode()) Ops.push_back(Load.getOperand(0)); @@ -371,9 +371,9 @@ static void MoveBelowCallSeqStart(SelectionDAG *CurDAG, SDValue Load, Ops.clear(); Ops.push_back(NewChain); } - for (unsigned i = 1, e = CallSeqStart.getNumOperands(); i != e; ++i) - Ops.push_back(CallSeqStart.getOperand(i)); - CurDAG->UpdateNodeOperands(CallSeqStart, &Ops[0], Ops.size()); + for (unsigned i = 1, e = OrigChain.getNumOperands(); i != e; ++i) + Ops.push_back(OrigChain.getOperand(i)); + CurDAG->UpdateNodeOperands(OrigChain, &Ops[0], Ops.size()); CurDAG->UpdateNodeOperands(Load, Call.getOperand(0), Load.getOperand(1), Load.getOperand(2)); Ops.clear(); @@ -386,7 +386,9 @@ static void MoveBelowCallSeqStart(SelectionDAG *CurDAG, SDValue Load, /// isCalleeLoad - Return true if call address is a load and it can be /// moved below CALLSEQ_START and the chains leading up to the call. /// Return the CALLSEQ_START by reference as a second output. -static bool isCalleeLoad(SDValue Callee, SDValue &Chain) { +/// In the case of a tail call, there isn't a callseq node between the call +/// chain and the load. +static bool isCalleeLoad(SDValue Callee, SDValue &Chain, bool HasCallSeq) { if (Callee.getNode() == Chain.getNode() || !Callee.hasOneUse()) return false; LoadSDNode *LD = dyn_cast<LoadSDNode>(Callee.getNode()); @@ -397,12 +399,14 @@ static bool isCalleeLoad(SDValue Callee, SDValue &Chain) { return false; // Now let's find the callseq_start. - while (Chain.getOpcode() != ISD::CALLSEQ_START) { + while (HasCallSeq && Chain.getOpcode() != ISD::CALLSEQ_START) { if (!Chain.hasOneUse()) return false; Chain = Chain.getOperand(0); } - + + if (!Chain.getNumOperands()) + return false; if (Chain.getOperand(0).getNode() == Callee.getNode()) return true; if (Chain.getOperand(0).getOpcode() == ISD::TokenFactor && @@ -420,7 +424,9 @@ void X86DAGToDAGISel::PreprocessISelDAG() { E = CurDAG->allnodes_end(); I != E; ) { SDNode *N = I++; // Preincrement iterator to avoid invalidation issues. - if (OptLevel != CodeGenOpt::None && N->getOpcode() == X86ISD::CALL) { + if (OptLevel != CodeGenOpt::None && + (N->getOpcode() == X86ISD::CALL || + N->getOpcode() == X86ISD::TC_RETURN)) { /// Also try moving call address load from outside callseq_start to just /// before the call to allow it to be folded. /// @@ -440,11 +446,12 @@ void X86DAGToDAGISel::PreprocessISelDAG() { /// \ / /// \ / /// [CALL] + bool HasCallSeq = N->getOpcode() == X86ISD::CALL; SDValue Chain = N->getOperand(0); SDValue Load = N->getOperand(1); - if (!isCalleeLoad(Load, Chain)) + if (!isCalleeLoad(Load, Chain, HasCallSeq)) continue; - MoveBelowCallSeqStart(CurDAG, Load, SDValue(N, 0), Chain); + MoveBelowOrigChain(CurDAG, Load, SDValue(N, 0), Chain); ++NumLoadMoved; continue; } diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 0cfcbb6f86e2..7d2140bf4d9d 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -16,7 +16,6 @@ #include "X86.h" #include "X86InstrBuilder.h" #include "X86ISelLowering.h" -#include "X86MCTargetExpr.h" #include "X86TargetMachine.h" #include "X86TargetObjectFile.h" #include "llvm/CallingConv.h" @@ -37,6 +36,7 @@ #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSymbol.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallSet.h" @@ -45,10 +45,12 @@ #include "llvm/ADT/VectorExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; +using namespace dwarf; STATISTIC(NumTailCalls, "Number of tail calls"); @@ -988,6 +990,7 @@ X86TargetLowering::X86TargetLowering(X86TargetMachine &TM) // We have target-specific dag combine patterns for the following nodes: setTargetDAGCombine(ISD::VECTOR_SHUFFLE); + setTargetDAGCombine(ISD::EXTRACT_VECTOR_ELT); setTargetDAGCombine(ISD::BUILD_VECTOR); setTargetDAGCombine(ISD::SELECT); setTargetDAGCombine(ISD::SHL); @@ -1118,8 +1121,8 @@ X86TargetLowering::LowerCustomJumpTableEntry(const MachineJumpTableInfo *MJTI, Subtarget->isPICStyleGOT()); // In 32-bit ELF systems, our jump table entries are formed with @GOTOFF // entries. - return X86MCTargetExpr::Create(MBB->getSymbol(Ctx), - X86MCTargetExpr::GOTOFF, Ctx); + return MCSymbolRefExpr::Create(MBB->getSymbol(), + MCSymbolRefExpr::VK_GOTOFF, Ctx); } /// getPICJumpTableRelocaBase - Returns relocation base for the given PIC @@ -1378,6 +1381,8 @@ bool X86TargetLowering::IsCalleePop(bool IsVarArg, CallingConv::ID CallingConv){ return !Subtarget->is64Bit(); case CallingConv::Fast: return GuaranteedTailCallOpt; + case CallingConv::GHC: + return GuaranteedTailCallOpt; } } @@ -1385,7 +1390,9 @@ bool X86TargetLowering::IsCalleePop(bool IsVarArg, CallingConv::ID CallingConv){ /// given CallingConvention value. CCAssignFn *X86TargetLowering::CCAssignFnForNode(CallingConv::ID CC) const { if (Subtarget->is64Bit()) { - if (Subtarget->isTargetWin64()) + if (CC == CallingConv::GHC) + return CC_X86_64_GHC; + else if (Subtarget->isTargetWin64()) return CC_X86_Win64_C; else return CC_X86_64_C; @@ -1395,6 +1402,8 @@ CCAssignFn *X86TargetLowering::CCAssignFnForNode(CallingConv::ID CC) const { return CC_X86_32_FastCall; else if (CC == CallingConv::Fast) return CC_X86_32_FastCC; + else if (CC == CallingConv::GHC) + return CC_X86_32_GHC; else return CC_X86_32_C; } @@ -1412,10 +1421,16 @@ CreateCopyOfByValArgument(SDValue Src, SDValue Dst, SDValue Chain, /*AlwaysInline=*/true, NULL, 0, NULL, 0); } +/// IsTailCallConvention - Return true if the calling convention is one that +/// supports tail call optimization. +static bool IsTailCallConvention(CallingConv::ID CC) { + return (CC == CallingConv::Fast || CC == CallingConv::GHC); +} + /// FuncIsMadeTailCallSafe - Return true if the function is being made into /// a tailcall target by changing its ABI. static bool FuncIsMadeTailCallSafe(CallingConv::ID CC) { - return GuaranteedTailCallOpt && CC == CallingConv::Fast; + return GuaranteedTailCallOpt && IsTailCallConvention(CC); } SDValue @@ -1465,7 +1480,6 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) { - MachineFunction &MF = DAG.getMachineFunction(); X86MachineFunctionInfo *FuncInfo = MF.getInfo<X86MachineFunctionInfo>(); @@ -1479,8 +1493,8 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain, bool Is64Bit = Subtarget->is64Bit(); bool IsWin64 = Subtarget->isTargetWin64(); - assert(!(isVarArg && CallConv == CallingConv::Fast) && - "Var args not supported with calling convention fastcc"); + assert(!(isVarArg && IsTailCallConvention(CallConv)) && + "Var args not supported with calling convention fastcc or ghc"); // Assign locations to all of the incoming arguments. SmallVector<CCValAssign, 16> ArgLocs; @@ -1683,7 +1697,7 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain, } else { BytesToPopOnReturn = 0; // Callee pops nothing. // If this is an sret function, the return should pop the hidden pointer. - if (!Is64Bit && CallConv != CallingConv::Fast && ArgsAreStructReturn(Ins)) + if (!Is64Bit && !IsTailCallConvention(CallConv) && ArgsAreStructReturn(Ins)) BytesToPopOnReturn = 4; } @@ -1767,7 +1781,8 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee, if (isTailCall) { // Check if it's really possible to do a tail call. - isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, isVarArg, + isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, + isVarArg, IsStructRet, MF.getFunction()->hasStructRetAttr(), Outs, Ins, DAG); // Sibcalls are automatically detected tailcalls which do not require @@ -1779,8 +1794,8 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee, ++NumTailCalls; } - assert(!(isVarArg && CallConv == CallingConv::Fast) && - "Var args not supported with calling convention fastcc"); + assert(!(isVarArg && IsTailCallConvention(CallConv)) && + "Var args not supported with calling convention fastcc or ghc"); // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; @@ -1794,7 +1809,7 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee, // This is a sibcall. The memory operands are available in caller's // own caller's stack. NumBytes = 0; - else if (GuaranteedTailCallOpt && CallConv == CallingConv::Fast) + else if (GuaranteedTailCallOpt && IsTailCallConvention(CallConv)) NumBytes = GetAlignedArgumentStackSize(NumBytes, DAG); int FPDiff = 0; @@ -2074,18 +2089,6 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee, OpFlags); } - if (isTailCall && !WasGlobalOrExternal) { - // Force the address into a (call preserved) caller-saved register since - // tailcall must happen after callee-saved registers are poped. - // FIXME: Give it a special register class that contains caller-saved - // register instead? - unsigned TCReg = Is64Bit ? X86::R11 : X86::EAX; - Chain = DAG.getCopyToReg(Chain, dl, - DAG.getRegister(TCReg, getPointerTy()), - Callee,InFlag); - Callee = DAG.getRegister(TCReg, getPointerTy()); - } - // Returns a chain & a flag for retval copy to use. SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Flag); SmallVector<SDValue, 8> Ops; @@ -2131,14 +2134,6 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee, if (RVLocs[i].isRegLoc()) MF.getRegInfo().addLiveOut(RVLocs[i].getLocReg()); } - - assert(((Callee.getOpcode() == ISD::Register && - (cast<RegisterSDNode>(Callee)->getReg() == X86::EAX || - cast<RegisterSDNode>(Callee)->getReg() == X86::R11)) || - Callee.getOpcode() == ISD::TargetExternalSymbol || - Callee.getOpcode() == ISD::TargetGlobalAddress) && - "Expecting a global address, external symbol, or scratch register"); - return DAG.getNode(X86ISD::TC_RETURN, dl, NodeTys, &Ops[0], Ops.size()); } @@ -2150,7 +2145,7 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee, unsigned NumBytesForCalleeToPush; if (IsCalleePop(isVarArg, CallConv)) NumBytesForCalleeToPush = NumBytes; // Callee pops everything - else if (!Is64Bit && CallConv != CallingConv::Fast && IsStructRet) + else if (!Is64Bit && !IsTailCallConvention(CallConv) && IsStructRet) // If this is a call to a struct-return function, the callee // pops the hidden struct pointer, so we have to push it back. // This is common for Darwin/X86, Linux & Mingw32 targets. @@ -2285,17 +2280,19 @@ bool X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg, + bool isCalleeStructRet, + bool isCallerStructRet, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<ISD::InputArg> &Ins, SelectionDAG& DAG) const { - if (CalleeCC != CallingConv::Fast && + if (!IsTailCallConvention(CalleeCC) && CalleeCC != CallingConv::C) return false; // If -tailcallopt is specified, make fastcc functions tail-callable. const Function *CallerF = DAG.getMachineFunction().getFunction(); if (GuaranteedTailCallOpt) { - if (CalleeCC == CallingConv::Fast && + if (IsTailCallConvention(CalleeCC) && CallerF->getCallingConv() == CalleeCC) return true; return false; @@ -2304,10 +2301,15 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, // Look for obvious safe cases to perform tail call optimization that does not // requite ABI changes. This is what gcc calls sibcall. - // Do not tail call optimize vararg calls for now. + // Do not sibcall optimize vararg calls for now. if (isVarArg) return false; + // Also avoid sibcall optimization if either caller or callee uses struct + // return semantics. + if (isCalleeStructRet || isCallerStructRet) + return false; + // If the callee takes no arguments then go on to check the results of the // call. if (!Outs.empty()) { @@ -6158,7 +6160,7 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) { N2C && N2C->isNullValue() && RHSC && RHSC->isNullValue()) { SDValue CmpOp0 = Cmp.getOperand(0); - Cmp = DAG.getNode(X86ISD::CMP, dl, CmpOp0.getValueType(), + Cmp = DAG.getNode(X86ISD::CMP, dl, MVT::i32, CmpOp0, DAG.getConstant(1, CmpOp0.getValueType())); return DAG.getNode(X86ISD::SETCC_CARRY, dl, Op.getValueType(), DAG.getConstant(X86::COND_B, MVT::i8), Cmp); @@ -8439,6 +8441,11 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, case X86::CMOV_V4F32: case X86::CMOV_V2F64: case X86::CMOV_V2I64: + case X86::CMOV_GR16: + case X86::CMOV_GR32: + case X86::CMOV_RFP32: + case X86::CMOV_RFP64: + case X86::CMOV_RFP80: return EmitLoweredSelect(MI, BB, EM); case X86::FP32_TO_INT16_IN_MEM: @@ -8521,6 +8528,21 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, F->DeleteMachineInstr(MI); // The pseudo instruction is gone now. return BB; } + // DBG_VALUE. Only the frame index case is done here. + case X86::DBG_VALUE: { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + X86AddressMode AM; + MachineFunction *F = BB->getParent(); + AM.BaseType = X86AddressMode::FrameIndexBase; + AM.Base.FrameIndex = MI->getOperand(0).getImm(); + addFullAddress(BuildMI(BB, DL, TII->get(X86::DBG_VALUE)), AM). + addImm(MI->getOperand(1).getImm()). + addMetadata(MI->getOperand(2).getMetadata()); + F->DeleteMachineInstr(MI); // Remove pseudo. + return BB; + } + // String/text processing lowering. case X86::PCMPISTRM128REG: return EmitPCMP(MI, BB, 3, false /* in-mem */); @@ -8832,6 +8854,87 @@ static SDValue PerformShuffleCombine(SDNode *N, SelectionDAG &DAG, return SDValue(); } +/// PerformShuffleCombine - Detect vector gather/scatter index generation +/// and convert it from being a bunch of shuffles and extracts to a simple +/// store and scalar loads to extract the elements. +static SDValue PerformEXTRACT_VECTOR_ELTCombine(SDNode *N, SelectionDAG &DAG, + const TargetLowering &TLI) { + SDValue InputVector = N->getOperand(0); + + // Only operate on vectors of 4 elements, where the alternative shuffling + // gets to be more expensive. + if (InputVector.getValueType() != MVT::v4i32) + return SDValue(); + + // Check whether every use of InputVector is an EXTRACT_VECTOR_ELT with a + // single use which is a sign-extend or zero-extend, and all elements are + // used. + SmallVector<SDNode *, 4> Uses; + unsigned ExtractedElements = 0; + for (SDNode::use_iterator UI = InputVector.getNode()->use_begin(), + UE = InputVector.getNode()->use_end(); UI != UE; ++UI) { + if (UI.getUse().getResNo() != InputVector.getResNo()) + return SDValue(); + + SDNode *Extract = *UI; + if (Extract->getOpcode() != ISD::EXTRACT_VECTOR_ELT) + return SDValue(); + + if (Extract->getValueType(0) != MVT::i32) + return SDValue(); + if (!Extract->hasOneUse()) + return SDValue(); + if (Extract->use_begin()->getOpcode() != ISD::SIGN_EXTEND && + Extract->use_begin()->getOpcode() != ISD::ZERO_EXTEND) + return SDValue(); + if (!isa<ConstantSDNode>(Extract->getOperand(1))) + return SDValue(); + + // Record which element was extracted. + ExtractedElements |= + 1 << cast<ConstantSDNode>(Extract->getOperand(1))->getZExtValue(); + + Uses.push_back(Extract); + } + + // If not all the elements were used, this may not be worthwhile. + if (ExtractedElements != 15) + return SDValue(); + + // Ok, we've now decided to do the transformation. + DebugLoc dl = InputVector.getDebugLoc(); + + // Store the value to a temporary stack slot. + SDValue StackPtr = DAG.CreateStackTemporary(InputVector.getValueType()); + SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, InputVector, StackPtr, NULL, 0, + false, false, 0); + + // Replace each use (extract) with a load of the appropriate element. + for (SmallVectorImpl<SDNode *>::iterator UI = Uses.begin(), + UE = Uses.end(); UI != UE; ++UI) { + SDNode *Extract = *UI; + + // Compute the element's address. + SDValue Idx = Extract->getOperand(1); + unsigned EltSize = + InputVector.getValueType().getVectorElementType().getSizeInBits()/8; + uint64_t Offset = EltSize * cast<ConstantSDNode>(Idx)->getZExtValue(); + SDValue OffsetVal = DAG.getConstant(Offset, TLI.getPointerTy()); + + SDValue ScalarAddr = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), OffsetVal, StackPtr); + + // Load the scalar. + SDValue LoadScalar = DAG.getLoad(Extract->getValueType(0), dl, Ch, ScalarAddr, + NULL, 0, false, false, 0); + + // Replace the exact with the load. + DAG.ReplaceAllUsesOfValueWith(SDValue(Extract, 0), LoadScalar); + } + + // The replacement was made in place; don't return anything. + return SDValue(); +} + /// PerformSELECTCombine - Do target-specific dag combines on SELECT nodes. static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, const X86Subtarget *Subtarget) { @@ -9721,6 +9824,8 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N, switch (N->getOpcode()) { default: break; case ISD::VECTOR_SHUFFLE: return PerformShuffleCombine(N, DAG, *this); + case ISD::EXTRACT_VECTOR_ELT: + return PerformEXTRACT_VECTOR_ELTCombine(N, DAG, *this); case ISD::SELECT: return PerformSELECTCombine(N, DAG, Subtarget); case X86ISD::CMOV: return PerformCMOVCombine(N, DAG, DCI); case ISD::MUL: return PerformMulCombine(N, DAG, DCI); @@ -9810,7 +9915,8 @@ bool X86TargetLowering::ExpandInlineAsm(CallInst *CI) const { AsmPieces[2] == "${0:w}" && IA->getConstraintString().compare(0, 5, "=r,0,") == 0) { AsmPieces.clear(); - SplitString(IA->getConstraintString().substr(5), AsmPieces, ","); + const std::string &Constraints = IA->getConstraintString(); + SplitString(StringRef(Constraints).substr(5), AsmPieces, ","); std::sort(AsmPieces.begin(), AsmPieces.end()); if (AsmPieces.size() == 4 && AsmPieces[0] == "~{cc}" && @@ -10265,41 +10371,3 @@ X86TargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint, return Res; } - -//===----------------------------------------------------------------------===// -// X86 Widen vector type -//===----------------------------------------------------------------------===// - -/// getWidenVectorType: given a vector type, returns the type to widen -/// to (e.g., v7i8 to v8i8). If the vector type is legal, it returns itself. -/// If there is no vector type that we want to widen to, returns MVT::Other -/// When and where to widen is target dependent based on the cost of -/// scalarizing vs using the wider vector type. - -EVT X86TargetLowering::getWidenVectorType(EVT VT) const { - assert(VT.isVector()); - if (isTypeLegal(VT)) - return VT; - - // TODO: In computeRegisterProperty, we can compute the list of legal vector - // type based on element type. This would speed up our search (though - // it may not be worth it since the size of the list is relatively - // small). - EVT EltVT = VT.getVectorElementType(); - unsigned NElts = VT.getVectorNumElements(); - - // On X86, it make sense to widen any vector wider than 1 - if (NElts <= 1) - return MVT::Other; - - for (unsigned nVT = MVT::FIRST_VECTOR_VALUETYPE; - nVT <= MVT::LAST_VECTOR_VALUETYPE; ++nVT) { - EVT SVT = (MVT::SimpleValueType)nVT; - - if (isTypeLegal(SVT) && - SVT.getVectorElementType() == EltVT && - SVT.getVectorNumElements() > NElts) - return SVT; - } - return MVT::Other; -} diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 4c12fcc32fd3..0f15ebafb0e5 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -564,13 +564,6 @@ namespace llvm { (VT == MVT::f32 && X86ScalarSSEf32); // f32 is when SSE1 } - /// getWidenVectorType: given a vector type, returns the type to widen - /// to (e.g., v7i8 to v8i8). If the vector type is legal, it returns itself. - /// If there is no vector type that we want to widen to, returns EVT::Other - /// When and were to widen is target dependent based on the cost of - /// scalarizing vs using the wider vector type. - virtual EVT getWidenVectorType(EVT VT) const; - /// createFastISel - This method returns a target specific FastISel object, /// or null if the target does not support "fast" ISel. virtual FastISel * @@ -637,6 +630,8 @@ namespace llvm { bool IsEligibleForTailCallOptimization(SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg, + bool isCalleeStructRet, + bool isCallerStructRet, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<ISD::InputArg> &Ins, SelectionDAG& DAG) const; diff --git a/lib/Target/X86/X86Instr64bit.td b/lib/Target/X86/X86Instr64bit.td index 8e684c9be25c..4262c0ac0514 100644 --- a/lib/Target/X86/X86Instr64bit.td +++ b/lib/Target/X86/X86Instr64bit.td @@ -24,6 +24,7 @@ def i64i32imm : Operand<i64>; // pc relative. def i64i32imm_pcrel : Operand<i64> { let PrintMethod = "print_pcrel_imm"; + let ParserMatchClass = X86AbsMemAsmOperand; } @@ -32,17 +33,26 @@ def i64i8imm : Operand<i64> { let ParserMatchClass = ImmSExt8AsmOperand; } +// Special i64mem for addresses of load folding tail calls. These are not +// allowed to use callee-saved registers since they must be scheduled +// after callee-saved register are popped. +def i64mem_TC : Operand<i64> { + let PrintMethod = "printi64mem"; + let MIOperandInfo = (ops GR64_TC, i8imm, GR64_TC, i32imm, i8imm); + let ParserMatchClass = X86MemAsmOperand; +} + def lea64mem : Operand<i64> { let PrintMethod = "printlea64mem"; let MIOperandInfo = (ops GR64, i8imm, GR64_NOSP, i32imm); - let ParserMatchClass = X86MemAsmOperand; + let ParserMatchClass = X86NoSegMemAsmOperand; } def lea64_32mem : Operand<i32> { let PrintMethod = "printlea64_32mem"; let AsmOperandLowerMethod = "lower_lea64_32mem"; let MIOperandInfo = (ops GR32, i8imm, GR32_NOSP, i32imm); - let ParserMatchClass = X86MemAsmOperand; + let ParserMatchClass = X86NoSegMemAsmOperand; } //===----------------------------------------------------------------------===// @@ -176,22 +186,31 @@ let isCall = 1 in let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in -def TCRETURNdi64 : I<0, Pseudo, (outs), (ins i64imm:$dst, i32imm:$offset, - variable_ops), - "#TC_RETURN $dst $offset", - []>; - -let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in -def TCRETURNri64 : I<0, Pseudo, (outs), (ins GR64:$dst, i32imm:$offset, - variable_ops), - "#TC_RETURN $dst $offset", - []>; - - -let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in - def TAILJMPr64 : I<0xFF, MRM4r, (outs), (ins GR64:$dst, variable_ops), - "jmp{q}\t{*}$dst # TAILCALL", - []>; + let Defs = [RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11, + FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0, ST1, + MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, + XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, EFLAGS], + Uses = [RSP] in { + def TCRETURNdi64 : I<0, Pseudo, (outs), + (ins i64i32imm_pcrel:$dst, i32imm:$offset, variable_ops), + "#TC_RETURN $dst $offset", []>; + def TCRETURNri64 : I<0, Pseudo, (outs), (ins GR64_TC:$dst, i32imm:$offset, + variable_ops), + "#TC_RETURN $dst $offset", []>; + def TCRETURNmi64 : I<0, Pseudo, (outs), + (ins i64mem_TC:$dst, i32imm:$offset, variable_ops), + "#TC_RETURN $dst $offset", []>; + + def TAILJMPd64 : Ii32PCRel<0xE9, RawFrm, (outs), + (ins i64i32imm_pcrel:$dst, variable_ops), + "jmp\t$dst # TAILCALL", []>; + def TAILJMPr64 : I<0xFF, MRM4r, (outs), (ins GR64_TC:$dst, variable_ops), + "jmp{q}\t{*}$dst # TAILCALL", []>; + + def TAILJMPm64 : I<0xFF, MRM4m, (outs), (ins i64mem_TC:$dst, variable_ops), + "jmp{q}\t{*}$dst # TAILCALL", []>; +} // Branches let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { @@ -339,6 +358,22 @@ def MOV64mi32 : RIi32<0xC7, MRM0m, (outs), (ins i64mem:$dst, i64i32imm:$src), "mov{q}\t{$src, $dst|$dst, $src}", [(store i64immSExt32:$src, addr:$dst)]>; +/// Versions of MOV64rr, MOV64rm, and MOV64mr for i64mem_TC and GR64_TC. +let neverHasSideEffects = 1 in +def MOV64rr_TC : RI<0x89, MRMDestReg, (outs GR64_TC:$dst), (ins GR64_TC:$src), + "mov{q}\t{$src, $dst|$dst, $src}", []>; + +let mayLoad = 1, + canFoldAsLoad = 1, isReMaterializable = 1 in +def MOV64rm_TC : RI<0x8B, MRMSrcMem, (outs GR64_TC:$dst), (ins i64mem_TC:$src), + "mov{q}\t{$src, $dst|$dst, $src}", + []>; + +let mayStore = 1 in +def MOV64mr_TC : RI<0x89, MRMDestMem, (outs), (ins i64mem_TC:$dst, GR64_TC:$src), + "mov{q}\t{$src, $dst|$dst, $src}", + []>; + def MOV64o8a : RIi8<0xA0, RawFrm, (outs), (ins offset8:$src), "mov{q}\t{$src, %rax|%rax, $src}", []>; def MOV64o64a : RIi32<0xA1, RawFrm, (outs), (ins offset64:$src), @@ -463,8 +498,8 @@ let neverHasSideEffects = 1 in { let Defs = [EFLAGS] in { -def ADD64i32 : RI<0x05, RawFrm, (outs), (ins i32imm:$src), - "add{q}\t{$src, %rax|%rax, $src}", []>; +def ADD64i32 : RIi32<0x05, RawFrm, (outs), (ins i32imm:$src), + "add{q}\t{$src, %rax|%rax, $src}", []>; let isTwoAddress = 1 in { let isConvertibleToThreeAddress = 1 in { @@ -520,8 +555,8 @@ def ADD64mi32 : RIi32<0x81, MRM0m, (outs), (ins i64mem:$dst, i64i32imm :$src2), let Uses = [EFLAGS] in { -def ADC64i32 : RI<0x15, RawFrm, (outs), (ins i32imm:$src), - "adc{q}\t{$src, %rax|%rax, $src}", []>; +def ADC64i32 : RIi32<0x15, RawFrm, (outs), (ins i32imm:$src), + "adc{q}\t{$src, %rax|%rax, $src}", []>; let isTwoAddress = 1 in { let isCommutable = 1 in @@ -594,8 +629,8 @@ def SUB64ri32 : RIi32<0x81, MRM5r, (outs GR64:$dst), (implicit EFLAGS)]>; } // isTwoAddress -def SUB64i32 : RI<0x2D, RawFrm, (outs), (ins i32imm:$src), - "sub{q}\t{$src, %rax|%rax, $src}", []>; +def SUB64i32 : RIi32<0x2D, RawFrm, (outs), (ins i32imm:$src), + "sub{q}\t{$src, %rax|%rax, $src}", []>; // Memory-Register Subtraction def SUB64mr : RI<0x29, MRMDestMem, (outs), (ins i64mem:$dst, GR64:$src2), @@ -641,8 +676,8 @@ def SBB64ri32 : RIi32<0x81, MRM3r, (outs GR64:$dst), [(set GR64:$dst, (sube GR64:$src1, i64immSExt32:$src2))]>; } // isTwoAddress -def SBB64i32 : RI<0x1D, RawFrm, (outs), (ins i32imm:$src), - "sbb{q}\t{$src, %rax|%rax, $src}", []>; +def SBB64i32 : RIi32<0x1D, RawFrm, (outs), (ins i32imm:$src), + "sbb{q}\t{$src, %rax|%rax, $src}", []>; def SBB64mr : RI<0x19, MRMDestMem, (outs), (ins i64mem:$dst, GR64:$src2), "sbb{q}\t{$src2, $dst|$dst, $src2}", @@ -1047,8 +1082,8 @@ def NOT64m : RI<0xF7, MRM2m, (outs), (ins i64mem:$dst), "not{q}\t$dst", [(store (not (loadi64 addr:$dst)), addr:$dst)]>; let Defs = [EFLAGS] in { -def AND64i32 : RI<0x25, RawFrm, (outs), (ins i32imm:$src), - "and{q}\t{$src, %rax|%rax, $src}", []>; +def AND64i32 : RIi32<0x25, RawFrm, (outs), (ins i32imm:$src), + "and{q}\t{$src, %rax|%rax, $src}", []>; let isTwoAddress = 1 in { let isCommutable = 1 in @@ -1187,8 +1222,8 @@ def XOR64i32 : RIi32<0x35, RawFrm, (outs), (ins i32imm:$src), // Integer comparison let Defs = [EFLAGS] in { -def TEST64i32 : RI<0xa9, RawFrm, (outs), (ins i32imm:$src), - "test{q}\t{$src, %rax|%rax, $src}", []>; +def TEST64i32 : RIi32<0xa9, RawFrm, (outs), (ins i32imm:$src), + "test{q}\t{$src, %rax|%rax, $src}", []>; let isCommutable = 1 in def TEST64rr : RI<0x85, MRMDestReg, (outs), (ins GR64:$src1, GR64:$src2), "test{q}\t{$src2, $src1|$src1, $src2}", @@ -1210,8 +1245,8 @@ def TEST64mi32 : RIi32<0xF7, MRM0m, (outs), (implicit EFLAGS)]>; -def CMP64i32 : RI<0x3D, RawFrm, (outs), (ins i32imm:$src), - "cmp{q}\t{$src, %rax|%rax, $src}", []>; +def CMP64i32 : RIi32<0x3D, RawFrm, (outs), (ins i32imm:$src), + "cmp{q}\t{$src, %rax|%rax, $src}", []>; def CMP64rr : RI<0x39, MRMDestReg, (outs), (ins GR64:$src1, GR64:$src2), "cmp{q}\t{$src2, $src1|$src1, $src2}", [(X86cmp GR64:$src1, GR64:$src2), @@ -1884,14 +1919,21 @@ def : Pat<(X86call (i64 texternalsym:$dst)), (WINCALL64pcrel32 texternalsym:$dst)>, Requires<[IsWin64]>; // tailcall stuff -def : Pat<(X86tcret GR64:$dst, imm:$off), - (TCRETURNri64 GR64:$dst, imm:$off)>; +def : Pat<(X86tcret GR64_TC:$dst, imm:$off), + (TCRETURNri64 GR64_TC:$dst, imm:$off)>, + Requires<[In64BitMode]>; + +def : Pat<(X86tcret (load addr:$dst), imm:$off), + (TCRETURNmi64 addr:$dst, imm:$off)>, + Requires<[In64BitMode]>; def : Pat<(X86tcret (i64 tglobaladdr:$dst), imm:$off), - (TCRETURNdi64 tglobaladdr:$dst, imm:$off)>; + (TCRETURNdi64 tglobaladdr:$dst, imm:$off)>, + Requires<[In64BitMode]>; def : Pat<(X86tcret (i64 texternalsym:$dst), imm:$off), - (TCRETURNdi64 texternalsym:$dst, imm:$off)>; + (TCRETURNdi64 texternalsym:$dst, imm:$off)>, + Requires<[In64BitMode]>; // Comparisons. diff --git a/lib/Target/X86/X86InstrFPStack.td b/lib/Target/X86/X86InstrFPStack.td index ae24bfbb2d84..b7309180bbbc 100644 --- a/lib/Target/X86/X86InstrFPStack.td +++ b/lib/Target/X86/X86InstrFPStack.td @@ -350,20 +350,27 @@ def FBLDm : FPI<0xDF, MRM4m, (outs), (ins f32mem:$src), "fbld\t$src">; def FBSTPm : FPI<0xDF, MRM6m, (outs f32mem:$dst), (ins), "fbstp\t$dst">; // Floating point cmovs. +class FpIf32CMov<dag outs, dag ins, FPFormat fp, list<dag> pattern> : + FpI_<outs, ins, fp, pattern>, Requires<[FPStackf32, HasCMov]>; +class FpIf64CMov<dag outs, dag ins, FPFormat fp, list<dag> pattern> : + FpI_<outs, ins, fp, pattern>, Requires<[FPStackf64, HasCMov]>; + multiclass FPCMov<PatLeaf cc> { - def _Fp32 : FpIf32<(outs RFP32:$dst), (ins RFP32:$src1, RFP32:$src2), + def _Fp32 : FpIf32CMov<(outs RFP32:$dst), (ins RFP32:$src1, RFP32:$src2), CondMovFP, [(set RFP32:$dst, (X86cmov RFP32:$src1, RFP32:$src2, cc, EFLAGS))]>; - def _Fp64 : FpIf64<(outs RFP64:$dst), (ins RFP64:$src1, RFP64:$src2), + def _Fp64 : FpIf64CMov<(outs RFP64:$dst), (ins RFP64:$src1, RFP64:$src2), CondMovFP, [(set RFP64:$dst, (X86cmov RFP64:$src1, RFP64:$src2, cc, EFLAGS))]>; def _Fp80 : FpI_<(outs RFP80:$dst), (ins RFP80:$src1, RFP80:$src2), CondMovFP, [(set RFP80:$dst, (X86cmov RFP80:$src1, RFP80:$src2, - cc, EFLAGS))]>; + cc, EFLAGS))]>, + Requires<[HasCMov]>; } + let Uses = [EFLAGS], isTwoAddress = 1 in { defm CMOVB : FPCMov<X86_COND_B>; defm CMOVBE : FPCMov<X86_COND_BE>; @@ -375,6 +382,7 @@ defm CMOVNE : FPCMov<X86_COND_NE>; defm CMOVNP : FPCMov<X86_COND_NP>; } +let Predicates = [HasCMov] in { // These are not factored because there's no clean way to pass DA/DB. def CMOVB_F : FPI<0xC0, AddRegFrm, (outs RST:$op), (ins), "fcmovb\t{$op, %st(0)|%ST(0), $op}">, DA; @@ -392,6 +400,7 @@ def CMOVNE_F : FPI<0xC8, AddRegFrm, (outs RST:$op), (ins), "fcmovne\t{$op, %st(0)|%ST(0), $op}">, DB; def CMOVNP_F : FPI<0xD8, AddRegFrm, (outs RST:$op), (ins), "fcmovnu\t{$op, %st(0)|%ST(0), $op}">, DB; +} // Predicates = [HasCMov] // Floating point loads & stores. let canFoldAsLoad = 1 in { diff --git a/lib/Target/X86/X86InstrInfo.cpp b/lib/Target/X86/X86InstrInfo.cpp index 4fd91bbc2fd8..139a905ec38d 100644 --- a/lib/Target/X86/X86InstrInfo.cpp +++ b/lib/Target/X86/X86InstrInfo.cpp @@ -266,6 +266,7 @@ X86InstrInfo::X86InstrInfo(X86TargetMachine &tm) { X86::MOV16rr, X86::MOV16mr, 0, 0 }, { X86::MOV32ri, X86::MOV32mi, 0, 0 }, { X86::MOV32rr, X86::MOV32mr, 0, 0 }, + { X86::MOV32rr_TC, X86::MOV32mr_TC, 0, 0 }, { X86::MOV64ri32, X86::MOV64mi32, 0, 0 }, { X86::MOV64rr, X86::MOV64mr, 0, 0 }, { X86::MOV8ri, X86::MOV8mi, 0, 0 }, @@ -301,6 +302,7 @@ X86InstrInfo::X86InstrInfo(X86TargetMachine &tm) { X86::SETPr, X86::SETPm, 0, 0 }, { X86::SETSr, X86::SETSm, 0, 0 }, { X86::TAILJMPr, X86::TAILJMPm, 1, 0 }, + { X86::TAILJMPr64, X86::TAILJMPm64, 1, 0 }, { X86::TEST16ri, X86::TEST16mi, 1, 0 }, { X86::TEST32ri, X86::TEST32mi, 1, 0 }, { X86::TEST64ri32, X86::TEST64mi32, 1, 0 }, @@ -376,6 +378,7 @@ X86InstrInfo::X86InstrInfo(X86TargetMachine &tm) { X86::Int_UCOMISSrr, X86::Int_UCOMISSrm, 0 }, { X86::MOV16rr, X86::MOV16rm, 0 }, { X86::MOV32rr, X86::MOV32rm, 0 }, + { X86::MOV32rr_TC, X86::MOV32rm_TC, 0 }, { X86::MOV64rr, X86::MOV64rm, 0 }, { X86::MOV64toPQIrr, X86::MOVQI2PQIrm, 0 }, { X86::MOV64toSDrr, X86::MOV64toSDrm, 0 }, @@ -675,6 +678,8 @@ bool X86InstrInfo::isMoveInstr(const MachineInstr& MI, case X86::MOV16rr: case X86::MOV32rr: case X86::MOV64rr: + case X86::MOV32rr_TC: + case X86::MOV64rr_TC: // FP Stack register class copies case X86::MOV_Fp3232: case X86::MOV_Fp6464: case X86::MOV_Fp8080: @@ -1901,6 +1906,10 @@ bool X86InstrInfo::copyRegToReg(MachineBasicBlock &MBB, Opc = X86::MOV16rr; } else if (CommonRC == &X86::GR8_NOREXRegClass) { Opc = X86::MOV8rr; + } else if (CommonRC == &X86::GR64_TCRegClass) { + Opc = X86::MOV64rr_TC; + } else if (CommonRC == &X86::GR32_TCRegClass) { + Opc = X86::MOV32rr_TC; } else if (CommonRC == &X86::RFP32RegClass) { Opc = X86::MOV_Fp3232; } else if (CommonRC == &X86::RFP64RegClass || CommonRC == &X86::RSTRegClass) { @@ -2038,6 +2047,10 @@ static unsigned getStoreRegOpcode(unsigned SrcReg, Opc = X86::MOV16mr; } else if (RC == &X86::GR8_NOREXRegClass) { Opc = X86::MOV8mr; + } else if (RC == &X86::GR64_TCRegClass) { + Opc = X86::MOV64mr_TC; + } else if (RC == &X86::GR32_TCRegClass) { + Opc = X86::MOV32mr_TC; } else if (RC == &X86::RFP80RegClass) { Opc = X86::ST_FpP80m; // pops } else if (RC == &X86::RFP64RegClass) { @@ -2131,6 +2144,10 @@ static unsigned getLoadRegOpcode(unsigned DestReg, Opc = X86::MOV16rm; } else if (RC == &X86::GR8_NOREXRegClass) { Opc = X86::MOV8rm; + } else if (RC == &X86::GR64_TCRegClass) { + Opc = X86::MOV64rm_TC; + } else if (RC == &X86::GR32_TCRegClass) { + Opc = X86::MOV32rm_TC; } else if (RC == &X86::RFP80RegClass) { Opc = X86::LD_Fp80m; } else if (RC == &X86::RFP64RegClass) { diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 071c5aa31ace..1225b683b745 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -21,6 +21,7 @@ def SDTIntShiftDOp: SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisInt<0>, SDTCisInt<3>]>; +// FIXME: Should be modelled as returning i32 def SDTX86CmpTest : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; def SDTX86Cmov : SDTypeProfile<1, 4, @@ -83,7 +84,6 @@ def X86shld : SDNode<"X86ISD::SHLD", SDTIntShiftDOp>; def X86shrd : SDNode<"X86ISD::SHRD", SDTIntShiftDOp>; def X86cmp : SDNode<"X86ISD::CMP" , SDTX86CmpTest>; - def X86bt : SDNode<"X86ISD::BT", SDTX86CmpTest>; def X86cmov : SDNode<"X86ISD::CMOV", SDTX86Cmov>; @@ -234,6 +234,15 @@ def i8mem_NOREX : Operand<i64> { let ParserMatchClass = X86MemAsmOperand; } +// Special i32mem for addresses of load folding tail calls. These are not +// allowed to use callee-saved registers since they must be scheduled +// after callee-saved register are popped. +def i32mem_TC : Operand<i32> { + let PrintMethod = "printi32mem"; + let MIOperandInfo = (ops GR32_TC, i8imm, GR32_TC, i32imm, i8imm); + let ParserMatchClass = X86MemAsmOperand; +} + def lea32mem : Operand<i32> { let PrintMethod = "printlea32mem"; let MIOperandInfo = (ops GR32, i8imm, GR32_NOSP, i32imm); @@ -288,6 +297,8 @@ def tls32addr : ComplexPattern<i32, 4, "SelectTLSADDRAddr", //===----------------------------------------------------------------------===// // X86 Instruction Predicate Definitions. +def HasCMov : Predicate<"Subtarget->hasCMov()">; +def NoCMov : Predicate<"!Subtarget->hasCMov()">; def HasMMX : Predicate<"Subtarget->hasMMX()">; def HasSSE1 : Predicate<"Subtarget->hasSSE1()">; def HasSSE2 : Predicate<"Subtarget->hasSSE2()">; @@ -696,30 +707,33 @@ def ENTER : I<0xC8, RawFrm, (outs), (ins i16imm:$len, i8imm:$lvl), // Tail call stuff. let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in -def TCRETURNdi : I<0, Pseudo, (outs), - (ins i32imm:$dst, i32imm:$offset, variable_ops), - "#TC_RETURN $dst $offset", - []>; - -let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in -def TCRETURNri : I<0, Pseudo, (outs), - (ins GR32:$dst, i32imm:$offset, variable_ops), - "#TC_RETURN $dst $offset", - []>; - -// FIXME: The should be pseudo instructions that are lowered when going to -// mcinst. -let isCall = 1, isBranch = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in - def TAILJMPd : Ii32<0xE9, RawFrm, (outs),(ins i32imm_pcrel:$dst,variable_ops), + let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0, + MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, + XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, EFLAGS], + Uses = [ESP] in { + def TCRETURNdi : I<0, Pseudo, (outs), + (ins i32imm_pcrel:$dst, i32imm:$offset, variable_ops), + "#TC_RETURN $dst $offset", []>; + def TCRETURNri : I<0, Pseudo, (outs), + (ins GR32_TC:$dst, i32imm:$offset, variable_ops), + "#TC_RETURN $dst $offset", []>; + def TCRETURNmi : I<0, Pseudo, (outs), + (ins i32mem_TC:$dst, i32imm:$offset, variable_ops), + "#TC_RETURN $dst $offset", []>; + + // FIXME: The should be pseudo instructions that are lowered when going to + // mcinst. + def TAILJMPd : Ii32PCRel<0xE9, RawFrm, (outs), + (ins i32imm_pcrel:$dst, variable_ops), "jmp\t$dst # TAILCALL", []>; -let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in - def TAILJMPr : I<0xFF, MRM4r, (outs), (ins GR32:$dst, variable_ops), + def TAILJMPr : I<0xFF, MRM4r, (outs), (ins GR32_TC:$dst, variable_ops), "jmp{l}\t{*}$dst # TAILCALL", []>; -let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in - def TAILJMPm : I<0xFF, MRM4m, (outs), (ins i32mem:$dst, variable_ops), - "jmp\t{*}$dst # TAILCALL", []>; + def TAILJMPm : I<0xFF, MRM4m, (outs), (ins i32mem_TC:$dst, variable_ops), + "jmp{l}\t{*}$dst # TAILCALL", []>; +} //===----------------------------------------------------------------------===// // Miscellaneous Instructions... @@ -1032,6 +1046,22 @@ def MOV32mr : I<0x89, MRMDestMem, (outs), (ins i32mem:$dst, GR32:$src), "mov{l}\t{$src, $dst|$dst, $src}", [(store GR32:$src, addr:$dst)]>; +/// Versions of MOV32rr, MOV32rm, and MOV32mr for i32mem_TC and GR32_TC. +let neverHasSideEffects = 1 in +def MOV32rr_TC : I<0x89, MRMDestReg, (outs GR32_TC:$dst), (ins GR32_TC:$src), + "mov{l}\t{$src, $dst|$dst, $src}", []>; + +let mayLoad = 1, + canFoldAsLoad = 1, isReMaterializable = 1 in +def MOV32rm_TC : I<0x8B, MRMSrcMem, (outs GR32_TC:$dst), (ins i32mem_TC:$src), + "mov{l}\t{$src, $dst|$dst, $src}", + []>; + +let mayStore = 1 in +def MOV32mr_TC : I<0x89, MRMDestMem, (outs), (ins i32mem_TC:$dst, GR32_TC:$src), + "mov{l}\t{$src, $dst|$dst, $src}", + []>; + // Versions of MOV8rr, MOV8mr, and MOV8rm that use i8mem_NOREX and GR8_NOREX so // that they can be used for copying and storing h registers, which can't be // encoded when a REX prefix is present. @@ -1185,19 +1215,7 @@ let isTwoAddress = 1 in { // Conditional moves let Uses = [EFLAGS] in { -// X86 doesn't have 8-bit conditional moves. Use a customInserter to -// emit control flow. An alternative to this is to mark i8 SELECT as Promote, -// however that requires promoting the operands, and can induce additional -// i8 register pressure. Note that CMOV_GR8 is conservatively considered to -// clobber EFLAGS, because if one of the operands is zero, the expansion -// could involve an xor. -let usesCustomInserter = 1, isTwoAddress = 0, Defs = [EFLAGS] in -def CMOV_GR8 : I<0, Pseudo, - (outs GR8:$dst), (ins GR8:$src1, GR8:$src2, i8imm:$cond), - "#CMOV_GR8 PSEUDO!", - [(set GR8:$dst, (X86cmov GR8:$src1, GR8:$src2, - imm:$cond, EFLAGS))]>; - +let Predicates = [HasCMov] in { let isCommutable = 1 in { def CMOVB16rr : I<0x42, MRMSrcReg, // if <u, GR16 = GR16 (outs GR16:$dst), (ins GR16:$src1, GR16:$src2), @@ -1585,6 +1603,49 @@ def CMOVNO32rm : I<0x41, MRMSrcMem, // if !overflow, GR32 = [mem32] [(set GR32:$dst, (X86cmov GR32:$src1, (loadi32 addr:$src2), X86_COND_NO, EFLAGS))]>, TB; +} // Predicates = [HasCMov] + +// X86 doesn't have 8-bit conditional moves. Use a customInserter to +// emit control flow. An alternative to this is to mark i8 SELECT as Promote, +// however that requires promoting the operands, and can induce additional +// i8 register pressure. Note that CMOV_GR8 is conservatively considered to +// clobber EFLAGS, because if one of the operands is zero, the expansion +// could involve an xor. +let usesCustomInserter = 1, isTwoAddress = 0, Defs = [EFLAGS] in { +def CMOV_GR8 : I<0, Pseudo, + (outs GR8:$dst), (ins GR8:$src1, GR8:$src2, i8imm:$cond), + "#CMOV_GR8 PSEUDO!", + [(set GR8:$dst, (X86cmov GR8:$src1, GR8:$src2, + imm:$cond, EFLAGS))]>; + +let Predicates = [NoCMov] in { +def CMOV_GR32 : I<0, Pseudo, + (outs GR32:$dst), (ins GR32:$src1, GR32:$src2, i8imm:$cond), + "#CMOV_GR32* PSEUDO!", + [(set GR32:$dst, + (X86cmov GR32:$src1, GR32:$src2, imm:$cond, EFLAGS))]>; +def CMOV_GR16 : I<0, Pseudo, + (outs GR16:$dst), (ins GR16:$src1, GR16:$src2, i8imm:$cond), + "#CMOV_GR16* PSEUDO!", + [(set GR16:$dst, + (X86cmov GR16:$src1, GR16:$src2, imm:$cond, EFLAGS))]>; +def CMOV_RFP32 : I<0, Pseudo, + (outs RFP32:$dst), (ins RFP32:$src1, RFP32:$src2, i8imm:$cond), + "#CMOV_RFP32 PSEUDO!", + [(set RFP32:$dst, (X86cmov RFP32:$src1, RFP32:$src2, imm:$cond, + EFLAGS))]>; +def CMOV_RFP64 : I<0, Pseudo, + (outs RFP64:$dst), (ins RFP64:$src1, RFP64:$src2, i8imm:$cond), + "#CMOV_RFP64 PSEUDO!", + [(set RFP64:$dst, (X86cmov RFP64:$src1, RFP64:$src2, imm:$cond, + EFLAGS))]>; +def CMOV_RFP80 : I<0, Pseudo, + (outs RFP80:$dst), (ins RFP80:$src1, RFP80:$src2, i8imm:$cond), + "#CMOV_RFP80 PSEUDO!", + [(set RFP80:$dst, (X86cmov RFP80:$src1, RFP80:$src2, imm:$cond, + EFLAGS))]>; +} // Predicates = [NoCMov] +} // UsesCustomInserter = 1, isTwoAddress = 0, Defs = [EFLAGS] } // Uses = [EFLAGS] @@ -4294,14 +4355,21 @@ def : Pat<(store (i32 (X86Wrapper tblockaddress:$src)), addr:$dst), // Calls // tailcall stuff -def : Pat<(X86tcret GR32:$dst, imm:$off), - (TCRETURNri GR32:$dst, imm:$off)>; +def : Pat<(X86tcret GR32_TC:$dst, imm:$off), + (TCRETURNri GR32_TC:$dst, imm:$off)>, + Requires<[In32BitMode]>; + +def : Pat<(X86tcret (load addr:$dst), imm:$off), + (TCRETURNmi addr:$dst, imm:$off)>, + Requires<[In32BitMode]>; def : Pat<(X86tcret (i32 tglobaladdr:$dst), imm:$off), - (TCRETURNdi texternalsym:$dst, imm:$off)>; + (TCRETURNdi texternalsym:$dst, imm:$off)>, + Requires<[In32BitMode]>; def : Pat<(X86tcret (i32 texternalsym:$dst), imm:$off), - (TCRETURNdi texternalsym:$dst, imm:$off)>; + (TCRETURNdi texternalsym:$dst, imm:$off)>, + Requires<[In32BitMode]>; // Normal calls, with various flavors of addresses. def : Pat<(X86call (i32 tglobaladdr:$dst)), diff --git a/lib/Target/X86/X86InstrMMX.td b/lib/Target/X86/X86InstrMMX.td index eea0eb892326..e1203e2c2a37 100644 --- a/lib/Target/X86/X86InstrMMX.td +++ b/lib/Target/X86/X86InstrMMX.td @@ -272,9 +272,9 @@ defm MMX_PSRAD : MMXI_binop_rmi_int<0xE2, 0x72, MRM4r, "psrad", // Shift up / down and insert zero's. def : Pat<(v1i64 (X86vshl VR64:$src, (i8 imm:$amt))), - (MMX_PSLLQri VR64:$src, imm:$amt)>; + (MMX_PSLLQri VR64:$src, (GetLo32XForm imm:$amt))>; def : Pat<(v1i64 (X86vshr VR64:$src, (i8 imm:$amt))), - (MMX_PSRLQri VR64:$src, imm:$amt)>; + (MMX_PSRLQri VR64:$src, (GetLo32XForm imm:$amt))>; // Comparison Instructions defm MMX_PCMPEQB : MMXI_binop_rm_int<0x74, "pcmpeqb", int_x86_mmx_pcmpeq_b>; diff --git a/lib/Target/X86/X86InstrSSE.td b/lib/Target/X86/X86InstrSSE.td index bd6e1b8c190e..18f9e52d470d 100644 --- a/lib/Target/X86/X86InstrSSE.td +++ b/lib/Target/X86/X86InstrSSE.td @@ -379,7 +379,7 @@ let Constraints = "$src1 = $dst" in def MOVSSrr : SSI<0x10, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, FR32:$src2), "movss\t{$src2, $dst|$dst, $src2}", - [(set VR128:$dst, + [(set (v4f32 VR128:$dst), (movl VR128:$src1, (scalar_to_vector FR32:$src2)))]>; // Extract the low 32-bit value from one vector and insert it into another. @@ -1141,7 +1141,7 @@ let Constraints = "$src1 = $dst" in def MOVSDrr : SDI<0x10, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, FR64:$src2), "movsd\t{$src2, $dst|$dst, $src2}", - [(set VR128:$dst, + [(set (v2f64 VR128:$dst), (movl VR128:$src1, (scalar_to_vector FR64:$src2)))]>; // Extract the low 64-bit value from one vector and insert it into another. diff --git a/lib/Target/X86/X86JITInfo.cpp b/lib/Target/X86/X86JITInfo.cpp index d297d24e22be..6f0a8d91cb58 100644 --- a/lib/Target/X86/X86JITInfo.cpp +++ b/lib/Target/X86/X86JITInfo.cpp @@ -19,6 +19,7 @@ #include "llvm/Function.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/System/Valgrind.h" #include <cstdlib> #include <cstring> using namespace llvm; @@ -37,6 +38,10 @@ void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) { unsigned NewAddr = (intptr_t)New; unsigned OldAddr = (intptr_t)OldWord; *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code. + + // X86 doesn't need to invalidate the processor cache, so just invalidate + // Valgrind's cache directly. + sys::ValgrindDiscardTranslations(Old, 5); } @@ -393,8 +398,10 @@ X86CompilationCallback2(intptr_t *StackPtr, intptr_t RetAddr) { *(intptr_t *)(RetAddr - 0xa) = NewVal; ((unsigned char*)RetAddr)[0] = (2 | (4 << 3) | (3 << 6)); } + sys::ValgrindDiscardTranslations((void*)(RetAddr-0xc), 0xd); #else ((unsigned char*)RetAddr)[-1] = 0xE9; + sys::ValgrindDiscardTranslations((void*)(RetAddr-1), 5); #endif } diff --git a/lib/Target/X86/X86MCAsmInfo.cpp b/lib/Target/X86/X86MCAsmInfo.cpp index 9498810b1566..1afabc9d9c15 100644 --- a/lib/Target/X86/X86MCAsmInfo.cpp +++ b/lib/Target/X86/X86MCAsmInfo.cpp @@ -70,7 +70,7 @@ X86MCAsmInfoDarwin::X86MCAsmInfoDarwin(const Triple &Triple) { ExceptionsType = ExceptionHandling::Dwarf; } -X86ELFMCAsmInfo::X86ELFMCAsmInfo(const Triple &Triple) { +X86ELFMCAsmInfo::X86ELFMCAsmInfo(const Triple &T) { AsmTransCBE = x86_asm_table; AssemblerDialect = AsmWriterFlavor; @@ -89,6 +89,11 @@ X86ELFMCAsmInfo::X86ELFMCAsmInfo(const Triple &Triple) { // Exceptions handling ExceptionsType = ExceptionHandling::Dwarf; + + // OpenBSD has buggy support for .quad in 32-bit mode, just split into two + // .words. + if (T.getOS() == Triple::OpenBSD && T.getArch() == Triple::x86) + Data64bitsDirective = 0; } MCSection *X86ELFMCAsmInfo::getNonexecutableStackSection(MCContext &Ctx) const { diff --git a/lib/Target/X86/X86MCTargetExpr.cpp b/lib/Target/X86/X86MCTargetExpr.cpp deleted file mode 100644 index 17b4fe88c752..000000000000 --- a/lib/Target/X86/X86MCTargetExpr.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//===- X86MCTargetExpr.cpp - X86 Target Specific MCExpr Implementation ----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "X86MCTargetExpr.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCValue.h" -#include "llvm/Support/raw_ostream.h" -using namespace llvm; - -X86MCTargetExpr *X86MCTargetExpr::Create(const MCSymbol *Sym, VariantKind K, - MCContext &Ctx) { - return new (Ctx) X86MCTargetExpr(Sym, K); -} - -void X86MCTargetExpr::PrintImpl(raw_ostream &OS) const { - OS << *Sym; - - switch (Kind) { - case Invalid: OS << "@<invalid>"; break; - case GOT: OS << "@GOT"; break; - case GOTOFF: OS << "@GOTOFF"; break; - case GOTPCREL: OS << "@GOTPCREL"; break; - case GOTTPOFF: OS << "@GOTTPOFF"; break; - case INDNTPOFF: OS << "@INDNTPOFF"; break; - case NTPOFF: OS << "@NTPOFF"; break; - case PLT: OS << "@PLT"; break; - case TLSGD: OS << "@TLSGD"; break; - case TPOFF: OS << "@TPOFF"; break; - } -} - -bool X86MCTargetExpr::EvaluateAsRelocatableImpl(MCValue &Res) const { - // FIXME: I don't know if this is right, it followed MCSymbolRefExpr. - - // Evaluate recursively if this is a variable. - if (Sym->isVariable()) - return Sym->getValue()->EvaluateAsRelocatable(Res); - - Res = MCValue::get(Sym, 0, 0); - return true; -} diff --git a/lib/Target/X86/X86MCTargetExpr.h b/lib/Target/X86/X86MCTargetExpr.h deleted file mode 100644 index 7de8a5c57380..000000000000 --- a/lib/Target/X86/X86MCTargetExpr.h +++ /dev/null @@ -1,49 +0,0 @@ -//===- X86MCTargetExpr.h - X86 Target Specific MCExpr -----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef X86_MCTARGETEXPR_H -#define X86_MCTARGETEXPR_H - -#include "llvm/MC/MCExpr.h" - -namespace llvm { - -/// X86MCTargetExpr - This class represents symbol variants, like foo@GOT. -class X86MCTargetExpr : public MCTargetExpr { -public: - enum VariantKind { - Invalid, - GOT, - GOTOFF, - GOTPCREL, - GOTTPOFF, - INDNTPOFF, - NTPOFF, - PLT, - TLSGD, - TPOFF - }; -private: - /// Sym - The symbol being referenced. - const MCSymbol * const Sym; - /// Kind - The modifier. - const VariantKind Kind; - - X86MCTargetExpr(const MCSymbol *S, VariantKind K) : Sym(S), Kind(K) {} -public: - static X86MCTargetExpr *Create(const MCSymbol *Sym, VariantKind K, - MCContext &Ctx); - - void PrintImpl(raw_ostream &OS) const; - bool EvaluateAsRelocatableImpl(MCValue &Res) const; -}; - -} // end namespace llvm - -#endif diff --git a/lib/Target/X86/X86RegisterInfo.cpp b/lib/Target/X86/X86RegisterInfo.cpp index cdb579c53878..3238ccebb99f 100644 --- a/lib/Target/X86/X86RegisterInfo.cpp +++ b/lib/Target/X86/X86RegisterInfo.cpp @@ -294,13 +294,20 @@ X86RegisterInfo::getCrossCopyRegClass(const TargetRegisterClass *RC) const { const unsigned * X86RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { bool callsEHReturn = false; + bool ghcCall = false; if (MF) { const MachineFrameInfo *MFI = MF->getFrameInfo(); const MachineModuleInfo *MMI = MFI->getMachineModuleInfo(); callsEHReturn = (MMI ? MMI->callsEHReturn() : false); + const Function *F = MF->getFunction(); + ghcCall = (F ? F->getCallingConv() == CallingConv::GHC : false); } + static const unsigned GhcCalleeSavedRegs[] = { + 0 + }; + static const unsigned CalleeSavedRegs32Bit[] = { X86::ESI, X86::EDI, X86::EBX, X86::EBP, 0 }; @@ -326,7 +333,9 @@ X86RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { X86::XMM14, X86::XMM15, 0 }; - if (Is64Bit) { + if (ghcCall) { + return GhcCalleeSavedRegs; + } else if (Is64Bit) { if (IsWin64) return CalleeSavedRegsWin64; else @@ -788,7 +797,7 @@ static int mergeSPUpdates(MachineBasicBlock &MBB, } void X86RegisterInfo::emitCalleeSavedFrameMoves(MachineFunction &MF, - unsigned LabelId, + MCSymbol *Label, unsigned FramePtr) const { MachineFrameInfo *MFI = MF.getFrameInfo(); MachineModuleInfo *MMI = MFI->getMachineModuleInfo(); @@ -851,7 +860,7 @@ void X86RegisterInfo::emitCalleeSavedFrameMoves(MachineFunction &MF, MachineLocation CSDst(MachineLocation::VirtualFP, Offset); MachineLocation CSSrc(Reg); - Moves.push_back(MachineMove(LabelId, CSDst, CSSrc)); + Moves.push_back(MachineMove(Label, CSDst, CSSrc)); } } @@ -929,10 +938,7 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { std::vector<MachineMove> &Moves = MMI->getFrameMoves(); const TargetData *TD = MF.getTarget().getTargetData(); uint64_t NumBytes = 0; - int stackGrowth = - (MF.getTarget().getFrameInfo()->getStackGrowthDirection() == - TargetFrameInfo::StackGrowsUp ? - TD->getPointerSize() : -TD->getPointerSize()); + int stackGrowth = -TD->getPointerSize(); if (HasFP) { // Calculate required stack adjustment. @@ -953,26 +959,25 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { if (needsFrameMoves) { // Mark the place where EBP/RBP was saved. - unsigned FrameLabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addImm(FrameLabelId); + MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addSym(FrameLabel); // Define the current CFA rule to use the provided offset. if (StackSize) { MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, 2 * stackGrowth); - Moves.push_back(MachineMove(FrameLabelId, SPDst, SPSrc)); + Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); } else { // FIXME: Verify & implement for FP MachineLocation SPDst(StackPtr); MachineLocation SPSrc(StackPtr, stackGrowth); - Moves.push_back(MachineMove(FrameLabelId, SPDst, SPSrc)); + Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); } // Change the rule for the FramePtr to be an "offset" rule. - MachineLocation FPDst(MachineLocation::VirtualFP, - 2 * stackGrowth); + MachineLocation FPDst(MachineLocation::VirtualFP, 2 * stackGrowth); MachineLocation FPSrc(FramePtr); - Moves.push_back(MachineMove(FrameLabelId, FPDst, FPSrc)); + Moves.push_back(MachineMove(FrameLabel, FPDst, FPSrc)); } // Update EBP with the new base value... @@ -982,13 +987,13 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { if (needsFrameMoves) { // Mark effective beginning of when frame pointer becomes valid. - unsigned FrameLabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addImm(FrameLabelId); + MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addSym(FrameLabel); // Define the current CFA to use the EBP/RBP register. MachineLocation FPDst(FramePtr); MachineLocation FPSrc(MachineLocation::VirtualFP); - Moves.push_back(MachineMove(FrameLabelId, FPDst, FPSrc)); + Moves.push_back(MachineMove(FrameLabel, FPDst, FPSrc)); } // Mark the FramePtr as live-in in every block except the entry. @@ -1022,15 +1027,15 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { if (!HasFP && needsFrameMoves) { // Mark callee-saved push instruction. - unsigned LabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addImm(LabelId); + MCSymbol *Label = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addSym(Label); // Define the current CFA rule to use the provided offset. unsigned Ptr = StackSize ? MachineLocation::VirtualFP : StackPtr; MachineLocation SPDst(Ptr); MachineLocation SPSrc(Ptr, StackOffset); - Moves.push_back(MachineMove(LabelId, SPDst, SPSrc)); + Moves.push_back(MachineMove(Label, SPDst, SPSrc)); StackOffset += stackGrowth; } } @@ -1094,8 +1099,8 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { if ((NumBytes || PushedRegs) && needsFrameMoves) { // Mark end of stack pointer adjustment. - unsigned LabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addImm(LabelId); + MCSymbol *Label = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addSym(Label); if (!HasFP && NumBytes) { // Define the current CFA rule to use the provided offset. @@ -1103,18 +1108,18 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, -StackSize + stackGrowth); - Moves.push_back(MachineMove(LabelId, SPDst, SPSrc)); + Moves.push_back(MachineMove(Label, SPDst, SPSrc)); } else { // FIXME: Verify & implement for FP MachineLocation SPDst(StackPtr); MachineLocation SPSrc(StackPtr, stackGrowth); - Moves.push_back(MachineMove(LabelId, SPDst, SPSrc)); + Moves.push_back(MachineMove(Label, SPDst, SPSrc)); } } // Emit DWARF info specifying the offsets of the callee-saved registers. if (PushedRegs) - emitCalleeSavedFrameMoves(MF, LabelId, HasFP ? FramePtr : StackPtr); + emitCalleeSavedFrameMoves(MF, Label, HasFP ? FramePtr : StackPtr); } } @@ -1133,13 +1138,12 @@ void X86RegisterInfo::emitEpilogue(MachineFunction &MF, case X86::RETI: case X86::TCRETURNdi: case X86::TCRETURNri: - case X86::TCRETURNri64: + case X86::TCRETURNmi: case X86::TCRETURNdi64: + case X86::TCRETURNri64: + case X86::TCRETURNmi64: case X86::EH_RETURN: case X86::EH_RETURN64: - case X86::TAILJMPd: - case X86::TAILJMPr: - case X86::TAILJMPm: break; // These are ok } @@ -1224,11 +1228,14 @@ void X86RegisterInfo::emitEpilogue(MachineFunction &MF, TII.get(Is64Bit ? X86::MOV64rr : X86::MOV32rr), StackPtr).addReg(DestAddr.getReg()); } else if (RetOpcode == X86::TCRETURNri || RetOpcode == X86::TCRETURNdi || - RetOpcode== X86::TCRETURNri64 || RetOpcode == X86::TCRETURNdi64) { + RetOpcode == X86::TCRETURNmi || + RetOpcode == X86::TCRETURNri64 || RetOpcode == X86::TCRETURNdi64 || + RetOpcode == X86::TCRETURNmi64) { + bool isMem = RetOpcode == X86::TCRETURNmi || RetOpcode == X86::TCRETURNmi64; // Tail call return: adjust the stack pointer and jump to callee. MBBI = prior(MBB.end()); MachineOperand &JumpTarget = MBBI->getOperand(0); - MachineOperand &StackAdjust = MBBI->getOperand(1); + MachineOperand &StackAdjust = MBBI->getOperand(isMem ? 5 : 1); assert(StackAdjust.isImm() && "Expecting immediate value."); // Adjust stack pointer. @@ -1248,10 +1255,17 @@ void X86RegisterInfo::emitEpilogue(MachineFunction &MF, } // Jump to label or value in register. - if (RetOpcode == X86::TCRETURNdi|| RetOpcode == X86::TCRETURNdi64) { - BuildMI(MBB, MBBI, DL, TII.get(X86::TAILJMPd)). + if (RetOpcode == X86::TCRETURNdi || RetOpcode == X86::TCRETURNdi64) { + BuildMI(MBB, MBBI, DL, TII.get((RetOpcode == X86::TCRETURNdi) + ? X86::TAILJMPd : X86::TAILJMPd64)). addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(), JumpTarget.getTargetFlags()); + } else if (RetOpcode == X86::TCRETURNmi || RetOpcode == X86::TCRETURNmi64) { + MachineInstrBuilder MIB = + BuildMI(MBB, MBBI, DL, TII.get((RetOpcode == X86::TCRETURNmi) + ? X86::TAILJMPm : X86::TAILJMPm64)); + for (unsigned i = 0; i != 5; ++i) + MIB.addOperand(MBBI->getOperand(i)); } else if (RetOpcode == X86::TCRETURNri64) { BuildMI(MBB, MBBI, DL, TII.get(X86::TAILJMPr64), JumpTarget.getReg()); } else { diff --git a/lib/Target/X86/X86RegisterInfo.h b/lib/Target/X86/X86RegisterInfo.h index 12b2f3ee3e54..ac96c4c83112 100644 --- a/lib/Target/X86/X86RegisterInfo.h +++ b/lib/Target/X86/X86RegisterInfo.h @@ -149,7 +149,7 @@ public: void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS = NULL) const; - void emitCalleeSavedFrameMoves(MachineFunction &MF, unsigned LabelId, + void emitCalleeSavedFrameMoves(MachineFunction &MF, MCSymbol *Label, unsigned FramePtr) const; void emitPrologue(MachineFunction &MF) const; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; diff --git a/lib/Target/X86/X86RegisterInfo.td b/lib/Target/X86/X86RegisterInfo.td index ed2ce6c353d1..76b8f7a953c9 100644 --- a/lib/Target/X86/X86RegisterInfo.td +++ b/lib/Target/X86/X86RegisterInfo.td @@ -535,6 +535,13 @@ def GR32_ABCD : RegisterClass<"X86", [i32], 32, [EAX, ECX, EDX, EBX]> { def GR64_ABCD : RegisterClass<"X86", [i64], 64, [RAX, RCX, RDX, RBX]> { let SubRegClassList = [GR8_ABCD_L, GR8_ABCD_H, GR16_ABCD, GR32_ABCD]; } +def GR32_TC : RegisterClass<"X86", [i32], 32, [EAX, ECX, EDX]> { + let SubRegClassList = [GR8, GR8, GR16]; +} +def GR64_TC : RegisterClass<"X86", [i64], 64, [RAX, RCX, RDX, RSI, RDI, + R8, R9, R11]> { + let SubRegClassList = [GR8, GR8, GR16, GR32_TC]; +} // GR8_NOREX - GR8 registers which do not require a REX prefix. def GR8_NOREX : RegisterClass<"X86", [i8], 8, diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp index adef5bcb4802..f907614c86af 100644 --- a/lib/Target/X86/X86Subtarget.cpp +++ b/lib/Target/X86/X86Subtarget.cpp @@ -315,9 +315,14 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &FS, // If requesting codegen for X86-64, make sure that 64-bit features // are enabled. - if (Is64Bit) + if (Is64Bit) { HasX86_64 = true; + // All 64-bit cpus have cmov support. + HasCMov = true; + } + + DEBUG(dbgs() << "Subtarget features: SSELevel " << X86SSELevel << ", 3DNowLevel " << X863DNowLevel << ", 64bit " << HasX86_64 << "\n"); diff --git a/lib/Target/X86/X86Subtarget.h b/lib/Target/X86/X86Subtarget.h index 594a47000960..50338d33acf9 100644 --- a/lib/Target/X86/X86Subtarget.h +++ b/lib/Target/X86/X86Subtarget.h @@ -133,6 +133,7 @@ public: PICStyles::Style getPICStyle() const { return PICStyle; } void setPICStyle(PICStyles::Style Style) { PICStyle = Style; } + bool hasCMov() const { return HasCMov; } bool hasMMX() const { return X86SSELevel >= MMX; } bool hasSSE1() const { return X86SSELevel >= SSE1; } bool hasSSE2() const { return X86SSELevel >= SSE2; } diff --git a/lib/Target/X86/X86TargetObjectFile.cpp b/lib/Target/X86/X86TargetObjectFile.cpp index c80ae1969a73..c15dfbb1c8ec 100644 --- a/lib/Target/X86/X86TargetObjectFile.cpp +++ b/lib/Target/X86/X86TargetObjectFile.cpp @@ -7,11 +7,12 @@ // //===----------------------------------------------------------------------===// -#include "X86MCTargetExpr.h" #include "X86TargetObjectFile.h" #include "X86TargetMachine.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSectionMachO.h" #include "llvm/Target/Mangler.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Dwarf.h" @@ -19,28 +20,22 @@ using namespace llvm; using namespace dwarf; const MCExpr *X8664_MachoTargetObjectFile:: -getSymbolForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, - MachineModuleInfo *MMI, - unsigned Encoding) const { +getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const { // On Darwin/X86-64, we can reference dwarf symbols with foo@GOTPCREL+4, which // is an indirect pc-relative reference. if (Encoding & (DW_EH_PE_indirect | DW_EH_PE_pcrel)) { - SmallString<128> Name; - Mang->getNameWithPrefix(Name, GV, false); - const MCSymbol *Sym; - if (GV->hasPrivateLinkage()) - Sym = getContext().GetOrCreateTemporarySymbol(Name); - else - Sym = getContext().GetOrCreateSymbol(Name); + const MCSymbol *Sym = Mang->getSymbol(GV); const MCExpr *Res = - X86MCTargetExpr::Create(Sym, X86MCTargetExpr::GOTPCREL, getContext()); + MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOTPCREL, getContext()); const MCExpr *Four = MCConstantExpr::Create(4, getContext()); return MCBinaryExpr::CreateAdd(Res, Four, getContext()); } return TargetLoweringObjectFileMachO:: - getSymbolForDwarfGlobalReference(GV, Mang, MMI, Encoding); + getExprForDwarfGlobalReference(GV, Mang, MMI, Encoding, Streamer); } unsigned X8632_ELFTargetObjectFile::getPersonalityEncoding() const { diff --git a/lib/Target/X86/X86TargetObjectFile.h b/lib/Target/X86/X86TargetObjectFile.h index 044441715499..f2fd49caca38 100644 --- a/lib/Target/X86/X86TargetObjectFile.h +++ b/lib/Target/X86/X86TargetObjectFile.h @@ -17,14 +17,14 @@ namespace llvm { class X86TargetMachine; - /// X8664_MachoTargetObjectFile - This TLOF implementation is used for - /// Darwin/x86-64. + /// X8664_MachoTargetObjectFile - This TLOF implementation is used for Darwin + /// x86-64. class X8664_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { public: - virtual const MCExpr * - getSymbolForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, - MachineModuleInfo *MMI, unsigned Encoding) const; + getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const; }; class X8632_ELFTargetObjectFile : public TargetLoweringObjectFileELF { diff --git a/lib/Target/XCore/AsmPrinter/Makefile b/lib/Target/XCore/AsmPrinter/Makefile index 82dc1df95d3b..581f736b7431 100644 --- a/lib/Target/XCore/AsmPrinter/Makefile +++ b/lib/Target/XCore/AsmPrinter/Makefile @@ -11,6 +11,6 @@ LEVEL = ../../../.. LIBRARYNAME = LLVMXCoreAsmPrinter # Hack: we need to include 'main' XCore target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. include $(LEVEL)/Makefile.common diff --git a/lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp b/lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp index 82e23a13e802..c88233877903 100644 --- a/lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp +++ b/lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp @@ -30,6 +30,7 @@ #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegistry.h" @@ -53,9 +54,8 @@ namespace { const XCoreSubtarget &Subtarget; public: explicit XCoreAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, - MCContext &Ctx, MCStreamer &Streamer, - const MCAsmInfo *T) - : AsmPrinter(O, TM, Ctx, Streamer, T), + MCStreamer &Streamer) + : AsmPrinter(O, TM, Streamer), Subtarget(TM.getSubtarget<XCoreSubtarget>()) {} virtual const char *getPassName() const { @@ -129,7 +129,7 @@ void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GV, Mang,TM)); - MCSymbol *GVSym = GetGlobalValueSymbol(GV); + MCSymbol *GVSym = Mang->getSymbol(GV); Constant *C = GV->getInitializer(); unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType()); @@ -276,7 +276,7 @@ printInlineJT(const MachineInstr *MI, int opNum, const std::string &directive) MachineBasicBlock *MBB = JTBBs[i]; if (i > 0) O << ","; - O << *MBB->getSymbol(OutContext); + O << *MBB->getSymbol(); } } @@ -290,10 +290,10 @@ void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum) { O << MO.getImm(); break; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(OutContext); + O << *MO.getMBB()->getSymbol(); break; case MachineOperand::MO_GlobalAddress: - O << *GetGlobalValueSymbol(MO.getGlobal()); + O << *Mang->getSymbol(MO.getGlobal()); break; case MachineOperand::MO_ExternalSymbol: O << MO.getSymbolName(); diff --git a/lib/Target/XCore/README.txt b/lib/Target/XCore/README.txt index deaeb0f2a93b..b69205b49b6c 100644 --- a/lib/Target/XCore/README.txt +++ b/lib/Target/XCore/README.txt @@ -5,4 +5,3 @@ To-do * Tailcalls * Investigate loop alignment * Add builtins -* Make better use of lmul / macc diff --git a/lib/Target/XCore/XCoreISelDAGToDAG.cpp b/lib/Target/XCore/XCoreISelDAGToDAG.cpp index 29a6ab77d013..1615547b4152 100644 --- a/lib/Target/XCore/XCoreISelDAGToDAG.cpp +++ b/lib/Target/XCore/XCoreISelDAGToDAG.cpp @@ -173,29 +173,6 @@ SDNode *XCoreDAGToDAGISel::Select(SDNode *N) { } break; } - case ISD::SMUL_LOHI: { - // FIXME fold addition into the macc instruction - SDValue Zero(CurDAG->getMachineNode(XCore::LDC_ru6, dl, MVT::i32, - CurDAG->getTargetConstant(0, MVT::i32)), 0); - SDValue Ops[] = { Zero, Zero, N->getOperand(0), N->getOperand(1) }; - SDNode *ResNode = CurDAG->getMachineNode(XCore::MACCS_l4r, dl, - MVT::i32, MVT::i32, Ops, 4); - ReplaceUses(SDValue(N, 0), SDValue(ResNode, 1)); - ReplaceUses(SDValue(N, 1), SDValue(ResNode, 0)); - return NULL; - } - case ISD::UMUL_LOHI: { - // FIXME fold addition into the macc / lmul instruction - SDValue Zero(CurDAG->getMachineNode(XCore::LDC_ru6, dl, MVT::i32, - CurDAG->getTargetConstant(0, MVT::i32)), 0); - SDValue Ops[] = { N->getOperand(0), N->getOperand(1), - Zero, Zero }; - SDNode *ResNode = CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, - MVT::i32, Ops, 4); - ReplaceUses(SDValue(N, 0), SDValue(ResNode, 1)); - ReplaceUses(SDValue(N, 1), SDValue(ResNode, 0)); - return NULL; - } case XCoreISD::LADD: { SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) }; diff --git a/lib/Target/XCore/XCoreISelLowering.cpp b/lib/Target/XCore/XCoreISelLowering.cpp index 82492193d209..bf1a45762795 100644 --- a/lib/Target/XCore/XCoreISelLowering.cpp +++ b/lib/Target/XCore/XCoreISelLowering.cpp @@ -324,6 +324,10 @@ LowerConstantPool(SDValue Op, SelectionDAG &DAG) return DAG.getNode(XCoreISD::CPRelativeWrapper, dl, MVT::i32, Res); } +unsigned XCoreTargetLowering::getJumpTableEncoding() const { + return MachineJumpTableInfo::EK_Inline; +} + SDValue XCoreTargetLowering:: LowerBR_JT(SDValue Op, SelectionDAG &DAG) { @@ -1341,12 +1345,41 @@ SDValue XCoreTargetLowering::PerformDAGCombine(SDNode *N, } } break; + case XCoreISD::LMUL: { + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + SDValue N2 = N->getOperand(2); + SDValue N3 = N->getOperand(3); + ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0); + ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1); + EVT VT = N0.getValueType(); + // Canonicalize multiplicative constant to RHS. If both multiplicative + // operands are constant canonicalize smallest to RHS. + if ((N0C && !N1C) || + (N0C && N1C && N0C->getZExtValue() < N1C->getZExtValue())) + return DAG.getNode(XCoreISD::LMUL, dl, DAG.getVTList(VT, VT), N1, N0, N2, N3); + + // lmul(x, 0, a, b) + if (N1C && N1C->isNullValue()) { + // If the high result is unused fold to add(a, b) + if (N->hasNUsesOfValue(0, 0)) { + SDValue Lo = DAG.getNode(ISD::ADD, dl, VT, N2, N3); + SDValue Ops [] = { Lo, Lo }; + return DAG.getMergeValues(Ops, 2, dl); + } + // Otherwise fold to ladd(a, b, 0) + return DAG.getNode(XCoreISD::LADD, dl, DAG.getVTList(VT, VT), N2, N3, N1); + } + } + break; case ISD::ADD: { - // Fold expressions such as add(add(mul(x,y),a),b) -> lmul(x, y, a, b). + // Fold 32 bit expressions such as add(add(mul(x,y),a),b) -> + // lmul(x, y, a, b). The high result of lmul will be ignored. // This is only profitable if the intermediate results are unused // elsewhere. SDValue Mul0, Mul1, Addend0, Addend1; - if (isADDADDMUL(SDValue(N, 0), Mul0, Mul1, Addend0, Addend1, true)) { + if (N->getValueType(0) == MVT::i32 && + isADDADDMUL(SDValue(N, 0), Mul0, Mul1, Addend0, Addend1, true)) { SDValue Zero = DAG.getConstant(0, MVT::i32); SDValue Ignored = DAG.getNode(XCoreISD::LMUL, dl, DAG.getVTList(MVT::i32, MVT::i32), Mul0, @@ -1354,6 +1387,31 @@ SDValue XCoreTargetLowering::PerformDAGCombine(SDNode *N, SDValue Result(Ignored.getNode(), 1); return Result; } + APInt HighMask = APInt::getHighBitsSet(64, 32); + // Fold 64 bit expression such as add(add(mul(x,y),a),b) -> + // lmul(x, y, a, b) if all operands are zero-extended. We do this + // before type legalization as it is messy to match the operands after + // that. + if (N->getValueType(0) == MVT::i64 && + isADDADDMUL(SDValue(N, 0), Mul0, Mul1, Addend0, Addend1, false) && + DAG.MaskedValueIsZero(Mul0, HighMask) && + DAG.MaskedValueIsZero(Mul1, HighMask) && + DAG.MaskedValueIsZero(Addend0, HighMask) && + DAG.MaskedValueIsZero(Addend1, HighMask)) { + SDValue Mul0L = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, + Mul0, DAG.getConstant(0, MVT::i32)); + SDValue Mul1L = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, + Mul1, DAG.getConstant(0, MVT::i32)); + SDValue Addend0L = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, + Addend0, DAG.getConstant(0, MVT::i32)); + SDValue Addend1L = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, + Addend1, DAG.getConstant(0, MVT::i32)); + SDValue Hi = DAG.getNode(XCoreISD::LMUL, dl, + DAG.getVTList(MVT::i32, MVT::i32), Mul0L, Mul1L, + Addend0L, Addend1L); + SDValue Lo(Hi.getNode(), 1); + return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi); + } } break; case ISD::STORE: { diff --git a/lib/Target/XCore/XCoreISelLowering.h b/lib/Target/XCore/XCoreISelLowering.h index f597780d6911..3ccdeec141bb 100644 --- a/lib/Target/XCore/XCoreISelLowering.h +++ b/lib/Target/XCore/XCoreISelLowering.h @@ -80,6 +80,8 @@ namespace llvm { explicit XCoreTargetLowering(XCoreTargetMachine &TM); + virtual unsigned getJumpTableEncoding() const; + /// LowerOperation - Provide custom lowering hooks for some operations. virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG); diff --git a/lib/Target/XCore/XCoreInstrInfo.cpp b/lib/Target/XCore/XCoreInstrInfo.cpp index 722e7470f066..e5f5a6dbd38a 100644 --- a/lib/Target/XCore/XCoreInstrInfo.cpp +++ b/lib/Target/XCore/XCoreInstrInfo.cpp @@ -429,10 +429,9 @@ bool XCoreInstrInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB, storeRegToStackSlot(MBB, MI, it->getReg(), true, it->getFrameIdx(), it->getRegClass()); if (emitFrameMoves) { - unsigned SaveLabelId = MMI->NextLabelID(); - BuildMI(MBB, MI, DL, get(XCore::DBG_LABEL)).addImm(SaveLabelId); - XFI->getSpillLabels().push_back( - std::pair<unsigned, CalleeSavedInfo>(SaveLabelId, *it)); + MCSymbol *SaveLabel = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MI, DL, get(XCore::DBG_LABEL)).addSym(SaveLabel); + XFI->getSpillLabels().push_back(std::make_pair(SaveLabel, *it)); } } return true; diff --git a/lib/Target/XCore/XCoreMachineFunctionInfo.h b/lib/Target/XCore/XCoreMachineFunctionInfo.h index 124a011f3cb8..a575a0f69541 100644 --- a/lib/Target/XCore/XCoreMachineFunctionInfo.h +++ b/lib/Target/XCore/XCoreMachineFunctionInfo.h @@ -31,7 +31,7 @@ private: int LRSpillSlot; int FPSpillSlot; int VarArgsFrameIndex; - std::vector<std::pair<unsigned, CalleeSavedInfo> > SpillLabels; + std::vector<std::pair<MCSymbol*, CalleeSavedInfo> > SpillLabels; public: XCoreFunctionInfo() : @@ -60,7 +60,7 @@ public: void setFPSpillSlot(int off) { FPSpillSlot = off; } int getFPSpillSlot() const { return FPSpillSlot; } - std::vector<std::pair<unsigned, CalleeSavedInfo> >&getSpillLabels() { + std::vector<std::pair<MCSymbol*, CalleeSavedInfo> > &getSpillLabels() { return SpillLabels; } }; diff --git a/lib/Target/XCore/XCoreRegisterInfo.cpp b/lib/Target/XCore/XCoreRegisterInfo.cpp index 0ab312eb2760..88925047ccd7 100644 --- a/lib/Target/XCore/XCoreRegisterInfo.cpp +++ b/lib/Target/XCore/XCoreRegisterInfo.cpp @@ -456,17 +456,17 @@ void XCoreRegisterInfo::emitPrologue(MachineFunction &MF) const { std::vector<MachineMove> &Moves = MMI->getFrameMoves(); // Show update of SP. - unsigned FrameLabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addImm(FrameLabelId); + MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addSym(FrameLabel); MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, -FrameSize * 4); - Moves.push_back(MachineMove(FrameLabelId, SPDst, SPSrc)); + Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc)); if (LRSavedOnEntry) { MachineLocation CSDst(MachineLocation::VirtualFP, 0); MachineLocation CSSrc(XCore::LR); - Moves.push_back(MachineMove(FrameLabelId, CSDst, CSSrc)); + Moves.push_back(MachineMove(FrameLabel, CSDst, CSSrc)); } } if (saveLR) { @@ -475,12 +475,11 @@ void XCoreRegisterInfo::emitPrologue(MachineFunction &MF) const { MBB.addLiveIn(XCore::LR); if (emitFrameMoves) { - unsigned SaveLRLabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addImm(SaveLRLabelId); + MCSymbol *SaveLRLabel = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addSym(SaveLRLabel); MachineLocation CSDst(MachineLocation::VirtualFP, LRSpillOffset); MachineLocation CSSrc(XCore::LR); - MMI->getFrameMoves().push_back(MachineMove(SaveLRLabelId, - CSDst, CSSrc)); + MMI->getFrameMoves().push_back(MachineMove(SaveLRLabel, CSDst, CSSrc)); } } } @@ -492,12 +491,11 @@ void XCoreRegisterInfo::emitPrologue(MachineFunction &MF) const { // R10 is live-in. It is killed at the spill. MBB.addLiveIn(XCore::R10); if (emitFrameMoves) { - unsigned SaveR10LabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addImm(SaveR10LabelId); + MCSymbol *SaveR10Label = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addSym(SaveR10Label); MachineLocation CSDst(MachineLocation::VirtualFP, FPSpillOffset); MachineLocation CSSrc(XCore::R10); - MMI->getFrameMoves().push_back(MachineMove(SaveR10LabelId, - CSDst, CSSrc)); + MMI->getFrameMoves().push_back(MachineMove(SaveR10Label, CSDst, CSSrc)); } // Set the FP from the SP. unsigned FramePtr = XCore::R10; @@ -505,21 +503,21 @@ void XCoreRegisterInfo::emitPrologue(MachineFunction &MF) const { .addImm(0); if (emitFrameMoves) { // Show FP is now valid. - unsigned FrameLabelId = MMI->NextLabelID(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addImm(FrameLabelId); + MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addSym(FrameLabel); MachineLocation SPDst(FramePtr); MachineLocation SPSrc(MachineLocation::VirtualFP); - MMI->getFrameMoves().push_back(MachineMove(FrameLabelId, SPDst, SPSrc)); + MMI->getFrameMoves().push_back(MachineMove(FrameLabel, SPDst, SPSrc)); } } if (emitFrameMoves) { // Frame moves for callee saved. std::vector<MachineMove> &Moves = MMI->getFrameMoves(); - std::vector<std::pair<unsigned, CalleeSavedInfo> >&SpillLabels = + std::vector<std::pair<MCSymbol*, CalleeSavedInfo> >&SpillLabels = XFI->getSpillLabels(); for (unsigned I = 0, E = SpillLabels.size(); I != E; ++I) { - unsigned SpillLabel = SpillLabels[I].first; + MCSymbol *SpillLabel = SpillLabels[I].first; CalleeSavedInfo &CSI = SpillLabels[I].second; int Offset = MFI->getObjectOffset(CSI.getFrameIdx()); unsigned Reg = CSI.getReg(); diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 0582210d4072..bdb46ebd1a64 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -751,120 +751,41 @@ static bool isSafeToEliminateVarargsCast(const CallSite CS, return true; } +namespace { +class InstCombineFortifiedLibCalls : public SimplifyFortifiedLibCalls { + InstCombiner *IC; +protected: + void replaceCall(Value *With) { + NewInstruction = IC->ReplaceInstUsesWith(*CI, With); + } + bool isFoldable(unsigned SizeCIOp, unsigned SizeArgOp, bool isString) const { + if (ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(SizeCIOp))) { + if (SizeCI->isAllOnesValue()) + return true; + if (isString) + return SizeCI->getZExtValue() >= + GetStringLength(CI->getOperand(SizeArgOp)); + if (ConstantInt *Arg = dyn_cast<ConstantInt>(CI->getOperand(SizeArgOp))) + return SizeCI->getZExtValue() <= Arg->getZExtValue(); + } + return false; + } +public: + InstCombineFortifiedLibCalls(InstCombiner *IC) : IC(IC), NewInstruction(0) { } + Instruction *NewInstruction; +}; +} // end anonymous namespace + // Try to fold some different type of calls here. // Currently we're only working with the checking functions, memcpy_chk, // mempcpy_chk, memmove_chk, memset_chk, strcpy_chk, stpcpy_chk, strncpy_chk, // strcat_chk and strncat_chk. Instruction *InstCombiner::tryOptimizeCall(CallInst *CI, const TargetData *TD) { if (CI->getCalledFunction() == 0) return 0; - - StringRef Name = CI->getCalledFunction()->getName(); - BasicBlock *BB = CI->getParent(); - IRBuilder<> B(CI->getParent()->getContext()); - - // Set the builder to the instruction after the call. - B.SetInsertPoint(BB, CI); - - if (Name == "__memcpy_chk") { - ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4)); - if (!SizeCI) - return 0; - ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3)); - if (!SizeArg) - return 0; - if (SizeCI->isAllOnesValue() || - SizeCI->getZExtValue() <= SizeArg->getZExtValue()) { - EmitMemCpy(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3), - 1, B, TD); - return ReplaceInstUsesWith(*CI, CI->getOperand(1)); - } - return 0; - } - - // Should be similar to memcpy. - if (Name == "__mempcpy_chk") { - return 0; - } - - if (Name == "__memmove_chk") { - ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4)); - if (!SizeCI) - return 0; - ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3)); - if (!SizeArg) - return 0; - if (SizeCI->isAllOnesValue() || - SizeCI->getZExtValue() <= SizeArg->getZExtValue()) { - EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3), - 1, B, TD); - return ReplaceInstUsesWith(*CI, CI->getOperand(1)); - } - return 0; - } - - if (Name == "__memset_chk") { - ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4)); - if (!SizeCI) - return 0; - ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3)); - if (!SizeArg) - return 0; - if (SizeCI->isAllOnesValue() || - SizeCI->getZExtValue() <= SizeArg->getZExtValue()) { - Value *Val = B.CreateIntCast(CI->getOperand(2), B.getInt8Ty(), - false); - EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B, TD); - return ReplaceInstUsesWith(*CI, CI->getOperand(1)); - } - return 0; - } - - if (Name == "__strcpy_chk") { - ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(3)); - if (!SizeCI) - return 0; - // If a) we don't have any length information, or b) we know this will - // fit then just lower to a plain strcpy. Otherwise we'll keep our - // strcpy_chk call which may fail at runtime if the size is too long. - // TODO: It might be nice to get a maximum length out of the possible - // string lengths for varying. - if (SizeCI->isAllOnesValue() || - SizeCI->getZExtValue() >= GetStringLength(CI->getOperand(2))) { - Value *Ret = EmitStrCpy(CI->getOperand(1), CI->getOperand(2), B, TD); - return ReplaceInstUsesWith(*CI, Ret); - } - return 0; - } - - // Should be similar to strcpy. - if (Name == "__stpcpy_chk") { - return 0; - } - if (Name == "__strncpy_chk") { - ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4)); - if (!SizeCI) - return 0; - ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3)); - if (!SizeArg) - return 0; - if (SizeCI->isAllOnesValue() || - SizeCI->getZExtValue() <= SizeArg->getZExtValue()) { - Value *Ret = EmitStrCpy(CI->getOperand(1), CI->getOperand(2), B, TD); - return ReplaceInstUsesWith(*CI, Ret); - } - return 0; - } - - if (Name == "__strcat_chk") { - return 0; - } - - if (Name == "__strncat_chk") { - return 0; - } - - return 0; + InstCombineFortifiedLibCalls Simplifier(this); + Simplifier.fold(CI, TD); + return Simplifier.NewInstruction; } // visitCallSite - Improvements for call and invoke instructions. diff --git a/lib/Transforms/Scalar/CodeGenPrepare.cpp b/lib/Transforms/Scalar/CodeGenPrepare.cpp index 7ceda1fa1f2c..50c96304db09 100644 --- a/lib/Transforms/Scalar/CodeGenPrepare.cpp +++ b/lib/Transforms/Scalar/CodeGenPrepare.cpp @@ -28,6 +28,7 @@ #include "llvm/Transforms/Utils/AddrModeMatcher.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" +#include "llvm/Transforms/Utils/BuildLibCalls.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Assembly/Writer.h" @@ -36,6 +37,7 @@ #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/PatternMatch.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/IRBuilder.h" using namespace llvm; using namespace llvm::PatternMatch; @@ -72,6 +74,7 @@ namespace { DenseMap<Value*,Value*> &SunkAddrs); bool OptimizeInlineAsmInst(Instruction *I, CallSite CS, DenseMap<Value*,Value*> &SunkAddrs); + bool OptimizeCallInst(CallInst *CI); bool MoveExtToFormExtLoad(Instruction *I); bool OptimizeExtUses(Instruction *I); void findLoopBackEdges(const Function &F); @@ -537,6 +540,47 @@ static bool OptimizeCmpExpression(CmpInst *CI) { return MadeChange; } +namespace { +class CodeGenPrepareFortifiedLibCalls : public SimplifyFortifiedLibCalls { +protected: + void replaceCall(Value *With) { + CI->replaceAllUsesWith(With); + CI->eraseFromParent(); + } + bool isFoldable(unsigned SizeCIOp, unsigned, bool) const { + if (ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(SizeCIOp))) + return SizeCI->isAllOnesValue(); + return false; + } +}; +} // end anonymous namespace + +bool CodeGenPrepare::OptimizeCallInst(CallInst *CI) { + // Lower all uses of llvm.objectsize.* + IntrinsicInst *II = dyn_cast<IntrinsicInst>(CI); + if (II && II->getIntrinsicID() == Intrinsic::objectsize) { + bool Min = (cast<ConstantInt>(II->getOperand(2))->getZExtValue() == 1); + const Type *ReturnTy = CI->getType(); + Constant *RetVal = ConstantInt::get(ReturnTy, Min ? 0 : -1ULL); + CI->replaceAllUsesWith(RetVal); + CI->eraseFromParent(); + return true; + } + + // From here on out we're working with named functions. + if (CI->getCalledFunction() == 0) return false; + + // We'll need TargetData from here on out. + const TargetData *TD = TLI ? TLI->getTargetData() : 0; + if (!TD) return false; + + // Lower all default uses of _chk calls. This is very similar + // to what InstCombineCalls does, but here we are only lowering calls + // that have the default "don't know" as the objectsize. Anything else + // should be left alone. + CodeGenPrepareFortifiedLibCalls Simplifier; + return Simplifier.fold(CI, TD); +} //===----------------------------------------------------------------------===// // Memory Optimization //===----------------------------------------------------------------------===// @@ -913,6 +957,10 @@ bool CodeGenPrepare::OptimizeBlock(BasicBlock &BB) { } else // Sink address computing for memory operands into the block. MadeChange |= OptimizeInlineAsmInst(I, &(*CI), SunkAddrs); + } else { + // Other CallInst optimizations that don't need to muck with the + // enclosing iterator here. + MadeChange |= OptimizeCallInst(CI); } } } diff --git a/lib/Transforms/Scalar/IndVarSimplify.cpp b/lib/Transforms/Scalar/IndVarSimplify.cpp index cb563c3a7d03..de93e9f621fe 100644 --- a/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -43,6 +43,7 @@ #include "llvm/BasicBlock.h" #include "llvm/Constants.h" #include "llvm/Instructions.h" +#include "llvm/IntrinsicInst.h" #include "llvm/LLVMContext.h" #include "llvm/Type.h" #include "llvm/Analysis/Dominators.h" @@ -215,7 +216,7 @@ ICmpInst *IndVarSimplify::LinearFunctionTestReplace(Loop *L, void IndVarSimplify::RewriteLoopExitValues(Loop *L, SCEVExpander &Rewriter) { // Verify the input to the pass in already in LCSSA form. - assert(L->isLCSSAForm()); + assert(L->isLCSSAForm(*DT)); SmallVector<BasicBlock*, 8> ExitBlocks; L->getUniqueExitBlocks(ExitBlocks); @@ -445,7 +446,7 @@ bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) { // Clean up dead instructions. Changed |= DeleteDeadPHIs(L->getHeader()); // Check a post-condition. - assert(L->isLCSSAForm() && "Indvars did not leave the loop in lcssa form!"); + assert(L->isLCSSAForm(*DT) && "Indvars did not leave the loop in lcssa form!"); return Changed; } @@ -556,6 +557,9 @@ void IndVarSimplify::SinkUnusedInvariants(Loop *L) { // dominates the exit block. if (I->mayHaveSideEffects() || I->mayReadFromMemory()) continue; + // Skip debug info intrinsics. + if (isa<DbgInfoIntrinsic>(I)) + continue; // Don't sink static AllocaInsts out of the entry block, which would // turn them into dynamic allocas! if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) diff --git a/lib/Transforms/Scalar/LoopUnrollPass.cpp b/lib/Transforms/Scalar/LoopUnrollPass.cpp index a355ec3a7e68..4ad41ae4b59f 100644 --- a/lib/Transforms/Scalar/LoopUnrollPass.cpp +++ b/lib/Transforms/Scalar/LoopUnrollPass.cpp @@ -86,7 +86,6 @@ static unsigned ApproximateLoopSize(const Loop *L, unsigned &NumCalls) { } bool LoopUnroll::runOnLoop(Loop *L, LPPassManager &LPM) { - assert(L->isLCSSAForm()); LoopInfo *LI = &getAnalysis<LoopInfo>(); BasicBlock *Header = L->getHeader(); diff --git a/lib/Transforms/Scalar/LoopUnswitch.cpp b/lib/Transforms/Scalar/LoopUnswitch.cpp index 071e9b7c9e97..e3b809e35d4c 100644 --- a/lib/Transforms/Scalar/LoopUnswitch.cpp +++ b/lib/Transforms/Scalar/LoopUnswitch.cpp @@ -206,7 +206,7 @@ bool LoopUnswitch::runOnLoop(Loop *L, LPPassManager &LPM_Ref) { Function *F = currentLoop->getHeader()->getParent(); bool Changed = false; do { - assert(currentLoop->isLCSSAForm()); + assert(currentLoop->isLCSSAForm(*DT)); redoLoop = false; Changed |= processCurrentLoop(); } while(redoLoop); diff --git a/lib/Transforms/Scalar/Scalar.cpp b/lib/Transforms/Scalar/Scalar.cpp index b54565cb80ec..cb034232df53 100644 --- a/lib/Transforms/Scalar/Scalar.cpp +++ b/lib/Transforms/Scalar/Scalar.cpp @@ -14,6 +14,8 @@ #include "llvm-c/Transforms/Scalar.h" #include "llvm/PassManager.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Target/TargetData.h" #include "llvm/Transforms/Scalar.h" using namespace llvm; @@ -90,6 +92,11 @@ void LLVMAddScalarReplAggregatesPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createScalarReplAggregatesPass()); } +void LLVMAddScalarReplAggregatesPassWithThreshold(LLVMPassManagerRef PM, + int Threshold) { + unwrap(PM)->add(createScalarReplAggregatesPass(Threshold)); +} + void LLVMAddSimplifyLibCallsPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createSimplifyLibCallsPass()); } @@ -105,3 +112,7 @@ void LLVMAddConstantPropagationPass(LLVMPassManagerRef PM) { void LLVMAddDemoteMemoryToRegisterPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createDemoteRegisterToMemoryPass()); } + +void LLVMAddVerifierPass(LLVMPassManagerRef PM) { + unwrap(PM)->add(createVerifierPass()); +} diff --git a/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/lib/Transforms/Scalar/SimplifyCFGPass.cpp index 62f34a2ee068..738c5e8d13d1 100644 --- a/lib/Transforms/Scalar/SimplifyCFGPass.cpp +++ b/lib/Transforms/Scalar/SimplifyCFGPass.cpp @@ -26,6 +26,7 @@ #include "llvm/Transforms/Utils/Local.h" #include "llvm/Constants.h" #include "llvm/Instructions.h" +#include "llvm/IntrinsicInst.h" #include "llvm/Module.h" #include "llvm/Attributes.h" #include "llvm/Support/CFG.h" @@ -210,12 +211,16 @@ static bool MergeEmptyReturnBlocks(Function &F) { // Check for something else in the block. BasicBlock::iterator I = Ret; --I; - if (!isa<PHINode>(I) || I != BB.begin() || - Ret->getNumOperands() == 0 || - Ret->getOperand(0) != I) + // Skip over debug info. + while (isa<DbgInfoIntrinsic>(I) && I != BB.begin()) + --I; + if (!isa<DbgInfoIntrinsic>(I) && + (!isa<PHINode>(I) || I != BB.begin() || + Ret->getNumOperands() == 0 || + Ret->getOperand(0) != I)) continue; } - + // If this is the first returning block, remember it and keep going. if (RetBlock == 0) { RetBlock = &BB; @@ -239,7 +244,7 @@ static bool MergeEmptyReturnBlocks(Function &F) { // If the canonical return block has no PHI node, create one now. PHINode *RetBlockPHI = dyn_cast<PHINode>(RetBlock->begin()); if (RetBlockPHI == 0) { - Value *InVal = cast<ReturnInst>(RetBlock->begin())->getOperand(0); + Value *InVal = cast<ReturnInst>(RetBlock->getTerminator())->getOperand(0); RetBlockPHI = PHINode::Create(Ret->getOperand(0)->getType(), "merge", &RetBlock->front()); diff --git a/lib/Transforms/Utils/BuildLibCalls.cpp b/lib/Transforms/Utils/BuildLibCalls.cpp index 2ea4bb6dc98c..b44f01976044 100644 --- a/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/lib/Transforms/Utils/BuildLibCalls.cpp @@ -72,21 +72,41 @@ Value *llvm::EmitStrChr(Value *Ptr, char C, IRBuilder<> &B, /// EmitStrCpy - Emit a call to the strcpy function to the builder, for the /// specified pointer arguments. Value *llvm::EmitStrCpy(Value *Dst, Value *Src, IRBuilder<> &B, - const TargetData *TD) { + const TargetData *TD, StringRef Name) { Module *M = B.GetInsertBlock()->getParent()->getParent(); AttributeWithIndex AWI[2]; AWI[0] = AttributeWithIndex::get(2, Attribute::NoCapture); AWI[1] = AttributeWithIndex::get(~0u, Attribute::NoUnwind); const Type *I8Ptr = B.getInt8PtrTy(); - Value *StrCpy = M->getOrInsertFunction("strcpy", AttrListPtr::get(AWI, 2), + Value *StrCpy = M->getOrInsertFunction(Name, AttrListPtr::get(AWI, 2), I8Ptr, I8Ptr, I8Ptr, NULL); CallInst *CI = B.CreateCall2(StrCpy, CastToCStr(Dst, B), CastToCStr(Src, B), - "strcpy"); + Name); if (const Function *F = dyn_cast<Function>(StrCpy->stripPointerCasts())) CI->setCallingConv(F->getCallingConv()); return CI; } +/// EmitStrNCpy - Emit a call to the strncpy function to the builder, for the +/// specified pointer arguments. +Value *llvm::EmitStrNCpy(Value *Dst, Value *Src, Value *Len, + IRBuilder<> &B, const TargetData *TD) { + Module *M = B.GetInsertBlock()->getParent()->getParent(); + AttributeWithIndex AWI[2]; + AWI[0] = AttributeWithIndex::get(2, Attribute::NoCapture); + AWI[1] = AttributeWithIndex::get(~0u, Attribute::NoUnwind); + const Type *I8Ptr = B.getInt8PtrTy(); + Value *StrNCpy = M->getOrInsertFunction("strncpy", AttrListPtr::get(AWI, 2), + I8Ptr, I8Ptr, I8Ptr, + Len->getType(), NULL); + CallInst *CI = B.CreateCall3(StrNCpy, CastToCStr(Dst, B), CastToCStr(Src, B), + Len, "strncpy"); + if (const Function *F = dyn_cast<Function>(StrNCpy->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + return CI; +} + + /// EmitMemCpy - Emit a call to the memcpy function to the builder. This always /// expects that the size has type 'intptr_t' and Dst/Src are pointers. Value *llvm::EmitMemCpy(Value *Dst, Value *Src, Value *Len, @@ -322,3 +342,86 @@ void llvm::EmitFWrite(Value *Ptr, Value *Size, Value *File, if (const Function *Fn = dyn_cast<Function>(F->stripPointerCasts())) CI->setCallingConv(Fn->getCallingConv()); } + +SimplifyFortifiedLibCalls::~SimplifyFortifiedLibCalls() { } + +bool SimplifyFortifiedLibCalls::fold(CallInst *CI, const TargetData *TD) { + this->CI = CI; + StringRef Name = CI->getCalledFunction()->getName(); + BasicBlock *BB = CI->getParent(); + IRBuilder<> B(CI->getParent()->getContext()); + + // Set the builder to the instruction after the call. + B.SetInsertPoint(BB, CI); + + if (Name == "__memcpy_chk") { + if (isFoldable(4, 3, false)) { + EmitMemCpy(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3), + 1, B, TD); + replaceCall(CI->getOperand(1)); + return true; + } + return false; + } + + // Should be similar to memcpy. + if (Name == "__mempcpy_chk") { + return false; + } + + if (Name == "__memmove_chk") { + if (isFoldable(4, 3, false)) { + EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3), + 1, B, TD); + replaceCall(CI->getOperand(1)); + return true; + } + return false; + } + + if (Name == "__memset_chk") { + if (isFoldable(4, 3, false)) { + Value *Val = B.CreateIntCast(CI->getOperand(2), B.getInt8Ty(), + false); + EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B, TD); + replaceCall(CI->getOperand(1)); + return true; + } + return false; + } + + if (Name == "__strcpy_chk" || Name == "__stpcpy_chk") { + // If a) we don't have any length information, or b) we know this will + // fit then just lower to a plain st[rp]cpy. Otherwise we'll keep our + // st[rp]cpy_chk call which may fail at runtime if the size is too long. + // TODO: It might be nice to get a maximum length out of the possible + // string lengths for varying. + if (isFoldable(3, 2, true)) { + Value *Ret = EmitStrCpy(CI->getOperand(1), CI->getOperand(2), B, TD, + Name.substr(2, 6)); + replaceCall(Ret); + return true; + } + return false; + } + + if (Name == "__strncpy_chk") { + if (isFoldable(4, 3, false)) { + Value *Ret = EmitStrNCpy(CI->getOperand(1), CI->getOperand(2), + CI->getOperand(3), B, TD); + replaceCall(Ret); + return true; + } + return false; + } + + if (Name == "__strcat_chk") { + return false; + } + + if (Name == "__strncat_chk") { + return false; + } + + return false; +} diff --git a/lib/Transforms/Utils/LCSSA.cpp b/lib/Transforms/Utils/LCSSA.cpp index 590d667a1aa3..df6e603c0ba2 100644 --- a/lib/Transforms/Utils/LCSSA.cpp +++ b/lib/Transforms/Utils/LCSSA.cpp @@ -88,7 +88,7 @@ namespace { /// verifyAnalysis() - Verify loop nest. virtual void verifyAnalysis() const { // Check the special guarantees that LCSSA makes. - assert(L->isLCSSAForm() && "LCSSA form not preserved!"); + assert(L->isLCSSAForm(*DT) && "LCSSA form not preserved!"); } /// inLoop - returns true if the given block is within the current loop @@ -164,7 +164,7 @@ bool LCSSA::runOnLoop(Loop *TheLoop, LPPassManager &LPM) { } } - assert(L->isLCSSAForm()); + assert(L->isLCSSAForm(*DT)); PredCache.clear(); return MadeChange; diff --git a/lib/Transforms/Utils/LoopSimplify.cpp b/lib/Transforms/Utils/LoopSimplify.cpp index 584ec143669f..1ef3c32ae58f 100644 --- a/lib/Transforms/Utils/LoopSimplify.cpp +++ b/lib/Transforms/Utils/LoopSimplify.cpp @@ -41,6 +41,7 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Constants.h" #include "llvm/Instructions.h" +#include "llvm/IntrinsicInst.h" #include "llvm/Function.h" #include "llvm/LLVMContext.h" #include "llvm/Type.h" @@ -290,6 +291,9 @@ ReprocessLoop: bool AllInvariant = true; for (BasicBlock::iterator I = ExitingBlock->begin(); &*I != BI; ) { Instruction *Inst = I++; + // Skip debug info intrinsics. + if (isa<DbgInfoIntrinsic>(Inst)) + continue; if (Inst == CI) continue; if (!L->makeLoopInvariant(Inst, Changed, diff --git a/lib/Transforms/Utils/LoopUnroll.cpp b/lib/Transforms/Utils/LoopUnroll.cpp index e47c86d23b3d..ac59b4d7b3e8 100644 --- a/lib/Transforms/Utils/LoopUnroll.cpp +++ b/lib/Transforms/Utils/LoopUnroll.cpp @@ -105,8 +105,6 @@ static BasicBlock *FoldBlockIntoPredecessor(BasicBlock *BB, LoopInfo* LI) { /// If a LoopPassManager is passed in, and the loop is fully removed, it will be /// removed from the LoopPassManager as well. LPM can also be NULL. bool llvm::UnrollLoop(Loop *L, unsigned Count, LoopInfo* LI, LPPassManager* LPM) { - assert(L->isLCSSAForm()); - BasicBlock *Preheader = L->getLoopPreheader(); if (!Preheader) { DEBUG(dbgs() << " Can't unroll; loop preheader-insertion failed.\n"); @@ -370,9 +368,5 @@ bool llvm::UnrollLoop(Loop *L, unsigned Count, LoopInfo* LI, LPPassManager* LPM) if (CompletelyUnroll && LPM != NULL) LPM->deleteLoopFromQueue(L); - // If we didn't completely unroll the loop, it should still be in LCSSA form. - if (!CompletelyUnroll) - assert(L->isLCSSAForm()); - return true; } diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index f343c3811da2..2ce5bdcd61d4 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1826,7 +1826,7 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { // switch. if (BasicBlock *OnlyPred = BB->getSinglePredecessor()) if (SimplifyEqualityComparisonWithOnlyPredecessor(BI, OnlyPred)) - return SimplifyCFG(BB) || 1; + return SimplifyCFG(BB) | true; // This block must be empty, except for the setcond inst, if it exists. // Ignore dbg intrinsics. @@ -1860,7 +1860,7 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { // branches to us and one of our successors, fold the setcc into the // predecessor and use logical operations to pick the right destination. if (FoldBranchToCommonDest(BI)) - return SimplifyCFG(BB) | 1; + return SimplifyCFG(BB) | true; // Scan predecessor blocks for conditional branches. diff --git a/lib/VMCore/IntrinsicInst.cpp b/lib/VMCore/IntrinsicInst.cpp index d8f015a9e2c7..c37d5b03cdc8 100644 --- a/lib/VMCore/IntrinsicInst.cpp +++ b/lib/VMCore/IntrinsicInst.cpp @@ -24,8 +24,7 @@ #include "llvm/IntrinsicInst.h" #include "llvm/Constants.h" #include "llvm/GlobalVariable.h" -#include "llvm/Analysis/ValueTracking.h" -#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/Metadata.h" using namespace llvm; //===----------------------------------------------------------------------===// diff --git a/lib/VMCore/LLVMContextImpl.h b/lib/VMCore/LLVMContextImpl.h index 9887f28821ca..9978f40ed0da 100644 --- a/lib/VMCore/LLVMContextImpl.h +++ b/lib/VMCore/LLVMContextImpl.h @@ -105,6 +105,11 @@ public: StringMap<MDString*> MDStringCache; FoldingSet<MDNode> MDNodeSet; + // MDNodes may be uniqued or not uniqued. When they're not uniqued, they + // aren't in the MDNodeSet, but they're still shared between objects, so no + // one object can destroy them. This set allows us to at least destroy them + // on Context destruction. + SmallPtrSet<MDNode*, 1> NonUniquedMDNodes; ConstantUniqueMap<char, Type, ConstantAggregateZero> AggZeroConstants; @@ -235,17 +240,21 @@ public: (*I)->AbstractTypeUsers.clear(); delete *I; } - // Destroy MDNode operands first. + // Destroy MDNodes. ~MDNode can move and remove nodes between the MDNodeSet + // and the NonUniquedMDNodes sets, so copy the values out first. + SmallVector<MDNode*, 8> MDNodes; + MDNodes.reserve(MDNodeSet.size() + NonUniquedMDNodes.size()); for (FoldingSetIterator<MDNode> I = MDNodeSet.begin(), E = MDNodeSet.end(); - I != E;) { - MDNode *N = &(*I); - ++I; - N->replaceAllOperandsWithNull(); + I != E; ++I) { + MDNodes.push_back(&*I); } - while (!MDNodeSet.empty()) { - MDNode *N = &(*MDNodeSet.begin()); - N->destroy(); + MDNodes.append(NonUniquedMDNodes.begin(), NonUniquedMDNodes.end()); + for (SmallVector<MDNode*, 8>::iterator I = MDNodes.begin(), + E = MDNodes.end(); I != E; ++I) { + (*I)->destroy(); } + assert(MDNodeSet.empty() && NonUniquedMDNodes.empty() && + "Destroying all MDNodes didn't empty the Context's sets."); // Destroy MDStrings. for (StringMap<MDString*>::iterator I = MDStringCache.begin(), E = MDStringCache.end(); I != E; ++I) { diff --git a/lib/VMCore/Metadata.cpp b/lib/VMCore/Metadata.cpp index 379aeb540a18..06d4fd4ae5c6 100644 --- a/lib/VMCore/Metadata.cpp +++ b/lib/VMCore/Metadata.cpp @@ -101,8 +101,10 @@ MDNode::MDNode(LLVMContext &C, Value *const *Vals, unsigned NumVals, MDNode::~MDNode() { assert((getSubclassDataFromValue() & DestroyFlag) != 0 && "Not being destroyed through destroy()?"); - if (!isNotUniqued()) { - LLVMContextImpl *pImpl = getType()->getContext().pImpl; + LLVMContextImpl *pImpl = getType()->getContext().pImpl; + if (isNotUniqued()) { + pImpl->NonUniquedMDNodes.erase(this); + } else { pImpl->MDNodeSet.RemoveNode(this); } @@ -248,12 +250,10 @@ void MDNode::Profile(FoldingSetNodeID &ID) const { ID.AddPointer(getOperand(i)); } -// replaceAllOperandsWithNull - This is used while destroying llvm context to -// gracefully delete all nodes. This method replaces all operands with null. -void MDNode::replaceAllOperandsWithNull() { - for (MDNodeOperand *Op = getOperandPtr(this, 0), *E = Op+NumOperands; - Op != E; ++Op) - replaceOperand(Op, 0); +void MDNode::setIsNotUniqued() { + setValueSubclassData(getSubclassDataFromValue() | NotUniquedBit); + LLVMContextImpl *pImpl = getType()->getContext().pImpl; + pImpl->NonUniquedMDNodes.insert(this); } // Replace value from this node's operand list. diff --git a/lib/VMCore/Type.cpp b/lib/VMCore/Type.cpp index 9b2c2cab81fb..2a0cfa8470ea 100644 --- a/lib/VMCore/Type.cpp +++ b/lib/VMCore/Type.cpp @@ -87,6 +87,11 @@ void Type::destroy() const { pImpl->OpaqueTypes.erase(opaque_this); } + if (ForwardType && ForwardType->isAbstract()) { + ForwardType->dropRef(); + ForwardType = NULL; + } + // For all the other type subclasses, there is either no contained types or // just one (all Sequentials). For Sequentials, the PATypeHandle is not // allocated past the type object, its included directly in the SequentialType @@ -254,10 +259,12 @@ const Type *Type::getForwardedTypeInternal() const { // Yes, it is forwarded again. First thing, add the reference to the new // forward type. if (RealForwardedType->isAbstract()) - cast<DerivedType>(RealForwardedType)->addRef(); + RealForwardedType->addRef(); // Now drop the old reference. This could cause ForwardType to get deleted. - cast<DerivedType>(ForwardType)->dropRef(); + // ForwardType must be abstract because only abstract types can have their own + // ForwardTypes. + ForwardType->dropRef(); // Return the updated type. ForwardType = RealForwardedType; @@ -1142,8 +1149,8 @@ void DerivedType::unlockedRefineAbstractTypeTo(const Type *NewType) { // Any PATypeHolders referring to this type will now automatically forward to // the type we are resolved to. ForwardType = NewType; - if (NewType->isAbstract()) - cast<DerivedType>(NewType)->addRef(); + if (ForwardType->isAbstract()) + ForwardType->addRef(); // Add a self use of the current type so that we don't delete ourself until // after the function exits. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5ad48eff4e7d..ab060c91a582 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -7,6 +7,21 @@ set(TARGETS_TO_BUILD ${TARGETS_BUILT}) set(LLVM_LIBS_DIR "${LLVM_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}") set(SHLIBEXT "${LTDL_SHLIB_EXT}") +if(BUILD_SHARED_LIBS) + set(LLVM_SHARED_LIBS_ENABLED "1") +else() + set(LLVM_SHARED_LIBS_ENABLED "0") +endif(BUILD_SHARED_LIBS) + +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(SHLIBPATH_VAR "DYLD_LIBRARY_PATH") +else() # Default for all other unix like systems. + # CMake hardcodes the library locaction using rpath. + # Therefore LD_LIBRARY_PATH is not required to run binaries in the + # build dir. We pass it anyways. + set(SHLIBPATH_VAR "LD_LIBRARY_PATH") +endif() + include(FindPythonInterp) if(PYTHONINTERP_FOUND) configure_file( @@ -27,6 +42,8 @@ if(PYTHONINTERP_FOUND) -e "s#\@LLVM_TOOLS_DIR\@#${LLVM_TOOLS_BINARY_DIR}/${CMAKE_CFG_INTDIR}#" -e "s#\@LLVMGCCDIR\@##" -e "s#\@LLVM_BUILD_MODE\@#${CMAKE_CFG_INTDIR}#" + -e "s#\@ENABLE_SHARED\@#${LLVM_SHARED_LIBS_ENABLED}#" + -e "s#\@SHLIBPATH_VAR\@#${SHLIBPATH_VAR}#" ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in > ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg COMMAND ${PYTHON_EXECUTABLE} diff --git a/test/CodeGen/ARM/fp16.ll b/test/CodeGen/ARM/fp16.ll new file mode 100644 index 000000000000..c5583b94befd --- /dev/null +++ b/test/CodeGen/ARM/fp16.ll @@ -0,0 +1,32 @@ +; RUN: llc < %s | FileCheck %s +; RUN: llc -mattr=+vfp3,+fp16 < %s | FileCheck --check-prefix=CHECK-FP16 %s +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n32" +target triple = "armv7-eabi" + +@x = global i16 12902 +@y = global i16 0 +@z = common global i16 0 + +define arm_aapcs_vfpcc void @foo() nounwind { +; CHECK: foo: +; CHECK-FP6: foo: +entry: + %0 = load i16* @x, align 2 + %1 = load i16* @y, align 2 + %2 = tail call float @llvm.convert.from.fp16(i16 %0) +; CHECK: __gnu_h2f_ieee +; CHECK-FP16: vcvtb.f16.f32 + %3 = tail call float @llvm.convert.from.fp16(i16 %1) +; CHECK: __gnu_h2f_ieee +; CHECK-FP16: vcvtb.f16.f32 + %4 = fadd float %2, %3 + %5 = tail call i16 @llvm.convert.to.fp16(float %4) +; CHECK: __gnu_f2h_ieee +; CHECK-FP16: vcvtb.f32.f16 + store i16 %5, i16* @x, align 2 + ret void +} + +declare float @llvm.convert.from.fp16(i16) nounwind readnone + +declare i16 @llvm.convert.to.fp16(float) nounwind readnone diff --git a/test/CodeGen/ARM/indirectbr.ll b/test/CodeGen/ARM/indirectbr.ll index f05033773bb5..f898060581a9 100644 --- a/test/CodeGen/ARM/indirectbr.ll +++ b/test/CodeGen/ARM/indirectbr.ll @@ -59,6 +59,6 @@ L1: ; preds = %L2, %bb2 store i8* blockaddress(@foo, %L5), i8** @nextaddr, align 4 ret i32 %res.3 } -; ARM: .long L_BA4__foo_L5-(LPC{{.*}}+8) -; THUMB: .long L_BA4__foo_L5-(LPC{{.*}}+4) -; THUMB2: .long L_BA4__foo_L5 +; ARM: .long Ltmp0-(LPC{{.*}}+8) +; THUMB: .long Ltmp0-(LPC{{.*}}+4) +; THUMB2: .long Ltmp0 diff --git a/test/CodeGen/Generic/2007-04-13-SwitchLowerBadPhi.ll b/test/CodeGen/Generic/2007-04-13-SwitchLowerBadPhi.ll index a0b1403cf8d1..9c3c804aa754 100644 --- a/test/CodeGen/Generic/2007-04-13-SwitchLowerBadPhi.ll +++ b/test/CodeGen/Generic/2007-04-13-SwitchLowerBadPhi.ll @@ -1,9 +1,6 @@ ; RUN: llc < %s -O0 ; PR 1323 -; ModuleID = 'test.bc' -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64" -target triple = "i686-apple-darwin8" %struct.comp = type { i8*, i32, i8*, [3 x i8], i32 } define void @regbranch() { diff --git a/test/CodeGen/Generic/2007-11-21-UndeadIllegalNode.ll b/test/CodeGen/Generic/2007-11-21-UndeadIllegalNode.ll index e220be6389dc..3090857d9649 100644 --- a/test/CodeGen/Generic/2007-11-21-UndeadIllegalNode.ll +++ b/test/CodeGen/Generic/2007-11-21-UndeadIllegalNode.ll @@ -1,7 +1,5 @@ ; RUN: llc < %s -o - -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32" -target triple = "i686-pc-linux-gnu" %struct.RETURN = type { i32, i32 } %struct.ada__finalization__controlled = type { %struct.system__finalization_root__root_controlled } %struct.ada__streams__root_stream_type = type { %struct.ada__tags__dispatch_table* } diff --git a/test/CodeGen/Generic/2007-12-17-InvokeAsm.ll b/test/CodeGen/Generic/2007-12-17-InvokeAsm.ll index bd26481bd306..4cc1e7c181ed 100644 --- a/test/CodeGen/Generic/2007-12-17-InvokeAsm.ll +++ b/test/CodeGen/Generic/2007-12-17-InvokeAsm.ll @@ -1,7 +1,5 @@ ; RUN: llc < %s -enable-eh -target triple = "i686-pc-linux-gnu" - define fastcc void @bc__support__high_resolution_time__initialize_clock_rate() { entry: invoke void asm "rdtsc\0A\09movl %eax, $0\0A\09movl %edx, $1", "=*imr,=*imr,~{dirflag},~{fpsr},~{flags},~{dx},~{ax}"( i32* null, i32* null ) diff --git a/test/CodeGen/Generic/2007-12-31-UnusedSelector.ll b/test/CodeGen/Generic/2007-12-31-UnusedSelector.ll index fc9164f7c4aa..d2e97a477b44 100644 --- a/test/CodeGen/Generic/2007-12-31-UnusedSelector.ll +++ b/test/CodeGen/Generic/2007-12-31-UnusedSelector.ll @@ -1,8 +1,6 @@ ; RUN: llc < %s -enable-eh ; PR1833 -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32" -target triple = "i686-pc-linux-gnu" %struct.__class_type_info_pseudo = type { %struct.__type_info_pseudo } %struct.__type_info_pseudo = type { i8*, i8* } @_ZTI2e1 = external constant %struct.__class_type_info_pseudo ; <%struct.__class_type_info_pseudo*> [#uses=1] diff --git a/test/CodeGen/Generic/2008-08-07-PtrToInt-SmallerInt.ll b/test/CodeGen/Generic/2008-08-07-PtrToInt-SmallerInt.ll index 4f95dfe8a730..00ca8c756b42 100644 --- a/test/CodeGen/Generic/2008-08-07-PtrToInt-SmallerInt.ll +++ b/test/CodeGen/Generic/2008-08-07-PtrToInt-SmallerInt.ll @@ -1,7 +1,5 @@ ; RUN: llc < %s ; PR2603 -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32" -target triple = "i386-pc-linux-gnu" %struct.A = type { i8 } %struct.B = type { i8, [1 x i8] } @Foo = constant %struct.A { i8 ptrtoint (i8* getelementptr ([1 x i8]* inttoptr (i32 17 to [1 x i8]*), i32 0, i32 -16) to i8) } ; <%struct.A*> [#uses=0] diff --git a/test/CodeGen/Generic/2009-11-16-BadKillsCrash.ll b/test/CodeGen/Generic/2009-11-16-BadKillsCrash.ll index a51c75d62224..22bd4d7e6a41 100644 --- a/test/CodeGen/Generic/2009-11-16-BadKillsCrash.ll +++ b/test/CodeGen/Generic/2009-11-16-BadKillsCrash.ll @@ -1,7 +1,5 @@ ; RUN: llc < %s ; PR5495 -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32" -target triple = "i386-pc-linux-gnu" %"struct.std::__ctype_abstract_base<wchar_t>" = type { %"struct.std::locale::facet" } %"struct.std::basic_ios<char,std::char_traits<char> >" = type { %"struct.std::ios_base", %"struct.std::basic_ostream<char,std::char_traits<char> >"*, i8, i8, %"struct.std::basic_streambuf<char,std::char_traits<char> >"*, %"struct.std::ctype<char>"*, %"struct.std::__ctype_abstract_base<wchar_t>"*, %"struct.std::__ctype_abstract_base<wchar_t>"* } diff --git a/test/CodeGen/Generic/GC/redundant_init.ll b/test/CodeGen/Generic/GC/redundant_init.ll deleted file mode 100644 index 10c70e731052..000000000000 --- a/test/CodeGen/Generic/GC/redundant_init.ll +++ /dev/null @@ -1,17 +0,0 @@ -; RUN: llc < %s -march=x86 | \ -; RUN: ignore grep {movl..0} | count 0 - -%struct.obj = type { i8*, %struct.obj* } - -declare void @g() gc "shadow-stack" - -define void @f(i8* %o) gc "shadow-stack" { -entry: - %root = alloca i8* - call void @llvm.gcroot(i8** %root, i8* null) - store i8* %o, i8** %root - call void @g() - ret void -} - -declare void @llvm.gcroot(i8**, i8*) diff --git a/test/CodeGen/Generic/addr-label.ll b/test/CodeGen/Generic/addr-label.ll new file mode 100644 index 000000000000..51741110e072 --- /dev/null +++ b/test/CodeGen/Generic/addr-label.ll @@ -0,0 +1,58 @@ +; RUN: llc %s -o - + +;; Reference to a label that gets deleted. +define i8* @test1() nounwind { +entry: + ret i8* blockaddress(@test1b, %test_label) +} + +define i32 @test1b() nounwind { +entry: + ret i32 -1 +test_label: + br label %ret +ret: + ret i32 -1 +} + + +;; Issues with referring to a label that gets RAUW'd later. +define i32 @test2a() nounwind { +entry: + %target = bitcast i8* blockaddress(@test2b, %test_label) to i8* + + call i32 @test2b(i8* %target) + + ret i32 0 +} + +define i32 @test2b(i8* %target) nounwind { +entry: + indirectbr i8* %target, [label %test_label] + +test_label: +; assume some code here... + br label %ret + +ret: + ret i32 -1 +} + +; Issues with a BB that gets RAUW'd to another one after references are +; generated. +define void @test3(i8** %P, i8** %Q) nounwind { +entry: + store i8* blockaddress(@test3b, %test_label), i8** %P + store i8* blockaddress(@test3b, %ret), i8** %Q + ret void +} + +define i32 @test3b() nounwind { +entry: + br label %test_label +test_label: + br label %ret +ret: + ret i32 -1 +} + diff --git a/test/CodeGen/PowerPC/2008-10-31-PPCF128Libcalls.ll b/test/CodeGen/PowerPC/2008-10-31-PPCF128Libcalls.ll index 20683b9019e0..8322a8430815 100644 --- a/test/CodeGen/PowerPC/2008-10-31-PPCF128Libcalls.ll +++ b/test/CodeGen/PowerPC/2008-10-31-PPCF128Libcalls.ll @@ -35,3 +35,10 @@ declare ppc_fp128 @"\01_sinl$LDBL128"(ppc_fp128) nounwind readonly declare ppc_fp128 @"\01_cosl$LDBL128"(ppc_fp128) nounwind readonly declare ppc_fp128 @llvm.pow.ppcf128(ppc_fp128, ppc_fp128) nounwind readonly + +declare ppc_fp128 @copysignl(ppc_fp128, ppc_fp128) + +define ppc_fp128 @cs(ppc_fp128 %from, ppc_fp128 %to) { + %tmp = call ppc_fp128 @copysignl(ppc_fp128 %from, ppc_fp128 %to) + ret ppc_fp128 %tmp +} diff --git a/test/CodeGen/PowerPC/indirectbr.ll b/test/CodeGen/PowerPC/indirectbr.ll index 233d923695af..9b76ecc43db9 100644 --- a/test/CodeGen/PowerPC/indirectbr.ll +++ b/test/CodeGen/PowerPC/indirectbr.ll @@ -43,12 +43,12 @@ L2: ; preds = %L3, %bb2 L1: ; preds = %L2, %bb2 %res.3 = phi i32 [ %phitmp, %L2 ], [ 2, %bb2 ] ; <i32> [#uses=1] -; PIC: addis r4, r4, ha16(L_BA4__foo_L5-"L1$pb") -; PIC: li r6, lo16(L_BA4__foo_L5-"L1$pb") +; PIC: addis r4, r4, ha16(Ltmp0-"L1$pb") +; PIC: li r6, lo16(Ltmp0-"L1$pb") ; PIC: add r4, r4, r6 ; PIC: stw r4 -; STATIC: li r5, lo16(L_BA4__foo_L5) -; STATIC: addis r5, r5, ha16(L_BA4__foo_L5) +; STATIC: li r5, lo16(Ltmp0) +; STATIC: addis r5, r5, ha16(Ltmp0) ; STATIC: stw r5 store i8* blockaddress(@foo, %L5), i8** @nextaddr, align 4 ret i32 %res.3 diff --git a/test/CodeGen/PowerPC/ppc-prologue.ll b/test/CodeGen/PowerPC/ppc-prologue.ll index e49dcb82c60d..2ebfd3c319fc 100644 --- a/test/CodeGen/PowerPC/ppc-prologue.ll +++ b/test/CodeGen/PowerPC/ppc-prologue.ll @@ -5,9 +5,9 @@ define i32 @_Z4funci(i32 %a) ssp { ; CHECK-NEXT: stw r31, -4(r1) ; CHECK-NEXT: stw r0, 8(r1) ; CHECK-NEXT: stwu r1, -80(r1) -; CHECK-NEXT: Llabel1: +; CHECK-NEXT: Ltmp0: ; CHECK-NEXT: mr r31, r1 -; CHECK-NEXT: Llabel2: +; CHECK-NEXT: Ltmp1: entry: %a_addr = alloca i32 ; <i32*> [#uses=2] %retval = alloca i32 ; <i32*> [#uses=2] diff --git a/test/CodeGen/Thumb2/2010-03-15-AsmCCClobber.ll b/test/CodeGen/Thumb2/2010-03-15-AsmCCClobber.ll new file mode 100644 index 000000000000..71ff68aabebd --- /dev/null +++ b/test/CodeGen/Thumb2/2010-03-15-AsmCCClobber.ll @@ -0,0 +1,63 @@ +; RUN: llc < %s -mtriple=thumbv7-apple-darwin -mcpu=cortex-a8 | FileCheck %s +; Radar 7459078 +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:32-n32" + +%0 = type { i32, i32 } +%s1 = type { %s3, i32, %s4, i8*, void (i8*, i8*)*, i8*, i32*, i32*, i32*, i32, i64, [1 x i32] } +%s2 = type { i32 (...)**, %s4 } +%s3 = type { %s2, i32, i32, i32*, [4 x i8], float, %s4, i8*, i8* } +%s4 = type { %s5 } +%s5 = type { i32 } + +; Make sure the cmp is not scheduled before the InlineAsm that clobbers cc. +; CHECK: InlineAsm End +; CHECK: cmp +; CHECK: beq +define arm_apcscc void @test(%s1* %this, i32 %format, i32 %w, i32 %h, i32 %levels, i32* %s, i8* %data, i32* nocapture %rowbytes, void (i8*, i8*)* %release, i8* %info) nounwind { +entry: + %tmp1 = getelementptr inbounds %s1* %this, i32 0, i32 0, i32 0, i32 1, i32 0, i32 0 + volatile store i32 1, i32* %tmp1, align 4 + %tmp12 = getelementptr inbounds %s1* %this, i32 0, i32 1 + store i32 %levels, i32* %tmp12, align 4 + %tmp13 = getelementptr inbounds %s1* %this, i32 0, i32 3 + store i8* %data, i8** %tmp13, align 4 + %tmp14 = getelementptr inbounds %s1* %this, i32 0, i32 4 + store void (i8*, i8*)* %release, void (i8*, i8*)** %tmp14, align 4 + %tmp15 = getelementptr inbounds %s1* %this, i32 0, i32 5 + store i8* %info, i8** %tmp15, align 4 + %tmp16 = getelementptr inbounds %s1* %this, i32 0, i32 6 + store i32* null, i32** %tmp16, align 4 + %tmp17 = getelementptr inbounds %s1* %this, i32 0, i32 7 + store i32* null, i32** %tmp17, align 4 + %tmp19 = getelementptr inbounds %s1* %this, i32 0, i32 10 + store i64 0, i64* %tmp19, align 4 + %tmp20 = getelementptr inbounds %s1* %this, i32 0, i32 0 + tail call arm_apcscc void @f1(%s3* %tmp20, i32* %s) nounwind + %tmp21 = shl i32 %format, 6 + %tmp22 = tail call arm_apcscc zeroext i8 @f2(i32 %format) nounwind + %toBoolnot = icmp eq i8 %tmp22, 0 + %tmp23 = zext i1 %toBoolnot to i32 + %flags.0 = or i32 %tmp23, %tmp21 + %tmp24 = shl i32 %flags.0, 16 + %asmtmp.i.i.i = tail call %0 asm sideeffect "\0A0:\09ldrex $1, [$2]\0A\09orr $1, $1, $3\0A\09strex $0, $1, [$2]\0A\09cmp $0, #0\0A\09bne 0b", "=&r,=&r,r,r,~{memory},~{cc}"(i32* %tmp1, i32 %tmp24) nounwind + %tmp25 = getelementptr inbounds %s1* %this, i32 0, i32 2, i32 0, i32 0 + volatile store i32 1, i32* %tmp25, align 4 + %tmp26 = icmp eq i32 %levels, 0 + br i1 %tmp26, label %return, label %bb4 + +bb4: + %l.09 = phi i32 [ %tmp28, %bb4 ], [ 0, %entry ] + %scevgep = getelementptr %s1* %this, i32 0, i32 11, i32 %l.09 + %scevgep10 = getelementptr i32* %rowbytes, i32 %l.09 + %tmp27 = load i32* %scevgep10, align 4 + store i32 %tmp27, i32* %scevgep, align 4 + %tmp28 = add i32 %l.09, 1 + %exitcond = icmp eq i32 %tmp28, %levels + br i1 %exitcond, label %return, label %bb4 + +return: + ret void +} + +declare arm_apcscc void @f1(%s3*, i32*) +declare arm_apcscc zeroext i8 @f2(i32) diff --git a/test/CodeGen/X86/2004-03-30-Select-Max.ll b/test/CodeGen/X86/2004-03-30-Select-Max.ll index b6631b62118a..c44d10ac5b5a 100644 --- a/test/CodeGen/X86/2004-03-30-Select-Max.ll +++ b/test/CodeGen/X86/2004-03-30-Select-Max.ll @@ -1,6 +1,6 @@ -; RUN: llc < %s -march=x86 | not grep {j\[lgbe\]} +; RUN: llc < %s -march=x86 -mcpu=yonah | not grep {j\[lgbe\]} -define i32 @max(i32 %A, i32 %B) { +define i32 @max(i32 %A, i32 %B) nounwind { %gt = icmp sgt i32 %A, %B ; <i1> [#uses=1] %R = select i1 %gt, i32 %A, i32 %B ; <i32> [#uses=1] ret i32 %R diff --git a/test/CodeGen/Generic/2007-02-16-BranchFold.ll b/test/CodeGen/X86/2007-02-16-BranchFold.ll index 6bf5631b4e34..6bf5631b4e34 100644 --- a/test/CodeGen/Generic/2007-02-16-BranchFold.ll +++ b/test/CodeGen/X86/2007-02-16-BranchFold.ll diff --git a/test/CodeGen/Generic/2007-05-05-Personality.ll b/test/CodeGen/X86/2007-05-05-Personality.ll index c92783e5e4eb..c92783e5e4eb 100644 --- a/test/CodeGen/Generic/2007-05-05-Personality.ll +++ b/test/CodeGen/X86/2007-05-05-Personality.ll diff --git a/test/CodeGen/X86/2008-08-05-SpillerBug.ll b/test/CodeGen/X86/2008-08-05-SpillerBug.ll index 4c6493445a90..d9d95b595bee 100644 --- a/test/CodeGen/X86/2008-08-05-SpillerBug.ll +++ b/test/CodeGen/X86/2008-08-05-SpillerBug.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -mtriple=i386-apple-darwin -disable-fp-elim -stats |& grep asm-printer | grep 55 +; RUN: llc < %s -mtriple=i386-apple-darwin -mcpu=yonah -disable-fp-elim -stats |& grep asm-printer | grep 55 ; PR2568 @g_3 = external global i16 ; <i16*> [#uses=1] diff --git a/test/CodeGen/X86/2009-03-13-PHIElimBug.ll b/test/CodeGen/X86/2009-03-13-PHIElimBug.ll index ad7f9f7d1c11..8d426271a194 100644 --- a/test/CodeGen/X86/2009-03-13-PHIElimBug.ll +++ b/test/CodeGen/X86/2009-03-13-PHIElimBug.ll @@ -28,5 +28,5 @@ lpad: ; preds = %cont, %entry } ; CHECK: call{{.*}}f -; CHECK-NEXT: Llabel1: +; CHECK-NEXT: Ltmp0: ; CHECK-NEXT: movl %eax, %esi diff --git a/test/CodeGen/X86/2009-03-16-PHIElimInLPad.ll b/test/CodeGen/X86/2009-03-16-PHIElimInLPad.ll index 11c410173fcb..da493d4910e1 100644 --- a/test/CodeGen/X86/2009-03-16-PHIElimInLPad.ll +++ b/test/CodeGen/X86/2009-03-16-PHIElimInLPad.ll @@ -21,4 +21,4 @@ lpad: ; preds = %cont, %entry } ; CHECK: lpad -; CHECK-NEXT: Llabel +; CHECK-NEXT: Ltmp diff --git a/test/CodeGen/Generic/GC/alloc_loop.ll b/test/CodeGen/X86/GC/alloc_loop.ll index fb78ba2cd10b..fb78ba2cd10b 100644 --- a/test/CodeGen/Generic/GC/alloc_loop.ll +++ b/test/CodeGen/X86/GC/alloc_loop.ll diff --git a/test/CodeGen/Generic/GC/argpromotion.ll b/test/CodeGen/X86/GC/argpromotion.ll index c63ce222b869..c63ce222b869 100644 --- a/test/CodeGen/Generic/GC/argpromotion.ll +++ b/test/CodeGen/X86/GC/argpromotion.ll diff --git a/test/CodeGen/Generic/GC/badreadproto.ll b/test/CodeGen/X86/GC/badreadproto.ll index 4fe90b90833a..4fe90b90833a 100644 --- a/test/CodeGen/Generic/GC/badreadproto.ll +++ b/test/CodeGen/X86/GC/badreadproto.ll diff --git a/test/CodeGen/Generic/GC/badrootproto.ll b/test/CodeGen/X86/GC/badrootproto.ll index ff86d03c646a..ff86d03c646a 100644 --- a/test/CodeGen/Generic/GC/badrootproto.ll +++ b/test/CodeGen/X86/GC/badrootproto.ll diff --git a/test/CodeGen/Generic/GC/badwriteproto.ll b/test/CodeGen/X86/GC/badwriteproto.ll index be81f842672e..be81f842672e 100644 --- a/test/CodeGen/Generic/GC/badwriteproto.ll +++ b/test/CodeGen/X86/GC/badwriteproto.ll diff --git a/test/CodeGen/Generic/GC/deadargelim.ll b/test/CodeGen/X86/GC/deadargelim.ll index 176019020ad4..176019020ad4 100644 --- a/test/CodeGen/Generic/GC/deadargelim.ll +++ b/test/CodeGen/X86/GC/deadargelim.ll diff --git a/test/CodeGen/Generic/GC/dg.exp b/test/CodeGen/X86/GC/dg.exp index f2005891a59a..f2005891a59a 100644 --- a/test/CodeGen/Generic/GC/dg.exp +++ b/test/CodeGen/X86/GC/dg.exp diff --git a/test/CodeGen/Generic/GC/fat.ll b/test/CodeGen/X86/GC/fat.ll index d05ca3da8195..d05ca3da8195 100644 --- a/test/CodeGen/Generic/GC/fat.ll +++ b/test/CodeGen/X86/GC/fat.ll diff --git a/test/CodeGen/Generic/GC/inline.ll b/test/CodeGen/X86/GC/inline.ll index 9da33aef8dd3..9da33aef8dd3 100644 --- a/test/CodeGen/Generic/GC/inline.ll +++ b/test/CodeGen/X86/GC/inline.ll diff --git a/test/CodeGen/Generic/GC/inline2.ll b/test/CodeGen/X86/GC/inline2.ll index 15947056ee39..15947056ee39 100644 --- a/test/CodeGen/Generic/GC/inline2.ll +++ b/test/CodeGen/X86/GC/inline2.ll diff --git a/test/CodeGen/Generic/GC/lower_gcroot.ll b/test/CodeGen/X86/GC/lower_gcroot.ll index c2d418ac50ef..c2d418ac50ef 100644 --- a/test/CodeGen/Generic/GC/lower_gcroot.ll +++ b/test/CodeGen/X86/GC/lower_gcroot.ll diff --git a/test/CodeGen/Generic/GC/outside.ll b/test/CodeGen/X86/GC/outside.ll index 2968c6917ce1..2968c6917ce1 100644 --- a/test/CodeGen/Generic/GC/outside.ll +++ b/test/CodeGen/X86/GC/outside.ll diff --git a/test/CodeGen/Generic/GC/simple_ocaml.ll b/test/CodeGen/X86/GC/simple_ocaml.ll index f765dc029da5..f765dc029da5 100644 --- a/test/CodeGen/Generic/GC/simple_ocaml.ll +++ b/test/CodeGen/X86/GC/simple_ocaml.ll diff --git a/test/CodeGen/X86/clz.ll b/test/CodeGen/X86/clz.ll index 3f27187d44a8..623ac75b5299 100644 --- a/test/CodeGen/X86/clz.ll +++ b/test/CodeGen/X86/clz.ll @@ -1,10 +1,11 @@ -; RUN: llc < %s -march=x86 | grep bsr | count 2 -; RUN: llc < %s -march=x86 | grep bsf -; RUN: llc < %s -march=x86 | grep cmov | count 3 +; RUN: llc < %s -march=x86 -mcpu=yonah | FileCheck %s define i32 @t1(i32 %x) nounwind { %tmp = tail call i32 @llvm.ctlz.i32( i32 %x ) ret i32 %tmp +; CHECK: t1: +; CHECK: bsrl +; CHECK: cmov } declare i32 @llvm.ctlz.i32(i32) nounwind readnone @@ -12,6 +13,9 @@ declare i32 @llvm.ctlz.i32(i32) nounwind readnone define i32 @t2(i32 %x) nounwind { %tmp = tail call i32 @llvm.cttz.i32( i32 %x ) ret i32 %tmp +; CHECK: t2: +; CHECK: bsfl +; CHECK: cmov } declare i32 @llvm.cttz.i32(i32) nounwind readnone @@ -21,6 +25,9 @@ entry: %tmp1 = add i16 %x, %y %tmp2 = tail call i16 @llvm.ctlz.i16( i16 %tmp1 ) ; <i16> [#uses=1] ret i16 %tmp2 +; CHECK: t3: +; CHECK: bsrw +; CHECK: cmov } declare i16 @llvm.ctlz.i16(i16) nounwind readnone diff --git a/test/CodeGen/X86/crash.ll b/test/CodeGen/X86/crash.ll index 1e13046f2acd..4b7c85099389 100644 --- a/test/CodeGen/X86/crash.ll +++ b/test/CodeGen/X86/crash.ll @@ -18,3 +18,77 @@ entry: volatile store i32 %conv19.i, i32* undef ret i32 undef } + +; PR6533 +define void @test2(i1 %x, i32 %y) nounwind { + %land.ext = zext i1 %x to i32 ; <i32> [#uses=1] + %and = and i32 %y, 1 ; <i32> [#uses=1] + %xor = xor i32 %and, %land.ext ; <i32> [#uses=1] + %cmp = icmp eq i32 %xor, 1 ; <i1> [#uses=1] + br i1 %cmp, label %if.end, label %if.then + +if.then: ; preds = %land.end + ret void + +if.end: ; preds = %land.end + ret void +} + +; PR6577 +%pair = type { i64, double } + +define void @test3() { +dependentGraph243.exit: + %subject19 = load %pair* undef ; <%1> [#uses=1] + %0 = extractvalue %pair %subject19, 1 ; <double> [#uses=2] + %1 = select i1 undef, double %0, double undef ; <double> [#uses=1] + %2 = select i1 undef, double %1, double %0 ; <double> [#uses=1] + %3 = insertvalue %pair undef, double %2, 1 ; <%1> [#uses=1] + store %pair %3, %pair* undef + ret void +} + +; PR6605 +define i64 @test4(i8* %P) nounwind ssp { +entry: + %tmp1 = load i8* %P ; <i8> [#uses=3] + %tobool = icmp eq i8 %tmp1, 0 ; <i1> [#uses=1] + %tmp58 = sext i1 %tobool to i8 ; <i8> [#uses=1] + %mul.i = and i8 %tmp58, %tmp1 ; <i8> [#uses=1] + %conv6 = zext i8 %mul.i to i32 ; <i32> [#uses=1] + %cmp = icmp ne i8 %tmp1, 1 ; <i1> [#uses=1] + %conv11 = zext i1 %cmp to i32 ; <i32> [#uses=1] + %call12 = tail call i32 @safe(i32 %conv11) nounwind ; <i32> [#uses=1] + %and = and i32 %conv6, %call12 ; <i32> [#uses=1] + %tobool13 = icmp eq i32 %and, 0 ; <i1> [#uses=1] + br i1 %tobool13, label %if.else, label %return + +if.else: ; preds = %entry + br label %return + +return: ; preds = %if.else, %entry + ret i64 undef +} + +declare i32 @safe(i32) + +; PR6607 +define fastcc void @test5(i32 %FUNC) nounwind { +foo: + %0 = load i8* undef, align 1 ; <i8> [#uses=3] + %1 = sext i8 %0 to i32 ; <i32> [#uses=2] + %2 = zext i8 %0 to i32 ; <i32> [#uses=1] + %tmp1.i5037 = urem i32 %2, 10 ; <i32> [#uses=1] + %tmp.i5038 = icmp ugt i32 %tmp1.i5037, 15 ; <i1> [#uses=1] + %3 = zext i1 %tmp.i5038 to i8 ; <i8> [#uses=1] + %4 = icmp slt i8 %0, %3 ; <i1> [#uses=1] + %5 = add nsw i32 %1, 256 ; <i32> [#uses=1] + %storemerge.i.i57 = select i1 %4, i32 %5, i32 %1 ; <i32> [#uses=1] + %6 = shl i32 %storemerge.i.i57, 16 ; <i32> [#uses=1] + %7 = sdiv i32 %6, -256 ; <i32> [#uses=1] + %8 = trunc i32 %7 to i8 ; <i8> [#uses=1] + store i8 %8, i8* undef, align 1 + ret void +} + + diff --git a/test/CodeGen/X86/gather-addresses.ll b/test/CodeGen/X86/gather-addresses.ll new file mode 100644 index 000000000000..07198386b8ea --- /dev/null +++ b/test/CodeGen/X86/gather-addresses.ll @@ -0,0 +1,39 @@ +; RUN: llc -march=x86-64 < %s | FileCheck %s + +; When doing vector gather-scatter index calculation with 32-bit indices, +; bounce the vector off of cache rather than shuffling each individual +; element out of the index vector. + +; CHECK: pand (%rdx), %xmm0 +; CHECK: movaps %xmm0, -24(%rsp) +; CHECK: movslq -24(%rsp), %rax +; CHECK: movsd (%rdi,%rax,8), %xmm0 +; CHECK: movslq -20(%rsp), %rax +; CHECK: movhpd (%rdi,%rax,8), %xmm0 +; CHECK: movslq -16(%rsp), %rax +; CHECK: movsd (%rdi,%rax,8), %xmm1 +; CHECK: movslq -12(%rsp), %rax +; CHECK: movhpd (%rdi,%rax,8), %xmm1 + +define <4 x double> @foo(double* %p, <4 x i32>* %i, <4 x i32>* %h) nounwind { + %a = load <4 x i32>* %i + %b = load <4 x i32>* %h + %j = and <4 x i32> %a, %b + %d0 = extractelement <4 x i32> %j, i32 0 + %d1 = extractelement <4 x i32> %j, i32 1 + %d2 = extractelement <4 x i32> %j, i32 2 + %d3 = extractelement <4 x i32> %j, i32 3 + %q0 = getelementptr double* %p, i32 %d0 + %q1 = getelementptr double* %p, i32 %d1 + %q2 = getelementptr double* %p, i32 %d2 + %q3 = getelementptr double* %p, i32 %d3 + %r0 = load double* %q0 + %r1 = load double* %q1 + %r2 = load double* %q2 + %r3 = load double* %q3 + %v0 = insertelement <4 x double> undef, double %r0, i32 0 + %v1 = insertelement <4 x double> %v0, double %r1, i32 1 + %v2 = insertelement <4 x double> %v1, double %r2, i32 2 + %v3 = insertelement <4 x double> %v2, double %r3, i32 3 + ret <4 x double> %v3 +} diff --git a/test/CodeGen/X86/ghc-cc.ll b/test/CodeGen/X86/ghc-cc.ll new file mode 100644 index 000000000000..9393cf5a7383 --- /dev/null +++ b/test/CodeGen/X86/ghc-cc.ll @@ -0,0 +1,45 @@ +; RUN: llc < %s -tailcallopt -mtriple=i686-linux-gnu | FileCheck %s + +; Test the GHC call convention works (x86-32) + +@base = external global i32 ; assigned to register: EBX +@sp = external global i32 ; assigned to register: EBP +@hp = external global i32 ; assigned to register: EDI +@r1 = external global i32 ; assigned to register: ESI + +define void @zap(i32 %a, i32 %b) nounwind { +entry: + ; CHECK: movl {{[0-9]*}}(%esp), %ebx + ; CHECK-NEXT: movl {{[0-9]*}}(%esp), %ebp + ; CHECK-NEXT: call addtwo + %0 = call cc 10 i32 @addtwo(i32 %a, i32 %b) + ; CHECK: call foo + call void @foo() nounwind + ret void +} + +define cc 10 i32 @addtwo(i32 %x, i32 %y) nounwind { +entry: + ; CHECK: leal (%ebx,%ebp), %eax + %0 = add i32 %x, %y + ; CHECK-NEXT: ret + ret i32 %0 +} + +define cc 10 void @foo() nounwind { +entry: + ; CHECK: movl base, %ebx + ; CHECK-NEXT: movl sp, %ebp + ; CHECK-NEXT: movl hp, %edi + ; CHECK-NEXT: movl r1, %esi + %0 = load i32* @r1 + %1 = load i32* @hp + %2 = load i32* @sp + %3 = load i32* @base + ; CHECK: jmp bar + tail call cc 10 void @bar( i32 %3, i32 %2, i32 %1, i32 %0 ) nounwind + ret void +} + +declare cc 10 void @bar(i32, i32, i32, i32) + diff --git a/test/CodeGen/X86/ghc-cc64.ll b/test/CodeGen/X86/ghc-cc64.ll new file mode 100644 index 000000000000..fcf7e1797ad8 --- /dev/null +++ b/test/CodeGen/X86/ghc-cc64.ll @@ -0,0 +1,86 @@ +; RUN: llc < %s -tailcallopt -mtriple=x86_64-linux-gnu | FileCheck %s + +; Check the GHC call convention works (x86-64) + +@base = external global i64 ; assigned to register: R13 +@sp = external global i64 ; assigned to register: RBP +@hp = external global i64 ; assigned to register: R12 +@r1 = external global i64 ; assigned to register: RBX +@r2 = external global i64 ; assigned to register: R14 +@r3 = external global i64 ; assigned to register: RSI +@r4 = external global i64 ; assigned to register: RDI +@r5 = external global i64 ; assigned to register: R8 +@r6 = external global i64 ; assigned to register: R9 +@splim = external global i64 ; assigned to register: R15 + +@f1 = external global float ; assigned to register: XMM1 +@f2 = external global float ; assigned to register: XMM2 +@f3 = external global float ; assigned to register: XMM3 +@f4 = external global float ; assigned to register: XMM4 +@d1 = external global double ; assigned to register: XMM5 +@d2 = external global double ; assigned to register: XMM6 + +define void @zap(i64 %a, i64 %b) nounwind { +entry: + ; CHECK: movq %rdi, %r13 + ; CHECK-NEXT: movq %rsi, %rbp + ; CHECK-NEXT: callq addtwo + %0 = call cc 10 i64 @addtwo(i64 %a, i64 %b) + ; CHECK: callq foo + call void @foo() nounwind + ret void +} + +define cc 10 i64 @addtwo(i64 %x, i64 %y) nounwind { +entry: + ; CHECK: leaq (%r13,%rbp), %rax + %0 = add i64 %x, %y + ; CHECK-NEXT: ret + ret i64 %0 +} + +define cc 10 void @foo() nounwind { +entry: + ; CHECK: movq base(%rip), %r13 + ; CHECK-NEXT: movq sp(%rip), %rbp + ; CHECK-NEXT: movq hp(%rip), %r12 + ; CHECK-NEXT: movq r1(%rip), %rbx + ; CHECK-NEXT: movq r2(%rip), %r14 + ; CHECK-NEXT: movq r3(%rip), %rsi + ; CHECK-NEXT: movq r4(%rip), %rdi + ; CHECK-NEXT: movq r5(%rip), %r8 + ; CHECK-NEXT: movq r6(%rip), %r9 + ; CHECK-NEXT: movq splim(%rip), %r15 + ; CHECK-NEXT: movss f1(%rip), %xmm1 + ; CHECK-NEXT: movss f2(%rip), %xmm2 + ; CHECK-NEXT: movss f3(%rip), %xmm3 + ; CHECK-NEXT: movss f4(%rip), %xmm4 + ; CHECK-NEXT: movsd d1(%rip), %xmm5 + ; CHECK-NEXT: movsd d2(%rip), %xmm6 + %0 = load double* @d2 + %1 = load double* @d1 + %2 = load float* @f4 + %3 = load float* @f3 + %4 = load float* @f2 + %5 = load float* @f1 + %6 = load i64* @splim + %7 = load i64* @r6 + %8 = load i64* @r5 + %9 = load i64* @r4 + %10 = load i64* @r3 + %11 = load i64* @r2 + %12 = load i64* @r1 + %13 = load i64* @hp + %14 = load i64* @sp + %15 = load i64* @base + ; CHECK: jmp bar + tail call cc 10 void @bar( i64 %15, i64 %14, i64 %13, i64 %12, i64 %11, + i64 %10, i64 %9, i64 %8, i64 %7, i64 %6, + float %5, float %4, float %3, float %2, double %1, + double %0 ) nounwind + ret void +} + +declare cc 10 void @bar(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, + float, float, float, float, double, double) + diff --git a/test/CodeGen/X86/liveness-local-regalloc.ll b/test/CodeGen/X86/liveness-local-regalloc.ll new file mode 100644 index 000000000000..17e65d8f81d9 --- /dev/null +++ b/test/CodeGen/X86/liveness-local-regalloc.ll @@ -0,0 +1,60 @@ +; RUN: llc < %s -O3 -regalloc=local -mtriple=x86_64-apple-darwin10 +; <rdar://problem/7755473> + +%0 = type { i32, i8*, i8*, %1*, i8*, i64, i64, i32, i32, i32, i32, [1024 x i8] } +%1 = type { i8*, i32, i32, i16, i16, %2, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %2, %3*, i32, [3 x i8], [1 x i8], %2, i32, i64 } +%2 = type { i8*, i32 } +%3 = type opaque + +declare fastcc i32 @func(%0*, i32, i32) nounwind ssp + +define fastcc void @func2(%0* %arg, i32 %arg1) nounwind ssp { +bb: + br label %.exit3 + +.exit3: ; preds = %.exit3, %bb + switch i32 undef, label %.exit3 [ + i32 -1, label %.loopexit + i32 37, label %bb2 + ] + +bb2: ; preds = %bb5, %bb3, %.exit3 + br i1 undef, label %bb3, label %bb5 + +bb3: ; preds = %bb2 + switch i32 undef, label %infloop [ + i32 125, label %.loopexit + i32 -1, label %bb4 + i32 37, label %bb2 + ] + +bb4: ; preds = %bb3 + %tmp = add nsw i32 undef, 1 ; <i32> [#uses=1] + br label %.loopexit + +bb5: ; preds = %bb2 + switch i32 undef, label %infloop1 [ + i32 -1, label %.loopexit + i32 37, label %bb2 + ] + +.loopexit: ; preds = %bb5, %bb4, %bb3, %.exit3 + %.04 = phi i32 [ %tmp, %bb4 ], [ undef, %bb3 ], [ undef, %.exit3 ], [ undef, %bb5 ] ; <i32> [#uses=2] + br i1 undef, label %bb8, label %bb6 + +bb6: ; preds = %.loopexit + %tmp7 = tail call fastcc i32 @func(%0* %arg, i32 %.04, i32 undef) nounwind ssp ; <i32> [#uses=0] + ret void + +bb8: ; preds = %.loopexit + %tmp9 = sext i32 %.04 to i64 ; <i64> [#uses=1] + %tmp10 = getelementptr inbounds %0* %arg, i64 0, i32 11, i64 %tmp9 ; <i8*> [#uses=1] + store i8 0, i8* %tmp10, align 1 + ret void + +infloop: ; preds = %infloop, %bb3 + br label %infloop + +infloop1: ; preds = %infloop1, %bb5 + br label %infloop1 +} diff --git a/test/CodeGen/X86/object-size.ll b/test/CodeGen/X86/object-size.ll index eed3cfc85136..bbe6b2341e58 100644 --- a/test/CodeGen/X86/object-size.ll +++ b/test/CodeGen/X86/object-size.ll @@ -12,7 +12,7 @@ entry: %tmp = load i8** @p ; <i8*> [#uses=1] %0 = call i64 @llvm.objectsize.i64(i8* %tmp, i1 0) ; <i64> [#uses=1] %cmp = icmp ne i64 %0, -1 ; <i1> [#uses=1] -; X64: movq $-1, %rax +; X64: movabsq $-1, %rax ; X64: cmpq $-1, %rax br i1 %cmp, label %cond.true, label %cond.false diff --git a/test/CodeGen/X86/personality.ll b/test/CodeGen/X86/personality.ll index ce57e8fce6f2..5acf04cc06c1 100644 --- a/test/CodeGen/X86/personality.ll +++ b/test/CodeGen/X86/personality.ll @@ -39,7 +39,7 @@ declare void @__gxx_personality_v0() declare void @__cxa_end_catch() ; X64: Leh_frame_common_begin: -; X64: .long (___gxx_personality_v0@GOTPCREL)+4 +; X64: .long ___gxx_personality_v0@GOTPCREL+4 ; X32: Leh_frame_common_begin: ; X32: .long L___gxx_personality_v0$non_lazy_ptr- diff --git a/test/CodeGen/X86/phys_subreg_coalesce-3.ll b/test/CodeGen/X86/phys_subreg_coalesce-3.ll new file mode 100644 index 000000000000..f23669ed9a4a --- /dev/null +++ b/test/CodeGen/X86/phys_subreg_coalesce-3.ll @@ -0,0 +1,35 @@ +; RUN: llc < %s -mtriple=i386-apple-darwin | FileCheck %s +; rdar://5571034 + +define void @foo(i32* nocapture %quadrant, i32* nocapture %ptr, i32 %bbSize, i32 %bbStart, i32 %shifts) nounwind ssp { +; CHECK: foo: +entry: + %j.03 = add i32 %bbSize, -1 ; <i32> [#uses=2] + %0 = icmp sgt i32 %j.03, -1 ; <i1> [#uses=1] + br i1 %0, label %bb.nph, label %return + +bb.nph: ; preds = %entry + %tmp9 = add i32 %bbStart, %bbSize ; <i32> [#uses=1] + %tmp10 = add i32 %tmp9, -1 ; <i32> [#uses=1] + br label %bb + +bb: ; preds = %bb, %bb.nph +; CHECK: %bb +; CHECK-NOT: movb {{.*}}l, %cl +; CHECK: sarl %cl + %indvar = phi i32 [ 0, %bb.nph ], [ %indvar.next, %bb ] ; <i32> [#uses=3] + %j.06 = sub i32 %j.03, %indvar ; <i32> [#uses=1] + %tmp11 = sub i32 %tmp10, %indvar ; <i32> [#uses=1] + %scevgep = getelementptr i32* %ptr, i32 %tmp11 ; <i32*> [#uses=1] + %1 = load i32* %scevgep, align 4 ; <i32> [#uses=1] + %2 = ashr i32 %j.06, %shifts ; <i32> [#uses=1] + %3 = and i32 %2, 65535 ; <i32> [#uses=1] + %4 = getelementptr inbounds i32* %quadrant, i32 %1 ; <i32*> [#uses=1] + store i32 %3, i32* %4, align 4 + %indvar.next = add i32 %indvar, 1 ; <i32> [#uses=2] + %exitcond = icmp eq i32 %indvar.next, %bbSize ; <i1> [#uses=1] + br i1 %exitcond, label %return, label %bb + +return: ; preds = %bb, %entry + ret void +} diff --git a/test/CodeGen/X86/pic.ll b/test/CodeGen/X86/pic.ll index d3c28a055aee..e997233a5194 100644 --- a/test/CodeGen/X86/pic.ll +++ b/test/CodeGen/X86/pic.ll @@ -15,7 +15,7 @@ entry: ; LINUX: call .L1$pb ; LINUX-NEXT: .L1$pb: ; LINUX-NEXT: popl -; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.Lpicbaseref1-.L1$pb), +; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.L{{.*}}-.L1$pb), ; LINUX: movl dst@GOT(%eax), ; LINUX: movl ptr@GOT(%eax), ; LINUX: movl src@GOT(%eax), @@ -37,7 +37,7 @@ entry: ; LINUX: call .L2$pb ; LINUX-NEXT: .L2$pb: ; LINUX-NEXT: popl -; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.Lpicbaseref2-.L2$pb), %eax +; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.L{{.*}}-.L2$pb), %eax ; LINUX: movl dst2@GOT(%eax), ; LINUX: movl ptr2@GOT(%eax), ; LINUX: movl src2@GOT(%eax), @@ -57,7 +57,7 @@ entry: ; LINUX-NEXT: call .L3$pb ; LINUX-NEXT: .L3$pb: ; LINUX-NEXT: popl %ebx -; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.Lpicbaseref3-.L3$pb), %ebx +; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.L{{.*}}-.L3$pb), %ebx ; LINUX: movl $40, (%esp) ; LINUX: call malloc@PLT ; LINUX: addl $8, %esp @@ -78,7 +78,7 @@ entry: ; LINUX: call .L4$pb ; LINUX-NEXT: .L4$pb: ; LINUX: popl -; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.Lpicbaseref4-.L4$pb), +; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.L{{.*}}-.L4$pb), ; LINUX: movl pfoo@GOT(%esi), ; LINUX: call afoo@PLT ; LINUX: call * @@ -93,7 +93,7 @@ entry: ; LINUX: test5: ; LINUX: call .L5$pb ; LINUX: popl %ebx -; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.Lpicbaseref5-.L5$pb), %ebx +; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.L{{.*}}-.L5$pb), %ebx ; LINUX: call foo@PLT } @@ -115,7 +115,7 @@ entry: ; LINUX: call .L6$pb ; LINUX-NEXT: .L6$pb: ; LINUX-NEXT: popl %eax -; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.Lpicbaseref6-.L6$pb), %eax +; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.L{{.*}}-.L6$pb), %eax ; LINUX: leal dst6@GOTOFF(%eax), %ecx ; LINUX: movl %ecx, ptr6@GOTOFF(%eax) ; LINUX: movl src6@GOTOFF(%eax), %ecx @@ -136,7 +136,7 @@ entry: ; LINUX: test7: ; LINUX: call .L7$pb ; LINUX: .L7$pb: -; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.Lpicbaseref7-.L7$pb), +; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.L{{.*}}-.L7$pb), ; LINUX: fldl .LCPI7_0@GOTOFF( } @@ -188,7 +188,7 @@ bb12: ; LINUX: test8: ; LINUX: call .L8$pb ; LINUX: .L8$pb: -; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.Lpicbaseref8-.L8$pb), +; LINUX: addl $_GLOBAL_OFFSET_TABLE_+(.L{{.*}}-.L8$pb), ; LINUX: addl .LJTI8_0@GOTOFF( ; LINUX: jmpl * diff --git a/test/CodeGen/X86/tailcall-largecode.ll b/test/CodeGen/X86/tailcall-largecode.ll index 8ddc4054ca88..c7070f2abd25 100644 --- a/test/CodeGen/X86/tailcall-largecode.ll +++ b/test/CodeGen/X86/tailcall-largecode.ll @@ -20,7 +20,7 @@ define fastcc i32 @indirect_manyargs(i32(i32,i32,i32,i32,i32,i32,i32)* %target) ; CHECK: subq $8, %rsp ; Put the call target into R11, which won't be clobbered while restoring ; callee-saved registers and won't be used for passing arguments. -; CHECK: movq %rdi, %r11 +; CHECK: movq %rdi, %rax ; Pass the stack argument. ; CHECK: movl $7, 16(%rsp) ; Pass the register arguments, in the right registers. @@ -33,7 +33,7 @@ define fastcc i32 @indirect_manyargs(i32(i32,i32,i32,i32,i32,i32,i32)* %target) ; Adjust the stack to "return". ; CHECK: addq $8, %rsp ; And tail-call to the target. -; CHECK: jmpq *%r11 # TAILCALL +; CHECK: jmpq *%rax # TAILCALL %res = tail call fastcc i32 %target(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7) ret i32 %res @@ -60,11 +60,11 @@ define fastcc i32 @direct_manyargs() { ; the jmp instruction. Put it into R11, which won't be clobbered ; while restoring callee-saved registers and won't be used for passing ; arguments. -; CHECK: movabsq $manyargs_callee, %r11 +; CHECK: movabsq $manyargs_callee, %rax ; Adjust the stack to "return". ; CHECK: addq $8, %rsp ; And tail-call to the target. -; CHECK: jmpq *%r11 # TAILCALL +; CHECK: jmpq *%rax # TAILCALL %res = tail call fastcc i32 @manyargs_callee(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7) ret i32 %res diff --git a/test/CodeGen/X86/tailcallfp2.ll b/test/CodeGen/X86/tailcallfp2.ll index 3841f518976b..4ec127f81ac7 100644 --- a/test/CodeGen/X86/tailcallfp2.ll +++ b/test/CodeGen/X86/tailcallfp2.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -march=x86 -tailcallopt | grep {jmp} | grep {\\*%eax} +; RUN: llc < %s -march=x86 -tailcallopt | grep {jmp} | grep {\\*%edx} declare i32 @putchar(i32) diff --git a/test/CodeGen/XCore/addsub64.ll b/test/CodeGen/XCore/addsub64.ll index 0432e5e712e6..d06248022e31 100644 --- a/test/CodeGen/XCore/addsub64.ll +++ b/test/CodeGen/XCore/addsub64.ll @@ -42,3 +42,18 @@ entry: ; CHECK: maccs: ; CHECK: maccs r1, r0, r3, r2 ; CHECK-NEXT: retsp 0 + +define i64 @lmul(i32 %a, i32 %b, i32 %c, i32 %d) { +entry: + %0 = zext i32 %a to i64 + %1 = zext i32 %b to i64 + %2 = zext i32 %c to i64 + %3 = zext i32 %d to i64 + %4 = mul i64 %1, %0 + %5 = add i64 %4, %2 + %6 = add i64 %5, %3 + ret i64 %6 +} +; CHECK: lmul: +; CHECK: lmul r1, r0, r1, r0, r2, r3 +; CHECK-NEXT: retsp 0 diff --git a/test/CodeGen/XCore/indirectbr.ll b/test/CodeGen/XCore/indirectbr.ll index a8f00cc497fc..92690029cd0e 100644 --- a/test/CodeGen/XCore/indirectbr.ll +++ b/test/CodeGen/XCore/indirectbr.ll @@ -38,7 +38,7 @@ L2: ; preds = %L3, %bb2 L1: ; preds = %L2, %bb2 %res.3 = phi i32 [ %phitmp, %L2 ], [ 2, %bb2 ] ; <i32> [#uses=1] -; CHECK: ldap r11, .LBA3_foo_L5 +; CHECK: ldap r11, .Ltmp0 ; CHECK: stw r11, dp[nextaddr] store i8* blockaddress(@foo, %L5), i8** @nextaddr, align 4 ret i32 %res.3 diff --git a/test/CodeGen/XCore/mul64.ll b/test/CodeGen/XCore/mul64.ll index 329e214d1d23..1dc94712507e 100644 --- a/test/CodeGen/XCore/mul64.ll +++ b/test/CodeGen/XCore/mul64.ll @@ -37,3 +37,16 @@ entry: ; CHECK-NEXT: mul r0, r0, r3 ; CHECK-NEXT: lmul r0, r1, r1, r2, r11, r0 ; CHECK-NEXT: mov r0, r4 + +define i64 @mul64_2(i64 %a, i32 %b) { +entry: + %0 = zext i32 %b to i64 + %1 = mul i64 %a, %0 + ret i64 %1 +} +; CHECK: mul64_2: +; CHECK: ldc r3, 0 +; CHECK-NEXT: lmul r3, r0, r0, r2, r3, r3 +; CHECK-NEXT: mul r1, r1, r2 +; CHECK-NEXT: add r1, r3, r1 +; CHECK-NEXT: retsp 0 diff --git a/test/DebugInfo/2010-03-12-llc-crash.ll b/test/DebugInfo/2010-03-12-llc-crash.ll new file mode 100644 index 000000000000..f6de23495853 --- /dev/null +++ b/test/DebugInfo/2010-03-12-llc-crash.ll @@ -0,0 +1,20 @@ +; RUN: llc -O0 < %s -o /dev/null +; llc should not crash on this invalid input. +; PR6588 +declare void @llvm.dbg.declare(metadata, metadata) nounwind readnone + +define void @foo() { +entry: + call void @llvm.dbg.declare(metadata !{i32* undef}, metadata !0) + ret void +} + +!0 = metadata !{i32 524545, metadata !1, metadata !"sy", metadata !2, i32 890, metadata !7} ; [ DW_TAG_arg_variable ] +!1 = metadata !{i32 524334, i32 0, metadata !2, metadata !"foo", metadata !"foo", metadata !"foo", metadata !2, i32 892, metadata !4, i1 false, i1 true, i32 0, i32 0, null, i1 false} ; [ DW_TAG_subprogram ] +!2 = metadata !{i32 524329, metadata !"qpainter.h", metadata !"QtGui", metadata !3} ; [ DW_TAG_file_type ] +!3 = metadata !{i32 524305, i32 0, i32 4, metadata !"splineeditor.cpp", metadata !"editor", metadata !"clang 1.1", i1 true, i1 false, metadata !"", i32 0} ; [ DW_TAG_compile_unit ] +!4 = metadata !{i32 524309, metadata !5, metadata !"", metadata !5, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !6, i32 0, null} ; [ DW_TAG_subroutine_type ] +!5 = metadata !{i32 524329, metadata !"splineeditor.cpp", metadata !"src", metadata !3} ; [ DW_TAG_file_type ] +!6 = metadata !{null} +!7 = metadata !{i32 524324, metadata !5, metadata !"int", metadata !5, i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] + diff --git a/test/FrontendC/2010-03-10-arm-asmreg.c b/test/FrontendC/2010-03-10-arm-asmreg.c new file mode 100644 index 000000000000..70d3681ea40e --- /dev/null +++ b/test/FrontendC/2010-03-10-arm-asmreg.c @@ -0,0 +1,15 @@ +// RUN: %llvmgcc %s -S -O0 -o - | FileCheck %s +// pr6552 + +// XFAIL: * +// XTARGET: arm + +extern void bar(unsigned int ip); + +// CHECK: mov r0, r12 +void foo(void) +{ + register unsigned int ip __asm ("ip"); + bar(ip); +} + diff --git a/test/MC/AsmParser/X86/x86_32-bit.s b/test/MC/AsmParser/X86/x86_32-bit.s index 90e97be44c9e..ca0b26bef62a 100644 --- a/test/MC/AsmParser/X86/x86_32-bit.s +++ b/test/MC/AsmParser/X86/x86_32-bit.s @@ -1,4 +1,5 @@ // RUN: llvm-mc -triple i386-unknown-unknown %s | FileCheck %s +// XFAIL: * // CHECK: movb $127, 3735928559(%ebx,%ecx,8) movb $0x7f,0xdeadbeef(%ebx,%ecx,8) diff --git a/test/MC/AsmParser/X86/x86_32-bit_cat.s b/test/MC/AsmParser/X86/x86_32-bit_cat.s index f0c7804d9726..5429e8e23c64 100644 --- a/test/MC/AsmParser/X86/x86_32-bit_cat.s +++ b/test/MC/AsmParser/X86/x86_32-bit_cat.s @@ -4,6 +4,8 @@ // the file x86_32-encoding.s (and other tests that encode are in x86_32-bit.s). // RUN: llvm-mc -triple i386-unknown-unknown %s | FileCheck %s +// XFAIL: * + // CHECK: movb $127, 3735928559(%ebx,%ecx,8) movb $0x7f,0xdeadbeef(%ebx,%ecx,8) diff --git a/test/MC/AsmParser/X86/x86_32-encoding.s b/test/MC/AsmParser/X86/x86_32-encoding.s index e325bdd169d0..7dacc7508636 100644 --- a/test/MC/AsmParser/X86/x86_32-encoding.s +++ b/test/MC/AsmParser/X86/x86_32-encoding.s @@ -1,4 +1,6 @@ // RUN: llvm-mc -triple i386-unknown-unknown --show-encoding %s | FileCheck %s +// XFAIL: * + // CHECK: movb $127, 3735928559(%ebx,%ecx,8) // CHECK: encoding: [0xc6,0x84,0xcb,0xef,0xbe,0xad,0xde,0x7f] diff --git a/test/MC/AsmParser/X86/x86_32-mismatched-add.s b/test/MC/AsmParser/X86/x86_32-mismatched-add.s new file mode 100644 index 000000000000..0840c65ca95a --- /dev/null +++ b/test/MC/AsmParser/X86/x86_32-mismatched-add.s @@ -0,0 +1,8 @@ +// RUN: llvm-mc -triple i386-unknown-unknown --show-encoding %s | FileCheck %s +// XFAIL: * + +// CHECK: addl $4294967295, %eax # encoding: [0x83,0xc0,0xff] + addl $0xFFFFFFFF, %eax + +// CHECK: addl $65535, %eax # encoding: [0x66,0x83,0xc0,0xff] + addw $0xFFFF, %ax diff --git a/test/MC/AsmParser/X86/x86_32-new-encoder.s b/test/MC/AsmParser/X86/x86_32-new-encoder.s index d4e3be4bd28f..c00007fd168b 100644 --- a/test/MC/AsmParser/X86/x86_32-new-encoder.s +++ b/test/MC/AsmParser/X86/x86_32-new-encoder.s @@ -47,3 +47,6 @@ rdtscp // CHECK: addw %ax, %ax # encoding: [0x66,0x01,0xc0] addw %ax, %ax + +// CHECK: shrl %eax # encoding: [0xd1,0xe8] + shrl $1, %eax diff --git a/test/MC/AsmParser/X86/x86_64-new-encoder.s b/test/MC/AsmParser/X86/x86_64-new-encoder.s index 56ec0b38994f..797558a81ef9 100644 --- a/test/MC/AsmParser/X86/x86_64-new-encoder.s +++ b/test/MC/AsmParser/X86/x86_64-new-encoder.s @@ -24,3 +24,6 @@ movq $12, foo(%rip) // CHECK: movq $12, foo(%rip) // CHECK: encoding: [0x48,0xc7,0x05,A,A,A,A,0x0c,0x00,0x00,0x00] // CHECK: fixup A - offset: 3, value: foo-8, kind: reloc_riprel_4byte + +// CHECK: addq $-424, %rax # encoding: [0x48,0x05,0x58,0xfe,0xff,0xff] +addq $-424, %rax diff --git a/test/MC/AsmParser/X86/x86_64-operands.s b/test/MC/AsmParser/X86/x86_64-operands.s new file mode 100644 index 000000000000..9e15779138cf --- /dev/null +++ b/test/MC/AsmParser/X86/x86_64-operands.s @@ -0,0 +1,9 @@ +// FIXME: Actually test that we get the expected results. + +// RUN: llvm-mc -triple x86_64-unknown-unknown %s | FileCheck %s + +# CHECK: callq a + callq a + +# CHECK: leaq -40(%rbp), %r15 + leaq -40(%rbp), %r15 diff --git a/test/MC/MachO/Darwin/x86_32_diff_as.s b/test/MC/MachO/Darwin/x86_32_diff_as.s index dd5fb55183b8..7fe75aae3880 100644 --- a/test/MC/MachO/Darwin/x86_32_diff_as.s +++ b/test/MC/MachO/Darwin/x86_32_diff_as.s @@ -1,6 +1,7 @@ // Validate that we can assemble this file exactly like the platform // assembler. // +// XFAIL: * // RUN: llvm-mc -filetype=obj -triple i386-unknown-unknown -o %t.mc.o %s // RUN: as -arch i386 -o %t.as.o %s // RUN: diff %t.mc.o %t.as.o diff --git a/test/MC/MachO/absolutize.s b/test/MC/MachO/absolutize.s new file mode 100644 index 000000000000..ade5c195addc --- /dev/null +++ b/test/MC/MachO/absolutize.s @@ -0,0 +1,71 @@ +// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck %s + +// CHECK: # Relocation 0 +// CHECK: (('word-0', 0xa0000028), +// CHECK: ('word-1', 0x2b)), +// CHECK: # Relocation 1 +// CHECK: (('word-0', 0xa4000020), +// CHECK: ('word-1', 0x37)), +// CHECK: # Relocation 2 +// CHECK: (('word-0', 0xa1000000), +// CHECK: ('word-1', 0x33)), +// CHECK: # Relocation 3 +// CHECK: (('word-0', 0xa4000018), +// CHECK: ('word-1', 0x33)), +// CHECK: # Relocation 4 +// CHECK: (('word-0', 0xa1000000), +// CHECK: ('word-1', 0x2f)), +// CHECK: # Relocation 5 +// CHECK: (('word-0', 0xa4000010), +// CHECK: ('word-1', 0x2b)), +// CHECK: # Relocation 6 +// CHECK: (('word-0', 0xa1000000), +// CHECK: ('word-1', 0x2f)), +// CHECK-NEXT: ]) + +_text_a: + xorl %eax,%eax +_text_b: + xorl %eax,%eax +Ltext_c: + xorl %eax,%eax +Ltext_d: + xorl %eax,%eax + + movl $(_text_a - _text_b), %eax +Ltext_expr_0 = _text_a - _text_b + movl $(Ltext_expr_0), %eax + + movl $(Ltext_c - _text_b), %eax +Ltext_expr_1 = Ltext_c - _text_b + movl $(Ltext_expr_1), %eax + + movl $(Ltext_d - Ltext_c), %eax +Ltext_expr_2 = Ltext_d - Ltext_c + movl $(Ltext_expr_2), %eax + + movl $(_text_a + Ltext_expr_0), %eax + + .data +_data_a: + .long 0 +_data_b: + .long 0 +Ldata_c: + .long 0 +Ldata_d: + .long 0 + + .long _data_a - _data_b +Ldata_expr_0 = _data_a - _data_b + .long Ldata_expr_0 + + .long Ldata_c - _data_b +Ldata_expr_1 = Ldata_c - _data_b + .long Ldata_expr_1 + + .long Ldata_d - Ldata_c +Ldata_expr_2 = Ldata_d - Ldata_c + .long Ldata_expr_2 + + .long _data_a + Ldata_expr_0 diff --git a/test/MC/MachO/relax-jumps.s b/test/MC/MachO/relax-jumps.s new file mode 100644 index 000000000000..9c58aa768258 --- /dev/null +++ b/test/MC/MachO/relax-jumps.s @@ -0,0 +1,31 @@ +// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump --dump-section-data | FileCheck %s + +// FIXME: This is a horrible way of checking the output, we need an llvm-mc +// based 'otool'. Use: +// (f=relax-jumps; +// llvm-mc -filetype=obj -o $f.mc.o $f.s && +// as -arch i386 -o $f.as.o $f.s && +// otool -tvr $f.mc.o | tail +2 > $f.mc.dump && +// otool -tvr $f.as.o | tail +2 > $f.as.dump && +// diff $f.{as,mc}.dump) +// to examine the results in a more sensible fashion. + +// CHECK: ('_section_data', '\x90 +// CHECK: \x0f\x842\xff\xff\xff\x0f\x82\xe6\x00\x00\x00\x0f\x87&\xff\xff\xff\x0f\x8f\xda\x00\x00\x00\x0f\x88\x1a\xff\xff\xff\x0f\x83\xce\x00\x00\x00\x0f\x89\x0e\xff\xff\xff\x90 +// CHECK: \x901\xc0') + +L1: + .space 200, 0x90 + + je L1 + jb L2 + ja L1 + jg L2 + js L1 + jae L2 + jns L1 + + .space 200, 0x90 +L2: + + xorl %eax, %eax diff --git a/test/MC/MachO/relax-recompute-align.s b/test/MC/MachO/relax-recompute-align.s new file mode 100644 index 000000000000..249402502f71 --- /dev/null +++ b/test/MC/MachO/relax-recompute-align.s @@ -0,0 +1,37 @@ +// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump --dump-section-data | FileCheck %s + +// FIXME: This is a horrible way of checking the output, we need an llvm-mc +// based 'otool'. + +// This is a case where llvm-mc computes a better layout than Darwin 'as'. This +// issue is that after the first jmp slides, the .align size must be +// recomputed -- otherwise the second jump will appear to be out-of-range for a +// 1-byte jump. + +// CHECK: # Section 0 +// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 306) +// CHECK: ('offset', 324) +// CHECK: ('alignment', 4) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000400) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), + +L0: + .space 0x8a, 0x90 + jmp L0 + .space (0xb3 - 0x8f), 0x90 + jle L2 + .space (0xcd - 0xb5), 0x90 + .align 4, 0x90 +L1: + .space (0x130 - 0xd0),0x90 + jl L1 +L2: + +.zerofill __DATA,__bss,_sym,4,2 diff --git a/test/MC/MachO/reloc-pcrel-offset.s b/test/MC/MachO/reloc-pcrel-offset.s new file mode 100644 index 000000000000..46dc3a9c57d8 --- /dev/null +++ b/test/MC/MachO/reloc-pcrel-offset.s @@ -0,0 +1,14 @@ +// RUN: llvm-mc -n -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump --dump-section-data | FileCheck %s + +// CHECK: # Relocation 0 +// CHECK: (('word-0', 0x1), +// CHECK: ('word-1', 0x5000002)), +// CHECK-NEXT: ]) +// CHECK: ('_section_data', '\xe8\xfb\xff\xff\xff') + + .data + .long 0 + + .text +_a: + call _a diff --git a/test/MC/MachO/symbols-1.s b/test/MC/MachO/symbols-1.s index 4c72fb3e7c2d..623e5285fe5b 100644 --- a/test/MC/MachO/symbols-1.s +++ b/test/MC/MachO/symbols-1.s @@ -1,4 +1,5 @@ -// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck %s +// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck -check-prefix CHECK-X86_32 %s +// RUN: llvm-mc -triple x86_64-apple-darwin10 %s -filetype=obj -o - | macho-dump | FileCheck -check-prefix CHECK-X86_64 %s sym_local_B: .globl sym_globl_def_B @@ -16,146 +17,294 @@ sym_globl_def_C: Lsym_asm_temp: .long 0 -// CHECK: ('cputype', 7) -// CHECK: ('cpusubtype', 3) -// CHECK: ('filetype', 1) -// CHECK: ('num_load_commands', 1) -// CHECK: ('load_commands_size', 228) -// CHECK: ('flag', 0) -// CHECK: ('load_commands', [ -// CHECK: # Load Command 0 -// CHECK: (('command', 1) -// CHECK: ('size', 124) -// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') -// CHECK: ('vm_addr', 0) -// CHECK: ('vm_size', 4) -// CHECK: ('file_offset', 256) -// CHECK: ('file_size', 4) -// CHECK: ('maxprot', 7) -// CHECK: ('initprot', 7) -// CHECK: ('num_sections', 1) -// CHECK: ('flags', 0) -// CHECK: ('sections', [ -// CHECK: # Section 0 -// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') -// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') -// CHECK: ('address', 0) -// CHECK: ('size', 4) -// CHECK: ('offset', 256) -// CHECK: ('alignment', 0) -// CHECK: ('reloc_offset', 0) -// CHECK: ('num_reloc', 0) -// CHECK: ('flags', 0x80000000) -// CHECK: ('reserved1', 0) -// CHECK: ('reserved2', 0) -// CHECK: ), -// CHECK: ]) -// CHECK: ), -// CHECK: # Load Command 1 -// CHECK: (('command', 2) -// CHECK: ('size', 24) -// CHECK: ('symoff', 260) -// CHECK: ('nsyms', 9) -// CHECK: ('stroff', 368) -// CHECK: ('strsize', 140) -// CHECK: ('_string_data', '\x00sym_globl_def_B\x00sym_globl_undef_B\x00sym_globl_def_A\x00sym_globl_undef_A\x00sym_globl_def_C\x00sym_globl_undef_C\x00sym_local_B\x00sym_local_A\x00sym_local_C\x00\x00') -// CHECK: ('_symbols', [ -// CHECK: # Symbol 0 -// CHECK: (('n_strx', 103) -// CHECK: ('n_type', 0xe) -// CHECK: ('n_sect', 1) -// CHECK: ('n_desc', 0) -// CHECK: ('n_value', 0) -// CHECK: ('_string', 'sym_local_B') -// CHECK: ), -// CHECK: # Symbol 1 -// CHECK: (('n_strx', 115) -// CHECK: ('n_type', 0xe) -// CHECK: ('n_sect', 1) -// CHECK: ('n_desc', 0) -// CHECK: ('n_value', 0) -// CHECK: ('_string', 'sym_local_A') -// CHECK: ), -// CHECK: # Symbol 2 -// CHECK: (('n_strx', 127) -// CHECK: ('n_type', 0xe) -// CHECK: ('n_sect', 1) -// CHECK: ('n_desc', 0) -// CHECK: ('n_value', 0) -// CHECK: ('_string', 'sym_local_C') -// CHECK: ), -// CHECK: # Symbol 3 -// CHECK: (('n_strx', 35) -// CHECK: ('n_type', 0xf) -// CHECK: ('n_sect', 1) -// CHECK: ('n_desc', 0) -// CHECK: ('n_value', 0) -// CHECK: ('_string', 'sym_globl_def_A') -// CHECK: ), -// CHECK: # Symbol 4 -// CHECK: (('n_strx', 1) -// CHECK: ('n_type', 0xf) -// CHECK: ('n_sect', 1) -// CHECK: ('n_desc', 0) -// CHECK: ('n_value', 0) -// CHECK: ('_string', 'sym_globl_def_B') -// CHECK: ), -// CHECK: # Symbol 5 -// CHECK: (('n_strx', 69) -// CHECK: ('n_type', 0xf) -// CHECK: ('n_sect', 1) -// CHECK: ('n_desc', 0) -// CHECK: ('n_value', 0) -// CHECK: ('_string', 'sym_globl_def_C') -// CHECK: ), -// CHECK: # Symbol 6 -// CHECK: (('n_strx', 51) -// CHECK: ('n_type', 0x1) -// CHECK: ('n_sect', 0) -// CHECK: ('n_desc', 0) -// CHECK: ('n_value', 0) -// CHECK: ('_string', 'sym_globl_undef_A') -// CHECK: ), -// CHECK: # Symbol 7 -// CHECK: (('n_strx', 17) -// CHECK: ('n_type', 0x1) -// CHECK: ('n_sect', 0) -// CHECK: ('n_desc', 0) -// CHECK: ('n_value', 0) -// CHECK: ('_string', 'sym_globl_undef_B') -// CHECK: ), -// CHECK: # Symbol 8 -// CHECK: (('n_strx', 85) -// CHECK: ('n_type', 0x1) -// CHECK: ('n_sect', 0) -// CHECK: ('n_desc', 0) -// CHECK: ('n_value', 0) -// CHECK: ('_string', 'sym_globl_undef_C') -// CHECK: ), -// CHECK: ]) -// CHECK: ), -// CHECK: # Load Command 2 -// CHECK: (('command', 11) -// CHECK: ('size', 80) -// CHECK: ('ilocalsym', 0) -// CHECK: ('nlocalsym', 3) -// CHECK: ('iextdefsym', 3) -// CHECK: ('nextdefsym', 3) -// CHECK: ('iundefsym', 6) -// CHECK: ('nundefsym', 3) -// CHECK: ('tocoff', 0) -// CHECK: ('ntoc', 0) -// CHECK: ('modtaboff', 0) -// CHECK: ('nmodtab', 0) -// CHECK: ('extrefsymoff', 0) -// CHECK: ('nextrefsyms', 0) -// CHECK: ('indirectsymoff', 0) -// CHECK: ('nindirectsyms', 0) -// CHECK: ('extreloff', 0) -// CHECK: ('nextrel', 0) -// CHECK: ('locreloff', 0) -// CHECK: ('nlocrel', 0) -// CHECK: ('_indirect_symbols', [ -// CHECK: ]) -// CHECK: ), -// CHECK: ]) +// CHECK-X86_32: ('cputype', 7) +// CHECK-X86_32: ('cpusubtype', 3) +// CHECK-X86_32: ('filetype', 1) +// CHECK-X86_32: ('num_load_commands', 1) +// CHECK-X86_32: ('load_commands_size', 228) +// CHECK-X86_32: ('flag', 0) +// CHECK-X86_32: ('load_commands', [ +// CHECK-X86_32: # Load Command 0 +// CHECK-X86_32: (('command', 1) +// CHECK-X86_32: ('size', 124) +// CHECK-X86_32: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK-X86_32: ('vm_addr', 0) +// CHECK-X86_32: ('vm_size', 4) +// CHECK-X86_32: ('file_offset', 256) +// CHECK-X86_32: ('file_size', 4) +// CHECK-X86_32: ('maxprot', 7) +// CHECK-X86_32: ('initprot', 7) +// CHECK-X86_32: ('num_sections', 1) +// CHECK-X86_32: ('flags', 0) +// CHECK-X86_32: ('sections', [ +// CHECK-X86_32: # Section 0 +// CHECK-X86_32: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK-X86_32: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK-X86_32: ('address', 0) +// CHECK-X86_32: ('size', 4) +// CHECK-X86_32: ('offset', 256) +// CHECK-X86_32: ('alignment', 0) +// CHECK-X86_32: ('reloc_offset', 0) +// CHECK-X86_32: ('num_reloc', 0) +// CHECK-X86_32: ('flags', 0x80000000) +// CHECK-X86_32: ('reserved1', 0) +// CHECK-X86_32: ('reserved2', 0) +// CHECK-X86_32: ), +// CHECK-X86_32: ]) +// CHECK-X86_32: ), +// CHECK-X86_32: # Load Command 1 +// CHECK-X86_32: (('command', 2) +// CHECK-X86_32: ('size', 24) +// CHECK-X86_32: ('symoff', 260) +// CHECK-X86_32: ('nsyms', 9) +// CHECK-X86_32: ('stroff', 368) +// CHECK-X86_32: ('strsize', 140) +// CHECK-X86_32: ('_string_data', '\x00sym_globl_def_B\x00sym_globl_undef_B\x00sym_globl_def_A\x00sym_globl_undef_A\x00sym_globl_def_C\x00sym_globl_undef_C\x00sym_local_B\x00sym_local_A\x00sym_local_C\x00\x00') +// CHECK-X86_32: ('_symbols', [ +// CHECK-X86_32: # Symbol 0 +// CHECK-X86_32: (('n_strx', 103) +// CHECK-X86_32: ('n_type', 0xe) +// CHECK-X86_32: ('n_sect', 1) +// CHECK-X86_32: ('n_desc', 0) +// CHECK-X86_32: ('n_value', 0) +// CHECK-X86_32: ('_string', 'sym_local_B') +// CHECK-X86_32: ), +// CHECK-X86_32: # Symbol 1 +// CHECK-X86_32: (('n_strx', 115) +// CHECK-X86_32: ('n_type', 0xe) +// CHECK-X86_32: ('n_sect', 1) +// CHECK-X86_32: ('n_desc', 0) +// CHECK-X86_32: ('n_value', 0) +// CHECK-X86_32: ('_string', 'sym_local_A') +// CHECK-X86_32: ), +// CHECK-X86_32: # Symbol 2 +// CHECK-X86_32: (('n_strx', 127) +// CHECK-X86_32: ('n_type', 0xe) +// CHECK-X86_32: ('n_sect', 1) +// CHECK-X86_32: ('n_desc', 0) +// CHECK-X86_32: ('n_value', 0) +// CHECK-X86_32: ('_string', 'sym_local_C') +// CHECK-X86_32: ), +// CHECK-X86_32: # Symbol 3 +// CHECK-X86_32: (('n_strx', 35) +// CHECK-X86_32: ('n_type', 0xf) +// CHECK-X86_32: ('n_sect', 1) +// CHECK-X86_32: ('n_desc', 0) +// CHECK-X86_32: ('n_value', 0) +// CHECK-X86_32: ('_string', 'sym_globl_def_A') +// CHECK-X86_32: ), +// CHECK-X86_32: # Symbol 4 +// CHECK-X86_32: (('n_strx', 1) +// CHECK-X86_32: ('n_type', 0xf) +// CHECK-X86_32: ('n_sect', 1) +// CHECK-X86_32: ('n_desc', 0) +// CHECK-X86_32: ('n_value', 0) +// CHECK-X86_32: ('_string', 'sym_globl_def_B') +// CHECK-X86_32: ), +// CHECK-X86_32: # Symbol 5 +// CHECK-X86_32: (('n_strx', 69) +// CHECK-X86_32: ('n_type', 0xf) +// CHECK-X86_32: ('n_sect', 1) +// CHECK-X86_32: ('n_desc', 0) +// CHECK-X86_32: ('n_value', 0) +// CHECK-X86_32: ('_string', 'sym_globl_def_C') +// CHECK-X86_32: ), +// CHECK-X86_32: # Symbol 6 +// CHECK-X86_32: (('n_strx', 51) +// CHECK-X86_32: ('n_type', 0x1) +// CHECK-X86_32: ('n_sect', 0) +// CHECK-X86_32: ('n_desc', 0) +// CHECK-X86_32: ('n_value', 0) +// CHECK-X86_32: ('_string', 'sym_globl_undef_A') +// CHECK-X86_32: ), +// CHECK-X86_32: # Symbol 7 +// CHECK-X86_32: (('n_strx', 17) +// CHECK-X86_32: ('n_type', 0x1) +// CHECK-X86_32: ('n_sect', 0) +// CHECK-X86_32: ('n_desc', 0) +// CHECK-X86_32: ('n_value', 0) +// CHECK-X86_32: ('_string', 'sym_globl_undef_B') +// CHECK-X86_32: ), +// CHECK-X86_32: # Symbol 8 +// CHECK-X86_32: (('n_strx', 85) +// CHECK-X86_32: ('n_type', 0x1) +// CHECK-X86_32: ('n_sect', 0) +// CHECK-X86_32: ('n_desc', 0) +// CHECK-X86_32: ('n_value', 0) +// CHECK-X86_32: ('_string', 'sym_globl_undef_C') +// CHECK-X86_32: ), +// CHECK-X86_32: ]) +// CHECK-X86_32: ), +// CHECK-X86_32: # Load Command 2 +// CHECK-X86_32: (('command', 11) +// CHECK-X86_32: ('size', 80) +// CHECK-X86_32: ('ilocalsym', 0) +// CHECK-X86_32: ('nlocalsym', 3) +// CHECK-X86_32: ('iextdefsym', 3) +// CHECK-X86_32: ('nextdefsym', 3) +// CHECK-X86_32: ('iundefsym', 6) +// CHECK-X86_32: ('nundefsym', 3) +// CHECK-X86_32: ('tocoff', 0) +// CHECK-X86_32: ('ntoc', 0) +// CHECK-X86_32: ('modtaboff', 0) +// CHECK-X86_32: ('nmodtab', 0) +// CHECK-X86_32: ('extrefsymoff', 0) +// CHECK-X86_32: ('nextrefsyms', 0) +// CHECK-X86_32: ('indirectsymoff', 0) +// CHECK-X86_32: ('nindirectsyms', 0) +// CHECK-X86_32: ('extreloff', 0) +// CHECK-X86_32: ('nextrel', 0) +// CHECK-X86_32: ('locreloff', 0) +// CHECK-X86_32: ('nlocrel', 0) +// CHECK-X86_32: ('_indirect_symbols', [ +// CHECK-X86_32: ]) +// CHECK-X86_32: ), +// CHECK-X86_32: ]) + +// CHECK-X86_64: ('cputype', 16777223) +// CHECK-X86_64: ('cpusubtype', 3) +// CHECK-X86_64: ('filetype', 1) +// CHECK-X86_64: ('num_load_commands', 1) +// CHECK-X86_64: ('load_commands_size', 256) +// CHECK-X86_64: ('flag', 0) +// CHECK-X86_64: ('reserved', 0) +// CHECK-X86_64: ('load_commands', [ +// CHECK-X86_64: # Load Command 0 +// CHECK-X86_64: (('command', 25) +// CHECK-X86_64: ('size', 152) +// CHECK-X86_64: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK-X86_64: ('vm_addr', 0) +// CHECK-X86_64: ('vm_size', 4) +// CHECK-X86_64: ('file_offset', 288) +// CHECK-X86_64: ('file_size', 4) +// CHECK-X86_64: ('maxprot', 7) +// CHECK-X86_64: ('initprot', 7) +// CHECK-X86_64: ('num_sections', 1) +// CHECK-X86_64: ('flags', 0) +// CHECK-X86_64: ('sections', [ +// CHECK-X86_64: # Section 0 +// CHECK-X86_64: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK-X86_64: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK-X86_64: ('address', 0) +// CHECK-X86_64: ('size', 4) +// CHECK-X86_64: ('offset', 288) +// CHECK-X86_64: ('alignment', 0) +// CHECK-X86_64: ('reloc_offset', 0) +// CHECK-X86_64: ('num_reloc', 0) +// CHECK-X86_64: ('flags', 0x80000000) +// CHECK-X86_64: ('reserved1', 0) +// CHECK-X86_64: ('reserved2', 0) +// CHECK-X86_64: ('reserved3', 0) +// CHECK-X86_64: ), +// CHECK-X86_64: ('_relocations', [ +// CHECK-X86_64: ]) +// CHECK-X86_64: ]) +// CHECK-X86_64: ), +// CHECK-X86_64: # Load Command 1 +// CHECK-X86_64: (('command', 2) +// CHECK-X86_64: ('size', 24) +// CHECK-X86_64: ('symoff', 292) +// CHECK-X86_64: ('nsyms', 9) +// CHECK-X86_64: ('stroff', 436) +// CHECK-X86_64: ('strsize', 140) +// CHECK-X86_64: ('_string_data', '\x00sym_globl_def_B\x00sym_globl_undef_B\x00sym_globl_def_A\x00sym_globl_undef_A\x00sym_globl_def_C\x00sym_globl_undef_C\x00sym_local_B\x00sym_local_A\x00sym_local_C\x00\x00') +// CHECK-X86_64: ('_symbols', [ +// CHECK-X86_64: # Symbol 0 +// CHECK-X86_64: (('n_strx', 103) +// CHECK-X86_64: ('n_type', 0xe) +// CHECK-X86_64: ('n_sect', 1) +// CHECK-X86_64: ('n_desc', 0) +// CHECK-X86_64: ('n_value', 0) +// CHECK-X86_64: ('_string', 'sym_local_B') +// CHECK-X86_64: ), +// CHECK-X86_64: # Symbol 1 +// CHECK-X86_64: (('n_strx', 115) +// CHECK-X86_64: ('n_type', 0xe) +// CHECK-X86_64: ('n_sect', 1) +// CHECK-X86_64: ('n_desc', 0) +// CHECK-X86_64: ('n_value', 0) +// CHECK-X86_64: ('_string', 'sym_local_A') +// CHECK-X86_64: ), +// CHECK-X86_64: # Symbol 2 +// CHECK-X86_64: (('n_strx', 127) +// CHECK-X86_64: ('n_type', 0xe) +// CHECK-X86_64: ('n_sect', 1) +// CHECK-X86_64: ('n_desc', 0) +// CHECK-X86_64: ('n_value', 0) +// CHECK-X86_64: ('_string', 'sym_local_C') +// CHECK-X86_64: ), +// CHECK-X86_64: # Symbol 3 +// CHECK-X86_64: (('n_strx', 35) +// CHECK-X86_64: ('n_type', 0xf) +// CHECK-X86_64: ('n_sect', 1) +// CHECK-X86_64: ('n_desc', 0) +// CHECK-X86_64: ('n_value', 0) +// CHECK-X86_64: ('_string', 'sym_globl_def_A') +// CHECK-X86_64: ), +// CHECK-X86_64: # Symbol 4 +// CHECK-X86_64: (('n_strx', 1) +// CHECK-X86_64: ('n_type', 0xf) +// CHECK-X86_64: ('n_sect', 1) +// CHECK-X86_64: ('n_desc', 0) +// CHECK-X86_64: ('n_value', 0) +// CHECK-X86_64: ('_string', 'sym_globl_def_B') +// CHECK-X86_64: ), +// CHECK-X86_64: # Symbol 5 +// CHECK-X86_64: (('n_strx', 69) +// CHECK-X86_64: ('n_type', 0xf) +// CHECK-X86_64: ('n_sect', 1) +// CHECK-X86_64: ('n_desc', 0) +// CHECK-X86_64: ('n_value', 0) +// CHECK-X86_64: ('_string', 'sym_globl_def_C') +// CHECK-X86_64: ), +// CHECK-X86_64: # Symbol 6 +// CHECK-X86_64: (('n_strx', 51) +// CHECK-X86_64: ('n_type', 0x1) +// CHECK-X86_64: ('n_sect', 0) +// CHECK-X86_64: ('n_desc', 0) +// CHECK-X86_64: ('n_value', 0) +// CHECK-X86_64: ('_string', 'sym_globl_undef_A') +// CHECK-X86_64: ), +// CHECK-X86_64: # Symbol 7 +// CHECK-X86_64: (('n_strx', 17) +// CHECK-X86_64: ('n_type', 0x1) +// CHECK-X86_64: ('n_sect', 0) +// CHECK-X86_64: ('n_desc', 0) +// CHECK-X86_64: ('n_value', 0) +// CHECK-X86_64: ('_string', 'sym_globl_undef_B') +// CHECK-X86_64: ), +// CHECK-X86_64: # Symbol 8 +// CHECK-X86_64: (('n_strx', 85) +// CHECK-X86_64: ('n_type', 0x1) +// CHECK-X86_64: ('n_sect', 0) +// CHECK-X86_64: ('n_desc', 0) +// CHECK-X86_64: ('n_value', 0) +// CHECK-X86_64: ('_string', 'sym_globl_undef_C') +// CHECK-X86_64: ), +// CHECK-X86_64: ]) +// CHECK-X86_64: ), +// CHECK-X86_64: # Load Command 2 +// CHECK-X86_64: (('command', 11) +// CHECK-X86_64: ('size', 80) +// CHECK-X86_64: ('ilocalsym', 0) +// CHECK-X86_64: ('nlocalsym', 3) +// CHECK-X86_64: ('iextdefsym', 3) +// CHECK-X86_64: ('nextdefsym', 3) +// CHECK-X86_64: ('iundefsym', 6) +// CHECK-X86_64: ('nundefsym', 3) +// CHECK-X86_64: ('tocoff', 0) +// CHECK-X86_64: ('ntoc', 0) +// CHECK-X86_64: ('modtaboff', 0) +// CHECK-X86_64: ('nmodtab', 0) +// CHECK-X86_64: ('extrefsymoff', 0) +// CHECK-X86_64: ('nextrefsyms', 0) +// CHECK-X86_64: ('indirectsymoff', 0) +// CHECK-X86_64: ('nindirectsyms', 0) +// CHECK-X86_64: ('extreloff', 0) +// CHECK-X86_64: ('nextrel', 0) +// CHECK-X86_64: ('locreloff', 0) +// CHECK-X86_64: ('nlocrel', 0) +// CHECK-X86_64: ('_indirect_symbols', [ +// CHECK-X86_64: ]) +// CHECK-X86_64: ), +// CHECK-X86_64: ]) diff --git a/test/MC/MachO/sections.s b/test/MC/MachO/x86_32-sections.s index a7bcd2170f03..66ada2807ef9 100644 --- a/test/MC/MachO/sections.s +++ b/test/MC/MachO/x86_32-sections.s @@ -36,13 +36,9 @@ .objc_class_vars .objc_instance_vars .objc_module_info - -// FIXME: These are aliases for __TEXT, __cstring which we don't properly unique -// yet. -// .objc_class_names -// .objc_meth_var_types -// .objc_meth_var_names - + .objc_class_names + .objc_meth_var_types + .objc_meth_var_names .objc_selector_strs .section __TEXT,__picsymbolstub4,symbol_stubs,none,16 diff --git a/test/MC/MachO/x86_32-symbols.s b/test/MC/MachO/x86_32-symbols.s new file mode 100644 index 000000000000..629ba7de7ced --- /dev/null +++ b/test/MC/MachO/x86_32-symbols.s @@ -0,0 +1,1041 @@ +// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck %s + + .text +L0: +D0: + .section __TEXT,__text,regular,pure_instructions +L1: +D1: + .const +L2: +D2: + .static_const +L3: +D3: + .cstring +L4: +D4: + .literal4 +L5: +D5: + .literal8 +L6: +D6: + .literal16 +L7: +D7: + .constructor +L8: +D8: + .destructor +L9: +D9: + .symbol_stub +L10: +D10: + .picsymbol_stub +L11: +D11: + .data +L12: +D12: + .static_data +L13: +D13: + .non_lazy_symbol_pointer +L14: +D14: + .lazy_symbol_pointer +L15: +D15: + .dyld +L16: +D16: + .mod_init_func +L17: +D17: + .mod_term_func +L18: +D18: + .const_data +L19: +D19: + .objc_class +L20: +D20: + .objc_meta_class +L21: +D21: + .objc_cat_cls_meth +L22: +D22: + .objc_cat_inst_meth +L23: +D23: + .objc_protocol +L24: +D24: + .objc_string_object +L25: +D25: + .objc_cls_meth +L26: +D26: + .objc_inst_meth +L27: +D27: + .objc_cls_refs +L28: +D28: + .objc_message_refs +L29: +D29: + .objc_symbols +L30: +D30: + .objc_category +L31: +D31: + .objc_class_vars +L32: +D32: + .objc_instance_vars +L33: +D33: + .objc_module_info +L34: +D34: + .objc_class_names +L35: +D35: + .objc_meth_var_types +L36: +D36: + .objc_meth_var_names +L37: +D37: + .objc_selector_strs +L38: +D38: + .section __TEXT,__picsymbolstub4,symbol_stubs,none,16 +L39: +D39: + +// CHECK: ('cputype', 7) +// CHECK: ('cpusubtype', 3) +// CHECK: ('filetype', 1) +// CHECK: ('num_load_commands', 1) +// CHECK: ('load_commands_size', 2608) +// CHECK: ('flag', 0) +// CHECK: ('load_commands', [ +// CHECK: # Load Command 0 +// CHECK: (('command', 1) +// CHECK: ('size', 2504) +// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('vm_addr', 0) +// CHECK: ('vm_size', 0) +// CHECK: ('file_offset', 2636) +// CHECK: ('file_size', 0) +// CHECK: ('maxprot', 7) +// CHECK: ('initprot', 7) +// CHECK: ('num_sections', 36) +// CHECK: ('flags', 0) +// CHECK: ('sections', [ +// CHECK: # Section 0 +// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 1 +// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 2 +// CHECK: (('section_name', '__static_const\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 3 +// CHECK: (('section_name', '__cstring\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x2) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 4 +// CHECK: (('section_name', '__literal4\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x3) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 5 +// CHECK: (('section_name', '__literal8\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 3) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x4) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 6 +// CHECK: (('section_name', '__literal16\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 4) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0xe) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 7 +// CHECK: (('section_name', '__constructor\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 8 +// CHECK: (('section_name', '__destructor\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 9 +// CHECK: (('section_name', '__symbol_stub\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000008) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 16) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 10 +// CHECK: (('section_name', '__picsymbol_stub') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000008) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 26) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 11 +// CHECK: (('section_name', '__data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 12 +// CHECK: (('section_name', '__static_data\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 13 +// CHECK: (('section_name', '__nl_symbol_ptr\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x6) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 14 +// CHECK: (('section_name', '__la_symbol_ptr\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x7) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 15 +// CHECK: (('section_name', '__dyld\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 16 +// CHECK: (('section_name', '__mod_init_func\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x9) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 17 +// CHECK: (('section_name', '__mod_term_func\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0xa) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 18 +// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 19 +// CHECK: (('section_name', '__class\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 20 +// CHECK: (('section_name', '__meta_class\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 21 +// CHECK: (('section_name', '__cat_cls_meth\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 22 +// CHECK: (('section_name', '__cat_inst_meth\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 23 +// CHECK: (('section_name', '__protocol\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 24 +// CHECK: (('section_name', '__string_object\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 25 +// CHECK: (('section_name', '__cls_meth\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 26 +// CHECK: (('section_name', '__inst_meth\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 27 +// CHECK: (('section_name', '__cls_refs\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000005) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 28 +// CHECK: (('section_name', '__message_refs\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000005) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 29 +// CHECK: (('section_name', '__symbols\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 30 +// CHECK: (('section_name', '__category\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 31 +// CHECK: (('section_name', '__class_vars\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 32 +// CHECK: (('section_name', '__instance_vars\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 33 +// CHECK: (('section_name', '__module_info\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 34 +// CHECK: (('section_name', '__selector_strs\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x2) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 35 +// CHECK: (('section_name', '__picsymbolstub4') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x8) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 16) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 1 +// CHECK: (('command', 2) +// CHECK: ('size', 24) +// CHECK: ('symoff', 2636) +// CHECK: ('nsyms', 40) +// CHECK: ('stroff', 3116) +// CHECK: ('strsize', 152) +// CHECK: ('_string_data', '\x00D0\x00D1\x00D2\x00D3\x00D4\x00D5\x00D6\x00D7\x00D8\x00D9\x00D10\x00D11\x00D12\x00D13\x00D14\x00D15\x00D16\x00D17\x00D18\x00D19\x00D20\x00D21\x00D22\x00D23\x00D24\x00D25\x00D26\x00D27\x00D28\x00D29\x00D30\x00D31\x00D32\x00D33\x00D34\x00D35\x00D36\x00D37\x00D38\x00D39\x00\x00') +// CHECK: ('_symbols', [ +// CHECK: # Symbol 0 +// CHECK: (('n_strx', 1) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D0') +// CHECK: ), +// CHECK: # Symbol 1 +// CHECK: (('n_strx', 4) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D1') +// CHECK: ), +// CHECK: # Symbol 2 +// CHECK: (('n_strx', 7) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 2) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D2') +// CHECK: ), +// CHECK: # Symbol 3 +// CHECK: (('n_strx', 10) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 3) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D3') +// CHECK: ), +// CHECK: # Symbol 4 +// CHECK: (('n_strx', 13) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D4') +// CHECK: ), +// CHECK: # Symbol 5 +// CHECK: (('n_strx', 16) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 5) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D5') +// CHECK: ), +// CHECK: # Symbol 6 +// CHECK: (('n_strx', 19) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 6) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D6') +// CHECK: ), +// CHECK: # Symbol 7 +// CHECK: (('n_strx', 22) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 7) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D7') +// CHECK: ), +// CHECK: # Symbol 8 +// CHECK: (('n_strx', 25) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 8) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D8') +// CHECK: ), +// CHECK: # Symbol 9 +// CHECK: (('n_strx', 28) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 9) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D9') +// CHECK: ), +// CHECK: # Symbol 10 +// CHECK: (('n_strx', 31) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 10) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D10') +// CHECK: ), +// CHECK: # Symbol 11 +// CHECK: (('n_strx', 35) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 11) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D11') +// CHECK: ), +// CHECK: # Symbol 12 +// CHECK: (('n_strx', 39) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 12) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D12') +// CHECK: ), +// CHECK: # Symbol 13 +// CHECK: (('n_strx', 43) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 13) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D13') +// CHECK: ), +// CHECK: # Symbol 14 +// CHECK: (('n_strx', 47) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 14) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D14') +// CHECK: ), +// CHECK: # Symbol 15 +// CHECK: (('n_strx', 51) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 15) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D15') +// CHECK: ), +// CHECK: # Symbol 16 +// CHECK: (('n_strx', 55) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 16) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D16') +// CHECK: ), +// CHECK: # Symbol 17 +// CHECK: (('n_strx', 59) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 17) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D17') +// CHECK: ), +// CHECK: # Symbol 18 +// CHECK: (('n_strx', 63) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 18) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D18') +// CHECK: ), +// CHECK: # Symbol 19 +// CHECK: (('n_strx', 67) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 19) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D19') +// CHECK: ), +// CHECK: # Symbol 20 +// CHECK: (('n_strx', 71) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 20) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D20') +// CHECK: ), +// CHECK: # Symbol 21 +// CHECK: (('n_strx', 75) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 21) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D21') +// CHECK: ), +// CHECK: # Symbol 22 +// CHECK: (('n_strx', 79) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 22) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D22') +// CHECK: ), +// CHECK: # Symbol 23 +// CHECK: (('n_strx', 83) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 23) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D23') +// CHECK: ), +// CHECK: # Symbol 24 +// CHECK: (('n_strx', 87) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 24) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D24') +// CHECK: ), +// CHECK: # Symbol 25 +// CHECK: (('n_strx', 91) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 25) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D25') +// CHECK: ), +// CHECK: # Symbol 26 +// CHECK: (('n_strx', 95) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 26) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D26') +// CHECK: ), +// CHECK: # Symbol 27 +// CHECK: (('n_strx', 99) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 27) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D27') +// CHECK: ), +// CHECK: # Symbol 28 +// CHECK: (('n_strx', 103) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 28) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D28') +// CHECK: ), +// CHECK: # Symbol 29 +// CHECK: (('n_strx', 107) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 29) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D29') +// CHECK: ), +// CHECK: # Symbol 30 +// CHECK: (('n_strx', 111) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 30) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D30') +// CHECK: ), +// CHECK: # Symbol 31 +// CHECK: (('n_strx', 115) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 31) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D31') +// CHECK: ), +// CHECK: # Symbol 32 +// CHECK: (('n_strx', 119) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 32) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D32') +// CHECK: ), +// CHECK: # Symbol 33 +// CHECK: (('n_strx', 123) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 33) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D33') +// CHECK: ), +// CHECK: # Symbol 34 +// CHECK: (('n_strx', 127) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 34) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D34') +// CHECK: ), +// CHECK: # Symbol 35 +// CHECK: (('n_strx', 131) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D35') +// CHECK: ), +// CHECK: # Symbol 36 +// CHECK: (('n_strx', 135) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D36') +// CHECK: ), +// CHECK: # Symbol 37 +// CHECK: (('n_strx', 139) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D37') +// CHECK: ), +// CHECK: # Symbol 38 +// CHECK: (('n_strx', 143) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 35) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D38') +// CHECK: ), +// CHECK: # Symbol 39 +// CHECK: (('n_strx', 147) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 36) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D39') +// CHECK: ), +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 2 +// CHECK: (('command', 11) +// CHECK: ('size', 80) +// CHECK: ('ilocalsym', 0) +// CHECK: ('nlocalsym', 40) +// CHECK: ('iextdefsym', 40) +// CHECK: ('nextdefsym', 0) +// CHECK: ('iundefsym', 40) +// CHECK: ('nundefsym', 0) +// CHECK: ('tocoff', 0) +// CHECK: ('ntoc', 0) +// CHECK: ('modtaboff', 0) +// CHECK: ('nmodtab', 0) +// CHECK: ('extrefsymoff', 0) +// CHECK: ('nextrefsyms', 0) +// CHECK: ('indirectsymoff', 0) +// CHECK: ('nindirectsyms', 0) +// CHECK: ('extreloff', 0) +// CHECK: ('nextrel', 0) +// CHECK: ('locreloff', 0) +// CHECK: ('nlocrel', 0) +// CHECK: ('_indirect_symbols', [ +// CHECK: ]) +// CHECK: ), +// CHECK: ]) diff --git a/test/MC/MachO/x86_64-sections.s b/test/MC/MachO/x86_64-sections.s new file mode 100644 index 000000000000..8efd35e6cbff --- /dev/null +++ b/test/MC/MachO/x86_64-sections.s @@ -0,0 +1,561 @@ +// RUN: llvm-mc -triple x86_64-apple-darwin10 %s -filetype=obj -o - | macho-dump | FileCheck %s + + .text + .section __TEXT,__text,regular,pure_instructions + + .const + .static_const + .cstring + .literal4 + .literal8 + .literal16 + .constructor + .destructor + .data + .static_data + .dyld + .mod_init_func + .mod_term_func + .const_data + .objc_class + .objc_meta_class + .objc_cat_cls_meth + .objc_cat_inst_meth + .objc_protocol + .objc_string_object + .objc_cls_meth + .objc_inst_meth + .objc_cls_refs + .objc_message_refs + .objc_symbols + .objc_category + .objc_class_vars + .objc_instance_vars + .objc_module_info + .objc_class_names + .objc_meth_var_types + .objc_meth_var_names + .objc_selector_strs + + .subsections_via_symbols + +// CHECK: ('cputype', 16777223) +// CHECK: ('cpusubtype', 3) +// CHECK: ('filetype', 1) +// CHECK: ('num_load_commands', 1) +// CHECK: ('load_commands_size', 2552) +// CHECK: ('flag', 8192) +// CHECK: ('reserved', 0) +// CHECK: ('load_commands', [ +// CHECK: # Load Command 0 +// CHECK: (('command', 25) +// CHECK: ('size', 2552) +// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('vm_addr', 0) +// CHECK: ('vm_size', 0) +// CHECK: ('file_offset', 2584) +// CHECK: ('file_size', 0) +// CHECK: ('maxprot', 7) +// CHECK: ('initprot', 7) +// CHECK: ('num_sections', 31) +// CHECK: ('flags', 0) +// CHECK: ('sections', [ +// CHECK: # Section 0 +// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 1 +// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 2 +// CHECK: (('section_name', '__static_const\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 3 +// CHECK: (('section_name', '__cstring\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x2) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 4 +// CHECK: (('section_name', '__literal4\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x3) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 5 +// CHECK: (('section_name', '__literal8\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 3) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x4) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 6 +// CHECK: (('section_name', '__literal16\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 4) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0xe) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 7 +// CHECK: (('section_name', '__constructor\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 8 +// CHECK: (('section_name', '__destructor\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 9 +// CHECK: (('section_name', '__data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 10 +// CHECK: (('section_name', '__static_data\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 11 +// CHECK: (('section_name', '__dyld\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 12 +// CHECK: (('section_name', '__mod_init_func\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x9) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 13 +// CHECK: (('section_name', '__mod_term_func\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0xa) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 14 +// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 15 +// CHECK: (('section_name', '__class\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 16 +// CHECK: (('section_name', '__meta_class\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 17 +// CHECK: (('section_name', '__cat_cls_meth\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 18 +// CHECK: (('section_name', '__cat_inst_meth\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 19 +// CHECK: (('section_name', '__protocol\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 20 +// CHECK: (('section_name', '__string_object\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 21 +// CHECK: (('section_name', '__cls_meth\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 22 +// CHECK: (('section_name', '__inst_meth\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 23 +// CHECK: (('section_name', '__cls_refs\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000005) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 24 +// CHECK: (('section_name', '__message_refs\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000005) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 25 +// CHECK: (('section_name', '__symbols\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 26 +// CHECK: (('section_name', '__category\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 27 +// CHECK: (('section_name', '__class_vars\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 28 +// CHECK: (('section_name', '__instance_vars\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 29 +// CHECK: (('section_name', '__module_info\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 30 +// CHECK: (('section_name', '__selector_strs\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2584) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x2) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: ]) +// CHECK: ), +// CHECK: ]) diff --git a/test/MC/MachO/x86_64-symbols.s b/test/MC/MachO/x86_64-symbols.s new file mode 100644 index 000000000000..c5c39a6fd47f --- /dev/null +++ b/test/MC/MachO/x86_64-symbols.s @@ -0,0 +1,998 @@ +// RUN: llvm-mc -triple x86_64-apple-darwin10 %s -filetype=obj -o - | macho-dump | FileCheck %s + + .text +L0: +D0: + .section __TEXT,__text,regular,pure_instructions +L1: +D1: + .const +L2: +D2: + .static_const +L3: +D3: + .cstring +L4: +D4: + .literal4 +L5: +D5: + .literal8 +L6: +D6: + .literal16 +L7: +D7: + .constructor +L8: +D8: + .destructor +L9: +D9: +// .symbol_stub +//L10: +//D10: +// .picsymbol_stub +//L11: +//D11: + .data +L12: +D12: + .static_data +L13: +D13: +// .non_lazy_symbol_pointer +//L14: +//D14: +// .lazy_symbol_pointer +//L15: +//D15: + .dyld +L16: +D16: + .mod_init_func +L17: +D17: + .mod_term_func +L18: +D18: + .const_data +L19: +D19: + .objc_class +L20: +D20: + .objc_meta_class +L21: +D21: + .objc_cat_cls_meth +L22: +D22: + .objc_cat_inst_meth +L23: +D23: + .objc_protocol +L24: +D24: + .objc_string_object +L25: +D25: + .objc_cls_meth +L26: +D26: + .objc_inst_meth +L27: +D27: + .objc_cls_refs +L28: +D28: + .objc_message_refs +L29: +D29: + .objc_symbols +L30: +D30: + .objc_category +L31: +D31: + .objc_class_vars +L32: +D32: + .objc_instance_vars +L33: +D33: + .objc_module_info +L34: +D34: + .objc_class_names +L35: +D35: + .objc_meth_var_types +L36: +D36: + .objc_meth_var_names +L37: +D37: + .objc_selector_strs +L38: +D38: +// .section __TEXT,__picsymbolstub4,symbol_stubs,none,16 +//L39: +//D39: + +// CHECK: ('cputype', 16777223) +// CHECK: ('cpusubtype', 3) +// CHECK: ('filetype', 1) +// CHECK: ('num_load_commands', 1) +// CHECK: ('load_commands_size', 2656) +// CHECK: ('flag', 0) +// CHECK: ('reserved', 0) +// CHECK: ('load_commands', [ +// CHECK: # Load Command 0 +// CHECK: (('command', 25) +// CHECK: ('size', 2552) +// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('vm_addr', 0) +// CHECK: ('vm_size', 0) +// CHECK: ('file_offset', 2688) +// CHECK: ('file_size', 0) +// CHECK: ('maxprot', 7) +// CHECK: ('initprot', 7) +// CHECK: ('num_sections', 31) +// CHECK: ('flags', 0) +// CHECK: ('sections', [ +// CHECK: # Section 0 +// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 1 +// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 2 +// CHECK: (('section_name', '__static_const\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 3 +// CHECK: (('section_name', '__cstring\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x2) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 4 +// CHECK: (('section_name', '__literal4\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x3) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 5 +// CHECK: (('section_name', '__literal8\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 3) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x4) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 6 +// CHECK: (('section_name', '__literal16\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 4) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0xe) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 7 +// CHECK: (('section_name', '__constructor\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 8 +// CHECK: (('section_name', '__destructor\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 9 +// CHECK: (('section_name', '__data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 10 +// CHECK: (('section_name', '__static_data\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 11 +// CHECK: (('section_name', '__dyld\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 12 +// CHECK: (('section_name', '__mod_init_func\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x9) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 13 +// CHECK: (('section_name', '__mod_term_func\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0xa) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 14 +// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 15 +// CHECK: (('section_name', '__class\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 16 +// CHECK: (('section_name', '__meta_class\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 17 +// CHECK: (('section_name', '__cat_cls_meth\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 18 +// CHECK: (('section_name', '__cat_inst_meth\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 19 +// CHECK: (('section_name', '__protocol\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 20 +// CHECK: (('section_name', '__string_object\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 21 +// CHECK: (('section_name', '__cls_meth\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 22 +// CHECK: (('section_name', '__inst_meth\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 23 +// CHECK: (('section_name', '__cls_refs\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000005) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 24 +// CHECK: (('section_name', '__message_refs\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000005) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 25 +// CHECK: (('section_name', '__symbols\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 26 +// CHECK: (('section_name', '__category\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 27 +// CHECK: (('section_name', '__class_vars\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 28 +// CHECK: (('section_name', '__instance_vars\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 29 +// CHECK: (('section_name', '__module_info\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 30 +// CHECK: (('section_name', '__selector_strs\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x2) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 1 +// CHECK: (('command', 2) +// CHECK: ('size', 24) +// CHECK: ('symoff', 2688) +// CHECK: ('nsyms', 40) +// CHECK: ('stroff', 3328) +// CHECK: ('strsize', 152) +// CHECK: ('_string_data', '\x00D0\x00D1\x00D2\x00D3\x00L4\x00D4\x00D5\x00D6\x00D7\x00D8\x00D9\x00D12\x00D13\x00D16\x00D17\x00D18\x00D19\x00D20\x00D21\x00D22\x00D23\x00D24\x00D25\x00D26\x00D27\x00D28\x00D29\x00D30\x00D31\x00D32\x00D33\x00D34\x00L35\x00D35\x00L36\x00D36\x00L37\x00D37\x00L38\x00D38\x00\x00\x00') +// CHECK: ('_symbols', [ +// CHECK: # Symbol 0 +// CHECK: (('n_strx', 1) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D0') +// CHECK: ), +// CHECK: # Symbol 1 +// CHECK: (('n_strx', 4) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D1') +// CHECK: ), +// CHECK: # Symbol 2 +// CHECK: (('n_strx', 7) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 2) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D2') +// CHECK: ), +// CHECK: # Symbol 3 +// CHECK: (('n_strx', 10) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 3) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D3') +// CHECK: ), +// CHECK: # Symbol 4 +// CHECK: (('n_strx', 13) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'L4') +// CHECK: ), +// CHECK: # Symbol 5 +// CHECK: (('n_strx', 16) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D4') +// CHECK: ), +// CHECK: # Symbol 6 +// CHECK: (('n_strx', 19) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 5) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D5') +// CHECK: ), +// CHECK: # Symbol 7 +// CHECK: (('n_strx', 22) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 6) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D6') +// CHECK: ), +// CHECK: # Symbol 8 +// CHECK: (('n_strx', 25) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 7) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D7') +// CHECK: ), +// CHECK: # Symbol 9 +// CHECK: (('n_strx', 28) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 8) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D8') +// CHECK: ), +// CHECK: # Symbol 10 +// CHECK: (('n_strx', 31) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 9) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D9') +// CHECK: ), +// CHECK: # Symbol 11 +// CHECK: (('n_strx', 34) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 10) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D12') +// CHECK: ), +// CHECK: # Symbol 12 +// CHECK: (('n_strx', 38) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 11) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D13') +// CHECK: ), +// CHECK: # Symbol 13 +// CHECK: (('n_strx', 42) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 12) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D16') +// CHECK: ), +// CHECK: # Symbol 14 +// CHECK: (('n_strx', 46) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 13) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D17') +// CHECK: ), +// CHECK: # Symbol 15 +// CHECK: (('n_strx', 50) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 14) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D18') +// CHECK: ), +// CHECK: # Symbol 16 +// CHECK: (('n_strx', 54) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 15) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D19') +// CHECK: ), +// CHECK: # Symbol 17 +// CHECK: (('n_strx', 58) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 16) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D20') +// CHECK: ), +// CHECK: # Symbol 18 +// CHECK: (('n_strx', 62) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 17) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D21') +// CHECK: ), +// CHECK: # Symbol 19 +// CHECK: (('n_strx', 66) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 18) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D22') +// CHECK: ), +// CHECK: # Symbol 20 +// CHECK: (('n_strx', 70) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 19) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D23') +// CHECK: ), +// CHECK: # Symbol 21 +// CHECK: (('n_strx', 74) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 20) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D24') +// CHECK: ), +// CHECK: # Symbol 22 +// CHECK: (('n_strx', 78) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 21) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D25') +// CHECK: ), +// CHECK: # Symbol 23 +// CHECK: (('n_strx', 82) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 22) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D26') +// CHECK: ), +// CHECK: # Symbol 24 +// CHECK: (('n_strx', 86) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 23) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D27') +// CHECK: ), +// CHECK: # Symbol 25 +// CHECK: (('n_strx', 90) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 24) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D28') +// CHECK: ), +// CHECK: # Symbol 26 +// CHECK: (('n_strx', 94) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 25) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D29') +// CHECK: ), +// CHECK: # Symbol 27 +// CHECK: (('n_strx', 98) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 26) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D30') +// CHECK: ), +// CHECK: # Symbol 28 +// CHECK: (('n_strx', 102) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 27) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D31') +// CHECK: ), +// CHECK: # Symbol 29 +// CHECK: (('n_strx', 106) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 28) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D32') +// CHECK: ), +// CHECK: # Symbol 30 +// CHECK: (('n_strx', 110) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 29) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D33') +// CHECK: ), +// CHECK: # Symbol 31 +// CHECK: (('n_strx', 114) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 30) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D34') +// CHECK: ), +// CHECK: # Symbol 32 +// CHECK: (('n_strx', 118) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'L35') +// CHECK: ), +// CHECK: # Symbol 33 +// CHECK: (('n_strx', 122) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D35') +// CHECK: ), +// CHECK: # Symbol 34 +// CHECK: (('n_strx', 126) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'L36') +// CHECK: ), +// CHECK: # Symbol 35 +// CHECK: (('n_strx', 130) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D36') +// CHECK: ), +// CHECK: # Symbol 36 +// CHECK: (('n_strx', 134) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'L37') +// CHECK: ), +// CHECK: # Symbol 37 +// CHECK: (('n_strx', 138) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D37') +// CHECK: ), +// CHECK: # Symbol 38 +// CHECK: (('n_strx', 142) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 31) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'L38') +// CHECK: ), +// CHECK: # Symbol 39 +// CHECK: (('n_strx', 146) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 31) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D38') +// CHECK: ), +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 2 +// CHECK: (('command', 11) +// CHECK: ('size', 80) +// CHECK: ('ilocalsym', 0) +// CHECK: ('nlocalsym', 40) +// CHECK: ('iextdefsym', 40) +// CHECK: ('nextdefsym', 0) +// CHECK: ('iundefsym', 40) +// CHECK: ('nundefsym', 0) +// CHECK: ('tocoff', 0) +// CHECK: ('ntoc', 0) +// CHECK: ('modtaboff', 0) +// CHECK: ('nmodtab', 0) +// CHECK: ('extrefsymoff', 0) +// CHECK: ('nextrefsyms', 0) +// CHECK: ('indirectsymoff', 0) +// CHECK: ('nindirectsyms', 0) +// CHECK: ('extreloff', 0) +// CHECK: ('nextrel', 0) +// CHECK: ('locreloff', 0) +// CHECK: ('nlocrel', 0) +// CHECK: ('_indirect_symbols', [ +// CHECK: ]) +// CHECK: ), +// CHECK: ]) diff --git a/test/Other/constant-fold-gep.ll b/test/Other/constant-fold-gep.ll index 5358e1f52339..ecef9c48492e 100644 --- a/test/Other/constant-fold-gep.ll +++ b/test/Other/constant-fold-gep.ll @@ -21,10 +21,12 @@ ; PLAIN: %1 = type { double, float, double, double } ; PLAIN: %2 = type { i1, i1* } ; PLAIN: %3 = type { i64, i64 } +; PLAIN: %4 = type { i32, i32 } ; OPT: %0 = type { i1, double } ; OPT: %1 = type { double, float, double, double } ; OPT: %2 = type { i1, i1* } ; OPT: %3 = type { i64, i64 } +; OPT: %4 = type { i32, i32 } ; The automatic constant folder in opt does not have targetdata access, so ; it can't fold gep arithmetic, in general. However, the constant folder run @@ -118,9 +120,19 @@ ; TO: @N = constant i64* inttoptr (i64 8 to i64*) ; TO: @O = constant i64* inttoptr (i64 8 to i64*) -@M = constant i64* getelementptr (i64 *null, i32 1) -@N = constant i64* getelementptr ({ i64, i64 } *null, i32 0, i32 1) -@O = constant i64* getelementptr ([2 x i64] *null, i32 0, i32 1) +@M = constant i64* getelementptr (i64* null, i32 1) +@N = constant i64* getelementptr ({ i64, i64 }* null, i32 0, i32 1) +@O = constant i64* getelementptr ([2 x i64]* null, i32 0, i32 1) + +; Fold GEP of a GEP. Theoretically some of these cases could be folded +; without using targetdata, however that's not implemented yet. + +; PLAIN: @Z = global i32* getelementptr inbounds (i32* getelementptr inbounds ([3 x %4]* @ext, i64 0, i64 1, i32 0), i64 1) +; OPT: @Z = global i32* getelementptr (i32* getelementptr inbounds ([3 x %4]* @ext, i64 0, i64 1, i32 0), i64 1) +; TO: @Z = global i32* getelementptr inbounds ([3 x %0]* @ext, i64 0, i64 1, i32 1) + +@ext = external global [3 x { i32, i32 }] +@Z = global i32* getelementptr inbounds (i32* getelementptr inbounds ([3 x { i32, i32 }]* @ext, i64 0, i64 1, i32 0), i64 1) ; Duplicate all of the above as function return values rather than ; global initializers. @@ -457,14 +469,33 @@ define i64 @fk() nounwind { ; SCEV: --> sizeof(i64) define i64* @fM() nounwind { - %t = bitcast i64* getelementptr (i64 *null, i32 1) to i64* + %t = bitcast i64* getelementptr (i64* null, i32 1) to i64* ret i64* %t } define i64* @fN() nounwind { - %t = bitcast i64* getelementptr ({ i64, i64 } *null, i32 0, i32 1) to i64* + %t = bitcast i64* getelementptr ({ i64, i64 }* null, i32 0, i32 1) to i64* ret i64* %t } define i64* @fO() nounwind { - %t = bitcast i64* getelementptr ([2 x i64] *null, i32 0, i32 1) to i64* + %t = bitcast i64* getelementptr ([2 x i64]* null, i32 0, i32 1) to i64* ret i64* %t } + +; PLAIN: define i32* @fZ() nounwind { +; PLAIN: %t = bitcast i32* getelementptr inbounds (i32* getelementptr inbounds ([3 x %4]* @ext, i64 0, i64 1, i32 0), i64 1) to i32* +; PLAIN: ret i32* %t +; PLAIN: } +; OPT: define i32* @fZ() nounwind { +; OPT: ret i32* getelementptr inbounds (i32* getelementptr inbounds ([3 x %4]* @ext, i64 0, i64 1, i32 0), i64 1) +; OPT: } +; TO: define i32* @fZ() nounwind { +; TO: ret i32* getelementptr inbounds ([3 x %0]* @ext, i64 0, i64 1, i32 1) +; TO: } +; SCEV: Classifying expressions for: @fZ +; SCEV: %t = bitcast i32* getelementptr inbounds (i32* getelementptr inbounds ([3 x %4]* @ext, i64 0, i64 1, i32 0), i64 1) to i32* +; SCEV: --> ((3 * sizeof(i32)) + @ext) + +define i32* @fZ() nounwind { + %t = bitcast i32* getelementptr inbounds (i32* getelementptr inbounds ([3 x { i32, i32 }]* @ext, i64 0, i64 1, i32 0), i64 1) to i32* + ret i32* %t +} diff --git a/test/Scripts/macho-dump b/test/Scripts/macho-dump index 5b9943ada2ca..72f833975d04 100755 --- a/test/Scripts/macho-dump +++ b/test/Scripts/macho-dump @@ -12,12 +12,10 @@ class Reader: else: self.file = open(path,'rb') self.isLSB = None + self.is64Bit = None self.string_table = None - def setLSB(self, isLSB): - self.isLSB = bool(isLSB) - def tell(self): return self.file.tell() @@ -42,6 +40,9 @@ class Reader: Value = struct.unpack('><'[self.isLSB] + 'I', self.read(4))[0] return int(Value) + def read64(self): + return struct.unpack('><'[self.isLSB] + 'Q', self.read(8))[0] + def registerStringTable(self, strings): if self.string_table is not None: raise ValueError,"%s: warning: multiple string tables" % sys.argv[0] @@ -60,9 +61,13 @@ def dumpmacho(path, opts): magic = f.read(4) if magic == '\xFE\xED\xFA\xCE': - f.setLSB(False) + f.isLSB, f.is64Bit = False, False elif magic == '\xCE\xFA\xED\xFE': - f.setLSB(True) + f.isLSB, f.is64Bit = True, False + elif magic == '\xFE\xED\xFA\xCF': + f.isLSB, f.is64Bit = False, True + elif magic == '\xCF\xFA\xED\xFE': + f.isLSB, f.is64Bit = True, True else: raise ValueError,"Not a Mach-O object file: %r (bad magic)" % path @@ -79,6 +84,9 @@ def dumpmacho(path, opts): print "('flag', %r)" % f.read32() + if f.is64Bit: + print "('reserved', %r)" % f.read32() + start = f.tell() print "('load_commands', [" @@ -87,7 +95,8 @@ def dumpmacho(path, opts): print "])" if f.tell() - start != loadCommandsSize: - raise ValueError,"%s: warning: invalid load commands size: %r" % (sys.argv[0], loadCommandsSize) + raise ValueError,"%s: warning: invalid load commands size: %r" % ( + sys.argv[0], loadCommandsSize) def dumpLoadCommand(f, i, opts): start = f.tell() @@ -99,28 +108,38 @@ def dumpLoadCommand(f, i, opts): print " ('size', %r)" % cmdSize if cmd == 1: - dumpSegmentLoadCommand32(f, opts) + dumpSegmentLoadCommand(f, opts, False) elif cmd == 2: dumpSymtabCommand(f, opts) elif cmd == 11: dumpDysymtabCommand(f, opts) + elif cmd == 25: + dumpSegmentLoadCommand(f, opts, True) elif cmd == 27: import uuid print " ('uuid', %s)" % uuid.UUID(bytes=f.read(16)) else: - print >>sys.stderr,"%s: warning: unknown load command: %r" % (sys.argv[0], cmd) + print >>sys.stderr,"%s: warning: unknown load command: %r" % ( + sys.argv[0], cmd) f.read(cmdSize - 8) print " )," if f.tell() - start != cmdSize: - raise ValueError,"%s: warning: invalid load command size: %r" % (sys.argv[0], cmdSize) + raise ValueError,"%s: warning: invalid load command size: %r" % ( + sys.argv[0], cmdSize) -def dumpSegmentLoadCommand32(f, opts): +def dumpSegmentLoadCommand(f, opts, is64Bit): print " ('segment_name', %r)" % f.read(16) - print " ('vm_addr', %r)" % f.read32() - print " ('vm_size', %r)" % f.read32() - print " ('file_offset', %r)" % f.read32() - print " ('file_size', %r)" % f.read32() + if is64Bit: + print " ('vm_addr', %r)" % f.read64() + print " ('vm_size', %r)" % f.read64() + print " ('file_offset', %r)" % f.read64() + print " ('file_size', %r)" % f.read64() + else: + print " ('vm_addr', %r)" % f.read32() + print " ('vm_size', %r)" % f.read32() + print " ('file_offset', %r)" % f.read32() + print " ('file_size', %r)" % f.read32() print " ('maxprot', %r)" % f.read32() print " ('initprot', %r)" % f.read32() numSections = f.read32() @@ -129,7 +148,7 @@ def dumpSegmentLoadCommand32(f, opts): print " ('sections', [" for i in range(numSections): - dumpSection32(f, i, opts) + dumpSection(f, i, opts, is64Bit) print " ])" def dumpSymtabCommand(f, opts): @@ -168,8 +187,12 @@ def dumpNlist32(f, i, opts): print " ('n_sect', %r)" % n_sect n_desc = f.read16() print " ('n_desc', %r)" % n_desc - n_value = f.read32() - print " ('n_value', %r)" % n_value + if f.is64Bit: + n_value = f.read64() + print " ('n_value', %r)" % n_value + else: + n_value = f.read32() + print " ('n_value', %r)" % n_value print " ('_string', %r)" % f.getString(n_strx) print " )," @@ -206,13 +229,18 @@ def dumpDysymtabCommand(f, opts): f.seek(prev_pos) -def dumpSection32(f, i, opts): +def dumpSection(f, i, opts, is64Bit): print " # Section %r" % i print " (('section_name', %r)" % f.read(16) print " ('segment_name', %r)" % f.read(16) - print " ('address', %r)" % f.read32() - size = f.read32() - print " ('size', %r)" % size + if is64Bit: + print " ('address', %r)" % f.read64() + size = f.read64() + print " ('size', %r)" % size + else: + print " ('address', %r)" % f.read32() + size = f.read32() + print " ('size', %r)" % size offset = f.read32() print " ('offset', %r)" % offset print " ('alignment', %r)" % f.read32() @@ -223,6 +251,8 @@ def dumpSection32(f, i, opts): print " ('flags', %#x)" % f.read32() print " ('reserved1', %r)" % f.read32() print " ('reserved2', %r)" % f.read32() + if is64Bit: + print " ('reserved3', %r)" % f.read32() print " )," prev_pos = f.tell() diff --git a/test/Transforms/InstCombine/gepgep.ll b/test/Transforms/InstCombine/gepgep.ll new file mode 100644 index 000000000000..9e681d28c424 --- /dev/null +++ b/test/Transforms/InstCombine/gepgep.ll @@ -0,0 +1,13 @@ +; RUN: opt < %s -instcombine -disable-output + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" +target triple = "x86_64-unknown-linux-gnu" + +@buffer = external global [64 x float] + +declare void @use(i8*) + +define void @f() { + call void @use(i8* getelementptr (i8* getelementptr (i8* bitcast ([64 x float]* @buffer to i8*), i64 and (i64 sub (i64 0, i64 ptrtoint ([64 x float]* @buffer to i64)), i64 63)), i64 64)) + ret void +} diff --git a/test/Transforms/InstCombine/shift-sra.ll b/test/Transforms/InstCombine/shift-sra.ll index 58f322635c25..a578bbe4d4fc 100644 --- a/test/Transforms/InstCombine/shift-sra.ll +++ b/test/Transforms/InstCombine/shift-sra.ll @@ -56,3 +56,23 @@ C: ; CHECK: %P = phi i64 ; CHECK-NEXT: ret i64 %P } + +; rdar://7732987 +define i32 @test5(i32 %Y) { + br i1 undef, label %A, label %C +A: + br i1 undef, label %B, label %D +B: + br label %D +C: + br i1 undef, label %D, label %E +D: + %P = phi i32 [0, %A], [0, %B], [%Y, %C] + %S = ashr i32 %P, 16 + ret i32 %S +; CHECK: @test5 +; CHECK: %P = phi i32 +; CHECK-NEXT: ashr i32 %P, 16 +E: + ret i32 0 +} diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index feda331177b1..7228c01567a9 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -28,7 +28,7 @@ namespace { // for miscompilation. // enum OutputType { - AutoPick, RunLLI, RunJIT, RunLLC, RunCBE, CBE_bug, LLC_Safe, Custom + AutoPick, RunLLI, RunJIT, RunLLC, RunLLCIA, RunCBE, CBE_bug, LLC_Safe,Custom }; cl::opt<double> @@ -45,6 +45,8 @@ namespace { "Execute with the interpreter"), clEnumValN(RunJIT, "run-jit", "Execute with JIT"), clEnumValN(RunLLC, "run-llc", "Compile with LLC"), + clEnumValN(RunLLCIA, "run-llc-ia", + "Compile with LLC with integrated assembler"), clEnumValN(RunCBE, "run-cbe", "Compile with CBE"), clEnumValN(CBE_bug,"cbe-bug", "Find CBE bugs"), clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"), @@ -168,9 +170,11 @@ bool BugDriver::initializeExecutionEnvironment() { &ToolArgv); break; case RunLLC: + case RunLLCIA: case LLC_Safe: Interpreter = AbstractInterpreter::createLLC(getToolName(), Message, - &ToolArgv, &GCCToolArgv); + &ToolArgv, &GCCToolArgv, + InterpreterSel == RunLLCIA); break; case RunJIT: Interpreter = AbstractInterpreter::createJIT(getToolName(), Message, @@ -244,10 +248,12 @@ bool BugDriver::initializeExecutionEnvironment() { } break; case RunLLC: + case RunLLCIA: SafeToolArgs.push_back("--relocation-model=pic"); SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, &SafeToolArgs, - &GCCToolArgv); + &GCCToolArgv, + SafeInterpreterSel == RunLLCIA); break; case RunCBE: SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message, diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 645776eafdb9..62df0f1dff07 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -141,7 +141,7 @@ static void ProcessFailure(sys::Path ProgPath, const char** Args) { for (const char **Arg = Args; *Arg; ++Arg) OS << " " << *Arg; OS << "\n"; - + // Rerun the compiler, capturing any error messages to print them. sys::Path ErrorFilename("bugpoint.program_error_messages"); std::string ErrMsg; @@ -352,7 +352,8 @@ AbstractInterpreter *AbstractInterpreter::createCustom( // GCC::FileType LLC::OutputCode(const std::string &Bitcode, sys::Path &OutputAsmFile) { - sys::Path uniqueFile(Bitcode+".llc.s"); + const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s"); + sys::Path uniqueFile(Bitcode + Suffix); std::string ErrMsg; if (uniqueFile.makeUnique(true, &ErrMsg)) { errs() << "Error making unique filename: " << ErrMsg << "\n"; @@ -360,18 +361,23 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode, } OutputAsmFile = uniqueFile; std::vector<const char *> LLCArgs; - LLCArgs.push_back (LLCPath.c_str()); + LLCArgs.push_back(LLCPath.c_str()); // Add any extra LLC args. for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) LLCArgs.push_back(ToolArgs[i].c_str()); - LLCArgs.push_back ("-o"); - LLCArgs.push_back (OutputAsmFile.c_str()); // Output to the Asm file - LLCArgs.push_back (Bitcode.c_str()); // This is the input bitcode + LLCArgs.push_back("-o"); + LLCArgs.push_back(OutputAsmFile.c_str()); // Output to the Asm file + LLCArgs.push_back(Bitcode.c_str()); // This is the input bitcode + + if (UseIntegratedAssembler) + LLCArgs.push_back("-filetype=obj"); + LLCArgs.push_back (0); - outs() << "<llc>"; outs().flush(); + outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>"); + outs().flush(); DEBUG(errs() << "\nAbout to run:\t"; for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i) errs() << " " << LLCArgs[i]; @@ -381,7 +387,7 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode, sys::Path(), sys::Path(), sys::Path())) ProcessFailure(sys::Path(LLCPath), &LLCArgs[0]); - return GCC::AsmFile; + return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile; } void LLC::compileProgram(const std::string &Bitcode) { @@ -400,7 +406,7 @@ int LLC::ExecuteProgram(const std::string &Bitcode, unsigned MemoryLimit) { sys::Path OutputAsmFile; - OutputCode(Bitcode, OutputAsmFile); + GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile); FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); std::vector<std::string> GCCArgs(ArgsForGCC); @@ -408,7 +414,7 @@ int LLC::ExecuteProgram(const std::string &Bitcode, GCCArgs.insert(GCCArgs.end(), gccArgs.begin(), gccArgs.end()); // Assuming LLC worked, compile the result with GCC and run it. - return gcc->ExecuteProgram(OutputAsmFile.str(), Args, GCC::AsmFile, + return gcc->ExecuteProgram(OutputAsmFile.str(), Args, FileKind, InputFile, OutputFile, GCCArgs, Timeout, MemoryLimit); } @@ -418,7 +424,8 @@ int LLC::ExecuteProgram(const std::string &Bitcode, LLC *AbstractInterpreter::createLLC(const char *Argv0, std::string &Message, const std::vector<std::string> *Args, - const std::vector<std::string> *GCCArgs) { + const std::vector<std::string> *GCCArgs, + bool UseIntegratedAssembler) { std::string LLCPath = FindExecutable("llc", Argv0, (void *)(intptr_t)&createLLC).str(); if (LLCPath.empty()) { @@ -432,7 +439,7 @@ LLC *AbstractInterpreter::createLLC(const char *Argv0, errs() << Message << "\n"; exit(1); } - return new LLC(LLCPath, gcc, Args, GCCArgs); + return new LLC(LLCPath, gcc, Args, GCCArgs, UseIntegratedAssembler); } //===---------------------------------------------------------------------===// @@ -605,17 +612,14 @@ CBE *AbstractInterpreter::createCBE(const char *Argv0, // GCC abstraction // -static bool -IsARMArchitecture(std::vector<std::string> Args) -{ +static bool IsARMArchitecture(std::vector<std::string> Args) { for (std::vector<std::string>::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { StringRef S(*I); if (!S.equals_lower("-arch")) { ++I; - if (I != E && !S.substr(0, strlen("arm")).equals_lower("arm")) { + if (I != E && !S.substr(0, strlen("arm")).equals_lower("arm")) return true; - } } } @@ -634,26 +638,33 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, GCCArgs.push_back(GCCPath.c_str()); + if (TargetTriple.getArch() == Triple::x86) + GCCArgs.push_back("-m32"); + for (std::vector<std::string>::const_iterator I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I) GCCArgs.push_back(I->c_str()); // Specify -x explicitly in case the extension is wonky - GCCArgs.push_back("-x"); - if (fileType == CFile) { - GCCArgs.push_back("c"); - GCCArgs.push_back("-fno-strict-aliasing"); - } else { - GCCArgs.push_back("assembler"); - - // For ARM architectures we don't want this flag. bugpoint isn't - // explicitly told what architecture it is working on, so we get - // it from gcc flags - if ((TargetTriple.getOS() == Triple::Darwin) && - !IsARMArchitecture(ArgsForGCC)) - GCCArgs.push_back("-force_cpusubtype_ALL"); + if (fileType != ObjectFile) { + GCCArgs.push_back("-x"); + if (fileType == CFile) { + GCCArgs.push_back("c"); + GCCArgs.push_back("-fno-strict-aliasing"); + } else { + GCCArgs.push_back("assembler"); + + // For ARM architectures we don't want this flag. bugpoint isn't + // explicitly told what architecture it is working on, so we get + // it from gcc flags + if ((TargetTriple.getOS() == Triple::Darwin) && + !IsARMArchitecture(ArgsForGCC)) + GCCArgs.push_back("-force_cpusubtype_ALL"); + } } - GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename... + + GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename. + GCCArgs.push_back("-x"); GCCArgs.push_back("none"); GCCArgs.push_back("-o"); @@ -765,13 +776,18 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, GCCArgs.push_back(GCCPath.c_str()); + if (TargetTriple.getArch() == Triple::x86) + GCCArgs.push_back("-m32"); + for (std::vector<std::string>::const_iterator I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I) GCCArgs.push_back(I->c_str()); // Compile the C/asm file into a shared object - GCCArgs.push_back("-x"); - GCCArgs.push_back(fileType == AsmFile ? "assembler" : "c"); + if (fileType != ObjectFile) { + GCCArgs.push_back("-x"); + GCCArgs.push_back(fileType == AsmFile ? "assembler" : "c"); + } GCCArgs.push_back("-fno-strict-aliasing"); GCCArgs.push_back(InputFile.c_str()); // Specify the input filename. GCCArgs.push_back("-x"); diff --git a/tools/bugpoint/ToolRunner.h b/tools/bugpoint/ToolRunner.h index 39b0bbfdd5ec..0f75e99db4be 100644 --- a/tools/bugpoint/ToolRunner.h +++ b/tools/bugpoint/ToolRunner.h @@ -58,7 +58,7 @@ class GCC { if (GCCArgs) gccArgs = *GCCArgs; } public: - enum FileType { AsmFile, CFile }; + enum FileType { AsmFile, ObjectFile, CFile }; static GCC *create(std::string &Message, const std::vector<std::string> *Args); @@ -101,7 +101,8 @@ public: const std::vector<std::string> *GCCArgs = 0); static LLC *createLLC(const char *Argv0, std::string &Message, const std::vector<std::string> *Args = 0, - const std::vector<std::string> *GCCArgs = 0); + const std::vector<std::string> *GCCArgs = 0, + bool UseIntegratedAssembler = false); static AbstractInterpreter* createLLI(const char *Argv0, std::string &Message, const std::vector<std::string> *Args=0); @@ -195,11 +196,14 @@ class LLC : public AbstractInterpreter { std::vector<std::string> ToolArgs; // Extra args to pass to LLC. std::vector<std::string> gccArgs; // Extra args to pass to GCC. GCC *gcc; + bool UseIntegratedAssembler; public: LLC(const std::string &llcPath, GCC *Gcc, const std::vector<std::string> *Args, - const std::vector<std::string> *GCCArgs) - : LLCPath(llcPath), gcc(Gcc) { + const std::vector<std::string> *GCCArgs, + bool useIntegratedAssembler) + : LLCPath(llcPath), gcc(Gcc), + UseIntegratedAssembler(useIntegratedAssembler) { ToolArgs.clear(); if (Args) ToolArgs = *Args; if (GCCArgs) gccArgs = *GCCArgs; diff --git a/tools/edis/EDDisassembler.cpp b/tools/edis/EDDisassembler.cpp index 99864fb322ca..f2b2f9157754 100644 --- a/tools/edis/EDDisassembler.cpp +++ b/tools/edis/EDDisassembler.cpp @@ -341,19 +341,17 @@ int EDDisassembler::parseInst(SmallVectorImpl<MCParsedAsmOperand*> &operands, SourceMgr sourceMgr; sourceMgr.AddNewSourceBuffer(buf, SMLoc()); // ownership of buf handed over - MCContext context; - OwningPtr<MCStreamer> streamer - (createNullStreamer(context)); + MCContext context(*AsmInfo); + OwningPtr<MCStreamer> streamer(createNullStreamer(context)); AsmParser genericParser(sourceMgr, context, *streamer, *AsmInfo); - OwningPtr<TargetAsmParser> specificParser - (Tgt->createAsmParser(genericParser)); + OwningPtr<TargetAsmParser> TargetParser(Tgt->createAsmParser(genericParser)); AsmToken OpcodeToken = genericParser.Lex(); if(OpcodeToken.is(AsmToken::Identifier)) { instName = OpcodeToken.getString(); instLoc = OpcodeToken.getLoc(); - if (specificParser->ParseInstruction(instName, instLoc, operands)) + if (TargetParser->ParseInstruction(instName, instLoc, operands)) ret = -1; } else { diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index 76ce080caea5..66e126092db2 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -26,7 +26,9 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/System/Host.h" #include "llvm/System/Signals.h" +#include "llvm/Target/TargetAsmBackend.h" #include "llvm/Target/TargetAsmParser.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetRegistry.h" @@ -75,9 +77,16 @@ IncludeDirs("I", cl::desc("Directory of include files"), cl::value_desc("directory"), cl::Prefix); static cl::opt<std::string> +ArchName("arch", cl::desc("Target arch to assemble for, " + "see -version for available targets")); + +static cl::opt<std::string> TripleName("triple", cl::desc("Target triple to assemble for, " - "see -version for available targets"), - cl::init(LLVM_HOSTTRIPLE)); + "see -version for available targets")); + +static cl::opt<bool> +NoInitialTextSection("n", cl::desc( + "Don't assume assembly file starts in the text section")); enum ActionType { AC_AsLex, @@ -97,6 +106,15 @@ Action(cl::desc("Action to perform:"), clEnumValEnd)); static const Target *GetTarget(const char *ProgName) { + // Figure out the target triple. + if (TripleName.empty()) + TripleName = sys::getHostTriple(); + if (!ArchName.empty()) { + llvm::Triple TT(TripleName); + TT.setArchName(ArchName); + TripleName = TT.str(); + } + // Get the target specific parser. std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error); @@ -241,7 +259,11 @@ static int AssembleInput(const char *ProgName) { // it later. SrcMgr.setIncludeDirs(IncludeDirs); - MCContext Ctx; + + const MCAsmInfo *MAI = TheTarget->createAsmInfo(TripleName); + assert(MAI && "Unable to create target asm info!"); + + MCContext Ctx(*MAI); formatted_raw_ostream *Out = GetOutputStream(); if (!Out) return 1; @@ -259,22 +281,20 @@ static int AssembleInput(const char *ProgName) { OwningPtr<MCInstPrinter> IP; OwningPtr<MCCodeEmitter> CE; OwningPtr<MCStreamer> Str; - - const MCAsmInfo *MAI = TheTarget->createAsmInfo(TripleName); - assert(MAI && "Unable to create target asm info!"); + OwningPtr<TargetAsmBackend> TAB; if (FileType == OFT_AssemblyFile) { IP.reset(TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *Out)); if (ShowEncoding) CE.reset(TheTarget->createCodeEmitter(*TM, Ctx)); - Str.reset(createAsmStreamer(Ctx, *Out, *MAI, - TM->getTargetData()->isLittleEndian(), + Str.reset(createAsmStreamer(Ctx, *Out,TM->getTargetData()->isLittleEndian(), /*asmverbose*/true, IP.get(), CE.get(), ShowInst)); } else { assert(FileType == OFT_ObjectFile && "Invalid file type!"); CE.reset(TheTarget->createCodeEmitter(*TM, Ctx)); - Str.reset(createMachOStreamer(Ctx, *Out, CE.get())); + TAB.reset(TheTarget->createAsmBackend(TripleName)); + Str.reset(createMachOStreamer(Ctx, *TAB, *Out, CE.get())); } AsmParser Parser(SrcMgr, Ctx, *Str.get(), *MAI); @@ -287,10 +307,14 @@ static int AssembleInput(const char *ProgName) { Parser.setTargetParser(*TAP.get()); - int Res = Parser.Run(); + int Res = Parser.Run(NoInitialTextSection); if (Out != &fouts()) delete Out; + // Delete output on errors. + if (Res && OutputFilename != "-") + sys::Path(OutputFilename).eraseFromDisk(); + return Res; } diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index 0a58aa7e898f..15753d350ff8 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -27,24 +27,25 @@ #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/StandardPasses.h" -#include "llvm/Support/SystemUtils.h" -#include "llvm/System/Host.h" -#include "llvm/System/Program.h" -#include "llvm/System/Signals.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/SubtargetFeature.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/MC/MCAsmInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/StandardPasses.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/System/Host.h" +#include "llvm/System/Program.h" +#include "llvm/System/Signals.h" #include "llvm/Config/config.h" #include <cstdlib> #include <unistd.h> @@ -252,7 +253,8 @@ bool LTOCodeGenerator::assemble(const std::string& asmPath, args.push_back(arch); } // add -static to assembler command line when code model requires - if ( (_assemblerPath != NULL) && (_codeModel == LTO_CODEGEN_PIC_MODEL_STATIC) ) + if ( (_assemblerPath != NULL) && + (_codeModel == LTO_CODEGEN_PIC_MODEL_STATIC) ) args.push_back("-static"); } if ( needsCompilerOptions ) { @@ -303,44 +305,44 @@ bool LTOCodeGenerator::determineTarget(std::string& errMsg) // construct LTModule, hand over ownership of module and target const std::string FeatureStr = - SubtargetFeatures::getDefaultSubtargetFeatures(llvm::Triple(Triple)); + SubtargetFeatures::getDefaultSubtargetFeatures(llvm::Triple(Triple)); _target = march->createTargetMachine(Triple, FeatureStr); } return false; } -void LTOCodeGenerator::applyScopeRestrictions() -{ - if ( !_scopeRestrictionsDone ) { - Module* mergedModule = _linker.getModule(); - - // Start off with a verification pass. - PassManager passes; - passes.add(createVerifierPass()); - - // mark which symbols can not be internalized - if ( !_mustPreserveSymbols.empty() ) { - Mangler mangler(*_target->getMCAsmInfo()); - std::vector<const char*> mustPreserveList; - for (Module::iterator f = mergedModule->begin(), - e = mergedModule->end(); f != e; ++f) { - if ( !f->isDeclaration() - && _mustPreserveSymbols.count(mangler.getNameWithPrefix(f)) ) - mustPreserveList.push_back(::strdup(f->getNameStr().c_str())); - } - for (Module::global_iterator v = mergedModule->global_begin(), - e = mergedModule->global_end(); v != e; ++v) { - if ( !v->isDeclaration() - && _mustPreserveSymbols.count(mangler.getNameWithPrefix(v)) ) - mustPreserveList.push_back(::strdup(v->getNameStr().c_str())); - } - passes.add(createInternalizePass(mustPreserveList)); - } - // apply scope restrictions - passes.run(*mergedModule); - - _scopeRestrictionsDone = true; +void LTOCodeGenerator::applyScopeRestrictions() { + if (_scopeRestrictionsDone) return; + Module *mergedModule = _linker.getModule(); + + // Start off with a verification pass. + PassManager passes; + passes.add(createVerifierPass()); + + // mark which symbols can not be internalized + if (!_mustPreserveSymbols.empty()) { + MCContext Context(*_target->getMCAsmInfo()); + Mangler mangler(Context, *_target->getTargetData()); + std::vector<const char*> mustPreserveList; + for (Module::iterator f = mergedModule->begin(), + e = mergedModule->end(); f != e; ++f) { + if (!f->isDeclaration() && + _mustPreserveSymbols.count(mangler.getNameWithPrefix(f))) + mustPreserveList.push_back(::strdup(f->getNameStr().c_str())); + } + for (Module::global_iterator v = mergedModule->global_begin(), + e = mergedModule->global_end(); v != e; ++v) { + if (v->isDeclaration() && + _mustPreserveSymbols.count(mangler.getNameWithPrefix(v))) + mustPreserveList.push_back(::strdup(v->getNameStr().c_str())); } + passes.add(createInternalizePass(mustPreserveList)); + } + + // apply scope restrictions + passes.run(*mergedModule); + + _scopeRestrictionsDone = true; } /// Optimize merged modules using various IPO passes diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index 15fb3f549b68..08576abac456 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -1,4 +1,4 @@ -//===-LTOModule.cpp - LLVM Link Time Optimizer ----------------------------===// +//===-- LTOModule.cpp - LLVM Link Time Optimizer --------------------------===// // // The LLVM Compiler Infrastructure // @@ -29,6 +29,7 @@ #include "llvm/Target/Mangler.h" #include "llvm/Target/SubtargetFeature.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetSelect.h" @@ -437,7 +438,8 @@ void LTOModule::lazyParseSymbols() _symbolsParsed = true; // Use mangler to add GlobalPrefix to names to match linker names. - Mangler mangler(*_target->getMCAsmInfo()); + MCContext Context(*_target->getMCAsmInfo()); + Mangler mangler(Context, *_target->getTargetData()); // add functions for (Module::iterator f = _module->begin(); f != _module->end(); ++f) { diff --git a/unittests/Transforms/Utils/Cloning.cpp b/unittests/Transforms/Utils/Cloning.cpp index 17047e7ca15a..b65ac34dacdf 100644 --- a/unittests/Transforms/Utils/Cloning.cpp +++ b/unittests/Transforms/Utils/Cloning.cpp @@ -11,78 +11,131 @@ #include "llvm/Argument.h" #include "llvm/Instructions.h" #include "llvm/LLVMContext.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/STLExtras.h" using namespace llvm; -TEST(CloneInstruction, OverflowBits) { +class CloneInstruction : public ::testing::Test { +protected: + virtual void SetUp() { + V = NULL; + } + + template <typename T> + T *clone(T *V1) { + Value *V2 = V1->clone(); + Orig.insert(V1); + Clones.insert(V2); + return cast<T>(V2); + } + + void eraseClones() { + DeleteContainerPointers(Clones); + } + + virtual void TearDown() { + eraseClones(); + DeleteContainerPointers(Orig); + delete V; + } + + SmallPtrSet<Value *, 4> Orig; // Erase on exit + SmallPtrSet<Value *, 4> Clones; // Erase in eraseClones + LLVMContext context; - Value *V = new Argument(Type::getInt32Ty(context)); + Value *V; +}; + +TEST_F(CloneInstruction, OverflowBits) { + V = new Argument(Type::getInt32Ty(context)); BinaryOperator *Add = BinaryOperator::Create(Instruction::Add, V, V); BinaryOperator *Sub = BinaryOperator::Create(Instruction::Sub, V, V); BinaryOperator *Mul = BinaryOperator::Create(Instruction::Mul, V, V); - EXPECT_FALSE(cast<BinaryOperator>(Add->clone())->hasNoUnsignedWrap()); - EXPECT_FALSE(cast<BinaryOperator>(Add->clone())->hasNoSignedWrap()); - EXPECT_FALSE(cast<BinaryOperator>(Sub->clone())->hasNoUnsignedWrap()); - EXPECT_FALSE(cast<BinaryOperator>(Sub->clone())->hasNoSignedWrap()); - EXPECT_FALSE(cast<BinaryOperator>(Mul->clone())->hasNoUnsignedWrap()); - EXPECT_FALSE(cast<BinaryOperator>(Mul->clone())->hasNoSignedWrap()); + BinaryOperator *AddClone = this->clone(Add); + BinaryOperator *SubClone = this->clone(Sub); + BinaryOperator *MulClone = this->clone(Mul); + + EXPECT_FALSE(AddClone->hasNoUnsignedWrap()); + EXPECT_FALSE(AddClone->hasNoSignedWrap()); + EXPECT_FALSE(SubClone->hasNoUnsignedWrap()); + EXPECT_FALSE(SubClone->hasNoSignedWrap()); + EXPECT_FALSE(MulClone->hasNoUnsignedWrap()); + EXPECT_FALSE(MulClone->hasNoSignedWrap()); + + eraseClones(); Add->setHasNoUnsignedWrap(); Sub->setHasNoUnsignedWrap(); Mul->setHasNoUnsignedWrap(); - EXPECT_TRUE(cast<BinaryOperator>(Add->clone())->hasNoUnsignedWrap()); - EXPECT_FALSE(cast<BinaryOperator>(Add->clone())->hasNoSignedWrap()); - EXPECT_TRUE(cast<BinaryOperator>(Sub->clone())->hasNoUnsignedWrap()); - EXPECT_FALSE(cast<BinaryOperator>(Sub->clone())->hasNoSignedWrap()); - EXPECT_TRUE(cast<BinaryOperator>(Mul->clone())->hasNoUnsignedWrap()); - EXPECT_FALSE(cast<BinaryOperator>(Mul->clone())->hasNoSignedWrap()); + AddClone = this->clone(Add); + SubClone = this->clone(Sub); + MulClone = this->clone(Mul); + + EXPECT_TRUE(AddClone->hasNoUnsignedWrap()); + EXPECT_FALSE(AddClone->hasNoSignedWrap()); + EXPECT_TRUE(SubClone->hasNoUnsignedWrap()); + EXPECT_FALSE(SubClone->hasNoSignedWrap()); + EXPECT_TRUE(MulClone->hasNoUnsignedWrap()); + EXPECT_FALSE(MulClone->hasNoSignedWrap()); + + eraseClones(); Add->setHasNoSignedWrap(); Sub->setHasNoSignedWrap(); Mul->setHasNoSignedWrap(); - EXPECT_TRUE(cast<BinaryOperator>(Add->clone())->hasNoUnsignedWrap()); - EXPECT_TRUE(cast<BinaryOperator>(Add->clone())->hasNoSignedWrap()); - EXPECT_TRUE(cast<BinaryOperator>(Sub->clone())->hasNoUnsignedWrap()); - EXPECT_TRUE(cast<BinaryOperator>(Sub->clone())->hasNoSignedWrap()); - EXPECT_TRUE(cast<BinaryOperator>(Mul->clone())->hasNoUnsignedWrap()); - EXPECT_TRUE(cast<BinaryOperator>(Mul->clone())->hasNoSignedWrap()); + AddClone = this->clone(Add); + SubClone = this->clone(Sub); + MulClone = this->clone(Mul); + + EXPECT_TRUE(AddClone->hasNoUnsignedWrap()); + EXPECT_TRUE(AddClone->hasNoSignedWrap()); + EXPECT_TRUE(SubClone->hasNoUnsignedWrap()); + EXPECT_TRUE(SubClone->hasNoSignedWrap()); + EXPECT_TRUE(MulClone->hasNoUnsignedWrap()); + EXPECT_TRUE(MulClone->hasNoSignedWrap()); + + eraseClones(); Add->setHasNoUnsignedWrap(false); Sub->setHasNoUnsignedWrap(false); Mul->setHasNoUnsignedWrap(false); - EXPECT_FALSE(cast<BinaryOperator>(Add->clone())->hasNoUnsignedWrap()); - EXPECT_TRUE(cast<BinaryOperator>(Add->clone())->hasNoSignedWrap()); - EXPECT_FALSE(cast<BinaryOperator>(Sub->clone())->hasNoUnsignedWrap()); - EXPECT_TRUE(cast<BinaryOperator>(Sub->clone())->hasNoSignedWrap()); - EXPECT_FALSE(cast<BinaryOperator>(Mul->clone())->hasNoUnsignedWrap()); - EXPECT_TRUE(cast<BinaryOperator>(Mul->clone())->hasNoSignedWrap()); + AddClone = this->clone(Add); + SubClone = this->clone(Sub); + MulClone = this->clone(Mul); + + EXPECT_FALSE(AddClone->hasNoUnsignedWrap()); + EXPECT_TRUE(AddClone->hasNoSignedWrap()); + EXPECT_FALSE(SubClone->hasNoUnsignedWrap()); + EXPECT_TRUE(SubClone->hasNoSignedWrap()); + EXPECT_FALSE(MulClone->hasNoUnsignedWrap()); + EXPECT_TRUE(MulClone->hasNoSignedWrap()); } -TEST(CloneInstruction, Inbounds) { - LLVMContext context; - Value *V = new Argument(Type::getInt32PtrTy(context)); +TEST_F(CloneInstruction, Inbounds) { + V = new Argument(Type::getInt32PtrTy(context)); + Constant *Z = Constant::getNullValue(Type::getInt32Ty(context)); std::vector<Value *> ops; ops.push_back(Z); GetElementPtrInst *GEP = GetElementPtrInst::Create(V, ops.begin(), ops.end()); - EXPECT_FALSE(cast<GetElementPtrInst>(GEP->clone())->isInBounds()); + EXPECT_FALSE(this->clone(GEP)->isInBounds()); GEP->setIsInBounds(); - EXPECT_TRUE(cast<GetElementPtrInst>(GEP->clone())->isInBounds()); + EXPECT_TRUE(this->clone(GEP)->isInBounds()); } -TEST(CloneInstruction, Exact) { - LLVMContext context; - Value *V = new Argument(Type::getInt32Ty(context)); +TEST_F(CloneInstruction, Exact) { + V = new Argument(Type::getInt32Ty(context)); BinaryOperator *SDiv = BinaryOperator::Create(Instruction::SDiv, V, V); - EXPECT_FALSE(cast<BinaryOperator>(SDiv->clone())->isExact()); + EXPECT_FALSE(this->clone(SDiv)->isExact()); SDiv->setIsExact(true); - EXPECT_TRUE(cast<BinaryOperator>(SDiv->clone())->isExact()); + EXPECT_TRUE(this->clone(SDiv)->isExact()); } diff --git a/unittests/VMCore/InstructionsTest.cpp b/unittests/VMCore/InstructionsTest.cpp new file mode 100644 index 000000000000..2d98cad27fb8 --- /dev/null +++ b/unittests/VMCore/InstructionsTest.cpp @@ -0,0 +1,41 @@ +//===- llvm/unittest/VMCore/InstructionsTest.cpp - Instructions unit tests ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Instructions.h" +#include "llvm/DerivedTypes.h" +#include "llvm/LLVMContext.h" +#include "gtest/gtest.h" + +namespace llvm { +namespace { + +TEST(InstructionsTest, ReturnInst) { + LLVMContext &C(getGlobalContext()); + + // test for PR6589 + const ReturnInst* r0 = ReturnInst::Create(C); + EXPECT_EQ(r0->op_begin(), r0->op_end()); + + const IntegerType* Int1 = IntegerType::get(C, 1); + Constant* One = ConstantInt::get(Int1, 1, true); + const ReturnInst* r1 = ReturnInst::Create(C, One); + User::const_op_iterator b(r1->op_begin()); + EXPECT_NE(b, r1->op_end()); + EXPECT_EQ(*b, One); + EXPECT_EQ(r1->getOperand(0), One); + ++b; + EXPECT_EQ(b, r1->op_end()); + + // clean up + delete r0; + delete r1; +} + +} // end anonymous namespace +} // end namespace llvm diff --git a/unittests/VMCore/MetadataTest.cpp b/unittests/VMCore/MetadataTest.cpp index 13bf27e5d8fa..04db486cd871 100644 --- a/unittests/VMCore/MetadataTest.cpp +++ b/unittests/VMCore/MetadataTest.cpp @@ -132,9 +132,9 @@ TEST(NamedMDNodeTest, Search) { MDNode *Nodes[2] = { n, n2 }; - Module *M = new Module("MyModule", Context); + Module M("MyModule", Context); const char *Name = "llvm.NMD1"; - NamedMDNode *NMD = NamedMDNode::Create(Context, Name, &Nodes[0], 2, M); + NamedMDNode *NMD = NamedMDNode::Create(Context, Name, &Nodes[0], 2, &M); std::string Str; raw_string_ostream oss(Str); NMD->print(oss); diff --git a/unittests/VMCore/PassManagerTest.cpp b/unittests/VMCore/PassManagerTest.cpp index cb8f9ebb939b..bc21298ef200 100644 --- a/unittests/VMCore/PassManagerTest.cpp +++ b/unittests/VMCore/PassManagerTest.cpp @@ -324,10 +324,10 @@ namespace llvm { template<typename T> void MemoryTestHelper(int run) { - Module *M = makeLLVMModule(); + OwningPtr<Module> M(makeLLVMModule()); T *P = new T(); PassManager Passes; - Passes.add(new TargetData(M)); + Passes.add(new TargetData(M.get())); Passes.add(P); Passes.run(*M); T::finishedOK(run); diff --git a/unittests/VMCore/VerifierTest.cpp b/unittests/VMCore/VerifierTest.cpp index c8838c5276db..1173b2d18f76 100644 --- a/unittests/VMCore/VerifierTest.cpp +++ b/unittests/VMCore/VerifierTest.cpp @@ -12,6 +12,7 @@ #include "llvm/Function.h" #include "llvm/Instructions.h" #include "llvm/LLVMContext.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/Analysis/Verifier.h" #include "gtest/gtest.h" @@ -21,9 +22,9 @@ namespace { TEST(VerifierTest, Branch_i1) { LLVMContext &C = getGlobalContext(); FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false); - Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage); - BasicBlock *Entry = BasicBlock::Create(C, "entry", F); - BasicBlock *Exit = BasicBlock::Create(C, "exit", F); + OwningPtr<Function> F(Function::Create(FTy, GlobalValue::ExternalLinkage)); + BasicBlock *Entry = BasicBlock::Create(C, "entry", F.get()); + BasicBlock *Exit = BasicBlock::Create(C, "exit", F.get()); ReturnInst::Create(C, Exit); // To avoid triggering an assertion in BranchInst::Create, we first create diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index e793333eef5c..6e894a46bce4 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -15,44 +15,17 @@ #include "CodeGenDAGPatterns.h" #include "Record.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include <set> #include <algorithm> -#include <iostream> using namespace llvm; //===----------------------------------------------------------------------===// -// Helpers for working with extended types. - -/// FilterVTs - Filter a list of VT's according to a predicate. -/// -template<typename T> -static std::vector<MVT::SimpleValueType> -FilterVTs(const std::vector<MVT::SimpleValueType> &InVTs, T Filter) { - std::vector<MVT::SimpleValueType> Result; - for (unsigned i = 0, e = InVTs.size(); i != e; ++i) - if (Filter(InVTs[i])) - Result.push_back(InVTs[i]); - return Result; -} - -template<typename T> -static std::vector<unsigned char> -FilterEVTs(const std::vector<unsigned char> &InVTs, T Filter) { - std::vector<unsigned char> Result; - for (unsigned i = 0, e = InVTs.size(); i != e; ++i) - if (Filter((MVT::SimpleValueType)InVTs[i])) - Result.push_back(InVTs[i]); - return Result; -} +// EEVT::TypeSet Implementation +//===----------------------------------------------------------------------===// -static std::vector<unsigned char> -ConvertVTs(const std::vector<MVT::SimpleValueType> &InVTs) { - std::vector<unsigned char> Result; - for (unsigned i = 0, e = InVTs.size(); i != e; ++i) - Result.push_back(InVTs[i]); - return Result; -} +// FIXME: Remove EEVT::isUnknown! static inline bool isInteger(MVT::SimpleValueType VT) { return EVT(VT).isInteger(); @@ -66,39 +39,361 @@ static inline bool isVector(MVT::SimpleValueType VT) { return EVT(VT).isVector(); } -static bool LHSIsSubsetOfRHS(const std::vector<unsigned char> &LHS, - const std::vector<unsigned char> &RHS) { - if (LHS.size() > RHS.size()) return false; - for (unsigned i = 0, e = LHS.size(); i != e; ++i) - if (std::find(RHS.begin(), RHS.end(), LHS[i]) == RHS.end()) - return false; - return true; +EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) { + if (VT == MVT::iAny) + EnforceInteger(TP); + else if (VT == MVT::fAny) + EnforceFloatingPoint(TP); + else if (VT == MVT::vAny) + EnforceVector(TP); + else { + assert((VT < MVT::LAST_VALUETYPE || VT == MVT::iPTR || + VT == MVT::iPTRAny) && "Not a concrete type!"); + TypeVec.push_back(VT); + } } -namespace llvm { -namespace EEVT { -/// isExtIntegerInVTs - Return true if the specified extended value type vector -/// contains iAny or an integer value type. -bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs) { - assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!"); - return EVTs[0] == MVT::iAny || !(FilterEVTs(EVTs, isInteger).empty()); + +EEVT::TypeSet::TypeSet(const std::vector<MVT::SimpleValueType> &VTList) { + assert(!VTList.empty() && "empty list?"); + TypeVec.append(VTList.begin(), VTList.end()); + + if (!VTList.empty()) + assert(VTList[0] != MVT::iAny && VTList[0] != MVT::vAny && + VTList[0] != MVT::fAny); + + // Remove duplicates. + array_pod_sort(TypeVec.begin(), TypeVec.end()); + TypeVec.erase(std::unique(TypeVec.begin(), TypeVec.end()), TypeVec.end()); } -/// isExtFloatingPointInVTs - Return true if the specified extended value type -/// vector contains fAny or a FP value type. -bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs) { - assert(!EVTs.empty() && "Cannot check for FP in empty ExtVT list!"); - return EVTs[0] == MVT::fAny || !(FilterEVTs(EVTs, isFloatingPoint).empty()); + +/// hasIntegerTypes - Return true if this TypeSet contains iAny or an +/// integer value type. +bool EEVT::TypeSet::hasIntegerTypes() const { + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) + if (isInteger(TypeVec[i])) + return true; + return false; +} + +/// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or +/// a floating point value type. +bool EEVT::TypeSet::hasFloatingPointTypes() const { + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) + if (isFloatingPoint(TypeVec[i])) + return true; + return false; +} + +/// hasVectorTypes - Return true if this TypeSet contains a vAny or a vector +/// value type. +bool EEVT::TypeSet::hasVectorTypes() const { + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) + if (isVector(TypeVec[i])) + return true; + return false; } -/// isExtVectorInVTs - Return true if the specified extended value type -/// vector contains vAny or a vector value type. -bool isExtVectorInVTs(const std::vector<unsigned char> &EVTs) { - assert(!EVTs.empty() && "Cannot check for vector in empty ExtVT list!"); - return EVTs[0] == MVT::vAny || !(FilterEVTs(EVTs, isVector).empty()); + +std::string EEVT::TypeSet::getName() const { + if (TypeVec.empty()) return "isUnknown"; + + std::string Result; + + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) { + std::string VTName = llvm::getEnumName(TypeVec[i]); + // Strip off MVT:: prefix if present. + if (VTName.substr(0,5) == "MVT::") + VTName = VTName.substr(5); + if (i) Result += ':'; + Result += VTName; + } + + if (TypeVec.size() == 1) + return Result; + return "{" + Result + "}"; } -} // end namespace EEVT. -} // end namespace llvm. + +/// MergeInTypeInfo - This merges in type information from the specified +/// argument. If 'this' changes, it returns true. If the two types are +/// contradictory (e.g. merge f32 into i32) then this throws an exception. +bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){ + if (InVT.isCompletelyUnknown() || *this == InVT) + return false; + + if (isCompletelyUnknown()) { + *this = InVT; + return true; + } + + assert(TypeVec.size() >= 1 && InVT.TypeVec.size() >= 1 && "No unknowns"); + + // Handle the abstract cases, seeing if we can resolve them better. + switch (TypeVec[0]) { + default: break; + case MVT::iPTR: + case MVT::iPTRAny: + if (InVT.hasIntegerTypes()) { + EEVT::TypeSet InCopy(InVT); + InCopy.EnforceInteger(TP); + InCopy.EnforceScalar(TP); + + if (InCopy.isConcrete()) { + // If the RHS has one integer type, upgrade iPTR to i32. + TypeVec[0] = InVT.TypeVec[0]; + return true; + } + + // If the input has multiple scalar integers, this doesn't add any info. + if (!InCopy.isCompletelyUnknown()) + return false; + } + break; + } + + // If the input constraint is iAny/iPTR and this is an integer type list, + // remove non-integer types from the list. + if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) && + hasIntegerTypes()) { + bool MadeChange = EnforceInteger(TP); + + // If we're merging in iPTR/iPTRAny and the node currently has a list of + // multiple different integer types, replace them with a single iPTR. + if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) && + TypeVec.size() != 1) { + TypeVec.resize(1); + TypeVec[0] = InVT.TypeVec[0]; + MadeChange = true; + } + + return MadeChange; + } + + // If this is a type list and the RHS is a typelist as well, eliminate entries + // from this list that aren't in the other one. + bool MadeChange = false; + TypeSet InputSet(*this); + + for (unsigned i = 0; i != TypeVec.size(); ++i) { + bool InInVT = false; + for (unsigned j = 0, e = InVT.TypeVec.size(); j != e; ++j) + if (TypeVec[i] == InVT.TypeVec[j]) { + InInVT = true; + break; + } + + if (InInVT) continue; + TypeVec.erase(TypeVec.begin()+i--); + MadeChange = true; + } + + // If we removed all of our types, we have a type contradiction. + if (!TypeVec.empty()) + return MadeChange; + + // FIXME: Really want an SMLoc here! + TP.error("Type inference contradiction found, merging '" + + InVT.getName() + "' into '" + InputSet.getName() + "'"); + return true; // unreachable +} + +/// EnforceInteger - Remove all non-integer types from this set. +bool EEVT::TypeSet::EnforceInteger(TreePattern &TP) { + TypeSet InputSet(*this); + bool MadeChange = false; + + // If we know nothing, then get the full set. + if (TypeVec.empty()) { + *this = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + MadeChange = true; + } + + if (!hasFloatingPointTypes()) + return MadeChange; + + // Filter out all the fp types. + for (unsigned i = 0; i != TypeVec.size(); ++i) + if (isFloatingPoint(TypeVec[i])) + TypeVec.erase(TypeVec.begin()+i--); + + if (TypeVec.empty()) + TP.error("Type inference contradiction found, '" + + InputSet.getName() + "' needs to be integer"); + return MadeChange; +} + +/// EnforceFloatingPoint - Remove all integer types from this set. +bool EEVT::TypeSet::EnforceFloatingPoint(TreePattern &TP) { + TypeSet InputSet(*this); + bool MadeChange = false; + + // If we know nothing, then get the full set. + if (TypeVec.empty()) { + *this = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + MadeChange = true; + } + + if (!hasIntegerTypes()) + return MadeChange; + + // Filter out all the fp types. + for (unsigned i = 0; i != TypeVec.size(); ++i) + if (isInteger(TypeVec[i])) + TypeVec.erase(TypeVec.begin()+i--); + + if (TypeVec.empty()) + TP.error("Type inference contradiction found, '" + + InputSet.getName() + "' needs to be floating point"); + return MadeChange; +} + +/// EnforceScalar - Remove all vector types from this. +bool EEVT::TypeSet::EnforceScalar(TreePattern &TP) { + TypeSet InputSet(*this); + bool MadeChange = false; + + // If we know nothing, then get the full set. + if (TypeVec.empty()) { + *this = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + MadeChange = true; + } + + if (!hasVectorTypes()) + return MadeChange; + + // Filter out all the vector types. + for (unsigned i = 0; i != TypeVec.size(); ++i) + if (isVector(TypeVec[i])) + TypeVec.erase(TypeVec.begin()+i--); + + if (TypeVec.empty()) + TP.error("Type inference contradiction found, '" + + InputSet.getName() + "' needs to be scalar"); + return MadeChange; +} + +/// EnforceVector - Remove all vector types from this. +bool EEVT::TypeSet::EnforceVector(TreePattern &TP) { + TypeSet InputSet(*this); + bool MadeChange = false; + + // If we know nothing, then get the full set. + if (TypeVec.empty()) { + *this = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + MadeChange = true; + } + + // Filter out all the scalar types. + for (unsigned i = 0; i != TypeVec.size(); ++i) + if (!isVector(TypeVec[i])) + TypeVec.erase(TypeVec.begin()+i--); + + if (TypeVec.empty()) + TP.error("Type inference contradiction found, '" + + InputSet.getName() + "' needs to be a vector"); + return MadeChange; +} + + +/// EnforceSmallerThan - 'this' must be a smaller VT than Other. Update +/// this an other based on this information. +bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { + // Both operands must be integer or FP, but we don't care which. + bool MadeChange = false; + + // This code does not currently handle nodes which have multiple types, + // where some types are integer, and some are fp. Assert that this is not + // the case. + assert(!(hasIntegerTypes() && hasFloatingPointTypes()) && + !(Other.hasIntegerTypes() && Other.hasFloatingPointTypes()) && + "SDTCisOpSmallerThanOp does not handle mixed int/fp types!"); + // If one side is known to be integer or known to be FP but the other side has + // no information, get at least the type integrality info in there. + if (hasIntegerTypes()) + MadeChange |= Other.EnforceInteger(TP); + else if (hasFloatingPointTypes()) + MadeChange |= Other.EnforceFloatingPoint(TP); + if (Other.hasIntegerTypes()) + MadeChange |= EnforceInteger(TP); + else if (Other.hasFloatingPointTypes()) + MadeChange |= EnforceFloatingPoint(TP); + + assert(!isCompletelyUnknown() && !Other.isCompletelyUnknown() && + "Should have a type list now"); + + // If one contains vectors but the other doesn't pull vectors out. + if (!hasVectorTypes() && Other.hasVectorTypes()) + MadeChange |= Other.EnforceScalar(TP); + if (hasVectorTypes() && !Other.hasVectorTypes()) + MadeChange |= EnforceScalar(TP); + + // FIXME: This is a bone-headed way to do this. + + // Get the set of legal VTs and filter it based on the known integrality. + const CodeGenTarget &CGT = TP.getDAGPatterns().getTargetInfo(); + TypeSet LegalVTs = CGT.getLegalValueTypes(); + + // TODO: If one or the other side is known to be a specific VT, we could prune + // LegalVTs. + if (hasIntegerTypes()) + LegalVTs.EnforceInteger(TP); + else if (hasFloatingPointTypes()) + LegalVTs.EnforceFloatingPoint(TP); + else + return MadeChange; + + switch (LegalVTs.TypeVec.size()) { + case 0: assert(0 && "No legal VTs?"); + default: // Too many VT's to pick from. + // TODO: If the biggest type in LegalVTs is in this set, we could remove it. + // If one or the other side is known to be a specific VT, we could prune + // LegalVTs. + return MadeChange; + case 1: + // Only one VT of this flavor. Cannot ever satisfy the constraints. + return MergeInTypeInfo(MVT::Other, TP); // throw + case 2: + // If we have exactly two possible types, the little operand must be the + // small one, the big operand should be the big one. This is common with + // float/double for example. + assert(LegalVTs.TypeVec[0] < LegalVTs.TypeVec[1] && "Should be sorted!"); + MadeChange |= MergeInTypeInfo(LegalVTs.TypeVec[0], TP); + MadeChange |= Other.MergeInTypeInfo(LegalVTs.TypeVec[1], TP); + return MadeChange; + } +} + +/// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type +/// whose element is VT. +bool EEVT::TypeSet::EnforceVectorEltTypeIs(MVT::SimpleValueType VT, + TreePattern &TP) { + TypeSet InputSet(*this); + bool MadeChange = false; + + // If we know nothing, then get the full set. + if (TypeVec.empty()) { + *this = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + MadeChange = true; + } + + // Filter out all the non-vector types and types which don't have the right + // element type. + for (unsigned i = 0; i != TypeVec.size(); ++i) + if (!isVector(TypeVec[i]) || + EVT(TypeVec[i]).getVectorElementType().getSimpleVT().SimpleTy != VT) { + TypeVec.erase(TypeVec.begin()+i--); + MadeChange = true; + } + + if (TypeVec.empty()) // FIXME: Really want an SMLoc here! + TP.error("Type inference contradiction found, forcing '" + + InputSet.getName() + "' to have a vector element"); + return MadeChange; +} + +//===----------------------------------------------------------------------===// +// Helpers for working with extended types. bool RecordPtrCmp::operator()(const Record *LHS, const Record *RHS) const { return LHS->getID() < RHS->getID(); @@ -208,8 +503,7 @@ SDTypeConstraint::SDTypeConstraint(Record *R) { R->getValueAsInt("BigOperandNum"); } else if (R->isSubClassOf("SDTCisEltOfVec")) { ConstraintType = SDTCisEltOfVec; - x.SDTCisEltOfVec_Info.OtherOperandNum = - R->getValueAsInt("OtherOpNum"); + x.SDTCisEltOfVec_Info.OtherOperandNum = R->getValueAsInt("OtherOpNum"); } else { errs() << "Unrecognized SDTypeConstraint '" << R->getName() << "'!\n"; exit(1); @@ -255,8 +549,6 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, itostr(NodeInfo.getNumOperands()) + " operands!"); } - const CodeGenTarget &CGT = TP.getDAGPatterns().getTargetInfo(); - TreePatternNode *NodeToApply = getOperandNum(OperandNo, N, NumResults); switch (ConstraintType) { @@ -264,45 +556,23 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, case SDTCisVT: // Operand must be a particular type. return NodeToApply->UpdateNodeType(x.SDTCisVT_Info.VT, TP); - case SDTCisPtrTy: { + case SDTCisPtrTy: // Operand must be same as target pointer type. return NodeToApply->UpdateNodeType(MVT::iPTR, TP); - } - case SDTCisInt: { - // If there is only one integer type supported, this must be it. - std::vector<MVT::SimpleValueType> IntVTs = - FilterVTs(CGT.getLegalValueTypes(), isInteger); - - // If we found exactly one supported integer type, apply it. - if (IntVTs.size() == 1) - return NodeToApply->UpdateNodeType(IntVTs[0], TP); - return NodeToApply->UpdateNodeType(MVT::iAny, TP); - } - case SDTCisFP: { - // If there is only one FP type supported, this must be it. - std::vector<MVT::SimpleValueType> FPVTs = - FilterVTs(CGT.getLegalValueTypes(), isFloatingPoint); - - // If we found exactly one supported FP type, apply it. - if (FPVTs.size() == 1) - return NodeToApply->UpdateNodeType(FPVTs[0], TP); - return NodeToApply->UpdateNodeType(MVT::fAny, TP); - } - case SDTCisVec: { - // If there is only one vector type supported, this must be it. - std::vector<MVT::SimpleValueType> VecVTs = - FilterVTs(CGT.getLegalValueTypes(), isVector); - - // If we found exactly one supported vector type, apply it. - if (VecVTs.size() == 1) - return NodeToApply->UpdateNodeType(VecVTs[0], TP); - return NodeToApply->UpdateNodeType(MVT::vAny, TP); - } + case SDTCisInt: + // Require it to be one of the legal integer VTs. + return NodeToApply->getExtType().EnforceInteger(TP); + case SDTCisFP: + // Require it to be one of the legal fp VTs. + return NodeToApply->getExtType().EnforceFloatingPoint(TP); + case SDTCisVec: + // Require it to be one of the legal vector VTs. + return NodeToApply->getExtType().EnforceVector(TP); case SDTCisSameAs: { TreePatternNode *OtherNode = getOperandNum(x.SDTCisSameAs_Info.OtherOperandNum, N, NumResults); - return NodeToApply->UpdateNodeType(OtherNode->getExtTypes(), TP) | - OtherNode->UpdateNodeType(NodeToApply->getExtTypes(), TP); + return NodeToApply->UpdateNodeType(OtherNode->getExtType(), TP) | + OtherNode->UpdateNodeType(NodeToApply->getExtType(), TP); } case SDTCisVTSmallerThanOp: { // The NodeToApply must be a leaf node that is a VT. OtherOperandNum must @@ -321,78 +591,37 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, getOperandNum(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N,NumResults); // It must be integer. - bool MadeChange = OtherNode->UpdateNodeType(MVT::iAny, TP); - - // This code only handles nodes that have one type set. Assert here so - // that we can change this if we ever need to deal with multiple value - // types at this point. - assert(OtherNode->getExtTypes().size() == 1 && "Node has too many types!"); - if (OtherNode->hasTypeSet() && OtherNode->getTypeNum(0) <= VT) + bool MadeChange = OtherNode->getExtType().EnforceInteger(TP); + + // This doesn't try to enforce any information on the OtherNode, it just + // validates it when information is determined. + if (OtherNode->hasTypeSet() && OtherNode->getType() <= VT) OtherNode->UpdateNodeType(MVT::Other, TP); // Throw an error. return MadeChange; } case SDTCisOpSmallerThanOp: { TreePatternNode *BigOperand = getOperandNum(x.SDTCisOpSmallerThanOp_Info.BigOperandNum, N, NumResults); - - // Both operands must be integer or FP, but we don't care which. - bool MadeChange = false; - - // This code does not currently handle nodes which have multiple types, - // where some types are integer, and some are fp. Assert that this is not - // the case. - assert(!(EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes()) && - EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) && - !(EEVT::isExtIntegerInVTs(BigOperand->getExtTypes()) && - EEVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) && - "SDTCisOpSmallerThanOp does not handle mixed int/fp types!"); - if (EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) - MadeChange |= BigOperand->UpdateNodeType(MVT::iAny, TP); - else if (EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) - MadeChange |= BigOperand->UpdateNodeType(MVT::fAny, TP); - if (EEVT::isExtIntegerInVTs(BigOperand->getExtTypes())) - MadeChange |= NodeToApply->UpdateNodeType(MVT::iAny, TP); - else if (EEVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) - MadeChange |= NodeToApply->UpdateNodeType(MVT::fAny, TP); - - std::vector<MVT::SimpleValueType> VTs = CGT.getLegalValueTypes(); - - if (EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) { - VTs = FilterVTs(VTs, isInteger); - } else if (EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) { - VTs = FilterVTs(VTs, isFloatingPoint); - } else { - VTs.clear(); - } - - switch (VTs.size()) { - default: // Too many VT's to pick from. - case 0: break; // No info yet. - case 1: - // Only one VT of this flavor. Cannot ever satisfy the constraints. - return NodeToApply->UpdateNodeType(MVT::Other, TP); // throw - case 2: - // If we have exactly two possible types, the little operand must be the - // small one, the big operand should be the big one. Common with - // float/double for example. - assert(VTs[0] < VTs[1] && "Should be sorted!"); - MadeChange |= NodeToApply->UpdateNodeType(VTs[0], TP); - MadeChange |= BigOperand->UpdateNodeType(VTs[1], TP); - break; - } - return MadeChange; + return NodeToApply->getExtType(). + EnforceSmallerThan(BigOperand->getExtType(), TP); } case SDTCisEltOfVec: { - TreePatternNode *OtherOperand = - getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum, - N, NumResults); - if (OtherOperand->hasTypeSet()) { - if (!isVector(OtherOperand->getTypeNum(0))) + TreePatternNode *VecOperand = + getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum, N, NumResults); + if (VecOperand->hasTypeSet()) { + if (!isVector(VecOperand->getType())) TP.error(N->getOperator()->getName() + " VT operand must be a vector!"); - EVT IVT = OtherOperand->getTypeNum(0); + EVT IVT = VecOperand->getType(); IVT = IVT.getVectorElementType(); return NodeToApply->UpdateNodeType(IVT.getSimpleVT().SimpleTy, TP); } + + if (NodeToApply->hasTypeSet() && VecOperand->getExtType().hasVectorTypes()){ + // Filter vector types out of VecOperand that don't have the right element + // type. + return VecOperand->getExtType(). + EnforceVectorEltTypeIs(NodeToApply->getType(), TP); + } return false; } } @@ -482,133 +711,6 @@ TreePatternNode::~TreePatternNode() { #endif } -/// UpdateNodeType - Set the node type of N to VT if VT contains -/// information. If N already contains a conflicting type, then throw an -/// exception. This returns true if any information was updated. -/// -bool TreePatternNode::UpdateNodeType(const std::vector<unsigned char> &ExtVTs, - TreePattern &TP) { - assert(!ExtVTs.empty() && "Cannot update node type with empty type vector!"); - - if (ExtVTs[0] == EEVT::isUnknown || LHSIsSubsetOfRHS(getExtTypes(), ExtVTs)) - return false; - if (isTypeCompletelyUnknown() || LHSIsSubsetOfRHS(ExtVTs, getExtTypes())) { - setTypes(ExtVTs); - return true; - } - - if (getExtTypeNum(0) == MVT::iPTR || getExtTypeNum(0) == MVT::iPTRAny) { - if (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny || - ExtVTs[0] == MVT::iAny) - return false; - if (EEVT::isExtIntegerInVTs(ExtVTs)) { - std::vector<unsigned char> FVTs = FilterEVTs(ExtVTs, isInteger); - if (FVTs.size()) { - setTypes(ExtVTs); - return true; - } - } - } - - // Merge vAny with iAny/fAny. The latter include vector types so keep them - // as the more specific information. - if (ExtVTs[0] == MVT::vAny && - (getExtTypeNum(0) == MVT::iAny || getExtTypeNum(0) == MVT::fAny)) - return false; - if (getExtTypeNum(0) == MVT::vAny && - (ExtVTs[0] == MVT::iAny || ExtVTs[0] == MVT::fAny)) { - setTypes(ExtVTs); - return true; - } - - if (ExtVTs[0] == MVT::iAny && - EEVT::isExtIntegerInVTs(getExtTypes())) { - assert(hasTypeSet() && "should be handled above!"); - std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isInteger); - if (getExtTypes() == FVTs) - return false; - setTypes(FVTs); - return true; - } - if ((ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny) && - EEVT::isExtIntegerInVTs(getExtTypes())) { - //assert(hasTypeSet() && "should be handled above!"); - std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isInteger); - if (getExtTypes() == FVTs) - return false; - if (FVTs.size()) { - setTypes(FVTs); - return true; - } - } - if (ExtVTs[0] == MVT::fAny && - EEVT::isExtFloatingPointInVTs(getExtTypes())) { - assert(hasTypeSet() && "should be handled above!"); - std::vector<unsigned char> FVTs = - FilterEVTs(getExtTypes(), isFloatingPoint); - if (getExtTypes() == FVTs) - return false; - setTypes(FVTs); - return true; - } - if (ExtVTs[0] == MVT::vAny && - EEVT::isExtVectorInVTs(getExtTypes())) { - assert(hasTypeSet() && "should be handled above!"); - std::vector<unsigned char> FVTs = FilterEVTs(getExtTypes(), isVector); - if (getExtTypes() == FVTs) - return false; - setTypes(FVTs); - return true; - } - - // If we know this is an int, FP, or vector type, and we are told it is a - // specific one, take the advice. - // - // Similarly, we should probably set the type here to the intersection of - // {iAny|fAny|vAny} and ExtVTs - if ((getExtTypeNum(0) == MVT::iAny && - EEVT::isExtIntegerInVTs(ExtVTs)) || - (getExtTypeNum(0) == MVT::fAny && - EEVT::isExtFloatingPointInVTs(ExtVTs)) || - (getExtTypeNum(0) == MVT::vAny && - EEVT::isExtVectorInVTs(ExtVTs))) { - setTypes(ExtVTs); - return true; - } - if (getExtTypeNum(0) == MVT::iAny && - (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny)) { - setTypes(ExtVTs); - return true; - } - - if (isLeaf()) { - dump(); - errs() << " "; - TP.error("Type inference contradiction found in node!"); - } else { - TP.error("Type inference contradiction found in node " + - getOperator()->getName() + "!"); - } - return true; // unreachable -} - -static std::string GetTypeName(unsigned char TypeID) { - switch (TypeID) { - case MVT::Other: return "Other"; - case MVT::iAny: return "iAny"; - case MVT::fAny: return "fAny"; - case MVT::vAny: return "vAny"; - case EEVT::isUnknown: return "isUnknown"; - case MVT::iPTR: return "iPTR"; - case MVT::iPTRAny: return "iPTRAny"; - default: - std::string VTName = llvm::getName((MVT::SimpleValueType)TypeID); - // Strip off EVT:: prefix if present. - if (VTName.substr(0,5) == "MVT::") - VTName = VTName.substr(5); - return VTName; - } -} void TreePatternNode::print(raw_ostream &OS) const { @@ -618,10 +720,8 @@ void TreePatternNode::print(raw_ostream &OS) const { OS << '(' << getOperator()->getName(); } - // FIXME: At some point we should handle printing all the value types for - // nodes that are multiply typed. - if (getExtTypeNum(0) != EEVT::isUnknown) - OS << ':' << GetTypeName(getExtTypeNum(0)); + if (!isTypeCompletelyUnknown()) + OS << ':' << getExtType().getName(); if (!isLeaf()) { if (getNumChildren() != 0) { @@ -657,7 +757,7 @@ void TreePatternNode::dump() const { bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N, const MultipleUseVarSet &DepVars) const { if (N == this) return true; - if (N->isLeaf() != isLeaf() || getExtTypes() != N->getExtTypes() || + if (N->isLeaf() != isLeaf() || getExtType() != N->getExtType() || getPredicateFns() != N->getPredicateFns() || getTransformFn() != N->getTransformFn()) return false; @@ -695,7 +795,7 @@ TreePatternNode *TreePatternNode::clone() const { New = new TreePatternNode(getOperator(), CChildren); } New->setName(getName()); - New->setTypes(getExtTypes()); + New->setType(getExtType()); New->setPredicateFns(getPredicateFns()); New->setTransformFn(getTransformFn()); return New; @@ -703,7 +803,7 @@ TreePatternNode *TreePatternNode::clone() const { /// RemoveAllTypes - Recursively strip all the types of this tree. void TreePatternNode::RemoveAllTypes() { - removeTypes(); + setType(EEVT::TypeSet()); // Reset to unknown type. if (isLeaf()) return; for (unsigned i = 0, e = getNumChildren(); i != e; ++i) getChild(i)->RemoveAllTypes(); @@ -785,7 +885,7 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { } FragTree->setName(getName()); - FragTree->UpdateNodeType(getExtTypes(), TP); + FragTree->UpdateNodeType(getExtType(), TP); // Transfer in the old predicates. for (unsigned i = 0, e = getPredicateFns().size(); i != e; ++i) @@ -803,47 +903,40 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { /// type which should be applied to it. This will infer the type of register /// references from the register file information, for example. /// -static std::vector<unsigned char> getImplicitType(Record *R, bool NotRegisters, - TreePattern &TP) { - // Some common return values - std::vector<unsigned char> Unknown(1, EEVT::isUnknown); - std::vector<unsigned char> Other(1, MVT::Other); - - // Check to see if this is a register or a register class... +static EEVT::TypeSet getImplicitType(Record *R, bool NotRegisters, + TreePattern &TP) { + // Check to see if this is a register or a register class. if (R->isSubClassOf("RegisterClass")) { if (NotRegisters) - return Unknown; - const CodeGenRegisterClass &RC = - TP.getDAGPatterns().getTargetInfo().getRegisterClass(R); - return ConvertVTs(RC.getValueTypes()); + return EEVT::TypeSet(); // Unknown. + const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); + return EEVT::TypeSet(T.getRegisterClass(R).getValueTypes()); } else if (R->isSubClassOf("PatFrag")) { // Pattern fragment types will be resolved when they are inlined. - return Unknown; + return EEVT::TypeSet(); // Unknown. } else if (R->isSubClassOf("Register")) { if (NotRegisters) - return Unknown; + return EEVT::TypeSet(); // Unknown. const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); - return T.getRegisterVTs(R); + return EEVT::TypeSet(T.getRegisterVTs(R)); } else if (R->isSubClassOf("ValueType") || R->isSubClassOf("CondCode")) { // Using a VTSDNode or CondCodeSDNode. - return Other; + return EEVT::TypeSet(MVT::Other, TP); } else if (R->isSubClassOf("ComplexPattern")) { if (NotRegisters) - return Unknown; - std::vector<unsigned char> - ComplexPat(1, TP.getDAGPatterns().getComplexPattern(R).getValueType()); - return ComplexPat; + return EEVT::TypeSet(); // Unknown. + return EEVT::TypeSet(TP.getDAGPatterns().getComplexPattern(R).getValueType(), + TP); } else if (R->isSubClassOf("PointerLikeRegClass")) { - Other[0] = MVT::iPTR; - return Other; + return EEVT::TypeSet(MVT::iPTR, TP); } else if (R->getName() == "node" || R->getName() == "srcvalue" || R->getName() == "zero_reg") { // Placeholder. - return Unknown; + return EEVT::TypeSet(); // Unknown. } TP.error("Unknown node flavor used in pattern: " + R->getName()); - return Other; + return EEVT::TypeSet(MVT::Other, TP); } @@ -927,40 +1020,33 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { if (IntInit *II = dynamic_cast<IntInit*>(getLeafValue())) { // Int inits are always integers. :) - bool MadeChange = UpdateNodeType(MVT::iAny, TP); + bool MadeChange = Type.EnforceInteger(TP); - if (hasTypeSet()) { - // At some point, it may make sense for this tree pattern to have - // multiple types. Assert here that it does not, so we revisit this - // code when appropriate. - assert(getExtTypes().size() >= 1 && "TreePattern doesn't have a type!"); - MVT::SimpleValueType VT = getTypeNum(0); - for (unsigned i = 1, e = getExtTypes().size(); i != e; ++i) - assert(getTypeNum(i) == VT && "TreePattern has too many types!"); - - VT = getTypeNum(0); - if (VT != MVT::iPTR && VT != MVT::iPTRAny) { - unsigned Size = EVT(VT).getSizeInBits(); - // Make sure that the value is representable for this type. - if (Size < 32) { - int Val = (II->getValue() << (32-Size)) >> (32-Size); - if (Val != II->getValue()) { - // If sign-extended doesn't fit, does it fit as unsigned? - unsigned ValueMask; - unsigned UnsignedVal; - ValueMask = unsigned(~uint32_t(0UL) >> (32-Size)); - UnsignedVal = unsigned(II->getValue()); - - if ((ValueMask & UnsignedVal) != UnsignedVal) { - TP.error("Integer value '" + itostr(II->getValue())+ - "' is out of range for type '" + - getEnumName(getTypeNum(0)) + "'!"); - } - } - } - } - } + if (!hasTypeSet()) + return MadeChange; + + MVT::SimpleValueType VT = getType(); + if (VT == MVT::iPTR || VT == MVT::iPTRAny) + return MadeChange; + + unsigned Size = EVT(VT).getSizeInBits(); + // Make sure that the value is representable for this type. + if (Size >= 32) return MadeChange; + int Val = (II->getValue() << (32-Size)) >> (32-Size); + if (Val == II->getValue()) return MadeChange; + + // If sign-extended doesn't fit, does it fit as unsigned? + unsigned ValueMask; + unsigned UnsignedVal; + ValueMask = unsigned(~uint32_t(0UL) >> (32-Size)); + UnsignedVal = unsigned(II->getValue()); + + if ((ValueMask & UnsignedVal) == UnsignedVal) + return MadeChange; + + TP.error("Integer value '" + itostr(II->getValue())+ + "' is out of range for type '" + getEnumName(getType()) + "'!"); return MadeChange; } return false; @@ -976,11 +1062,9 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { MadeChange |= getChild(NC-1)->ApplyTypeConstraints(TP, NotRegisters); // Types of operands must match. - MadeChange |= getChild(i)->UpdateNodeType(getChild(NC-1)->getExtTypes(), - TP); - MadeChange |= getChild(NC-1)->UpdateNodeType(getChild(i)->getExtTypes(), - TP); - MadeChange |= UpdateNodeType(MVT::isVoid, TP); + MadeChange |=getChild(i)->UpdateNodeType(getChild(NC-1)->getExtType(),TP); + MadeChange |=getChild(NC-1)->UpdateNodeType(getChild(i)->getExtType(),TP); + MadeChange |=UpdateNodeType(MVT::isVoid, TP); } return MadeChange; } @@ -998,6 +1082,15 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { bool MadeChange = false; MadeChange |= getChild(0)->ApplyTypeConstraints(TP, NotRegisters); MadeChange |= getChild(1)->ApplyTypeConstraints(TP, NotRegisters); + + // child #1 of COPY_TO_REGCLASS should be a register class. We don't care + // what type it gets, so if it didn't get a concrete type just give it the + // first viable type from the reg class. + if (!getChild(1)->hasTypeSet() && + !getChild(1)->getExtType().isCompletelyUnknown()) { + MVT::SimpleValueType RCVT = getChild(1)->getExtType().getTypeList()[0]; + MadeChange |= getChild(1)->UpdateNodeType(RCVT, TP); + } return MadeChange; } @@ -1058,22 +1151,26 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { Record *ResultNode = Inst.getResult(0); if (ResultNode->isSubClassOf("PointerLikeRegClass")) { - std::vector<unsigned char> VT; - VT.push_back(MVT::iPTR); - MadeChange = UpdateNodeType(VT, TP); + MadeChange = UpdateNodeType(MVT::iPTR, TP); } else if (ResultNode->getName() == "unknown") { - std::vector<unsigned char> VT; - VT.push_back(EEVT::isUnknown); - MadeChange = UpdateNodeType(VT, TP); + // Nothing to do. } else { assert(ResultNode->isSubClassOf("RegisterClass") && "Operands should be register classes!"); const CodeGenRegisterClass &RC = CDP.getTargetInfo().getRegisterClass(ResultNode); - MadeChange = UpdateNodeType(ConvertVTs(RC.getValueTypes()), TP); + MadeChange = UpdateNodeType(RC.getValueTypes(), TP); } } + + // If this is an INSERT_SUBREG, constrain the source and destination VTs to + // be the same. + if (getOperator()->getName() == "INSERT_SUBREG") { + MadeChange |= UpdateNodeType(getChild(0)->getExtType(), TP); + MadeChange |= getChild(0)->UpdateNodeType(getExtType(), TP); + } + unsigned ChildNo = 0; for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) { @@ -1097,14 +1194,14 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { if (OperandNode->isSubClassOf("RegisterClass")) { const CodeGenRegisterClass &RC = CDP.getTargetInfo().getRegisterClass(OperandNode); - MadeChange |= Child->UpdateNodeType(ConvertVTs(RC.getValueTypes()), TP); + MadeChange |= Child->UpdateNodeType(RC.getValueTypes(), TP); } else if (OperandNode->isSubClassOf("Operand")) { VT = getValueType(OperandNode->getValueAsDef("Type")); MadeChange |= Child->UpdateNodeType(VT, TP); } else if (OperandNode->isSubClassOf("PointerLikeRegClass")) { MadeChange |= Child->UpdateNodeType(MVT::iPTR, TP); } else if (OperandNode->getName() == "unknown") { - MadeChange |= Child->UpdateNodeType(EEVT::isUnknown, TP); + // Nothing to do. } else { assert(0 && "Unknown operand type!"); abort(); @@ -1126,15 +1223,20 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { TP.error("Node transform '" + getOperator()->getName() + "' requires one operand!"); + bool MadeChange = getChild(0)->ApplyTypeConstraints(TP, NotRegisters); + + // If either the output or input of the xform does not have exact // type info. We assume they must be the same. Otherwise, it is perfectly // legal to transform from one type to a completely different type. +#if 0 if (!hasTypeSet() || !getChild(0)->hasTypeSet()) { - bool MadeChange = UpdateNodeType(getChild(0)->getExtTypes(), TP); - MadeChange |= getChild(0)->UpdateNodeType(getExtTypes(), TP); + bool MadeChange = UpdateNodeType(getChild(0)->getExtType(), TP); + MadeChange |= getChild(0)->UpdateNodeType(getExtType(), TP); return MadeChange; } - return false; +#endif + return MadeChange; } /// OnlyOnRHSOfCommutative - Return true if this value is only allowed on the @@ -1194,9 +1296,9 @@ bool TreePatternNode::canPatternMatch(std::string &Reason, TreePattern::TreePattern(Record *TheRec, ListInit *RawPat, bool isInput, CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){ - isInputPattern = isInput; - for (unsigned i = 0, e = RawPat->getSize(); i != e; ++i) - Trees.push_back(ParseTreePattern((DagInit*)RawPat->getElement(i))); + isInputPattern = isInput; + for (unsigned i = 0, e = RawPat->getSize(); i != e; ++i) + Trees.push_back(ParseTreePattern((DagInit*)RawPat->getElement(i))); } TreePattern::TreePattern(Record *TheRec, DagInit *Pat, bool isInput, @@ -1211,13 +1313,24 @@ TreePattern::TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput, Trees.push_back(Pat); } - - void TreePattern::error(const std::string &Msg) const { dump(); throw TGError(TheRecord->getLoc(), "In " + TheRecord->getName() + ": " + Msg); } +void TreePattern::ComputeNamedNodes() { + for (unsigned i = 0, e = Trees.size(); i != e; ++i) + ComputeNamedNodes(Trees[i]); +} + +void TreePattern::ComputeNamedNodes(TreePatternNode *N) { + if (!N->getName().empty()) + NamedNodes[N->getName()].push_back(N); + + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) + ComputeNamedNodes(N->getChild(i)); +} + TreePatternNode *TreePattern::ParseTreePattern(DagInit *Dag) { DefInit *OpDef = dynamic_cast<DefInit*>(Dag->getOperator()); if (!OpDef) error("Pattern has unexpected operator type!"); @@ -1373,12 +1486,58 @@ TreePatternNode *TreePattern::ParseTreePattern(DagInit *Dag) { /// InferAllTypes - Infer/propagate as many types throughout the expression /// patterns as possible. Return true if all types are inferred, false /// otherwise. Throw an exception if a type contradiction is found. -bool TreePattern::InferAllTypes() { +bool TreePattern:: +InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > *InNamedTypes) { + if (NamedNodes.empty()) + ComputeNamedNodes(); + bool MadeChange = true; while (MadeChange) { MadeChange = false; for (unsigned i = 0, e = Trees.size(); i != e; ++i) MadeChange |= Trees[i]->ApplyTypeConstraints(*this, false); + + // If there are constraints on our named nodes, apply them. + for (StringMap<SmallVector<TreePatternNode*,1> >::iterator + I = NamedNodes.begin(), E = NamedNodes.end(); I != E; ++I) { + SmallVectorImpl<TreePatternNode*> &Nodes = I->second; + + // If we have input named node types, propagate their types to the named + // values here. + if (InNamedTypes) { + // FIXME: Should be error? + assert(InNamedTypes->count(I->getKey()) && + "Named node in output pattern but not input pattern?"); + + const SmallVectorImpl<TreePatternNode*> &InNodes = + InNamedTypes->find(I->getKey())->second; + + // The input types should be fully resolved by now. + for (unsigned i = 0, e = Nodes.size(); i != e; ++i) { + // If this node is a register class, and it is the root of the pattern + // then we're mapping something onto an input register. We allow + // changing the type of the input register in this case. This allows + // us to match things like: + // def : Pat<(v1i64 (bitconvert(v2i32 DPR:$src))), (v1i64 DPR:$src)>; + if (Nodes[i] == Trees[0] && Nodes[i]->isLeaf()) { + DefInit *DI = dynamic_cast<DefInit*>(Nodes[i]->getLeafValue()); + if (DI && DI->getDef()->isSubClassOf("RegisterClass")) + continue; + } + + MadeChange |=Nodes[i]->UpdateNodeType(InNodes[0]->getExtType(),*this); + } + } + + // If there are multiple nodes with the same name, they must all have the + // same type. + if (I->second.size() > 1) { + for (unsigned i = 0, e = Nodes.size()-1; i != e; ++i) { + MadeChange |=Nodes[i]->UpdateNodeType(Nodes[i+1]->getExtType(),*this); + MadeChange |=Nodes[i+1]->UpdateNodeType(Nodes[i]->getExtType(),*this); + } + } + } } bool HasUnresolvedTypes = false; @@ -1673,7 +1832,7 @@ static bool HandleUse(TreePattern *I, TreePatternNode *Pat, // Ensure that the inputs agree if we've already seen this input. if (Rec != SlotRec) I->error("All $" + Pat->getName() + " inputs must agree with each other"); - if (Slot->getExtTypes() != Pat->getExtTypes()) + if (Slot->getExtType() != Pat->getExtType()) I->error("All $" + Pat->getName() + " inputs must agree with each other"); return true; } @@ -1712,7 +1871,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, // If this is not a set, verify that the children nodes are not void typed, // and recurse. for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) { - if (Pat->getChild(i)->getExtTypeNum(0) == MVT::isVoid) + if (Pat->getChild(i)->getType() == MVT::isVoid) I->error("Cannot have void nodes inside of patterns!"); FindPatternInputsAndOutputs(I, Pat->getChild(i), InstInputs, InstResults, InstImpInputs, InstImpResults); @@ -1960,7 +2119,7 @@ void CodeGenDAGPatterns::ParseInstructions() { // fill in the InstResults map. for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) { TreePatternNode *Pat = I->getTree(j); - if (Pat->getExtTypeNum(0) != MVT::isVoid) + if (!Pat->hasTypeSet() || Pat->getType() != MVT::isVoid) I->error("Top-level forms in instruction pattern should have" " void types"); @@ -2072,7 +2231,7 @@ void CodeGenDAGPatterns::ParseInstructions() { new TreePatternNode(I->getRecord(), ResultNodeOperands); // Copy fully inferred output node type to instruction result pattern. if (NumResults > 0) - ResultPattern->setTypes(Res0Node->getExtTypes()); + ResultPattern->setType(Res0Node->getExtType()); // Create and insert the instruction. // FIXME: InstImpResults and InstImpInputs should not be part of @@ -2084,7 +2243,7 @@ void CodeGenDAGPatterns::ParseInstructions() { // constructed result is correct. This depends on the instruction already // being inserted into the Instructions map. TreePattern Temp(I->getRecord(), ResultPattern, false, *this); - Temp.InferAllTypes(); + Temp.InferAllTypes(&I->getNamedNodesMap()); DAGInstruction &TheInsertedInst = Instructions.find(I->getRecord())->second; TheInsertedInst.setResultPattern(Temp.getOnlyTree()); @@ -2133,7 +2292,7 @@ static void FindNames(const TreePatternNode *P, // If this is the first instance of the name, remember the node. if (Rec.second++ == 0) Rec.first = P; - else if (Rec.first->getExtTypes() != P->getExtTypes()) + else if (Rec.first->getType() != P->getType()) PatternTop->error("repetition of value: $" + P->getName() + " where different uses have different types!"); } @@ -2173,24 +2332,6 @@ void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern, if (SrcNames[I->first].first == 0) Pattern->error("Pattern has input without matching name in output: $" + I->first); - -#if 0 - const std::vector<unsigned char> &SrcTypeVec = - SrcNames[I->first].first->getExtTypes(); - const std::vector<unsigned char> &DstTypeVec = - I->second.first->getExtTypes(); - if (SrcTypeVec == DstTypeVec) continue; - - std::string SrcType, DstType; - for (unsigned i = 0, e = SrcTypeVec.size(); i != e; ++i) - SrcType += ":" + GetTypeName(SrcTypeVec[i]); - for (unsigned i = 0, e = DstTypeVec.size(); i != e; ++i) - DstType += ":" + GetTypeName(DstTypeVec[i]); - - Pattern->error("Variable $" + I->first + - " has different types in source (" + SrcType + - ") and dest (" + DstType + ") pattern!"); -#endif } // Scan all of the named values in the source pattern, rejecting them if the @@ -2220,6 +2361,30 @@ void CodeGenDAGPatterns::InferInstructionFlags() { } } +/// Given a pattern result with an unresolved type, see if we can find one +/// instruction with an unresolved result type. Force this result type to an +/// arbitrary element if it's possible types to converge results. +static bool ForceArbitraryInstResultType(TreePatternNode *N, TreePattern &TP) { + if (N->isLeaf()) + return false; + + // Analyze children. + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) + if (ForceArbitraryInstResultType(N->getChild(i), TP)) + return true; + + if (!N->getOperator()->isSubClassOf("Instruction")) + return false; + + // If this type is already concrete or completely unknown we can't do + // anything. + if (N->getExtType().isCompletelyUnknown() || N->getExtType().isConcrete()) + return false; + + // Otherwise, force its type to the first possibility (an arbitrary choice). + return N->getExtType().MergeInTypeInfo(N->getExtType().getTypeList()[0], TP); +} + void CodeGenDAGPatterns::ParsePatterns() { std::vector<Record*> Patterns = Records.getAllDerivedDefinitions("Pattern"); @@ -2278,28 +2443,47 @@ void CodeGenDAGPatterns::ParsePatterns() { do { // Infer as many types as possible. If we cannot infer all of them, we // can never do anything with this pattern: report it to the user. - InferredAllPatternTypes = Pattern->InferAllTypes(); + InferredAllPatternTypes = + Pattern->InferAllTypes(&Pattern->getNamedNodesMap()); // Infer as many types as possible. If we cannot infer all of them, we // can never do anything with this pattern: report it to the user. - InferredAllResultTypes = Result->InferAllTypes(); + InferredAllResultTypes = + Result->InferAllTypes(&Pattern->getNamedNodesMap()); // Apply the type of the result to the source pattern. This helps us // resolve cases where the input type is known to be a pointer type (which // is considered resolved), but the result knows it needs to be 32- or // 64-bits. Infer the other way for good measure. IterateInference = Pattern->getTree(0)-> - UpdateNodeType(Result->getTree(0)->getExtTypes(), *Result); + UpdateNodeType(Result->getTree(0)->getExtType(), *Result); IterateInference |= Result->getTree(0)-> - UpdateNodeType(Pattern->getTree(0)->getExtTypes(), *Result); + UpdateNodeType(Pattern->getTree(0)->getExtType(), *Result); + + // If our iteration has converged and the input pattern's types are fully + // resolved but the result pattern is not fully resolved, we may have a + // situation where we have two instructions in the result pattern and + // the instructions require a common register class, but don't care about + // what actual MVT is used. This is actually a bug in our modelling: + // output patterns should have register classes, not MVTs. + // + // In any case, to handle this, we just go through and disambiguate some + // arbitrary types to the result pattern's nodes. + if (!IterateInference && InferredAllPatternTypes && + !InferredAllResultTypes) + IterateInference = ForceArbitraryInstResultType(Result->getTree(0), + *Result); + } while (IterateInference); // Verify that we inferred enough types that we can do something with the // pattern and result. If these fire the user has to add type casts. if (!InferredAllPatternTypes) Pattern->error("Could not infer all types in pattern!"); - if (!InferredAllResultTypes) + if (!InferredAllResultTypes) { + Pattern->dump(); Result->error("Could not infer all types in pattern result!"); + } // Validate that the input pattern is correct. std::map<std::string, TreePatternNode*> InstInputs; @@ -2328,7 +2512,7 @@ void CodeGenDAGPatterns::ParsePatterns() { if (!DstPattern->isLeaf()) DstPattern = new TreePatternNode(DstPattern->getOperator(), ResultNodeOperands); - DstPattern->setTypes(Result->getOnlyTree()->getExtTypes()); + DstPattern->setType(Result->getOnlyTree()->getExtType()); TreePattern Temp(Result->getRecord(), DstPattern, false, *this); Temp.InferAllTypes(); @@ -2378,7 +2562,7 @@ static void CombineChildVariants(TreePatternNode *Orig, R->setName(Orig->getName()); R->setPredicateFns(Orig->getPredicateFns()); R->setTransformFn(Orig->getTransformFn()); - R->setTypes(Orig->getExtTypes()); + R->setType(Orig->getExtType()); // If this pattern cannot match, do not include it as a variant. std::string ErrString; diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h index 37d633ecc21d..44f82fe68469 100644 --- a/utils/TableGen/CodeGenDAGPatterns.h +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -21,6 +21,8 @@ #include "CodeGenTarget.h" #include "CodeGenIntrinsics.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" namespace llvm { class Record; @@ -40,20 +42,99 @@ namespace llvm { /// value is needed. namespace EEVT { enum DAGISelGenValueType { + // FIXME: Remove EEVT::isUnknown! isUnknown = MVT::LAST_VALUETYPE }; + + /// TypeSet - This is either empty if it's completely unknown, or holds a set + /// of types. It is used during type inference because register classes can + /// have multiple possible types and we don't know which one they get until + /// type inference is complete. + /// + /// TypeSet can have three states: + /// Vector is empty: The type is completely unknown, it can be any valid + /// target type. + /// Vector has multiple constrained types: (e.g. v4i32 + v4f32) it is one + /// of those types only. + /// Vector has one concrete type: The type is completely known. + /// + class TypeSet { + SmallVector<MVT::SimpleValueType, 2> TypeVec; + public: + TypeSet() {} + TypeSet(MVT::SimpleValueType VT, TreePattern &TP); + TypeSet(const std::vector<MVT::SimpleValueType> &VTList); + + bool isCompletelyUnknown() const { return TypeVec.empty(); } + + bool isConcrete() const { + if (TypeVec.size() != 1) return false; + unsigned char T = TypeVec[0]; (void)T; + assert(T < MVT::LAST_VALUETYPE || T == MVT::iPTR || T == MVT::iPTRAny); + return true; + } + + MVT::SimpleValueType getConcrete() const { + assert(isConcrete() && "Type isn't concrete yet"); + return (MVT::SimpleValueType)TypeVec[0]; + } + + bool isDynamicallyResolved() const { + return getConcrete() == MVT::iPTR || getConcrete() == MVT::iPTRAny; + } + + const SmallVectorImpl<MVT::SimpleValueType> &getTypeList() const { + assert(!TypeVec.empty() && "Not a type list!"); + return TypeVec; + } + + /// hasIntegerTypes - Return true if this TypeSet contains any integer value + /// types. + bool hasIntegerTypes() const; + + /// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or + /// a floating point value type. + bool hasFloatingPointTypes() const; + + /// hasVectorTypes - Return true if this TypeSet contains a vector value + /// type. + bool hasVectorTypes() const; + + /// getName() - Return this TypeSet as a string. + std::string getName() const; + + /// MergeInTypeInfo - This merges in type information from the specified + /// argument. If 'this' changes, it returns true. If the two types are + /// contradictory (e.g. merge f32 into i32) then this throws an exception. + bool MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP); + + bool MergeInTypeInfo(MVT::SimpleValueType InVT, TreePattern &TP) { + return MergeInTypeInfo(EEVT::TypeSet(InVT, TP), TP); + } + + /// Force this type list to only contain integer types. + bool EnforceInteger(TreePattern &TP); + + /// Force this type list to only contain floating point types. + bool EnforceFloatingPoint(TreePattern &TP); - /// isExtIntegerInVTs - Return true if the specified extended value type - /// vector contains iAny or an integer value type. - bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs); + /// EnforceScalar - Remove all vector types from this type list. + bool EnforceScalar(TreePattern &TP); - /// isExtFloatingPointInVTs - Return true if the specified extended value - /// type vector contains fAny or a FP value type. - bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs); + /// EnforceVector - Remove all non-vector types from this type list. + bool EnforceVector(TreePattern &TP); - /// isExtVectorinVTs - Return true if the specified extended value type - /// vector contains vAny or a vector value type. - bool isExtVectorInVTs(const std::vector<unsigned char> &EVTs); + /// EnforceSmallerThan - 'this' must be a smaller VT than Other. Update + /// this an other based on this information. + bool EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP); + + /// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type + /// whose element is VT. + bool EnforceVectorEltTypeIs(MVT::SimpleValueType VT, TreePattern &TP); + + bool operator!=(const TypeSet &RHS) const { return TypeVec != RHS.TypeVec; } + bool operator==(const TypeSet &RHS) const { return TypeVec == RHS.TypeVec; } + }; } /// Set type used to track multiply used variables in patterns @@ -72,7 +153,7 @@ struct SDTypeConstraint { union { // The discriminated union. struct { - unsigned char VT; + MVT::SimpleValueType VT; } SDTCisVT_Info; struct { unsigned OtherOperandNum; @@ -150,10 +231,10 @@ public: /// patterns), and as such should be ref counted. We currently just leak all /// TreePatternNode objects! class TreePatternNode { - /// The inferred type for this node, or EEVT::isUnknown if it hasn't - /// been determined yet. This is a std::vector because during inference - /// there may be multiple possible types. - std::vector<unsigned char> Types; + /// The type of this node. Before and during type inference, this may be a + /// set of possible types. After (successful) type inference, this is a + /// single type. + EEVT::TypeSet Type; /// Operator - The Record for the operator if this is an interior node (not /// a leaf). @@ -178,11 +259,9 @@ class TreePatternNode { std::vector<TreePatternNode*> Children; public: TreePatternNode(Record *Op, const std::vector<TreePatternNode*> &Ch) - : Types(), Operator(Op), Val(0), TransformFn(0), - Children(Ch) { Types.push_back(EEVT::isUnknown); } + : Operator(Op), Val(0), TransformFn(0), Children(Ch) { } TreePatternNode(Init *val) // leaf ctor - : Types(), Operator(0), Val(val), TransformFn(0) { - Types.push_back(EEVT::isUnknown); + : Operator(0), Val(val), TransformFn(0) { } ~TreePatternNode(); @@ -190,28 +269,16 @@ public: void setName(const std::string &N) { Name = N; } bool isLeaf() const { return Val != 0; } - bool hasTypeSet() const { - return (Types[0] < MVT::LAST_VALUETYPE) || (Types[0] == MVT::iPTR) || - (Types[0] == MVT::iPTRAny); - } - bool isTypeCompletelyUnknown() const { - return Types[0] == EEVT::isUnknown; - } - bool isTypeDynamicallyResolved() const { - return (Types[0] == MVT::iPTR) || (Types[0] == MVT::iPTRAny); - } - MVT::SimpleValueType getTypeNum(unsigned Num) const { - assert(hasTypeSet() && "Doesn't have a type yet!"); - assert(Types.size() > Num && "Type num out of range!"); - return (MVT::SimpleValueType)Types[Num]; - } - unsigned char getExtTypeNum(unsigned Num) const { - assert(Types.size() > Num && "Extended type num out of range!"); - return Types[Num]; - } - const std::vector<unsigned char> &getExtTypes() const { return Types; } - void setTypes(const std::vector<unsigned char> &T) { Types = T; } - void removeTypes() { Types = std::vector<unsigned char>(1, EEVT::isUnknown); } + + // Type accessors. + MVT::SimpleValueType getType() const { return Type.getConcrete(); } + const EEVT::TypeSet &getExtType() const { return Type; } + EEVT::TypeSet &getExtType() { return Type; } + void setType(const EEVT::TypeSet &T) { Type = T; } + + bool hasTypeSet() const { return Type.isConcrete(); } + bool isTypeCompletelyUnknown() const { return Type.isCompletelyUnknown(); } + bool isTypeDynamicallyResolved() const { return Type.isDynamicallyResolved();} Init *getLeafValue() const { assert(isLeaf()); return Val; } Record *getOperator() const { assert(!isLeaf()); return Operator; } @@ -304,17 +371,18 @@ public: // Higher level manipulation routines. /// information. If N already contains a conflicting type, then throw an /// exception. This returns true if any information was updated. /// - bool UpdateNodeType(const std::vector<unsigned char> &ExtVTs, - TreePattern &TP); - bool UpdateNodeType(unsigned char ExtVT, TreePattern &TP) { - std::vector<unsigned char> ExtVTs(1, ExtVT); - return UpdateNodeType(ExtVTs, TP); + bool UpdateNodeType(const EEVT::TypeSet &InTy, TreePattern &TP) { + return Type.MergeInTypeInfo(InTy, TP); + } + + bool UpdateNodeType(MVT::SimpleValueType InTy, TreePattern &TP) { + return Type.MergeInTypeInfo(EEVT::TypeSet(InTy, TP), TP); } /// ContainsUnresolvedType - Return true if this tree contains any /// unresolved types. bool ContainsUnresolvedType() const { - if (!hasTypeSet() && !isTypeDynamicallyResolved()) return true; + if (!hasTypeSet()) return true; for (unsigned i = 0, e = getNumChildren(); i != e; ++i) if (getChild(i)->ContainsUnresolvedType()) return true; return false; @@ -340,6 +408,10 @@ class TreePattern { /// std::vector<TreePatternNode*> Trees; + /// NamedNodes - This is all of the nodes that have names in the trees in this + /// pattern. + StringMap<SmallVector<TreePatternNode*,1> > NamedNodes; + /// TheRecord - The actual TableGen record corresponding to this pattern. /// Record *TheRecord; @@ -375,6 +447,12 @@ public: assert(Trees.size() == 1 && "Doesn't have exactly one pattern!"); return Trees[0]; } + + const StringMap<SmallVector<TreePatternNode*,1> > &getNamedNodesMap() { + if (NamedNodes.empty()) + ComputeNamedNodes(); + return NamedNodes; + } /// getRecord - Return the actual TableGen record corresponding to this /// pattern. @@ -401,7 +479,8 @@ public: /// InferAllTypes - Infer/propagate as many types throughout the expression /// patterns as possible. Return true if all types are inferred, false /// otherwise. Throw an exception if a type contradiction is found. - bool InferAllTypes(); + bool InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> > + *NamedTypes=0); /// error - Throw an exception, prefixing it with information about this /// pattern. @@ -412,6 +491,8 @@ public: private: TreePatternNode *ParseTreePattern(DagInit *DI); + void ComputeNamedNodes(); + void ComputeNamedNodes(TreePatternNode *N); }; /// DAGDefaultOperand - One of these is created for each PredicateOperand diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index 2688091359ad..ec6a31fd195f 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -184,16 +184,16 @@ void CodeGenTarget::ReadRegisterClasses() const { RegisterClasses.assign(RegClasses.begin(), RegClasses.end()); } -std::vector<unsigned char> CodeGenTarget::getRegisterVTs(Record *R) const { - std::vector<unsigned char> Result; +std::vector<MVT::SimpleValueType> CodeGenTarget:: +getRegisterVTs(Record *R) const { + std::vector<MVT::SimpleValueType> Result; const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses(); for (unsigned i = 0, e = RCs.size(); i != e; ++i) { const CodeGenRegisterClass &RC = RegisterClasses[i]; for (unsigned ei = 0, ee = RC.Elements.size(); ei != ee; ++ei) { if (R == RC.Elements[ei]) { const std::vector<MVT::SimpleValueType> &InVTs = RC.getValueTypes(); - for (unsigned i = 0, e = InVTs.size(); i != e; ++i) - Result.push_back(InVTs[i]); + Result.insert(Result.end(), InVTs.begin(), InVTs.end()); } } } diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h index 07bc54d28daa..1df74af36220 100644 --- a/utils/TableGen/CodeGenTarget.h +++ b/utils/TableGen/CodeGenTarget.h @@ -167,7 +167,7 @@ public: /// getRegisterVTs - Find the union of all possible SimpleValueTypes for the /// specified physical register. - std::vector<unsigned char> getRegisterVTs(Record *R) const; + std::vector<MVT::SimpleValueType> getRegisterVTs(Record *R) const; const std::vector<MVT::SimpleValueType> &getLegalValueTypes() const { if (LegalValueTypes.empty()) ReadLegalValueTypes(); diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp index e0fa7c82f8cb..73feac165120 100644 --- a/utils/TableGen/DAGISelEmitter.cpp +++ b/utils/TableGen/DAGISelEmitter.cpp @@ -25,13 +25,7 @@ using namespace llvm; /// patterns before small ones. This is used to determine the size of a /// pattern. static unsigned getPatternSize(TreePatternNode *P, CodeGenDAGPatterns &CGP) { - assert((EEVT::isExtIntegerInVTs(P->getExtTypes()) || - EEVT::isExtFloatingPointInVTs(P->getExtTypes()) || - P->getExtTypeNum(0) == MVT::isVoid || - P->getExtTypeNum(0) == MVT::Flag || - P->getExtTypeNum(0) == MVT::iPTR || - P->getExtTypeNum(0) == MVT::iPTRAny) && - "Not a valid pattern node to size!"); + assert(P->hasTypeSet() && "Not a valid pattern node to size!"); unsigned Size = 3; // The node itself. // If the root node is a ConstantSDNode, increases its size. // e.g. (set R32:$dst, 0). @@ -55,7 +49,7 @@ static unsigned getPatternSize(TreePatternNode *P, CodeGenDAGPatterns &CGP) { // Count children in the count if they are also nodes. for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) { TreePatternNode *Child = P->getChild(i); - if (!Child->isLeaf() && Child->getExtTypeNum(0) != MVT::Other) + if (!Child->isLeaf() && Child->getType() != MVT::Other) Size += getPatternSize(Child, CGP); else if (Child->isLeaf()) { if (dynamic_cast<IntInit*>(Child->getLeafValue())) diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp index 4951a425d94d..375df6b210a5 100644 --- a/utils/TableGen/DAGISelMatcherGen.cpp +++ b/utils/TableGen/DAGISelMatcherGen.cpp @@ -408,11 +408,11 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N, // If N and NodeNoTypes don't agree on a type, then this is a case where we // need to do a type check. Emit the check, apply the tyep to NodeNoTypes and // reinfer any correlated types. - unsigned NodeType = EEVT::isUnknown; - if (NodeNoTypes->getExtTypes() != N->getExtTypes()) { - NodeType = N->getTypeNum(0); - NodeNoTypes->setTypes(N->getExtTypes()); + bool DoTypeCheck = false; + if (NodeNoTypes->getExtType() != N->getExtType()) { + NodeNoTypes->setType(N->getExtType()); InferPossibleTypes(); + DoTypeCheck = true; } // If this node has a name associated with it, capture it in VariableMap. If @@ -442,8 +442,8 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N, for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i) AddMatcher(new CheckPredicateMatcher(N->getPredicateFns()[i])); - if (NodeType != EEVT::isUnknown) - AddMatcher(new CheckTypeMatcher((MVT::SimpleValueType)NodeType)); + if (DoTypeCheck) + AddMatcher(new CheckTypeMatcher(N->getType())); } /// EmitMatcherCode - Generate the code that matches the predicate of this @@ -567,7 +567,7 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N, assert(N->isLeaf() && "Must be a leaf"); if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) { - AddMatcher(new EmitIntegerMatcher(II->getValue(),N->getTypeNum(0))); + AddMatcher(new EmitIntegerMatcher(II->getValue(), N->getType())); ResultOps.push_back(NextRecordedOperandNo++); return; } @@ -575,14 +575,13 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N, // If this is an explicit register reference, handle it. if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) { if (DI->getDef()->isSubClassOf("Register")) { - AddMatcher(new EmitRegisterMatcher(DI->getDef(), - N->getTypeNum(0))); + AddMatcher(new EmitRegisterMatcher(DI->getDef(), N->getType())); ResultOps.push_back(NextRecordedOperandNo++); return; } if (DI->getDef()->getName() == "zero_reg") { - AddMatcher(new EmitRegisterMatcher(0, N->getTypeNum(0))); + AddMatcher(new EmitRegisterMatcher(0, N->getType())); ResultOps.push_back(NextRecordedOperandNo++); return; } @@ -709,10 +708,10 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, // Determine the result types. SmallVector<MVT::SimpleValueType, 4> ResultVTs; - if (NumResults != 0 && N->getTypeNum(0) != MVT::isVoid) { + if (NumResults != 0 && N->getType() != MVT::isVoid) { // FIXME2: If the node has multiple results, we should add them. For now, // preserve existing behavior?! - ResultVTs.push_back(N->getTypeNum(0)); + ResultVTs.push_back(N->getType()); } diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp index 910c4c5d697e..820ab63c1fa7 100644 --- a/utils/TableGen/DAGISelMatcherOpt.cpp +++ b/utils/TableGen/DAGISelMatcherOpt.cpp @@ -44,11 +44,13 @@ static void ContractNodes(OwningPtr<Matcher> &MatcherPtr, if (MoveChildMatcher *MC = dyn_cast<MoveChildMatcher>(N)) { Matcher *New = 0; if (RecordMatcher *RM = dyn_cast<RecordMatcher>(MC->getNext())) - New = new RecordChildMatcher(MC->getChildNo(), RM->getWhatFor(), - RM->getResultNo()); + if (MC->getChildNo() < 8) // Only have RecordChild0...7 + New = new RecordChildMatcher(MC->getChildNo(), RM->getWhatFor(), + RM->getResultNo()); if (CheckTypeMatcher *CT= dyn_cast<CheckTypeMatcher>(MC->getNext())) - New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType()); + if (MC->getChildNo() < 8) // Only have CheckChildType0...7 + New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType()); if (New) { // Insert the new node. diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp index 9aad2f609b48..214941071ebb 100644 --- a/utils/TableGen/EDEmitter.cpp +++ b/utils/TableGen/EDEmitter.cpp @@ -266,9 +266,11 @@ static int X86FlagFromOpName(FlagsConstantEmitter *flags, REG("GR16"); REG("GR32"); REG("GR32_NOREX"); + REG("GR32_TC"); REG("FR32"); REG("RFP32"); REG("GR64"); + REG("GR64_TC"); REG("FR64"); REG("VR64"); REG("RFP64"); @@ -284,11 +286,13 @@ static int X86FlagFromOpName(FlagsConstantEmitter *flags, MEM("i8mem_NOREX"); MEM("i16mem"); MEM("i32mem"); + MEM("i32mem_TC"); MEM("f32mem"); MEM("ssmem"); MEM("opaque32mem"); MEM("opaque48mem"); MEM("i64mem"); + MEM("i64mem_TC"); MEM("f64mem"); MEM("sdmem"); MEM("f80mem"); diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index f589bcc9e459..b94ded645261 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -73,10 +73,9 @@ struct OperandsSignature { if (!Op->getPredicateFns().empty()) return false; // For now, filter out any operand with multiple values. - if (Op->getExtTypes().size() != 1) - return false; + assert(Op->hasTypeSet() && "Type infererence not done?"); // For now, all the operands must have the same type. - if (Op->getTypeNum(0) != VT) + if (Op->getType() != VT) return false; if (!Op->isLeaf()) { if (Op->getOperator()->getName() == "imm") { @@ -296,10 +295,10 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { Record *InstPatOp = InstPatNode->getOperator(); std::string OpcodeName = getOpcodeName(InstPatOp, CGP); - MVT::SimpleValueType RetVT = InstPatNode->getTypeNum(0); + MVT::SimpleValueType RetVT = InstPatNode->getType(); MVT::SimpleValueType VT = RetVT; if (InstPatNode->getNumChildren()) - VT = InstPatNode->getChild(0)->getTypeNum(0); + VT = InstPatNode->getChild(0)->getType(); // For now, filter out instructions which just set a register to // an Operand or an immediate, like MOV32ri. diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index ea78d4193eaf..d71252caf274 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -298,6 +298,7 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { Name.find("_int") != Name.npos || Name.find("Int_") != Name.npos || Name.find("_NOREX") != Name.npos || + Name.find("_TC") != Name.npos || Name.find("EH_RETURN") != Name.npos || Name.find("V_SET") != Name.npos || Name.find("LOCK_") != Name.npos || diff --git a/utils/lit/lit/TestFormats.py b/utils/lit/lit/TestFormats.py index d87a467559c2..6ab3f9c4626d 100644 --- a/utils/lit/lit/TestFormats.py +++ b/utils/lit/lit/TestFormats.py @@ -72,6 +72,14 @@ class GoogleTest(object): testName = os.path.join(namePrefix, testName) cmd = [testPath, '--gtest_filter=' + testName] + if litConfig.useValgrind: + valgrindArgs = ['valgrind', '-q', + '--tool=memcheck', '--trace-children=yes', + '--error-exitcode=123'] + valgrindArgs.extend(litConfig.valgrindArgs) + + cmd = valgrindArgs + cmd + out, err, exitCode = TestRunner.executeCommand( cmd, env=test.config.environment) diff --git a/utils/mkpatch b/utils/mkpatch index 278a241018fa..2741563f041c 100755 --- a/utils/mkpatch +++ b/utils/mkpatch @@ -23,7 +23,7 @@ echo "mkpatch: Generating differences on all directories" svn diff -x -u >> "$NAME".patch.raw 2>&1 \ autoconf docs utils include lib/System lib/Support lib/VMCore lib/AsmParser \ lib/Bitcode lib/Analysis lib/Transforms lib/CodeGen lib/Target \ - lib/ExecutionEngine lib/Linker \ + lib/ExecutionEngine lib/Linker lib/MC \ tools test unittests runtime projects examples Xcode echo "mkpatch: Removing cruft from the patch file" |